免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12
最近访问板块 发新帖
楼主: chishanmingshen
打印 上一主题 下一主题

[内核模块] prepare_to_wait的疑问。。。 [复制链接]

论坛徽章:
4
酉鸡
日期:2014-03-21 23:19:50狮子座
日期:2014-08-01 22:11:40酉鸡
日期:2015-01-10 21:31:442015年辞旧岁徽章
日期:2015-03-03 16:54:15
11 [报告]
发表于 2014-07-25 08:48 |只看该作者
本帖最后由 chishanmingshen 于 2014-07-25 08:51 编辑

因为浪费一次,可能就意味着永远不能被**了.....啊!

(唤-醒 是屏蔽成 ** 了....)

论坛徽章:
0
12 [报告]
发表于 2014-07-25 15:30 |只看该作者
schedule_timeout
wait_event_interruptible_timeout

论坛徽章:
1
双鱼座
日期:2013-08-28 13:47:26
13 [报告]
发表于 2014-07-25 15:36 |只看该作者
Process B should take the responsibility for waking up process A. Just one more loop.  If process B wakes up process A after the 'spacefree ' check, process A will be in task_running state, it will schedule back again a moment later. If process B wakes up process A before the 'parpare_to_wait', the spacefree will not be zero and the scheduling will not happened.

论坛徽章:
4
酉鸡
日期:2014-03-21 23:19:50狮子座
日期:2014-08-01 22:11:40酉鸡
日期:2015-01-10 21:31:442015年辞旧岁徽章
日期:2015-03-03 16:54:15
14 [报告]
发表于 2014-07-25 16:38 |只看该作者
回复 13# firkraag


    > If process B wakes up process A after the 'spacefree ' check, process A will be in task_running state, it will schedule back again a moment later.
  是啊,A会回来并且执行schedule,但是此时spacefree已经被B改了!

  这次**机会丢失了!

论坛徽章:
1
双鱼座
日期:2013-08-28 13:47:26
15 [报告]
发表于 2014-07-25 16:50 |只看该作者
If being wakes up, the process A is in task_running state. It will be selected by the scheduler and run again later.

论坛徽章:
4
酉鸡
日期:2014-03-21 23:19:50狮子座
日期:2014-08-01 22:11:40酉鸡
日期:2015-01-10 21:31:442015年辞旧岁徽章
日期:2015-03-03 16:54:15
16 [报告]
发表于 2014-07-25 19:40 |只看该作者
回复 15# firkraag


    哦,这样的话,一次也不浪费。。。

论坛徽章:
0
17 [报告]
发表于 2015-10-10 00:08 |只看该作者
  1.                                
  2. //解锁操作       
  3. //1
  4. prepare_to_wait(&(psp->inq),&ex_wait,TASK_INTERRUPTIBLE);
  5. //2
  6. if( !(psp->size) )  //important
  7. {
  8.         //3
  9.         schedule();
  10. }

  11. finish_wait(&(psp->inq),&ex_wait);

  12. if(signal_pending(current))
  13. {
  14.         err = -ERESTARTSYS;
  15.         goto scull_p_read_out;
  16. }

  17. //加锁操作

  18. if( (psp->size) )
  19. {
  20.         //可以读了
  21. }
  22. else
  23. {
  24.         //调到,解锁操作重复动作       
  25. }
复制代码
最近在看这代码,也有关于题主的问题下面是我理解,如果不对请指教:
在我的代码中有1,2,3个注释表示的是在这三个地方发生wake_up。
记住在1-3之间是无锁状态哦,以获取的一切值是可能随时变化的。
1. 在1处发生wakeup
        a.在1处发生wake_up那么prepare_to_wait把当前进程放入休眠队列中,
        b.(b.1)在3处可能psp->size != 0(几率很大)
                此时不调度(即不休眠),调用finish_wait结束休眠,对模块加锁
                注意此时加锁后,就只有你自己能修改,如果再判断size不为0,就可以读取了,此时read成了哦也。
          (b.2)在3处可能psp->size == 0(几率很小)
                此时那就继续调度呗,虽然有人调用了wakup,但是数据已经被哪个不知名的其他read进程读走了(记住此时可能不只有一个进程在读,也可能不只有一个进程在写)
                那我就调用schedule休眠吧。
