• 内核中的信号量


    自旋锁属于忙等待,信号量允许进程进入睡眠状态。

    特点

    • 允许任意数量的锁持有者,在信号量初始化时自定义,初始化信号量时,val > 1时,表示在同一时刻可以被val内核路径持有。
    • 当val = 1时,叫做互斥信号量或者二进制信号量,同一时刻只能被一个内核路径持有。
    • 适用于情况比较复杂,加锁时间比较长的场景。

    信号量在内核中的数据结构

    //include/linux/semaphore.h
    /* Please don't access any members of this structure directly */
    struct semaphore {
    	raw_spinlock_t		lock;
    	unsigned int		count;
    	struct list_head	wait_list;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • lock 是自旋锁变量,保护结构体内count和wait_list成员。
    • count 允许进入临界区内核执行路径的个数。
    • wait_list 用于管理所有在该信号量上睡眠的进程,没有成功获取锁的进程会在这个链表上睡眠。

    信号量的初始化

    //include/linux/semaphore.h
    #define __SEMAPHORE_INITIALIZER(name, n)				\
    {									\
    	.lock		= __RAW_SPIN_LOCK_UNLOCKED((name).lock),	\
    	.count		= n,						\
    	.wait_list	= LIST_HEAD_INIT((name).wait_list),		\
    }
    
    #define DEFINE_SEMAPHORE(name)	\
    	struct semaphore name = __SEMAPHORE_INITIALIZER(name, 1)
    
    static inline void sema_init(struct semaphore *sem, int val)
    {
    	static struct lock_class_key __key;
    	*sem = (struct semaphore) __SEMAPHORE_INITIALIZER(*sem, val);
    	lockdep_init_map(&sem->lock.dep_map, "semaphore->lock", &__key, 0);
    }
    
    extern void down(struct semaphore *sem);
    extern int __must_check down_interruptible(struct semaphore *sem);
    extern int __must_check down_killable(struct semaphore *sem);
    extern int __must_check down_trylock(struct semaphore *sem);
    extern int __must_check down_timeout(struct semaphore *sem, long jiffies);
    extern void up(struct semaphore *sem);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    sema_init用于信号量的初始化,第一个参数为指向semaphore结构体指针,第二个参数为允许进入临界区的内核执行路径的个数。

    获取信号量

    /**
     * down - acquire the semaphore
     * @sem: the semaphore to be acquired
     *
     * Acquires the semaphore.  If no more tasks are allowed to acquire the
     * semaphore, calling this function will put the task to sleep until the
     * semaphore is released.
     *
     * Use of this function is deprecated, please use down_interruptible() or
     * down_killable() instead.
     */
    void down(struct semaphore *sem)
    {
    	unsigned long flags;
    
    	might_sleep();
    	raw_spin_lock_irqsave(&sem->lock, flags);
    	if (likely(sem->count > 0))
    		sem->count--;
    	else
    		__down(sem);
    	raw_spin_unlock_irqrestore(&sem->lock, flags);
    }
    EXPORT_SYMBOL(down);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • down 使用该函数使得争用该信号量的进程进入不可中断睡眠状态。
    • down_interruptible 使用该函数使得争用该信号量的进程进入可中断睡眠状态。
    • down_trylock 尝试获取锁,返回0表示成功获取锁,返回1表示获取锁失败。

    释放信号量

    /**
     * up - release the semaphore
     * @sem: the semaphore to release
     *
     * Release the semaphore.  Unlike mutexes, up() may be called from any
     * context and even by tasks which have never called down().
     */
    void up(struct semaphore *sem)
    {
    	unsigned long flags;
    
    	raw_spin_lock_irqsave(&sem->lock, flags);
    	if (likely(list_empty(&sem->wait_list)))
    		sem->count++;
    	else
    		__up(sem);
    	raw_spin_unlock_irqrestore(&sem->lock, flags);
    }
    EXPORT_SYMBOL(up);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    其他函数说明

    /**
     * down_timeout - acquire the semaphore within a specified time
     * @sem: the semaphore to be acquired
     * @timeout: how long to wait before failing
     *
     * Attempts to acquire the semaphore.  If no more tasks are allowed to
     * acquire the semaphore, calling this function will put the task to sleep.
     * If the semaphore is not released within the specified number of jiffies,
     * this function returns -ETIME.  It returns 0 if the semaphore was acquired.
     */
    int down_timeout(struct semaphore *sem, long timeout)
    {
    	unsigned long flags;
    	int result = 0;
    
    	might_sleep();
    	raw_spin_lock_irqsave(&sem->lock, flags);
    	if (likely(sem->count > 0))
    		sem->count--;
    	else
    		result = __down_timeout(sem, timeout);
    	raw_spin_unlock_irqrestore(&sem->lock, flags);
    
    	return result;
    }
    EXPORT_SYMBOL(down_timeout);
    
    /**
     * down_killable - acquire the semaphore unless killed
     * @sem: the semaphore to be acquired
     *
     * Attempts to acquire the semaphore.  If no more tasks are allowed to
     * acquire the semaphore, calling this function will put the task to sleep.
     * If the sleep is interrupted by a fatal signal, this function will return
     * -EINTR.  If the semaphore is successfully acquired, this function returns
     * 0.
     */
    int down_killable(struct semaphore *sem)
    {
    	unsigned long flags;
    	int result = 0;
    
    	might_sleep();
    	raw_spin_lock_irqsave(&sem->lock, flags);
    	if (likely(sem->count > 0))
    		sem->count--;
    	else
    		result = __down_killable(sem);
    	raw_spin_unlock_irqrestore(&sem->lock, flags);
    
    	return result;
    }
    EXPORT_SYMBOL(down_killable);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • down_killable 一直尝试获取锁,除非进程Kill掉。
    • down_timeout 在设定的时间内一直尝试获取锁。
  • 相关阅读:
    聚类分类应用题
    Notion 类笔记软件的使用误区和反思
    应用DeepSORT实现目标跟踪
    VMware 中 Centos7 安装 Hyperledge Fabric v2.4.4 测试网络
    Chromium 调试指南2024 Mac篇 - 常见问题及解决方法(四)
    04_数据库
    fetch前后端通信
    TCP Reno/Westwood 的效率和公平
    动能方案 | 15693协议的读卡器应用 DP1363F 替代RC663
    计算机网络知多少面试---第2篇
  • 原文地址:https://blog.csdn.net/qq_42931917/article/details/128047392