poll系统调用的内核态实现机制分析
前面已经比较详尽的分析了系统调用引发的内核执行过程,本文将继续分析一下linux2.6.38内核源码中poll函数(与select实现类似)的实现。
通过前面的分析,我们知道,应用程序中的open、read、write函数系统调用都会触发软中断异常,从而进入异常处理,在异常处理中将会获取用户态传入的系统调用号,根据系统调用号在系统调用表中索引出实际的系统调用处理函数,如内核里的sys_open、sys_read、sys_write函数,而内核里的这些函数又会对应到驱动程序里的open、read、write函数。
poll机制也不例外,用户空间里调用poll函数或者select函数时,都会调用到内核空间的sys_poll或者sys_select函数。下面以sys_poll来分析用户空间poll的实现:
用户空间调用:poll
内核: asmlinkage long sys_poll(struct pollfd __user *ufds, unsigned int nfds,long timeout);
即SYSCALL_DEFINE3(poll, struct pollfd __user *, ufds, unsigned int, nfds,long, timeout_msecs) //以前分析过,实际为宏
其实现如下:
\fs\select.c
SYSCALL_DEFINE3(poll, struct pollfd __user *, ufds, unsigned int, nfds,
long, timeout_msecs)
{
struct timespec end_time, *to = NULL;
int ret; if (timeout_msecs >= 0) {
to = &end_time;
poll_select_set_timeout(to, timeout_msecs / MSEC_PER_SEC,
NSEC_PER_MSEC * (timeout_msecs % MSEC_PER_SEC));
} ret = do_sys_poll(ufds, nfds, to); if (ret == -EINTR) {
struct restart_block *restart_block; restart_block = ¤t_thread_info()->restart_block;
restart_block->fn = do_restart_poll;
restart_block->poll.ufds = ufds;
restart_block->poll.nfds = nfds; if (timeout_msecs >= 0) {
restart_block->poll.tv_sec = end_time.tv_sec;
restart_block->poll.tv_nsec = end_time.tv_nsec;
restart_block->poll.has_timeout = 1;
} else
restart_block->poll.has_timeout = 0; ret = -ERESTART_RESTARTBLOCK;
}
return ret;
}
为了使结构简要直观,我们只列出调用关系框架:
用户空间:poll
内核: asmlinkage long sys_poll(struct pollfd __user *ufds, unsigned int nfds,long timeout);
即SYSCALL_DEFINE3(poll, struct pollfd __user *, ufds, unsigned int, nfds,long, timeout_msecs) //以前分析过,实际为宏
poll_select_set_timeout(to, timeout_msecs / MSEC_PER_SEC,NSEC_PER_MSEC * (timeout_msecs % MSEC_PER_SEC));//配置超时时间
do_sys_poll(ufds, nfds, to);
poll_initwait(&table);//初始化等待队列
init_poll_funcptr(&pwq->pt, __pollwait);
pt->qproc = qproc; /*table->pt->qproc= __pollwait;详见注释1-2*/
do_poll(nfds, head, &table, end_time);
for (;;)
{
for (; pfd != pfd_end; pfd++)//针对多个进程
{
if (do_pollfd(pfd, pt)) /*do_pollfd会调用驱动poll函数,poll里面的poll_wait最终调用pt->qproc函数(即__pollwait)将进程中可能引起待监测内容状态变化的等待队列链表头挂载到查询表中,除此以外,poll还会根据条件判断事件是否发生,发生则返回真,详见注释1-1*/
{
count++; //记录等待事件发生的进程数
pt = NULL;
}
}
if (!count) /*若count为0(表示无等待的事件发生)*/
{
count = wait->error;
if (signal_pending(current)) /*判断是否为信号唤醒*/
count = -EINTR;
}
/*若count不为0(有等待的事件发生了)或者timed_out不为0(有信号发生或超时),则推出休眠*/
if (count || timed_out)
break ;
/*上述条件不满足时进入休眠,若有等待的事件发生了,超时或收到信号则唤醒*/
if (!poll_schedule_timeout(wait, TASK_INTERRUPTIBLE, to, slack))
timed_out = 1;
}
poll_freewait(&table); //清除poll_wqueues占用的资源,包括加入到查询表中的等待队列链表头
注释1-1:
do_pollfd(pfd, pt)
mask = file->f_op->poll(file, pwait);/*调用驱动程序中的poll函数,若poll驱动函数返回值不为0则会使count++*/
调用关系如下:
do_pollfd(pfd, pt)
mask = file->f_op->poll(file, pwait); //即调用驱动中的poll函数(在写驱动程序时编写poll函数)
poll_wait //其作用为挂载当前进程中可能引起待监测内容状态变化的等待队列链表头到poll_table查询表中,具体实现如下
p->qproc(filp, wait_address, p);(p->qproc = __pollwait前面已有初始化)
__pollwait(struct file *filp, wait_queue_head_t *wait_address,poll_table *p)(上面展开即为本函数调用)
{
entry->wait_address = wait_address; //挂载进程等待队列链表头到查询表
add_wait_queue(wait_address, &entry->wait);
}
除此以外,poll驱动函数还会根据条件判断事件是否发生,发生则返回真,退出休眠;
下面是一个poll驱动函数的例子:
static unsigned forth_drv_poll(struct file *file, poll_table *wait)
{
unsigned int mask = 0;
poll_wait(file, &button_waitq, wait); // 将button_waitq等待链表头加入wait查询表
if (ev_press) //判断事件是否发生,发生了则返回真;
mask |= POLLIN | POLLRDNORM;
return mask;
}
注释1-2:
1. 此处主要目的为初始化函数指针,使其指向__pollwait函数,在poll驱动函数中将调用poll_wait,而该函数中将调用__pollwait函数将当前进程挂到等待队列中,
2. __pollwait函数中有这么两句:entry->wait_address = wait_address; add_wait_queue(wait_address, &entry->wait);用于将当前进程中可能引起监测内容变化的等待队列链表头挂到查询表中,table->pt->qproc= __pollwait就就是初始化table->pt->qproc函数指针 。
从上述分析可知,poll即使只有一个描述符就绪,也要遍历整个集合。如果集合中活跃的描述符很少,遍历过程的开销就会变得很大,而如果集合中大部分的描述符都是活跃的,遍历过程的开销又可以忽略。因此集合中大部分的描述符都是活跃的情况下,poll的使用效率高。每次用户空间调用poll函数时,都要将全部的数据复制到内核,复制数据增加了开销
本文参考:http://watter1985.iteye.com/blog/1614039
poll系统调用的内核态实现机制分析的更多相关文章
- Linux内核态抢占机制分析(转)
Linux内核态抢占机制分析 http://blog.sina.com.cn/s/blog_502c8cc401012pxj.html 摘 要]本文首先介绍非抢占式内核(Non-Preemptive ...
- Linux内核态抢占机制分析
http://blog.sina.com.cn/s/blog_502c8cc401012pxj.html [摘要]本文首先介绍非抢占式内核(Non-Preemptive Kernel)和可抢占式内核( ...
- Linux内核态抢占机制分析【转】
转自:http://blog.csdn.net/yiyeguzhou100/article/details/53097665 目录(?)[-] 1非抢占式和可抢占式内核的区别 21 用户态抢占User ...
- Linux内核抢占实现机制分析【转】
Linux内核抢占实现机制分析 转自:http://blog.chinaunix.net/uid-24227137-id-3050754.html [摘要]本文详解了Linux内核抢占实现机制.首先介 ...
- linux内核剖析(六)Linux系统调用详解(实现机制分析)
本文介绍了系统调用的一些实现细节.首先分析了系统调用的意义,它们与库函数和应用程序接口(API)有怎样的关系.然后,我们考察了Linux内核如何实现系统调用,以及执行系统调用的连锁反应:陷入内核,传递 ...
- poll机制分析
更多文档:http://pan.baidu.com/s/1sjzzlDF linux poll/select用法及在字符驱动中的简单实现 1.poll和select 使用非阻塞I/O 的应用程序常常使 ...
- 系统调用syscall---用户态切换到内核态的唯一途径
1.应用程序有时需要内核协助完成一些处理,但是应用程序不可能执行内核代码(主要是安全性考虑), 那么,应用程序需要有一种机制告诉内核,它现在需要内核的帮助,这个机制就是系统调用. 2.系统调用的本质是 ...
- linux 用户态和内核态以及进程上下文、中断上下文 内核空间用户空间理解
1.特权级 Intel x86架构的cpu一共有0-4四个特权级,0级最高,3级最低,ARM架构也有不同的特权级,硬件上在执行每条指令时都会对指令所具有的特权级做相应的检查.硬件已经提 ...
- Linux操作系统学习_用户态与内核态之切换过程
因为操作系统的很多操作会消耗系统的物理资源,例如创建一个新进程时,要做很多底层的细致工作,如分配物理内存,从父进程拷贝相关信息,拷贝设置页目录.页表等,这些操作显然不能随便让任何程序都可以做,于是就产 ...
随机推荐
- C指针陷阱
问题一: #include <stdio.h> int main(int argc, char *argv[]) { ]={ ,,,, }; ); printf(),*(p-)); ; } ...
- 字符串匹配算法(KMP)
字符串匹配运用很广泛,举个简单例子,我们每天登QQ时输入账号和密码,大家有没有想过账号和密码是怎样匹配的呢?登录需要多长时间和匹配算法的效率有直接的关系. 首先理解一下前缀和后缀的概念: 给出一个问题 ...
- js中设置setInterval的注意点
<html> <head> <meta http-equiv="Content-Type" content="text/html; char ...
- 运行PHP
/usr/local/php/bin/php /home/www/index.php
- Python:爬取乌云厂商列表,使用BeautifulSoup解析
在SSS论坛看到有人写的Python爬取乌云厂商,想练一下手,就照着重新写了一遍 原帖:http://bbs.sssie.com/thread-965-1-1.html #coding:utf- im ...
- 转: seajs手册与文档之--模块定义
模块定义 define id dependencies factory exports require require.async require.resolve require.load requi ...
- VC++对象布局的奥秘:虚函数、多继承、虚拟继承
哈哈,从M$ Visual C++ Team的Andy Rich那里又偷学到一招:VC8的隐含编译项/d1reportSingleClassLayout和/d1reportAllClassLayout ...
- spring的定时执行代码 跑批
最近公司上线了抽奖的活动,活动需求 1:每天凌晨更新状态,实现自动开启和关闭活动 2:活动结束自动抽取中奖号码 在这里提供spring的定时调度功能 1:首先是配置文件 在你的web.xml中,查看配 ...
- Android绘图监听接口OnPreDrawListener详解
public static interface ViewTreeObserver.OnPreDrawListener 我们先看下API中的定义: 类概述: 为即将绘制视图树时执行的回调函数定义的接口. ...
- BZOJ 1607: [Usaco2008 Dec]Patting Heads 轻拍牛头
1607: [Usaco2008 Dec]Patting Heads 轻拍牛头 Description 今天是贝茜的生日,为了庆祝自己的生日,贝茜邀你来玩一个游戏. 贝茜让N(1≤N≤10 ...