免费注册 查看新帖 |

Chinaunix

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

单单一个wait_event_interruptible()就能唤醒自己? [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2012-03-13 17:08 |只看该作者 |倒序浏览
wait_event_interruptible()。该函数修改task的状态为TASK_INTERRUPTIBLE,意味着改进程将不会继续运行直到被唤醒,然后被添加到等待队列wq中。
在wait_event_interruptible()中首先判断condition是不是已经满足,如果是则直接返回0,否则调用__wait_event_interruptible(),并用__ret来存放返回值
---------------------------------------------------------------
#define wait_event_interruptible(wq, condition)          \
({                                                       \
    int __ret = 0;                                       \
    if (!(condition))                                    \
        __wait_event_interruptible(wq, condition, __ret);\
    __ret;                                               \
})
wait_event_interruptible() --> __wait_event_interruptible()
__wait_event_interruptible()首先定义并初始化一个wait_queue_t变量__wait,其中数据为当前进程current,并把__wait入队。
   
在无限循环中,__wait_event_interruptible()将本进程置为可中断的挂起状态,反复检查condition是否成立,如果成立
则退出,如果不成立则继续休眠;条件满足后,即把本进程运行状态置为运行态,并将__wait从等待队列中清除掉,从而进程能够调度运行。如果进程当前有
异步信号(POSIX的),则返回-ERESTARTSYS。

那既然这样,也就是单单一个wait_event_interruptible()就能唤醒自己 ?
我在某处
int flag = 0;
wait_event_interruptible(wq,flag !=0);
就会睡眠了,那我在其他函数里:flag =1 ;
按照上面的说法,进程就唤醒了??那要wake_up_interruptible()干嘛????

论坛徽章:
0
2 [报告]
发表于 2012-03-13 17:17 |只看该作者
你以为你那个for(;循环一直在跑啊,它里面有schedule,如果进程状态为TASK_INTERRUPTIBLE且没有pending的信号时,它就睡眠了,schedule就不返回了,此时你在某处flag=1有个P用?

论坛徽章:
0
3 [报告]
发表于 2012-03-13 17:18 |只看该作者
本帖最后由 MagicBoy2010 于 2012-03-13 17:18 编辑

靠,for(;  分号)居然还有表情,CU真是太强悍了

论坛徽章:
0
4 [报告]
发表于 2012-03-13 17:32 |只看该作者
MagicBoy2010 发表于 2012-03-13 17:18
靠,for(;  分号)居然还有表情,CU真是太强悍了


请教下:
在这个例子代码中, 你可找到一
个称为 sleepy 的模块. 它实现一个有简单行为的设备:任何试图从这个设备读取的进程
都被置为睡眠. 无论何时一个进程写这个设备, 所有的睡眠进程被唤醒. 这个行为由下面
的 read 和 write 方法实现:  

static DECLARE_WAIT_QUEUE_HEAD(wq);  
static int flag = 0;  
  
ssize_t sleepy_read (struct file *filp, char __user *buf, size_t count, loff_t  
*pos)  
{  
        printk(KERN_DEBUG "process %i (%s) going to sleep\n",  
               current->pid, current->comm);  
        wait_event_interruptible(wq, flag != 0);  
        flag = 0;  
        printk(KERN_DEBUG "awoken %i (%s)\n", current->pid, current->comm);  
        return 0; /* EOF */  
}  
ssize_t sleepy_write (struct file *filp, const char __user *buf, size_t count,  
loff_t *pos)  
{  
        printk(KERN_DEBUG "process %i (%s) awakening the readers...\n",  
               current->pid, current->comm);  
        flag = 1;  
        wake_up_interruptible(&wq);  
        return count; /* succeed, to avoid retrial */  
  
}  
有趣的是考虑当 sleepy_write 被调用时如果有 2 个进程在等待会发生什么. 因为  
sleepy_read 重置 flag 为 0 一旦它醒来, 你可能认为醒来的第 2 个进程会立刻回到睡
眠.
在一个单处理器系统, 这几乎一直是发生的事情

红色字体是为什么??想不通,2个都唤醒了,为什么第二个会睡眠?当第一个醒了后,flag=0 ,那又如何?难道read()函数会被调用2次吗????

论坛徽章:
0
5 [报告]
发表于 2012-03-13 17:40 |只看该作者
楼上的旁友,我快下班了,没时间仔细看你的代码了,我大概说一下,”wait_event_interruptible函数调用中, WQ_FLAG_EXCLUSIVE标志是被清除的,这意味着wake_up_interruptible会试图唤醒等待队列中每个结点上的进程“ --- ILDD P247

论坛徽章:
0
6 [报告]
发表于 2012-03-13 18:20 |只看该作者
win1naruto 发表于 2012-03-13 17:32
红色字体是为什么??想不通,2个都唤醒了,为什么第二个会睡眠?当第一个醒了后,flag=0 ,那又如何?难道read()函数会被调用2次吗????

wait_event_interruptible不是要判断flag !=0这个条件么?第二个进程被唤醒了,但是flag已经被改为0,__wait_event_interruptible又会继续睡眠。
  1. #define __wait_event_interruptible(wq, condition, ret)                        \
  2. do {                                                                        \
  3.         DEFINE_WAIT(__wait);                                                \
  4.                                                                         \
  5.         for (;;) {                                                        \
  6.                 prepare_to_wait(&wq, &__wait, TASK_INTERRUPTIBLE);        \
  7.                 if (condition)                                                \
  8.                         break;                                                \
  9.                 if (!signal_pending(current)) {                                \
  10.                         schedule();                                        \
  11.                         continue;                                        \
  12.                 }                                                        \
  13.                 ret = -ERESTARTSYS;                                        \
  14.                 break;                                                        \
  15.         }                                                                \
  16.         finish_wait(&wq, &__wait);                                        \
  17. } while (0)
复制代码

论坛徽章:
0
7 [报告]
发表于 2012-03-14 11:08 |只看该作者
kouu 发表于 2012-03-13 18:20
wait_event_interruptible不是要判断flag !=0这个条件么?第二个进程被唤醒了,但是flag已经被改为0,__w ...

也就是睡眠,然后被唤醒,唤醒后还要检测一次条件的,就是这个意思对吧

论坛徽章:
0
8 [报告]
发表于 2013-01-14 17:32 |只看该作者
请教大家几个问题,先在此谢过了!!!
/* 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,之后跳出wait_event_interruptible。进程继续向下执行。

二,如果进入for循环后,第一次检查condition为假时,
进入第二个if语句,调用schedule,将位于TASK_INTERRUPTIBLE状态的当前进程从runqueue
队列中删除,而从runqueue队列中删除的结果是,当前这个进程将不再参与调度,然后进程就停在这了!??等待唤醒,即等待调用wake_up。
如果不在其他函数内(中断处理程序)调用wake_up,那当前进程就死在这了????
如果中断处理程序中调用wake_up(将这个进程重新放入这个runqueue队列中),那当前进程就等待被调度,被调度之后,即执行continue。继续for循环。

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

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP