📄 _2_4_052_fs_select_c.html
字号:
<html lang="zh-CN" xmlns:gdoc=""> <head> <meta content="text/html; charset=utf-8" http-equiv="Content-Type"> <style type="text/css">/* default css */table { font-size: 1em; line-height: inherit;}div, address, ol, ul, li, option, select { margin-top: 0px; margin-bottom: 0px;}p { margin: 0px;}body { margin: 0px; padding: 0px; font-family: Verdana, sans-serif; font-size: 10pt; background-color: #ffffff;}h6 { font-size: 10pt }h5 { font-size: 11pt }h4 { font-size: 12pt }h3 { font-size: 13pt }h2 { font-size: 14pt }h1 { font-size: 16pt }blockquote {padding: 10px; border: 1px #DDD dashed }a img {border: 0}div.google_header, div.google_footer { position: relative; margin-top: 1em; margin-bottom: 1em;}/* end default css */ /* default print css */ @media print { body { padding: 0; margin: 0; } div.google_header, div.google_footer { display: block; min-height: 0; border: none; } div.google_header { flow: static(header); } /* used to insert page numbers */ div.google_header::before, div.google_footer::before { position: absolute; top: 0; } div.google_footer { flow: static(footer); } /* always consider this element at the start of the doc */ div#google_footer { flow: static(footer, start); } span.google_pagenumber { content: counter(page); } span.google_pagecount { content: counter(pages); } } @page { @top { content: flow(header); } @bottom { content: flow(footer); } } /* end default print css */ /* custom css *//* end custom css */ /* ui edited css */ body { font-family: Verdana; font-size: 10.0pt; line-height: normal; background-color: #ffffff; } .documentBG { background-color: #ffffff; } /* end ui edited css */</style> </head> <body revision="dcbsxfpf_213vc73kssk:62"> <div align=center id=kbdd>
<table align=center border=0 cellpadding=0 cellspacing=0 height=5716 id=v3vv width=800>
<tbody id=zytz>
<tr id=a9.i>
<td height=5716 id=q480 valign=top width=100%>
<pre id=h561>2008-4-22<br id=ngs3><br id=oli1>这里讨论的是select和poll的系统调用实现方式.<br id=eswo>首先要熟悉的是内核中为poll和select定义的各种输入输出消息的含义:<br id=l4k4> POLLIN 有数据可以读入,read不会阻塞,注意:select的请情况下,即使到EOF也是ready的.<br id=mo1g> POLLPRI 紧急数据,比如TCP,或者packet 模式的peseudo-terminal发现slave的状态有变化.<br id=f5ch> POLLOUT 写入不会阻塞.<br id=z2o1> POLLRDHUP :从Linux 2.6.17开始支持,不能再读取了. 比如tcp半连接状态.<br id=q1np> POLLERR :输出出错<br id=p4ir> POLLHUP :Hang up (output only).<br id=x_ry> POLLNVAL :Invalid request: fd not open (output only).<br id=fska><br id=u4.x> 如果定义了宏 _XOPEN_SOURCE下面的宏也有效:<br id=yfko> POLLRDNORM : POLLIN.<br id=wq.0> POLLRDBAND : 高优先级的数据read for read (generally unused on Linux).<br id=ojca> POLLWRNORM : Equivalent to POLLOUT.<br id=c4ou> POLLWRBAND : Priority data may be written.<br id=jga7><br id=wp34>asmlinkage long<br id=c-db>sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp)<br id=ssh0>{<br id=zhcg> fd_set_bits fds;<br id=qzg5> char *bits;<br id=dac2> .....<br id=xmui> timeout = MAX_SCHEDULE_TIMEOUT;<br id=ijar> if (tvp) { <font color=#0000ff id=mt5.>/*获取timeout */</font><br id=spz0> ......<br id=klmg> if ((unsigned long) sec < MAX_SELECT_SECONDS) {<br id=v7tz> timeout = ROUND_UP(usec, 1000000/HZ);<br id=oduk> timeout += sec * (unsigned long) HZ;<br id=ak4y> }<br id=kkr4> }<br id=mfl4><br id=si9:> ret = -EINVAL;<br id=c9-:> ... <font color=#0000ff id=ymn3>/*sanity check*/</font><br id=dtfl> /* 分配6个bitmaps, in/out/ex, res_in res_out res_ex */<br id=b76a> ......<br id=jm-b> ret = <font color=#38761d id=yq3s><span id=o363><b id=c512>do_select</b></span></font>(n, &fds, &timeout);<br id=fers> /*处理超时数据的返回方式:STICKY_TIMEOUTS*/ <br id=o.8y> ........<br id=li9:> <font color=#0000ff id=wr3v> /*把结果返回给用户(copy出去的,完全覆盖了用户传入的bit)*/</font><br id=k4zq> ....<br id=x6a9>}<br id=jcwp>#define POLLIN_SET (POLLRDNORM | POLLRDBAND | POLLIN | POLLHUP | POLLERR)<br id=gqfs>#define POLLOUT_SET (POLLWRBAND | POLLWRNORM | POLLOUT | POLLERR)<br id=egso>#define POLLEX_SET (POLLPRI) <font color=#0000ff id=w98u>/*可以看出,except就是所谓带外数据之类*/<br id=mzqb><br id=kym-></font>int do_select(int n, fd_set_bits *fds, long *timeout)<br id=luuo>{<br id=duhj> ....<br id=fn49> retval = max_select_fd(n, fds); /*根据已经打开文件的位图检查用户数据(对应fd必须打开),返回检测的文件个数*/<br id=nxrh> .....<br id=ku10> n = retval;<br id=lrhd> ....<br id=k.gx> poll_initwait(&table);<br id=rop2> wait = &table;<br id=pzp3> ......<br id=jkgv> for (;;) {<br id=qo3z> set_current_state(TASK_INTERRUPTIBLE);<font color=#0000ff id=vn94> /*睡眠过程容许被信号量唤醒*/</font><br id=j7b-> for (i = 0 ; i < n; i++) {<br id=p.u0> ...<br id=aroz> file = fget(i); <font color=#0000ff id=w46t>/*获取对应的文件指针*/</font><br id=h4bd> mask = POLLNVAL;<br id=hnxm> if (file) {<br id=mk:h> mask = DEFAULT_POLLMASK;<br id=c7sd> if (file->f_op && file->f_op->poll)<br id=jzpk> mask = file->f_op-><font color=#38761d id=d3v_><span id=r4id><b id=k701>poll</b></span></font>(file, wait); <font color=#0000ff id=jkee>/*调用对应文件的poll函数*/</font><br id=cypx> fput(file);<br id=xhe7> }<br id=wkwp> if ((mask & POLLIN_SET) && ISSET(bit, __IN(fds,off))) {<br id=lmk1> SET(bit, __RES_IN(fds,off));<br id=olxr> retval++;<br id=rdgb> wait = NULL;<font color=#ff0000 id=wu2v> /*有结果就不再等了*/</font><br id=krwj> }<br id=y_ve> .....<font color=#0000ff id=y.qx> /*根据返回值更新结果*/</font><br id=vxuo> }<br id=w1t5> <font color=#ff0000 id=mrmd>wait = NULL; /*只第一轮挂上等待队列即可*/</font><br id=j3q7> if (retval || !__timeout || signal_pending(current)) <font color=#0000ff id=tnxa>/*超时,有文件ready,有信号,都返回*/</font><br id=wl8y> break;<br id=z-8d> .....<br id=ygax> __timeout = schedule_timeout(__timeout);<font color=#0000ff id=lza7> /*否则休眠...*/</font><br id=vwzy> }<br id=q361> current->state = TASK_RUNNING;<br id=q04e><br id=u8ji> poll_freewait(&table);<br id=b_ge><br id=wlv8> /*<br id=cdqw> * Up-to-date the caller timeout.<br id=go5y> */<br id=lf54> *timeout = __timeout;<br id=y.vu> return retval;<br id=za3j>}<br id=wtyl><br id=xzg7>这里的逻辑是这样:<br id=mqws> 第一轮扫描的时候调用文件的poll函数(如,pipe_poll), 把证调用select的进程挂到文件所属的某个等待队列,以备文件ready的时候<br id=s2d1>唤醒这个队列.<br id=qydd> 第二轮就不用挂载等待队列了,如果有ready的也就不再挂载了,让app尽快处理.<br id=btt1><br id=fo7x> 令:有信号量的时候要返回,因为signal的处理函数是在进程返回的时候才能得到服务.(见arch/../kernel/entry.S.<br id=cq1q><br id=o6n4>简单看看一个poll的实现:<br id=az96>static unsigned int<br id=ljuv><font color=#0b5394 id=i060><span id=t:vt><b id=o:-i>pipe_poll</b></span></font>(struct file *filp, poll_table *wait)<br id=l5nu>{<br id=y_br> unsigned int mask;<br id=r5e5> struct inode *inode = filp->f_dentry->d_inode;<br id=i-vw><br id=zsk6> poll_wait(filp, PIPE_WAIT(*inode), wait);<br id=fa-d> <font color=#0000ff id=j70l>/*在wait(一个table)中申请poll_table_entry->wait挂入inode的等待队列*/</font><br id=euk2><br id=d.dk> /* Reading only -- no need for acquiring the semaphore. */<br id=x-e9> mask = POLLIN | POLLRDNORM;<br id=cwjh> if (PIPE_EMPTY(*inode)) <font color=#0000ff id=dg4r>/*pipe空了,进程可以写入*/</font><br id=pqzh> mask = POLLOUT | POLLWRNORM;<br id=eh7y> if (!PIPE_WRITERS(*inode) && filp->f_version != PIPE_WCOUNTER(*inode))<br id=bfs.> mask |= POLLHUP; /*写入hangup,禁止写入*/<br id=l4v4> if (!PIPE_READERS(*inode))<br id=b.7i> mask |= POLLERR;<br id=st8w><br id=s1.j> return mask;<br id=do:i>}<br id=w9d9><br id=fuf5>void __pollwait(struct file * filp, wait_queue_head_t * <font color=#0000ff id=ztg4>wait_address</font>, <font color=#ff00ff id=bgti>poll_table *p</font>)<br id=ng9s>{ <font color=#0000ff id=r8qf>/ *current要在这个队列上等待*/ <font color=#ff00ff id=hl4d>/*select的wait table*/</font></font><br id=ogw0> struct poll_table_page *table = p->table;<br id=j.lj><br id=hwhl> if (!table || POLL_TABLE_FULL(table)) {<br id=uciz> ...<font color=#0000ff id=n1_k>/* table初始化 */</font><br id=qdnf> }<br id=fh.g><br id=db72> /* Add a new entry */<br id=bum4> {<br id=rw7.> struct poll_table_entry * entry = table->entry;<br id=fzvo> table->entry = entry+1;<br id=o00e> get_file(filp);<br id=cegu> entry->filp = filp;<br id=nto1> entry->wait_address = wait_address; <font color=#0000ff id=vepz>/*wait address就是上面的pipe的inode的wait queue*/</font><br id=w:.t> init_waitqueue_entry(&entry->wait, current)<font color=#ff00ff id=me2i>;/*current是调用select的进程*/</font><br id=z:zg> add_wait_queue(wait_address,&entry->wait); <font color=#0000ff id=m20g>/*select的poll table等待在inode上....*/</font><br id=gh0g> }<br id=q6.v>}<br id=lr56><br id=p70w>可见,select的wait table记载了当前调用select的进程现在在等待多少资源,加入了多少等待队列.<br id=lt.n><br id=x.tu><br id=i83o>而sys_poll和select是极为类似的,不再分析了..<br id=g193>asmlinkage long sys_poll(struct pollfd * ufds, unsigned int nfds, long timeout)<br id=bvw3><br id=uvji><br id=mhsc><br id=iev1><br id=z4to></pre>
</td>
</tr>
</tbody>
</table>
</div></body></html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -