⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 _2_4_052_fs_select_c.html

📁 重读linux 2.4.2o所写的笔记
💻 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>       &nbsp;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 &lt; 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, &amp;fds, &amp;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(&amp;table);<br id=rop2>	wait = &amp;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 &lt; 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-&gt;f_op &amp;&amp; file-&gt;f_op-&gt;poll)<br id=jzpk>					mask = file-&gt;f_op-&gt;<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>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ((mask &amp; POLLIN_SET) &amp;&amp; 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-&gt;state = TASK_RUNNING;<br id=q04e><br id=u8ji>	poll_freewait(&amp;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-&gt;f_dentry-&gt;d_inode;<br id=i-vw><br id=zsk6>	poll_wait(filp, PIPE_WAIT(*inode), wait);<br id=fa-d>              &nbsp;<font color=#0000ff id=j70l>/*在wait(一个table)中申请poll_table_entry-&gt;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) &amp;&amp; filp-&gt;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-&gt;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-&gt;entry;<br id=fzvo>		table-&gt;entry = entry+1;<br id=o00e>	 	get_file(filp);<br id=cegu>	 	entry-&gt;filp = filp;<br id=nto1>		entry-&gt;wait_address = wait_address; <font color=#0000ff id=vepz>/*wait address就是上面的pipe的inode的wait queue*/</font><br id=w:.t>		init_waitqueue_entry(&amp;entry-&gt;wait, current)<font color=#ff00ff id=me2i>;/*current是调用select的进程*/</font><br id=z:zg>		add_wait_queue(wait_address,&amp;entry-&gt;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 + -