免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 7869 | 回复: 9
打印 上一主题 下一主题

关于wait_event_interruptible()函数的一个问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2011-12-22 11:31 |只看该作者 |倒序浏览
最近在看wait_event_interruptible()函数的源码,下面是其中的关键部分:
  1. for (;;) {                                                        \
  2.                 prepare_to_wait(&wq, &__wait, TASK_INTERRUPTIBLE);        \
  3.                 if (condition)                                                \
  4.                         break;                                                \
  5.                 if (!signal_pending(current)) {                                \
  6.                         schedule();                                        \
  7.                         continue;                                        \
  8.                 }                                                        \
  9.                 ret = -ERESTARTSYS;                                        \
  10.                 break;                                                        \
  11.         }                                                                \
  12.         finish_wait(&wq, &__wait);
复制代码
当condition条件满足的时候,就会跳出for循环,执行finish_wait函数。在finish_wait函数中,会将当前进程状态设为运行态,从而唤醒进程:
  1. __set_current_state(TASK_RUNNING);
复制代码
也就是说,wait_event_interruptible()函数一直循环等待condition为真,为真则唤醒进程,否则就执行cpu调度去运行别的进程。不知道我的理解对不对呢?如果对的话,我就有一个问题了,wait_event_interruptible()函数可以自己唤醒,那么为什么还要wake_up_interruptible()呢?

论坛徽章:
0
2 [报告]
发表于 2011-12-22 12:21 |只看该作者
一个进程能执行wait_event_interruptible()里面的代码,说明它是在CPU上运行的进程。一个进程能在CPU上运行,说明它已经是TASK_RUNNING状态的了。

后面为什么要__set_current_state(TASK_RUNNING)?因为prepare_to_wait()已经将状态设置成了TASK_INTERRUPTIBLE。不管是因为condition满足,还是因为收到信号,反正只有当这个进程不需要再睡眠的时候才会从循环中break出来。那么既然不需要睡眠了,最后当然应该把状态改回TASK_RUNNING。

论坛徽章:
0
3 [报告]
发表于 2011-12-22 12:54 |只看该作者
恩,那是不是说在执行了prepare_to_wait(&wq, &__wait, TASK_INTERRUPTIBLE)之后该进程的状态变成了TASK_INTERRUPTIBLE,然后阻塞在下面的schedule()调度函数,直到在其它进程中调用了wake_up_interruptible()将该进程的状态改为TASK_RUNNING,然后continue继续执行for循环。如果condition不满足且没有信号,在prepare_to_wait()中再次将它的状态改成TASK_INTERRUPTIBLE,然后等待下一次的唤醒。
我这样理解对吗?

论坛徽章:
0
4 [报告]
发表于 2011-12-22 12:56 |只看该作者
不会一直循环
因为状态是TASK_INTERRUPTIBLE,所以schedule()会调度别的进程运行,这个进程睡去
因wake_up_interruptible或信号被唤醒时才从schedule()返回

论坛徽章:
6
金牛座
日期:2013-10-08 10:19:10技术图书徽章
日期:2013-10-14 16:24:09CU十二周年纪念徽章
日期:2013-10-24 15:41:34狮子座
日期:2013-11-24 19:26:19未羊
日期:2014-01-23 15:50:002015年亚洲杯之阿联酋
日期:2015-05-09 14:36:15
5 [报告]
发表于 2011-12-22 13:24 |只看该作者
schedule()之后,就会切换到别的进程中执行,而且由于当前进程已经不再runqueue中,所以永远都不会在被执行了,除非通过wakeup_interruptible函数,将当前进程放到运行队列中。

论坛徽章:
22
丑牛
日期:2014-08-15 14:32:0015-16赛季CBA联赛之同曦
日期:2017-12-14 15:28:14黑曼巴
日期:2017-08-10 08:14:342017金鸡报晓
日期:2017-02-08 10:39:42黑曼巴
日期:2016-11-15 15:48:38CU十四周年纪念徽章
日期:2016-11-09 13:19:1015-16赛季CBA联赛之同曦
日期:2016-04-08 18:00:03平安夜徽章
日期:2015-12-26 00:06:30程序设计版块每日发帖之星
日期:2015-12-03 06:20:002015七夕节徽章
日期:2015-08-21 11:06:17IT运维版块每日发帖之星
日期:2015-08-09 06:20:002015亚冠之吉达阿赫利
日期:2015-07-03 08:39:42
6 [报告]
发表于 2011-12-22 20:48 |只看该作者
睡眠了 循环就停住了

论坛徽章:
1
拜羊年徽章
日期:2015-03-03 16:15:43
7 [报告]
发表于 2011-12-23 01:04 |只看该作者
本帖最后由 linuxfellow 于 2011-12-23 22:02 编辑

当前进程已经不在runqueque, 不能调用wait_event_interruptible()来改变自己的状态。任何进程调用wait_event_interruptible()只能改变自己的状态, 不改变其他进程的状态。当前进程回到runqueque只能靠它所等待的event发生。

论坛徽章:
2
技术图书徽章
日期:2015-12-16 09:12:1619周年集字徽章-庆
日期:2019-09-12 16:09:19
8 [报告]
发表于 2011-12-23 12:01 |只看该作者
学习

论坛徽章:
0
9 [报告]
发表于 2013-01-14 17:51 |只看该作者
请教大家几个问题,先在此谢过了!!!
/* wait_event_interruptible  宏 */   
#define wait_event_interruptible(wq, condition)    \
({                                                 \
     int __ret = 0;                                  \
     if (!(condition))                               \
      __wait_event_interruptible(wq, condition, __ret); \
      __ret;                                         \
})
       
当进程执行(进入)wait_event_interruptible宏时,首先检查一遍condition是否为真,如果为真,直接跳出wait_event_interruptible 宏,继续向下执行。


当condition为假时,进入__wait_event_interruptible:


/* __wait_event_interruptible 宏 */
#define __wait_event_interruptible(wq, condition, ret)      \
do {                                                        \
     DEFINE_WAIT(__wait);                                    \
     for (; {                                              \
         prepare_to_wait(&wq, &__wait, TASK_INTERRUPTIBLE); \
         if (condition)                                      \
             break;                                          \
         if (!signal_pending(current)) {                     \
             schedule();                                     \
             continue;                                       \
         }                                                   \
         ret = -ERESTARTSYS;                                 \
         break;                                              \
     }                                                       \
     finish_wait(&wq, &__wait);                              \
} while (0)

一,进入__wait_event_interruptible后,首先定义并初始化一个wait_queue_t变量__wait,其中数据为当前进程current,并把__wait入队。
接着进入for死循环中:
在for循环中,__wait_event_interruptible将本进程置为可中断的挂起状态,之后检查condition,如果condition为真,跳出for循环,执行finish_wait,在finish_wait函数中,会将当前进程状态设为运行态,之后跳出wait_event_interruptible。进程继续向下执行。

二,如果进入for循环后,第一次检查condition为假时,
进入第二个if语句,调用schedule,将位于TASK_INTERRUPTIBLE状态的当前进程从runqueue

队列中删除,而从runqueue队列中删除的结果是,当前这个进程将不再参与调度,(schedule()会调度别的进程运行,这个进程睡去,因wake_up_interruptible或信号被唤醒时才从schedule()返回)然后进程就停在这了!??等待唤醒,即等待调用wake_up。
如果不在其他函数内(中断处理程序)调用wake_up,那当前进程就死在这了????
如果中断处理程序中调用wake_up(将这个进程重新放入这个runqueue队列中),那当前进程就等待被调度,被调度之后,即执行continue。继续for循环。

我有几个疑问要请教:
一,我以上所述是否正确???
二,检查condition是否为真是在调用wake_up之后执行一次是吗?也就是说每wake_up一次才检测一次condition是否为真???
三,如果当前进程不被调度之后,一直没有wake_up执行,那当前进程就死在这了???

论坛徽章:
0
10 [报告]
发表于 2013-04-29 21:47 |只看该作者
回复 9# Unix-wang

看了wait_event_interruptible() 代码,比较认同你的观点;
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP