Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1270450
  • 博文数量: 482
  • 博客积分: 13297
  • 博客等级: 上将
  • 技术积分: 2890
  • 用 户 组: 普通用户
  • 注册时间: 2009-10-12 16:25
文章分类

全部博文(482)

文章存档

2012年(9)

2011年(407)

2010年(66)

分类: LINUX

2011-11-20 22:01:48

poll的作用:同时探测n个drivers,找到可以直接使用的driver,从而尽量block进程。
以下kernel源代码来自于: 与 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记录。
}
}====http://www.cnblogs.com/jack204/archive/2011/10/30.html
阅读(891) | 评论(0) | 转发(0) |
0

上一篇:C# Tips

下一篇:C#连接ACCESS数据库

给主人留下些什么吧!~~