/**
如果被一个信号打断了,那么该函数将会返回-ERESTARTSYS
*/
#define wait_event_interruptible(wq, condition) \
({ \
int __ret = 0;
/**
如果condition为false,
那么__wait_event_interruptible将会被执行
*/ \
if (!(condition)) \
__wait_event_interruptible(wq, condition, __ret); \
__ret; \
})
#define __wait_event_interruptible(wq, condition, ret) \
do { \
/**
定义了一个wait_queue_t 类型的等待队列项_wait
*/
DEFINE_WAIT(__wait); \
{
#define DEFINE_WAIT(name) DEFINE_WAIT_FUNC(name, autoremove_wake_function)
#define DEFINE_WAIT_FUNC(name, function) \
wait_queue_t name = { \
/**
private指向调用wait_event_interruptible的进程
*/
.private = current, \
/**
该进程被唤醒后会执行这个函数,初始化为默认autoremove_wake_function
*/
.func = function, \
.task_list = LIST_HEAD_INIT((name).task_list), \
}
}
\
for (;;) { \
/**
这个函数主要做了一下事情:
1 :将上面定义的wait等待队列项放入到等待队列中
2 : 将进程的状态设置为 TASK_INTERRUPTIBLE
(这里与 wait_event_timeout不同,wait_event_timeout会将进程的状态设置为 TASK_UNINTERRUPTIBLE)
unsigned long flags;
wait->flags &= ~WQ_FLAG_EXCLUSIVE;
/**
保存中断状态
关闭本地中断
获取自旋锁
*/
spin_lock_irqsave(&q->lock, flags);
if (list_empty(&wait->task_list))
{
/**
添加等待队列项到等待队列中,头插。
那么,会被第一个唤醒。
*/
__add_wait_queue(q, wait);
}
/**
设置进程状态为 TASK_INTERRUPTIBLE
*/
set_current_state(state);
spin_unlock_irqrestore(&q->lock, flags);
*/
prepare_to_wait(&wq, &__wait, TASK_INTERRUPTIBLE); \
/**
从上面的那个函数出来之后,就立即检查condition有没有满足,
如果满足,那么就break,跳出for循环。
*/
if (condition) \
break; \
/**
看有没有信号等待处理,
如果没有,那么就调用schedule() 放弃cpu,睡眠
*/
if (!signal_pending(current)) { \
schedule(); \
/**
如果睡眠了,那么就继续for循环
*/
continue; \
} \
/**
看,如果有信号到来,会返回这个-ERESTARTSYS
*/
ret = -ERESTARTSYS; \
break; \
} \
/**
进程被唤醒后调用的函数
这个函数主要做了一下事情 :
1 : 将该进程的状态设置为TASK_RUNNING
2 : 从等待队列中删除
unsigned long flags;
__set_current_state(TASK_RUNNING);
if (!list_empty_careful(&wait->task_list))
{
spin_lock_irqsave(&q->lock, flags);
list_del_init(&wait->task_list);
spin_unlock_irqrestore(&q->lock, flags);
}
*/
finish_wait(&wq, &__wait); \
} while (0)
/**
其实,就是调用队列中每个节点上的autoremove_wake_function()函数
看它的第二个参数 : TASK_INTERRUPTIBLE,不能唤醒TASK_UNINTERRUPTIBLE状态的进程
但是 wake_up() 则可以唤醒TASK_INTERRUPTIBLE、TASK_UNINTERRUPTIBLE状态的进程
因为: #define wake_up(x) __wake_up(x, TASK_NORMAL, 1, NULL)
#define TASK_NORMAL (TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE)
*/
#define wake_up_interruptible(x) __wake_up(x, TASK_INTERRUPTIBLE, 1, NULL)
void __wake_up(wait_queue_head_t *q, unsigned int mode,int nr_exclusive, void *key)
{
unsigned long flags;
spin_lock_irqsave(&q->lock, flags);
__wake_up_common(q, mode, nr_exclusive, 0, key);
spin_unlock_irqrestore(&q->lock, flags);
}
/**
真正干活的是这个函数
*/
static void __wake_up_common(wait_queue_head_t *q,unsigned int mode,int nr_exclusive,int wake_flags,void *key)
{
wait_queue_t *curr, *next;
/**
遍历等待队列
*/
list_for_each_entry_safe(curr, next, &q->task_list, task_list)
{
unsigned flags = curr->flags;
/**
对队列中的每个节点,都会调用func,这个func就是autoremove_wake_function()函数,
是再wait_event_interruptible中绑定的。
flags & WQ_FLAG_EXCLUSIVE :?
--nr_exclusive : 若设置为1 ,那么只会唤醒一个,其余的还在睡。
*/
if (curr->func(curr, mode, wake_flags, key) &&(flags & WQ_FLAG_EXCLUSIVE) && !--nr_exclusive)
{
break;
}
}
}
int autoremove_wake_function(wait_queue_t *wait, unsigned mode, int sync, void *key)
{
int ret = default_wake_function(wait, mode, sync, key);
/**
这里ret 就是 再try_to_wake_up()函数中定义的局部变量success的值
如果success为1,那么 将会return 1 ,唤醒成功。
*/
if (ret)
{
list_del_init(&wait->task_list);
}
return ret;
}
int default_wake_function(wait_queue_t *curr, unsigned mode, int wake_flags,void *key)
{
return try_to_wake_up(curr->private, mode, wake_flags);
}
static int try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags)
{
/**
success这个局部变量的值 会决定了唤醒的成功与否,
而它的值,是由传入的进程状态和待唤醒的进程的状态是否一致决定的。
*/
int cpu, success = 0;
...
/**
要唤醒的进程的状态 与 传入的状态比较,
如果一致,那么不会执行goto out
那么success 会被赋值为 1,否则success还是为 0,
那么再
*/
if (!(p->state & state))
{
goto out;
}
success = 1;
...
...
out:
raw_spin_unlock_irqrestore(&p->pi_lock, flags);
return success;
}
等待队列 赏析
最新推荐文章于 2025-05-08 08:19:42 发布