/*
* 2020/12/4 15:22 qing
*/
/*
* 信号量是一种睡眠锁
*
* 本质上信号量是一个计数器,是进程间通信处理同步互斥的机制。
* 是在多线程环境下使用的一种措施,它负责协调各个进程,以保证他们能够正确、合理的使用公共资源。
*
* 信号量一般可以用来标记可用资源的个数
*
* 信号量和spin lock最大的不同之处就是:无法获取信号量的进程可以睡眠,因此会导致系统调度。
*
*
*/
/*
* semaphore
*/
/* Please don't access any members of this structure directly */
struct semaphore {
raw_spinlock_t lock; /* spin lock, 保证自身的操作不被打断或修改 */
unsigned int count; /* 计数 */
struct list_head wait_list; /* 等待进程的链表头 */
};
/*
* raw_spinlock_t
*/
typedef struct raw_spinlock {
arch_spinlock_t raw_lock;
#ifdef CONFIG_GENERIC_LOCKBREAK
unsigned int break_lock;
#endif
#ifdef CONFIG_DEBUG_SPINLOCK
unsigned int magic, owner_cpu;
void *owner;
#endif
#ifdef CONFIG_DEBUG_LOCK_ALLOC
struct lockdep_map dep_map;
#endif
} raw_spinlock_t;
/*
* arch_spinlock_t
*/
typedef struct {
#ifdef __AARCH64EB__
u16 next;
u16 owner;
#else
u16 owner;
u16 next;
#endif
} __aligned(4) arch_spinlock_t;
/*
* semaphore_waiter
*/
struct semaphore_waiter {
struct list_head list; /* 当进程无法获取信号量的时候挂入semaphore的wait_list成员 */
struct task_struct *task; /* 记录后续被唤醒的进程信息 */
bool up;
};
/*
* down
*
* deprecated (已弃用)
*/
void down(struct semaphore *sem)
{
unsigned long flags;
raw_spin_lock_irqsave(&sem->lock, flags);
if (likely(sem->count > 0))
sem->count--;
else
__down(sem);
raw_spin_unlock_irqrestore(&sem->lock, flags);
}
/*
* down_interruptible
*/
int down_interruptible(struct semaphore *sem)
{
unsigned long flags;
int result = 0;
raw_spin_lock_irqsave(&sem->lock, flags);
if (likely(sem->count > 0))
sem->count--; /* 资源还有剩余 */
else
result = __down_interruptible(sem); /* 进入等待信号量,任务调度睡眠 */
raw_spin_unlock_irqrestore(&sem->lock, flags);
return result;
}
static noinline void __sched __down(struct semaphore *sem)
{
__down_common(sem, TASK_UNINTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
}
static noinline int __sched __down_interruptible(struct semaphore *sem)
{
return __down_common(sem, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
}
static noinline int __sched __down_killable(struct semaphore *sem)
{
return __down_common(sem, TASK_KILLABLE, MAX_SCHEDULE_TIMEOUT);
}
static noinline int __sched __down_timeout(struct semaphore *sem, long timeout)
{
return __down_common(sem, TASK_UNINTERRUPTIBLE, timeout);
}
/*
* __down_common
*
* 因为这个函数是内联的,所以'state'参数将是常量,因此编译器会对其进行优化。同样,对于没有超时的情况,使用"timeout"参数。
*/
static inline int __sched __down_common(struct semaphore *sem, long state,
long timeout)
{
struct task_struct *task = current;
struct semaphore_waiter waiter;
list_add_tail(&waiter.list, &sem->wait_list); /* 等待进程入链表 */
waiter.task = task;
waiter.up = false;
for (;;) {
if (signal_pending_state(state, task))
goto interrupted;
if (unlikely(timeout <= 0))
goto timed_out;
__set_task_state(task, state);
raw_spin_unlock_irq(&sem->lock);
timeout = schedule_timeout(timeout); /* 调度 */
raw_spin_lock_irq(&sem->lock);
if (waiter.up)
return 0;
}
timed_out:
list_del(&waiter.list);
return -ETIME;
interrupted:
list_del(&waiter.list);
return -EINTR;
}
/**
* up - release the semaphore
*
* 与互斥锁不同,up()可以从任何上下文调用,甚至可以由从未调用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++; /* 等待链表没有进程,资源计数加1 */
else
__up(sem);
raw_spin_unlock_irqrestore(&sem->lock, flags);
}
static noinline void __sched __up(struct semaphore *sem)
{
struct semaphore_waiter *waiter = list_first_entry(&sem->wait_list,
struct semaphore_waiter, list); /* 从等待进程链表头取出第一个进程 */
list_del(&waiter->list); /* 从链表上移除 */
waiter->up = true;
wake_up_process(waiter->task); /* 唤醒等待进程 */
}