2. 在2处发生wakeup
        a.在2处发生wake_up,此时当前进程已经在休眠队列中了
        b.重复1的b的步骤
3. 在3处发生wakeup
        a.在3处发生wake_up,此时当前进程已经在休眠队列中了,而且判断size已经为0,肿么办,我去要永远睡眠了么,no no no too young,too simple!
        b.在进入if( !(psp->size) )后还有发生wakeup之前prepare_to_wait将本进程的运行状态修改了
        设置成了什么呢look at
以下代码引自:lxr.oss.org.cn


  1. prepare_to_wait(wait_queue_head_t *q, wait_queue_t *wait, int state)
  2. {
  3.         unsigned long flags;

  4.         wait->flags &= ~WQ_FLAG_EXCLUSIVE;
  5.         spin_lock_irqsave(&q->lock, flags);
  6.         if (list_empty(&wait->task_list))
  7.                 __add_wait_queue(q, wait);
  8.         set_current_state(state);                                //我设置成TASK_INTERRUPTIBLE,如果你硬要做TASK_RUNNING这种闲着蛋疼的动作也是可以滴。
  9.         spin_unlock_irqrestore(&q->lock, flags);
  10. }
  11. EXPORT_SYMBOL(prepare_to_wait);
  12.                
复制代码
在3处还有wakeup的时候,进程已经变成了TASK_INTERRUPTIBLE,已经做好了最后的准备了,就剩最后的调度(休眠)了。
        c.此时在3处发生了wake_up(几率很小),看看wake_up怎么做的
  1.        
  2.         //wake_up默认调用的函数
  3. static int try_to_wake_up(struct task_struct *p, unsigned int state,
  4.                           int wake_flags)
  5. out_running:
  6.         trace_sched_wakeup(rq, p, success);
  7.         check_preempt_curr(rq, p, wake_flags);
  8.                
  9.                 p->state = TASK_RUNNING;                                //这里就是神秘的钥匙,开启运行的关键
复制代码
此时我们的进程状态已经变成了TASK_RUNNING,那是调度被忽略了。【真相只有一个那就是调度(休眠)被忽略了】,因为真正的休眠是在进程的state被设置成TASK_INTERRUPTIBLE的时候,而不是我们调用了schedule。
       
        d.调用finish_wait结束休眠,对模块加锁
          注意此时加锁后,就只有你自己能修改,如果再判断size不为0,就可以读取了,此时read成了哦也。
          否则重复动作。
       
所有的问题是建立在prepare_to_wait,schedule等调用可以看成是原子的,就是不能分割的不会被时间片中断等打断的情况下(但实际情况比这要复杂你可以继续读内核源码进行分析)。       

注释//important其实是你提问在这个点发生wakeup怎么办,其实//important可以根据情况分成2或3,最后希望写的东西能帮助你,共同努力,加了个油!!!!

       
               
               

论坛徽章:
20
程序设计版块每日发帖之星
日期:2015-08-17 06:20:00程序设计版块每日发帖之星
日期:2016-07-16 06:20:00程序设计版块每日发帖之星
日期:2016-07-18 06:20:00每日论坛发贴之星
日期:2016-07-18 06:20:00黑曼巴
日期:2016-12-26 16:00:3215-16赛季CBA联赛之江苏
日期:2017-06-26 11:05:5615-16赛季CBA联赛之上海
日期:2017-07-21 18:12:5015-16赛季CBA联赛之青岛
日期:2017-09-04 17:32:0515-16赛季CBA联赛之吉林
日期:2018-03-26 10:02:16程序设计版块每日发帖之星
日期:2016-07-15 06:20:0015-16赛季CBA联赛之江苏
日期:2016-07-07 18:37:512015亚冠之萨济拖拉机
日期:2015-08-17 12:21:08
18 [报告]
发表于 2015-10-12 20:07 |只看该作者
学了个习!

经过17#楼的详细解释,终于弄明白15#楼的意思:以running状态调用schedule,进程还是保留在rq队列里。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP