




已阅读5页,还剩1页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Select函数实现原理分析2009年05月12日 星期二 下午 03:21Select函数实现原理分析(转载)select需要驱动程序的支持,驱动程序实现fops内的poll函数。select通过每个设备文件对应的poll函数提供的信息判断当前是否有资源可用(如可读或写),如果有的话则返回可用资源的文件描述符个数,没有的话则睡眠,等待有资源变为可用时再被唤醒继续执行。下面我们分两个过程来分析select:1. select的睡眠过程支持阻塞操作的设备驱动通常会实现一组自身的等待队列如读/写等待队列用于支持上层(用户层)所需的BLOCK或NONBLOCK操作。当应用程序通过设备驱动访问该设备时(默认为BLOCK操作),若该设备当前没有数据可读或写,则将该用户进程插入到该设备驱动对应的读/写等待队列让其睡眠一段时间,等到有数据可读/写时再将该进程唤醒。select就是巧妙的利用等待队列机制让用户进程适当在没有资源可读/写时睡眠,有资源可读/写时唤醒。下面我们看看select睡眠的详细过程。select会循环遍历它所监测的fd_set(一组文件描述符(fd)的集合)内的所有文件描述符对应的驱动程序的poll函数。驱动程序提供的poll函数首先会将调用select的用户进程插入到该设备驱动对应资源的等待队列(如读/写等待队列),然后返回一个bitmask告诉select当前资源哪些可用。当select循环遍历完所有fd_set内指定的文件描述符对应的poll函数后,如果没有一个资源可用(即没有一个文件可供操作),则select让该进程睡眠,一直等到有资源可用为止,进程被唤醒(或者timeout)继续往下执行。 下面分析一下代码是如何实现的。select的调用path如下:sys_select - core_sys_select - do_select其中最重要的函数是do_select, 最主要的工作是在这里, 前面两个函数主要做一些准备工作。do_select定义如下:int do_select(int n, fd_set_bits *fds, s64 *timeout)struct poll_wqueues table;poll_table *wait;int retval, i;rcu_read_lock();retval = max_select_fd(n, fds);rcu_read_unlock();if (retval return retval;n = retval;poll_initwait(&table);wait = &table.pt;if (!*timeout)wait = NULL;retval = 0; /retval用于保存已经准备好的描述符数,初始为0for (;) unsigned long *rinp, *routp, *rexp, *inp, *outp, *exp;long _timeout;set_current_state(TASK_INTERRUPTIBLE); /将当前进程状态改为TASK_INTERRUPTIBLEinp = fds-in; outp = fds-out; exp = fds-ex;rinp = fds-res_in; routp = fds-res_out; rexp = fds-res_ex;for (i = 0; i 遍历每个描述符unsigned long in, out, ex, all_bits, bit = 1, mask, j;unsigned long res_in = 0, res_out = 0, res_ex = 0;const struct file_operations *f_op = NULL;struct file *file = NULL;in = *inp ; out = *outp ; ex = *exp ;all_bits = in | out | ex;if (all_bits = 0) i = _NFDBITS; / /如果这个字没有待查找的描述符, 跳过这个长字(32位)continue;for (j = 0; j 遍历每个长字里的每个位int fput_needed;if (i = n)break;if (!(bit & all_bits)continue;file = fget_light(i, &fput_needed);if (file) f_op = file-f_op;MARK(fs_select, %d %lld,i, (long long)*timeout);mask = DEFAULT_POLLMASK;if (f_op & f_op-poll)/* 在这里循环调用所监测的fd_set内的所有文件描述符对应的驱动程序的poll函数 */mask = (*f_op-poll)(file, retval ? NULL : wait);fput_light(file, fput_needed);if (mask & POLLIN_SET) & (in & bit) res_in |= bit; /如果是这个描述符可读, 将这个位置位retval ; /返回描述符个数加1if (mask & POLLOUT_SET) & (out & bit) res_out |= bit;retval ;if (mask & POLLEX_SET) & (ex & bit) res_ex |= bit;retval ;cond_resched();/返回结果if (res_in)*rinp = res_in;if (res_out)*routp = res_out;if (res_ex)*rexp = res_ex;wait = NULL;/* 到这里遍历结束。retval保存了检测到的可操作的文件描述符的个数。如果有文件可操作,则跳出for(;)循环,直接返回。若没有文件可操作且timeout时间未到同时没有收到signal,则执行schedule_timeout睡眠。睡眠时间长短由_timeout决定,一直等到该进程被唤醒。 那该进程是如何被唤醒的?被谁唤醒的呢?我们看下面的select唤醒过程*/if (retval | !*timeout | signal_pending(current)break;if(table.error) retval = table.error;break;if (*timeout /* Wait indefinitely */_timeout = MAX_SCHEDULE_TIMEOUT; else if (unlikely(*timeout = (s64)MAX_SCHEDULE_TIMEOUT - 1) /* Wait for longer than MAX_SCHEDULE_TIMEOUT. Do it in a loop */_timeout = MAX_SCHEDULE_TIMEOUT - 1;*timeout -= _timeout; else _timeout = *timeout;*timeout = 0;_timeout = schedule_timeout(_timeout);if (*timeout = 0)*timeout = _timeout;_set_current_state(TASK_RUNNING);poll_freewait(&table);return retval;2. select的唤醒过程前面介绍了select会循环遍历它所监测的fd_set内的所有文件描述符对应的驱动程序的poll函数。驱动程序提供的poll函数首先会将调用select的用户进程插入到该设备驱动对应资源的等待队列(如读/写等待队列),然后返回一个bitmask告诉select当前资源哪些可用。一个典型的驱动程序poll函数实现如下:(摘自Linux Device Drivers ThirdEditionPage 165)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_wait做的。Poll_wait定义如下:static inline void poll_wait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p)if (p & wait_address)p-qproc(filp, wait_address, p);这里的p-qproc在do_select内poll_initwait(&table)被初始化为_pollwait,如下:void poll_initwait(struct poll_wqueues *pwq)init_poll_funcptr(&pwq-pt, _pollwait);pwq-error = 0;pwq-table = NULL;pwq-inline_index = 0;_pollwait定义如下:/* Add a new entry */static void _pollwait(struct file *filp, wait_queue_head_t *wait_address,poll_table *p)struct poll_table_entry *entry = poll_get_entry(p);if (!entry)return;get_file(filp);entry-filp = filp;entry-wait_address = wait_address;init_waitqueue_entry(&entry-wait, current);add_wait_queue(wait_address,&entry-wait);通过init_waitqueue_entry初始化一个等待队列项,这个等待队列项关联的进程即当前调用select的进程。然后将这个等待队列项插入等待队列wait_address。Wait_address即在驱动poll函数内调用poll_wait(filp, &dev-inq, wait);时传入的该驱动的&dev-inq或者&dev-outq等待队列。注: 关于等待队列的工作原理可以参考下面这篇文档:/u2/60011/showart_1334657.html到这里我们明白了select如何将当前进程插入所有所监测的fd_set关联的驱动内的等待队列,那进程究竟是何时让出CPU进入睡眠状态的呢?进入睡眠状态是在do_select内调用schedule_timeout(_timeout)实现的。当select遍历完fd_set内的所有设备文件,发现没有文件可操作时(即retval=0),则调用schedule_timeout(_timeout)进入睡眠状态。唤醒该进程的过程通常是在所监测文件的设备驱动内实现的,驱动程序维护了针对自身资源读写的等待队列。当设备驱动发现自身资源变为可读写并且有进程睡眠在该资源的等待队列上时,就会唤醒这个资源等待队列上的进程。举个例子,比如内核的8250 uart driver:Uart是使用的Tty层维护的两个等待队列, 分别对应于读和写: (uart是tty设备的一种)struct tty_struct wait_queue_head_t write_wait;wait_queue_head_t read_wait;当uart设备接收到数据,会调用tty_flip_buffer_push(tty);将收到的数据push到tty层的buffer。然后查看是否有进程睡眠的读等待队列上,如果有则唤醒该等待会列。过程如下:serial8250_interrupt - serial8250_handle_port - receive_chars - tty_flip_buffer_push
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 运维合同保密协议范本
- 水鱼饲养协议书
- 茶水服务外包合同协议
- 行政管理模块培训
- 暑期支教协议书
- 遗产确权协议书模板
- 路灯车租赁合同协议
- 商业咨询服务协议详细规定
- 幼儿园劳动合同法律法规
- 产品定制与采购协议条款
- 2025年江苏省苏州市姑苏区中考数学一模试卷
- 2024年烟台龙口市卫生健康局所属事业单位招聘工作人员真题
- 二零二五版官方离婚协议书
- 山东铁投集团招聘招聘笔试真题2024
- 天猫公司转让合同协议
- 四川省绵阳市高中2022级第三次诊断性考试地理试题及答案(A卷)
- 压疮引起的疼痛护理
- 上海市静安区2025年高三二模英语试卷(含答案)
- 穿越时空的音乐鉴赏之旅智慧树知到期末考试答案章节答案2024年浙江中医药大学
- 架子工班组承包协议
- 化验室化学试剂台账范例
评论
0/150
提交评论