源出处:http://www.startos.com/linux/tips/2011011921499_2.html
全局或者在栈中定义一个wait_queue_t类型变量的同时对其初始化,这保证了系统的可靠性,避免因用户忘记初始化时导致的问题。通用的初始化宏,tsk为任意指针。分两步:
1) 内部宏__WAITQUEUE_INITIALIZER初始化相应成员;当wq内嵌在别的结构体中时,此宏很重要,提高了可移植性;
2) 提供给外部的接口,定义一个变量,并将第一步的结果赋值给该变量。
static inline void init_waitqueue_entry(wait_queue_t *q, struct task_struct *p)
{
q->flags = 0;
q->private = p;
q->func = default_wake_function;
}
动态初始化一个等待队列入口项,将其和当前进程关联起来,以便唤醒当前进程。
2.1.3 数据结构设计规则
今后凡遇到新设计一类结构体,若此类结构体变量必须初始化且有相对集中的操作,则应提供以下两个操作接口:
a) 定义新建一个结构体变量,并初始化之;
b) 动态初始化一个已经分配内存的该类变量
为了适应在堆栈及全局等任意地方分配的该变量,其应该接收指向该类变量的指针。
2.2 陈旧sleep_on系列
//初始化一个wait_queue_t
#define SLEEP_ON_VAR \
unsigned long flags; \
wait_queue_t wait; \
init_waitqueue_entry(&wait, current);
//添加到队列中
#define SLEEP_ON_HEAD \
spin_lock_irqsave(&q->lock,flags); \
__add_wait_queue(q, &wait); \
spin_unlock(&q->lock);
//从队列中删除
#define SLEEP_ON_TAIL \
spin_lock_irq(&q->lock); \
__remove_wait_queue(q, &wait); \
spin_unlock_irqrestore(&q->lock, flags);
SLEEP_ON_VAR、 SLEEP_ON_HEAD及SLEEP_ON_ TAIL总是同时出现,不可分割。上述宏不是函数,只是连续的表达式而已,因为函数就将他们隔离开来了,函数他退出后变量就无意义了。也不能写成 do――while的多语句宏,变量定义离开“{}”后就没有意义了。是为了编写代码更清晰明了,同时避免多写字,实际上就是代码封装复用。
void fastcall __sched interruptible_sleep_on(wait_queue_head_t *q)
{
SLEEP_ON_VAR //注意没“;”
current->state = TASK_INTERRUPTIBLE;
SLEEP_ON_HEAD
schedule(); //此处可能出问题
SLEEP_ON_TAIL
}
EXPORT_SYMBOL(interruptible_sleep_on);
添加到队列和从队列中删除由同一个模块做,符合模块设计规则,减小了耦合性。
唤醒的wakeup只负责改变进程状态,进程重新获得cpu后从队列中删除。
long fastcall __sched
interruptible_sleep_on_timeout(wait_queue_head_t *q, long timeout)
{
SLEEP_ON_VAR
current->state = TASK_INTERRUPTIBLE;
SLEEP_ON_HEAD
timeout = schedule_timeout(timeout);
SLEEP_ON_TAIL
return timeout;
}
EXPORT_SYMBOL(interruptible_sleep_on_timeout);
void fastcall __sched sleep_on(wait_queue_head_t *q)
{
SLEEP_ON_VAR
current->state = TASK_UNINTERRUPTIBLE;
SLEEP_ON_HEAD
schedule();
SLEEP_ON_TAIL
}
EXPORT_SYMBOL(sleep_on);
long fastcall __sched sleep_on_timeout(wait_queue_head_t *q, long timeout)
{
SLEEP_ON_VAR
current->state = TASK_UNINTERRUPTIBLE;
SLEEP_ON_HEAD
timeout = schedule_timeout(timeout);
SLEEP_ON_TAIL
return timeout;
}
EXPORT_SYMBOL(sleep_on_timeout);