struct wait_bit_key { void *flags; int bit_nr; #define WAIT_ATOMIC_T_BIT_NR -1 unsigned long timeout; };
struct wait_bit_queue { struct wait_bit_key key; wait_queue_t wait; };
对于等待队列头来说,可以通过下面方式初始化:
#define __WAIT_QUEUE_HEAD_INITIALIZER(name) { \ .lock = __SPIN_LOCK_UNLOCKED(name.lock), \ .task_list = { &(name).task_list, &(name).task_list } }
#define DECLARE_WAIT_QUEUE_HEAD(name) \ wait_queue_head_t name = __WAIT_QUEUE_HEAD_INITIALIZER(name)
而对于等待队列中的成员来说,其因为使用了struct __wait_queue结构,所以,
一般对等待队列中成员定义如下:
#define __WAITQUEUE_INITIALIZER(name, tsk) { \ .private = tsk, \ .func = default_wake_function, \ .task_list = { NULL, NULL } }
#define DECLARE_WAITQUEUE(name, tsk) \ wait_queue_t name = __WAITQUEUE_INITIALIZER(name, tsk)
或者其他一些形式定义,如下:
#define __WAIT_BIT_KEY_INITIALIZER(word, bit) \ { .flags = word, .bit_nr = bit, }
#define __WAIT_ATOMIC_T_KEY_INITIALIZER(p) \ { .flags = p, .bit_nr = WAIT_ATOMIC_T_BIT_NR, }
#define init_waitqueue_head(q) \ do { \ static struct lock_class_key __key; \ \ __init_waitqueue_head((q), #q, &__key); \ } while (0)
简单函数形式如下:
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;带唤醒函数 }
static inline void init_waitqueue_func_entry(wait_queue_t *q, wait_queue_func_t func) { q->flags = 0; q->private = NULL; q->func = func;设置唤醒函数,但任务未设置 }
简单的加入队列过程:
static inline void __add_wait_queue(wait_queue_head_t *head, wait_queue_t *new) { list_add(&new->task_list, &head->task_list); }
对外简单封装函数有:
一.
void add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait) { unsigned long flags;
wait->flags &= ~WQ_FLAG_EXCLUSIVE; spin_lock_irqsave(&q->lock, flags); __add_wait_queue(q, wait); spin_unlock_irqrestore(&q->lock, flags); } EXPORT_SYMBOL(add_wait_queue);
二.
void prepare_to_wait(wait_queue_head_t *q, wait_queue_t *wait, int state) { 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); set_current_state(state); spin_unlock_irqrestore(&q->lock, flags); } EXPORT_SYMBOL(prepare_to_wait);
三. long prepare_to_wait_event(wait_queue_head_t *q, wait_queue_t *wait, int state) { unsigned long flags; long ret = 0;
spin_lock_irqsave(&q->lock, flags); if (unlikely(signal_pending_state(state, current))) { /* * Exclusive waiter must not fail if it was selected by wakeup, * it should "consume" the condition we were waiting for. * * The caller will recheck the condition and return success if * we were already woken up, we can not miss the event because * wakeup locks/unlocks the same q->lock. * * But we need to ensure that set-condition + wakeup after that * can't see us, it should wake up another exclusive waiter if * we fail. */ list_del_init(&wait->task_list); ret = -ERESTARTSYS; } else { if (list_empty(&wait->task_list)) { if (wait->flags & WQ_FLAG_EXCLUSIVE) __add_wait_queue_tail(q, wait); else __add_wait_queue(q, wait); } set_current_state(state); } spin_unlock_irqrestore(&q->lock, flags);
return ret; } 四.
static inline void __add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t *wait) { wait->flags |= WQ_FLAG_EXCLUSIVE; __add_wait_queue(q, wait); }
等待队列的简单使用:
一, 定义等待队列头对象
如static DECLARE_WAIT_QUEUE_HEAD(nl_table_wait);
二. 等待资源时,把当前进程加入等待队列,队列成员
void netlink_table_grab(void) __acquires(nl_table_lock) { might_sleep();
write_lock_irq(&nl_table_lock);
if (atomic_read(&nl_table_users)) { DECLARE_WAITQUEUE(wait, current);自定义队列成员,并简单初始化
add_wait_queue_exclusive(&nl_table_wait, &wait);只是进入队列,但进程还可以运行 for (;;) { set_current_state(TASK_UNINTERRUPTIBLE);//改变进程状态 if (atomic_read(&nl_table_users) == 0)必须满足这个条件,否则不会被唤醒 break;//唤醒后,跳出 write_unlock_irq(&nl_table_lock); schedule();这一步放弃CPU,真正调度出去,回来也是从这里开始 write_lock_irq(&nl_table_lock);//再次回来时,获取锁 }
__set_current_state(TASK_RUNNING);//设置可运行 remove_wait_queue(&nl_table_wait, &wait);//把之前设置释放。 } }
三. 唤醒路径
void netlink_table_ungrab(void) __releases(nl_table_lock) { write_unlock_irq(&nl_table_lock); wake_up(&nl_table_wait); }