linux的wait使用方法

1.声明一个等待队列

    法一:static DECLARE_WAIT_QUEUE_HEAD(button_waitq);。

    法二:wait_queue_head_t button_waitq;    

               init_waitqueue_head(&button_waitq))

           用到此队列时,一般用的是&button_waiq

2.wait_event不能被信号来唤醒。而wait_event_interruptible可以被信号唤醒。两个的差别可以在内核函数定

    义处的注释中看到。

3.    wake_up() 可唤醒处于TASK_INTERRUPTIBLE和TASK_UNINTERRUPTIBLE的进程, 而                        

      wake_up_interruptible() 只能唤醒处于TASK_INTERRUPTIBLE的进程。

        在应用wait_event,  wait_event_interruptible,  wake_up,  wake_up_interruptible时这些不考虑信号问

     题时可以交叉使用。

 

4.《Linux设备驱动开发详解》=> 232页 有对队列元素的处理代码。此代码与wait_event_interruptible最后调 

     用到的__wait_event_interruptible宏里边的代码几乎一样。

 

poll_wait():

退出循环的条件:

(1)count非0,超时、有信号等待处理

(2)发生错误

(3)我们的驱动程序里注册的poll函数返回值非0

 

        应用程序执行poll调用后,如果(1)(2)(3)的条件不满足,进程就会进入休眠。那么,谁唤醒呢?除了休眠到指定时间被系统唤醒外,还可以被驱动程序唤醒,这就是驱动的poll里要调用poll_wait的原因,后面分析。

 poll_wait()作用

        把当前进程(app)挂入我们驱动程序里定义的一个队列里(为了让驱动程序能找到要唤醒的进程)。

一般poll_wait()函数在驱动的.poll中调用。如果应用程序没用到poll,可以不调用poll_wait。例:驱动的.read函数里调用wait_event_interruptible,中断里wake_up。

    

poll (app调用) => sys_poll => do_sys_poll => poll_initwait(&table) => do_poll

=>   do_pollfd =>   .poll  //驱动中自己写的poll函数;      schedule_timeout  //进入休眠。

如果我们的驱动程序发现情况就绪,可以把这个队列上挂着的进程唤醒。

 

wait_event_interruptible():

成功地唤醒一个被wait_event_interruptible()的进程,需要满足: 

     (1)condition为真的前提下  (2) 调用wake_up()。 

    condition一般声明为static volatile int类型

 

关于wait_event_interruptible的返回值 

根据 wait_event_interruptible 的宏定义知: 

   1) 条件condition为真时调用这个函数将直接返回0,而当前进程不会 

      被 wait_event_interruptible和从runqueue队列中删除。 

   2) 如果要被wait_event_interruptible的当前进程有nonblocked pending 

      signals, 那么会直接返回-ERESTARTSYS(i.e. -512),当前进程不会 

      被wait_event_interruptible 和从runqueue队列中删除。 

   3) 其他情况下,当前进程会被正常的wait_event_interruptible,并从 

      runqueue队列中删除,进入TASK_INTERRUPTIBLE状态退出运行调度, 

      直到再次被唤醒加入runqueue队列中后而参与调度,将正常返回0。 

 

wait_event_interruptible  宏 

 

#define wait_event_interruptible(wq, condition)    \ 

({                                                 \ 

     int __ret = 0;                                  \ 

     if (!(condition))                               \ 

      __wait_event_interruptible(wq, condition, __ret); \ 

      __ret;                                         \ 

}) 

 

注: C语言中{a,b, ..., x}的的值等于最后一项,即x,因此上述 

宏的值是 __ret。 

 #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_event_interruptible()的源码,不难发现这个函数先将 当前进程的状态设置成TASK_INTERRUPTIBLE,如果condition为假,调用schedule(), 而schedule()会将位于TASK_INTERRUPTIBLE状态的当前进程从runqueue 队列中删除。从runqueue队列中删除的

结果是,当前这个进程将不再参 与调度,除非通过其他函数将这个进程重新放入这个runqueue队列中, 

这就是wake_up()的作用了。 

      由于这一段代码位于一个由condition控制的for(;;)循环中,所以当由 shedule()返回时(当然是被wake_up之后,通过其他进程的schedule()而再次调度本进程),如果条件condition不满足,本进程将自动再次被设 置为TASK_INTERRUPTIBLE状态,接下来执行schedule()的结果是再次被 从runqueue队列中删除。这时候就需要再次通过wake_up重新添加到 runqueue队列中。 

      如此反复,直到condition为真的时候被wake_up.

 

总结一下poll机制:

1. poll(应用程序) > sys_poll > do_sys_poll > poll_initwait,poll_initwait函数注册一下回调函数         

    __pollwait,它就是我们的驱动程序执行poll_wait时,真正被调用的函数。

2. 接下来执行file->f_op->poll,即我们驱动程序里自己实现的poll函数

   它会调用poll_wait把当前进程(app)挂入我们的驱动自己定义的队列;

   它还判断一下设备是否就绪。(即驱动的poll的返回值是不是0,若 不是0,则设备就绪)

3. 如果设备未就绪,do_sys_poll里会让进程休眠应用中指定的时间

4. 进程被唤醒的条件有2:一是上面说的“一定时间”到了,二是被驱动程序唤醒。驱动程序发现条件就绪时,  

    就把“某个队列”上挂着的进程唤醒,这个队列,就是前面通过poll_wait把本进程挂过去的队列。

5. 如果驱动程序没有去唤醒进程,那么chedule_timeout(__timeou)超时后,会重复2、3动作,

     直到应用程序的 poll调用传入的时间到达。

 

http://blog.sina.com.cn/s/blog_14f1cd81a0102wxp5.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值