您的位置:首页 > 运维架构 > Linux

linux poll 和 等待队列休眠的关系

2012-03-01 19:24 447 查看
说明:linux版本2.6.37.1

结合相关资料的概括和总结,在此做个记录,有误之处请网友指正,谢谢!

1.poll机制和等待队列
应用层通过系统调用poll函数进入内核,内核执行相应的sys_poll函数。在sys_poll函数中调用do_sys_poll函数。do_sys_poll函数通过调用poll_initwait

函数初始化poll_wqueues变量table,并且将__pollwait函数赋值给table。这里的__pollwait函数将在驱动的poll方法中通过调用poll_wait函数来执行。

poll_initwait函数执行完后,do_sys_poll函数会调用do_poll函数。

在do_poll函数中有一个for的死循环,退出条件为count或者timeout为非零。

count为非零标识do_pollfd函数返回的mask为真,timeout表示定时时间到。

在do_pollfd函数中通过mask = file->f_op->poll来调用驱动中的poll方法,并且获得驱动中操作poll后的mask值。

在for死循环中,首先轮询整条poll_list。在所有等待poll的操作中寻找是否有已满足条件的操作,有则跳出循环

没有则继续向下执行。



上图中的唤醒操作是通过驱动中调用wake_up函数实现的。LDD3上的例子并不完整,

可以通过其他博文来学习驱动中poll的使用。

总结下poll的机制:

1.poll->sys_poll->do_sys_poll->poll_initwait

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;

}

此处需注意init_poll_funcptr(&pwq->pt, __pollwait)

将函数__pollwait函数赋值给&pwq->pt指向的pooll_table结构中的函数指针。

后面的驱动中将通过调用poll_wait函数来调用次函数。

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);

}

此处p->qproc操作指向的就是__pollwait函数

2.do_sys_poll->do_polll

static int do_poll(unsigned int nfds, struct poll_list *list,

struct poll_wqueues *wait, struct timespec *end_time)

{

for(;;){

do_pollfd(pfd, pt)

if (count || timed_out)

break;

poll_schedule_timeout(wait, TASK_INTERRUPTIBLE, to, slack)

}

}

在poll_initwait函数初始化完毕后,do_sys_poll函数会调用do_poll函数。

在do_poll函数中首先调用do_pollfd(pfd, pt)函数

static inline unsigned int do_pollfd(struct pollfd *pollfd, poll_table *pwait)

{

mask = file->f_op->poll(file, pwait);

}

通过file->f_op->poll来调用驱动中的poll方法,而驱动中的poll方法会调用poll_wait函数

poll_wait函数调用poll_initwait函数注册的__pollwait函数

static void __pollwait(struct file *filp, wait_queue_head_t *wait_address,

poll_table *p)

{

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);

}

可以发现此函数就是完成添加队列的工作。

然后继续向下执行poll_schedule_timeout()

执行完此函数后,进程进入休眠,直到被wake_up或者休眠时间到。

所以总结poll的操作:首先调用poll函数将__pollwait函数注册到系统,然后通过f_ops->poll

调用驱动的poll方法,通过poll->poll_wait来调用之前注册的__pollwait函数,

在__pollwait函数中添加等待队列,并调用poll_schedule_timeout()函数

将其休眠,等待其他线程唤醒。所以使用polll和使用等待队列进行简单休眠一样需要在其他地方使用

wake_up函数来通知

3.等待队列的休眠

驱动中调用wait_event可以将函数置入休眠,看下具体操作

#define wait_event(wq, condition) \

do { \

if (condition) \

break; \

__wait_event(wq, condition); \

} while (0)

#define __wait_event(wq, condition) \

do { \

DEFINE_WAIT(__wait); \

\

for (;;) { \

prepare_to_wait(&wq, &__wait, TASK_UNINTERRUPTIBLE); \

if (condition) \

break; \

schedule(); \

} \

finish_wait(&wq, &__wait); \

} while (0)

通过__wait_event中的for(;;)循环后,队列进入休眠。休眠后等待wake_up
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: