可以睡眠的poll-阿里云开发者社区

开发者社区> 科技小能手> 正文

可以睡眠的poll

简介:
+关注继续查看

file_operations中有许多的回调函数,正是这些回调函数实现了vfsvfs提供了一个机制,这些回调函数提供了不同的策略,等于说实现了vfs,照理说这些函数不应该有任何限制,但是唯独一个poll回调函数与众不同,它不能睡眠,这是为何呢?

     除了poll以外的回调函数都拥有直接的语义,比如read就是读,write就是写,因此系统调用层可以直接将执行路径交给vfs,比如在sys_read函数中,几乎做了简单的判断之后就马上调用了真正文件系统的file_operationsread函数,但是poll函数比较特殊,它并没有简单的语义,其实它就是轮询,可是它不像readwrite那样系统调用层和vfs层那么统一,pollvfs层的意思就是“看看这个文件是否有动作”,但是在系统调用层的意义就是“看看这些文件中哪个有动作”,这就是不同,为了将系统调用层的语义平滑的过度到vfs层,就必须在系统调用和vfs只见插入机制,这个机制实现了poll,当然还包括select。在poll的实现中,靠的是进程的状态来同步睡眠/唤醒动作的,它并不是在将进程加入睡眠队列后马上睡眠,而是不睡眠等到所有poll的文件描述符均加入队列后再睡眠,其实仅仅是左一个调度罢了,总体框架如下:

for (;;)

       set_current_state(TASK_INTERRUPTIBLE)

           for each fd to poll

           ask driver if I/O can happen

           add current process to driver wait queue

        if one or more fds are ready

           break

      schedule_timeout_range(...)

注意,这里是在一开始就将进程的状态设置为TASK_INTERRUPTIBLE但是不睡眠,在中间的for循环中陆续将进程加入到睡眠队列,到了最后才切换进程,等于说就是睡眠了,看看这个糟糕的实现,在设置了进程TASK_INTERRUPTIBLE状态后那么大一会才将进程切换,这很是丑陋,丑陋的本质原因就是vfs实现的pollpoll一个文件描述符,但是系统调用的语义是poll一大堆的文件描述符,在没有必要添加适配机制的情况下,只好用进程状态来实现了,2.6.29内核实在是看不下去这个局面了,于是提出了poll和别的file_operations的回调函数一样,也可以睡眠,并且可以用传统的睡眠唤醒函数来唤醒进程:

+static int pollwake(wait_queue_t *wait, unsigned mode, int sync, void *key)

+{

+     struct poll_wqueues *pwq = wait->private;

+     DECLARE_WAITQUEUE(dummy_wait, pwq->polling_task);

+

+     set_mb(pwq->triggered, 1);

+

+     /* perform the default wake up operation */

+     return default_wake_function(&dummy_wait, mode, sync, key);

+}

static void __pollwait(struct file *filp, wait_queue_head_t *wait_address, poll_table *p)

 {

-      struct poll_table_entry *entry = poll_get_entry(p);

+     struct poll_wqueues *pwq = container_of(p, struct poll_wqueues, pt);

+     struct poll_table_entry *entry = poll_get_entry(pwq);

      if (!entry)

             return;

      get_file(filp);

      entry->filp = filp;

      entry->wait_address = wait_address;

-      init_waitqueue_entry(&entry->wait, current);

+     init_waitqueue_func_entry(&entry->wait, pollwake);

+     entry->wait.private = pwq;

      add_wait_queue(wait_address, &entry->wait);

 }

+int poll_schedule_timeout(struct poll_wqueues *pwq, int state,

+                     ktime_t *expires, unsigned long slack)

+{

+     int rc = -EINTR;

+

+     set_current_state(state);

+     if (!pwq->triggered)

+            rc = schedule_hrtimeout_range(expires, slack, HRTIMER_MODE_ABS);

+     __set_current_state(TASK_RUNNING);

+

+     /* clear triggered for the next iteration */

+     pwq->triggered = 0;

+

+     return rc;

+}

 

int do_select(int n, fd_set_bits *fds, s

      for (;;) {

             unsigned long *rinp, *routp, *rexp, *inp, *outp, *exp;

-             set_current_state(TASK_INTERRUPTIBLE);

             inp = fds->in; outp = fds->out; exp = fds->ex;

             rinp = fds->res_in; routp = fds->res_out; rexp = fds->res_ex;

@@ -411,10 +436,10 @@ int do_select(int n, fd_set_bits *fds, s

                    to = &expire;

             }

-             if (!schedule_hrtimeout_range(to, slack, HRTIMER_MODE_ABS))

+            if (!poll_schedule_timeout(&table, TASK_INTERRUPTIBLE,

+                                    to, slack))

                    timed_out = 1;

      }

-      __set_current_state(TASK_RUNNING);

      poll_freewait(&table);

我们可以看到在这个可睡眠的poll的补丁中,去掉了刻意为了适配加入的设置进程状态的语句,加入了统一的linux的睡眠/唤醒机制,poll_schedule_timeout是个新加入的函数,实际上它就是poll中的睡眠函数,和wait_event没有本质区别的,这样的话,加入这些函数,poll的实现和别的回调函数变得统一起来的。

     实际上,我发现在2.6.29内核中,代码变得更加统一了,内核逻辑变得更加统一了,和前一篇文章我谈到的credtask_struct中分离一样,poll可睡眠的意义也十分的大,比如将来为了加入新的机制要大改代码,起码file_operations中的回调函数都是统一的,这样就可以将之独立成一个模块而不用和别的模块杂糅。


 本文转自 dog250 51CTO博客,原文链接:http://blog.51cto.com/dog250/1274186


版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
使用NAT网关轻松为单台云服务器设置多个公网IP
在应用中,有时会遇到用户询问如何使单台云服务器具备多个公网IP的问题。 具体如何操作呢,有了NAT网关这个也不是难题。
26784 0
阿里云服务器怎么设置密码?怎么停机?怎么重启服务器?
如果在创建实例时没有设置密码,或者密码丢失,您可以在控制台上重新设置实例的登录密码。本文仅描述如何在 ECS 管理控制台上修改实例登录密码。
10061 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,阿里云优惠总结大概有三种登录方式: 登录到ECS云服务器控制台 在ECS云服务器控制台用户可以更改密码、更换系.
13874 0
windows server 2008阿里云ECS服务器安全设置
最近我们Sinesafe安全公司在为客户使用阿里云ecs服务器做安全的过程中,发现服务器基础安全性都没有做。为了为站长们提供更加有效的安全基础解决方案,我们Sinesafe将对阿里云服务器win2008 系统进行基础安全部署实战过程! 比较重要的几部分 1.
9157 0
腾讯云服务器 设置ngxin + fastdfs +tomcat 开机自启动
在tomcat中新建一个可以启动的 .sh 脚本文件 /usr/local/tomcat7/bin/ export JAVA_HOME=/usr/local/java/jdk7 export PATH=$JAVA_HOME/bin/:$PATH export CLASSPATH=.
4654 0
阿里云ECS云服务器初始化设置教程方法
阿里云ECS云服务器初始化是指将云服务器系统恢复到最初状态的过程,阿里云的服务器初始化是通过更换系统盘来实现的,是免费的,阿里云百科网分享服务器初始化教程: 服务器初始化教程方法 本文的服务器初始化是指将ECS云服务器系统恢复到最初状态,服务器中的数据也会被清空,所以初始化之前一定要先备份好。
7360 0
阿里云服务器ECS登录用户名是什么?系统不同默认账号也不同
阿里云服务器Windows系统默认用户名administrator,Linux镜像服务器用户名root
4498 0
23706
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
《2021云上架构与运维峰会演讲合集》
立即下载
《零基础CSS入门教程》
立即下载
《零基础HTML入门教程》
立即下载