Orchid poll 剖析

来源:互联网 发布:淘宝站内推广有哪些 编辑:程序博客网 时间:2024/06/10 01:18


 

 

 

/*

int poll(struct pollfd *fds, nfds_t nfds, int timeout);

可以看到,poll 的参数中,直接列出了要监视的文件描述符的信息,而不像 select

一样要列出从 0 开始到 nfds-1 的所有文件描述符。这样的好处是,poll 不需要查询很多无

关的文件描述符的信息,在一定场合下效率会有所提高。

*/

 

 

struct poll_list {

struct poll_list *next;

int len;

struct pollfd entries[0];

}; //用来保存被监视的文件描述符的参数

 

struct pollfd {

int fd;

short events;

short revents;

};//记录被监视的文件描述符和它的状态。

 

 

 

 

asmlinkage long sys_poll(struct pollfd __user * ufds,unsigned int nfds,long timeout)

{

struct poll_wqueues table;

int fdcount, err;

unsigned int i;

struct poll_list *head;

struct poll_list *walk;

 

/* Do a sanity check on nfds ... */   

if (nfds > current->files->max_fdset && nfds > OPEN_MAX)

// 用户给的nfds数不可以超过一个struct file结构支持的最大fd数(默认是256)

return -EINVAL;

 

if (timeout) {

/* Careful about overflow in the intermediate values */

if ((unsigned long)timeout < MAX_SCHEDULE_TIMEOUT / HZ)

timeout = (unsigned long)(timeout*HZ + 999) / 1000 + 1;

else /* Negative or overflow */

timeout = MAX_SCHEDULE_TIMEOUT;

}

 

poll_initwait(&table); /*其中poll_initwait较为关键,从字面上看,应该是初始化变量table,

注意此处table在整个执行poll的过程中是很关键的变量。

struct poll_table其实就只包含了一个函数指针 :*/

//init_poll_funcptr(&pwq->pt, __pollwait);

 

head = NULL;

walk = NULL;

i = nfds;

err = -ENOMEM;

while (i != 0) {

struct poll_list *pp;

pp = kmalloc(sizeof(struct poll_list) +

sizeof(struct pollfd)*

(i>POLLFD_PER_PAGE ? POLLFD_PER_PAGE : i),

GFP_KERNEL);

if (pp == NULL)

goto out_fds;

pp->next = NULL;

pp->len = (i>POLLFD_PER_PAGE ? POLLFD_PER_PAGE : i);

if (head == NULL)

head = pp;

else

walk->next = pp;

 

walk = pp;

/*

这一大堆代码就是建立一个链表,每个链表的节点是一个page大小(通常是4k),这链表节点由一个指向

struct poll_list的指针掌控,而众多的struct pollfd就通过struct_list的entries成员访问。上面的循环就

是把用户态的struct pollfd拷进这些entries里。通常用户程序的poll调用就监控几个fd,所以上面这个链

表通常也就只需要一个节点,即操作系统的一页。但是,当用户传入的fd很多时,由于poll系统调用每次都

要把所有struct pollfd拷进内核,所以参数传递和页分配此时就成了poll系统调用的性能瓶颈。

*/

if (copy_from_user(pp->entries, ufds + nfds - i,   

sizeof(struct pollfd)*pp->len)) {

err = -EFAULT;

goto out_fds;

}

i -= pp->len;

}

fdcount = do_poll(nfds, head, &table, timeout); //****

 

/* OK, now copy the revents fields back to user space. */

walk = head;

err = -EFAULT;

while (walk != NULL) {

struct pollfd *fds = walk->entries;

int j;

 

for (j = 0; j < walk->len; j++, ufds++) {

if (__put_user(fds[j].revents, &ufds->revents))

goto out_fds;

}

walk = walk->next;

}

err = fdcount;

if (!fdcount && signal_pending(current))

err = -EINTR;

out_fds:

walk = head;

while (walk != NULL) {

struct poll_list *pp = walk->next;

kfree(walk);

walk = pp;

}

poll_freewait(&table);

return err;

}

 

 

 

void poll_initwait(struct poll_wqueues *pwq)

{

init_poll_funcptr(&pwq->pt, __pollwait);

pwq->error = 0;

pwq->table = NULL;

}

 

 

 

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

struct poll_wqueues *wait, long timeout)

{

int count = 0;

poll_table* pt = &wait->pt;

 

if (!timeout)

pt = NULL;

 

for (;;) {

struct poll_list *walk;

set_current_state(TASK_INTERRUPTIBLE);

walk = list;

while (walk != NULL) {

do_pollfd(walk->len, walk->entries, &pt, &count);

walk = walk->next;

}

pt = NULL;

if (count || !timeout || signal_pending(current))

break;

count = wait->error;

if (count)

break;

timeout = schedule_timeout(timeout);

}

__set_current_state(TASK_RUNNING);

return count;

}

 

 

static void do_pollfd(unsigned int num,struct pollfd * fdpage,

poll_table ** pwait, int *count)

{

int i;

 

for (i = 0; i < num; i++) {

int fd;

unsigned int mask;

struct pollfd *fdp;

 

mask = 0;

fdp = fdpage + i;

fd = fdp->fd;

if (fd >= 0) {

struct file * file = fget(fd);

mask = POLLNVAL;

if (file != NULL) {

mask = DEFAULT_POLLMASK;

if (file->f_op && file->f_op->poll)

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

mask &= fdp->events | POLLERR | POLLHUP;

fput(file);

}

if (mask) {

*pwait = NULL;

(*count)++;

}

}

fdp->revents = mask;

}

}

 

 


0 0
原创粉丝点击