linux的poll的工作机制
2014-09-26 16:29
148 查看
poll的作用:同时探测n个drivers,找到可以直接使用的driver,从而尽量block进程。
以下kernel源代码来自于:<linux/poll.h>
与 fs/select.c
poll调用之后,kernel针对每个driver进入其相应的poll函数。poll_wait负责将当前进程放入wait_queue,(对于每个driver,每个queue,申请wait_queue_t,
放入相应的queue,由kernel完成),但是现在并不阻塞current进程,直到所有的driver最后都没有合适的mask的时候,阻塞poll系统调用,当有信号将当前进程唤醒后,说明某一条件满足了。阻塞结束,返回将current从wait_queue挪出来。
具体poll系统调用的内部数据结构为:
上面poll_table的的数据结构。
然后poll_table_page, poll_table_entry.
具体poll的数据结构的示意图。
struct poll_wqueues ---> struct poll_table_page // poll_wqueues指向一个poll_table_page的单链表,每一个page占1个PAGE_SIZE大小的区域。
struct poll_table_page ---> struct poll_table_entry // 每个poll_table_page在申请的一个PAGE_SIZE的头,entry的空间都在剩下的空间中。
请看poll_wait是怎么操作poll的数据结构的。
以下kernel源代码来自于:<linux/poll.h>
与 fs/select.c
static unsigned int scull_p_poll(struct file *filp, poll_table *wait) { struct scull_pipe *dev = filp->private_data; unsigned int mask = 0; /* * The buffer is circular; it is considered full * if "wp" is right behind "rp" and empty if the * two are equal. */ down(&dev->sem); poll_wait(filp, &dev->inq, wait); poll_wait(filp, &dev->outq, wait); if (dev->rp != dev->wp) mask |= POLLIN | POLLRDNORM; /* readable */ if (spacefree(dev)) mask |= POLLOUT | POLLWRNORM; /* writable */ up(&dev->sem); return mask; }
poll调用之后,kernel针对每个driver进入其相应的poll函数。poll_wait负责将当前进程放入wait_queue,(对于每个driver,每个queue,申请wait_queue_t,
放入相应的queue,由kernel完成),但是现在并不阻塞current进程,直到所有的driver最后都没有合适的mask的时候,阻塞poll系统调用,当有信号将当前进程唤醒后,说明某一条件满足了。阻塞结束,返回将current从wait_queue挪出来。
具体poll系统调用的内部数据结构为:
struct poll_wqueues{ poll_table pt; struct poll_table_page * table; int error; }; //每一个poll系统调用只有一个poll_wqueues。是总的结构。 //但是对外接口是poll_table pt的地址。进入此模块后,使用container_of求出poll_wqueues的地址。绝对,面向对象的用法。 减少了耦合性。
上面poll_table的的数据结构。
typedef void (*poll_queue_proc)(struct file *, wait_queue_head_t *, struct poll_table_struct *); typedef struct poll_table_struct { poll_queue_proc qproc; }poll_table; //poll_table的变量是一个函数指针,先不用管。
然后poll_table_page, poll_table_entry.
struct poll_table_entry { struct file * filp; wait_queue_t wait; wait_queue_head_t * wait_address; }; struct poll_table_page { struct poll_table_page * next; struct poll_table_entry * entry; struct poll_table_entry entries[0]; //指向结构体的下一个地址,不占空间。 }; #define POLL_TABLE_FULL(table) \ ((unsigned long)((table)->entry+1) > PAGE_SIZE + (unsigned long)(table))
具体poll的数据结构的示意图。
struct poll_wqueues ---> struct poll_table_page // poll_wqueues指向一个poll_table_page的单链表,每一个page占1个PAGE_SIZE大小的区域。
struct poll_table_page ---> struct poll_table_entry // 每个poll_table_page在申请的一个PAGE_SIZE的头,entry的空间都在剩下的空间中。
请看poll_wait是怎么操作poll的数据结构的。
void __pollwait(struct file *filp, wait_queue_head_t *wait_address, poll_table *_p) { struct poll_wqueues *p = container_of(_p, struct poll_wqueues, pt); struct poll_table_page *table = p->table; if (!table || POLL_TABLE_FULL(table)) { struct poll_table_page *new_table; new_table = (struct poll_table_page *) __get_free_page(GFP_KERNEL); //如果空间不够,一下子申请PAGE_SIZE的大小。 if (!new_table) { p->error = -ENOMEM; __set_current_state(TASK_RUNNING); return; } new_table->entry = new_table->entries; new_table->next = table; p->table = new_table; table = new_table; } /* Add a new entry */ { struct poll_table_entry * entry = table->entry; table->entry = entry+1; //直接在当前页中往下给entry分配内存。 get_file(filp); entry->filp = filp; entry->wait_address = wait_address; init_waitqueue_entry(&entry->wait, current); add_wait_queue(wait_address,&entry->wait); //将当前进程放入wait_queue,并且entry中都有wait_queue_head_t记录。 } }
相关文章推荐
- linux的poll的工作机制
- linux poll工作机制
- Linux2.6中断下半部分的三种实现机制---软中断/tasklet/工作队列
- Linux 内核驱动--阻塞与非阻塞机制及Poll/Select分析if
- 通过两个案例初步了解Linux下selinux的安全机制工作机制 推荐
- POLL机制分析(韦东山的视频总结及针对linux-2.6.30.4)
- Linux 的并发可管理工作队列机制探讨
- Linux环境进程间通信 ——无名管道工作机制研究
- Linux操作系统工作机制分析
- 基于linux内核SPI子系统工作机制
- Linux2.6中断下半部分的三种实现机制---工作队列 .
- linux中的轮询机制select/poll/epoll
- Linux2.6中断下半部分的三种实现机制---软中断/tasklet/工作队列
- 基于Linux内核SPI子系统工作机制
- <2012 11 6 > linux设备驱动程序开发初探(5) poll机制分析
- Linux socket之四:使用POLL机制处理多连接
- Linux 的并发可管理工作队列机制探讨
- Linux工作队列实现机制
- Linux 的并发可管理工作队列机制探讨
- linux工作队列机制详解