__down_common这个函数主要处理上一节博客中讲述的API中对sem->count 小于零的case的处理.
可以看到下面这些函数都调用了__down_common,只是第二个和第三个形参有所不同
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);
}
其源码分析如下:
static inline int __sched __down_common(struct semaphore *sem, long state,
long timeout)
{
struct semaphore_waiter waiter;
#定义一个semaphore_waiter,并将这个waiter添加到sem中的wait_list这个链表中
list_add_tail(&waiter.list, &sem->wait_list);
#对waiter赋值,这里为啥不先赋值然后在添加到sem的wait_list中呢?
waiter.task = current;
waiter.up = false;
for (;;) {
#监视是否有形参指定的信号量在pending,有的话就删除waiter.list 然后返回被中断
if (signal_pending_state(state, current))
goto interrupted;
#超时时间小于零,说明已经超时了,同样删除waiter.list后,返回超时时间导致函数退出
if (unlikely(timeout <= 0))
goto timed_out;
#设置当前task为形参指定的状态,例如TASK_UNINTERRUPTIBLE/TASK_INTERRUPTIBLE/TASK_KILLABLE
__set_current_state(state);
raw_spin_unlock_irq(&sem->lock);
#在timeout这段时间内让出当前cpu
timeout = schedule_timeout(timeout);
raw_spin_lock_irq(&sem->lock);
#正常的退出出口在这里面。当waiter.up为true时,正确退出.
if (waiter.up)
return 0;
}
timed_out:
list_del(&waiter.list);
return -ETIME;
interrupted:
list_del(&waiter.list);
return -EINTR;
}
可以看到不同的down_xx 函数区别在于是否会被信号量中断,是否超时等。默认down这个函数在sem->count小于零时调用的是
static noinline void __sched __down(struct semaphore *sem)
{
__down_common(sem, TASK_UNINTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
}
可以看到在无法获取信号量时。系统会一直让出cpu,且当前task无法timeout,无法被signal 唤醒,因此正常情况下一般不适用down这个函数
内核同步机制API之__down_common
最新推荐文章于 2022-10-05 08:25:10 发布