1.正在运行的task从run queue上下来后,被放到wait queue上,从而进入睡眠。
typedef struct __wait_queue wait_queue_t;
typedef int (*wait_queue_func_t)(wait_queue_t *wait, unsigned mode, int sync, void *key);
int default_wake_function(wait_queue_t *wait, unsigned mode, int sync, void *key);
struct __wait_queue { //wait queue 中的每个节点的数据结构
unsigned int flags;
#define WQ_FLAG_EXCLUSIVE 0x01
void *private;
wait_queue_func_t func;
struct list_head task_list;
};
struct __wait_queue_head {//wait queue 的头节点
spinlock_t lock;
struct list_head task_list;
};
typedef struct __wait_queue_head wait_queue_head_t;
简单使用wait_queue
1.DECLARE_WAIT_QUEUE_HEAD(name);
或者等价使用
wait_queue_head_t my_queue;
init_waitqueue_head(&my_queue);//定义等待队列头
2.想要阻塞的task调用wait_event_interruptible(&my_queue,contion)即可
调用wake_up(&my_queue)可将等待队列里所有的进程唤醒,进程被唤醒后,判断如果contion为假则继续睡眠。
/**
* wait_event_interruptible - sleep until a condition gets true
* @wq: the waitqueue to wait on
* @condition: a C expression for the event to wait for
*
* The process is put to sleep (TASK_INTERRUPTIBLE) until the
* @condition evaluates to true or a signal is received.
* The @condition is checked each time the waitqueue @wq is woken up.
*
* wake_up() has to be called after changing any variable that could
* change the result of the wait condition.
*
* The function will return -ERESTARTSYS if it was interrupted by a
* signal and 0 if @condition evaluated to true.
*/
#define wait_event_interruptible(wq, condition) /
({ /
int __ret = 0; /
if (!(condition)) /
__wait_event_interruptible(wq, condition, __ret); /
__ret; /
})
#define __wait_event_interruptible_timeout(wq, condition, ret) /
do { /
DEFINE_WAIT(__wait); ///定义一个新的等待队列的节点
/
for (;;) { /
prepare_to_wait(&wq, &__wait, TASK_INTERRUPTIBLE); ///将新的节点加入队列中
if (condition) /
break; /
if (!signal_pending(current)) { /
ret = schedule_timeout(ret); /
if (!ret) /
break; /
continue; /
} /
ret = -ERESTARTSYS; /
break; /
} /
finish_wait(&wq, &__wait); ///将节点从等待队列中移除,并将进程设置成task_running
} while (0)
自己操作wait_queue
全局定义等待队列头
1. wait_queue_head_t test_head;//定义wait queue 头
init_waitqueue_head(&test_head);//初始化wait queue 头
需要阻塞的进程
2. DECLARE_WAITQUEUE(wait,current);//定义等待队列节点
add_wait_queue(&test_head,&wait);//添加到等待队列
set_task_state(current,TASK_INTERRUPTIBLE);//改变进程状态
printk(KERN_ALERT"process %s state is %d/n",current->comm,current ->state);
schedule();//让出cpu
remove_wait_queue(&test_head,&wait);//被其他进程唤醒后,将等待节点从等待队列中移除。
执行唤醒的进程
3. wake_up_interruptible(&test_head);将在等待队列上的进程都唤醒
以上讨论的wait queue 都是wake_up操作将所有在队列内的等待进程唤醒。如果 节点以 Exclusive waits 方式加入等待队列的话
那样调用wake_up只会唤醒到第一次遇到exclusive方式的节点。
add_wait_queue_exclusive()将节点以execlusive方式加入节点。