这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » STM32 » 有关 等待队列和wait_event_interruptible() 和 wak

共2条 1/1 1 跳转至

有关 等待队列和wait_event_interruptible() 和 wake_up()

高工
2018-11-27 08:36:20     打赏

linux内核里的等待队列机制在做驱动开发时用的非常多,多用来实现阻塞式访问,下面简单总结了等待队列的四种用法,希望对读者有所帮助。


1. 睡眠等待某个条件发生(条件为假时睡眠):


    睡眠方式:wait_event, wait_event_interruptible

            唤醒方式:wake_up (唤醒时要检测条件是否为真,如果还为假则继续睡眠,唤醒前一定要把条件变为真)


2. 手工休眠方式一:


    1)建立并初始化一个等待队列项

                DEFINE_WAIT(my_wait) <==> wait_queue_t my_wait; init_wait(&my_wait);

            2)将等待队列项添加到等待队列头中,并设置进程的状态

                prepare_to_wait(wait_queue_head_t *queue, wait_queue_t *wait, int state)

            3)调用schedule(),告诉内核调度别的进程运行

            4)schedule返回,完成后续清理工作

                finish_wait()


3. 手工休眠方式二:


    1)建立并初始化一个等待队列项:

                DEFINE_WAIT(my_wait) <==> wait_queue_t my_wait; init_wait(&my_wait);

            2)将等待队列项添加到等待队列头中:

                add_wait_queue

            3)设置进程状态

                __set_current_status(TASK_INTERRUPTIBLE);

            4)schedule()

            5)将等待队列项从等待队列中移除

                remove_wait_queue()


其实,这种休眠方式相当于把手工休眠方式一中的第二步prepare_to_wait拆成两步做了,即prepare_to_wait <====>add_wait_queue + __set_current_status,其他都是一样的。


4. 老版本的睡眠函数sleep_on(wait_queue_head_t *queue):


    将当前进程无条件休眠在给定的等待队列上,极不赞成使用这个函数,因为它对竞态没有任何保护机制。




1. 关于 wait_event_interruptible() 和 wake_up()的使用

  

读一下wait_event_interruptible()的源码,不难发现这个函数先将 

当前进程的状态设置成TASK_INTERRUPTIBLE,然后调用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. 

  

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

  

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


所以,如果你仅仅修改condition,那么只是满足其中一个条件,这个时候,

被wait_event_interruptible()起来的进程尚未位于runqueue队列中,因 

此不会被 schedule。这个时候只要wake_up一下就立刻会重新进入运行调度。 

  

2. 关于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。 

  

附1: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。 

  

  

附2:wait_event_interruptible()和 wake_up的等效代码 

  

wait_event_interruptible(wq, condition) /*等效没有考虑返回值*/ 

     if (!(condition)) 

     { 

         wait_queue_t _ _wait; 

         init_waitqueue_entry(&_ _wait, current); 

         add_wait_queue(&wq, &_ _wait); 

         for (;;) 

         { 

            set_current_state(TASK_INTERRUPTIBLE); 

            if (condition) 

            break; 

            schedule();  /* implicit call: del_from_runqueue(current)*/ 

         } 

         current->state = TASK_RUNNING; 

         remove_wait_queue(&wq, &_ _wait); 

      } 

  

  

void wake_up(wait_queue_head_t *q) 

      struct list_head *tmp; 

      wait_queue_t *curr; 

      list_for_each(tmp, &q->task_list) 

      { 

        curr = list_entry(tmp, wait_queue_t, task_list); 

        wake_up_process(curr->task); 

        /* implicit call: add_to_runqueue(curr->task);*/ 

        if (curr->flags) 

          break; 

      } 





管理员
2018-11-27 10:44:41     打赏
2楼

谢谢楼主分享


共2条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]