- schedule()
...
set_current_state(TASK_INTERRUPTIBLE);
schedule();
...
schedule_timeout();
// 定时唤醒,若指定时间内有其他wake_up,定时到达时不做wake_up操作
- 在 schedle 函数的执行中,current 进程进入睡眠,而一个新的进程被运行,
- 当下一次当前进程被唤醒并得到执行权时,又接着 schedule 后面的代码运行,
- wait_queue_t
DECLARE_WAITQUEUE(wait, current);
#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)
// 给wait这个等待队列赋值,
// private用来表示被唤醒的进程,
// 这里current代表了本进程,
// 而func是被唤醒时调用的回调函数, 唤醒private
add_wait_queue(w_wait, wait);
// 将wait加入到等待队列w_wait中, 被唤醒时遍历w_wait队列
wake_up(w_wait);
// 唤醒w_wait, 遍历队列中的wait, 调用wait的func来唤醒private
>用法总结:
task 1
DECLARE_WAITQUEUE(wait, current);
add_wait_queue(w_wait, wait);
__set_current_state(TASK_INTERRUPTIBLE);
schedule();
//task1 进程休眠
................//唤醒后从这儿执行
task 2 //唤醒task1
wake_up(w_wait);
- poll_wait
poll_wait()是用在select系统调用中的
// fs/select.c/do_select()
// struct file_operations fop; fop->poll指向驱动的poll函数, poll函数调用poll_wait()
> 当用户调用select系统调用时,在内核流程为:
> 1. select系统调用会先调用 poll_initwait(&table);
> 2. 然后调用你的 fop->poll();
> 3. 从而将current加到某个等待队列(这里调用poll_wait()), 并检查是否有效, 如果无效就调用 schedule_timeout() 去睡眠.
> 4. 事件发生后,schedule_timeout()回来,调用fop->poll(); 检查到可以运行,就调用 poll_freewait(&table); 从而完成select系统调用.
> 5. 重要的是fop->poll()里面要检查是否就绪, 如果是要返回相应标志
static inline void poll_wait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p)
{
if (p && wait_address)
p->qproc(filp, wait_address, p); //是在do_select中的poll_init_wait中为__pollwait
}
// 会在其他task唤醒 然后返回给do_select; do_select实现休眠等待唤醒和select中的延时
void poll_initwait(struct poll_wqueues *pwq)
{
init_poll_funcptr(&pwq->pt, __pollwait);
pwq->polling_task = current;
pwq->triggered = 0;
pwq->error = 0;
pwq->table = NULL;
pwq->inline_index = 0;
}
static void __pollwait(struct file *filp, wait_queue_head_t *wait_address, poll_table *p)
// Add a new entry
{
struct poll_wqueues *pwq = container_of(p, struct poll_wqueues, pt);
struct poll_table_entry *entry = poll_get_entry(pwq);
if (!entry)
return;
get_file(filp);
entry->filp = filp;
entry->wait_address = wait_address;
entry->key = p->key;
init_waitqueue_func_entry(&entry->wait, pollwake);
entry->wait.private = pwq;
add_wait_queue(wait_address, &entry->wait); // 把p中的entry->wait加入到等待队列
}
> 驱动
> 实现为(和do_select配合使用):
down(&dev->sem);
poll_wait(filp, &dev->r_wait, wait);
poll_wait(filp, &dev->w_wait, wait);
/*fifo非空*/
if (dev->current_len != 0)
{
mask |= POLLIN | POLLRDNORM;
}
/*fifo非满*/
if (dev->current_len != GLOBALFIFO_SIZE)
{
mask |= POLLOUT | POLLWRNORM;
}
up(&dev->sem);