- 论坛徽章:
- 0
|
-
- //解锁操作
- //1
- prepare_to_wait(&(psp->inq),&ex_wait,TASK_INTERRUPTIBLE);
- //2
- if( !(psp->size) ) //important
- {
- //3
- schedule();
- }
- finish_wait(&(psp->inq),&ex_wait);
- if(signal_pending(current))
- {
- err = -ERESTARTSYS;
- goto scull_p_read_out;
- }
- //加锁操作
- if( (psp->size) )
- {
- //可以读了
- }
- else
- {
- //调到,解锁操作重复动作
- }
复制代码 最近在看这代码,也有关于题主的问题下面是我理解,如果不对请指教:
在我的代码中有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
- prepare_to_wait(wait_queue_head_t *q, wait_queue_t *wait, int state)
- {
- unsigned long flags;
- wait->flags &= ~WQ_FLAG_EXCLUSIVE;
- spin_lock_irqsave(&q->lock, flags);
- if (list_empty(&wait->task_list))
- __add_wait_queue(q, wait);
- set_current_state(state); //我设置成TASK_INTERRUPTIBLE,如果你硬要做TASK_RUNNING这种闲着蛋疼的动作也是可以滴。
- spin_unlock_irqrestore(&q->lock, flags);
- }
- EXPORT_SYMBOL(prepare_to_wait);
-
复制代码 在3处还有wakeup的时候,进程已经变成了TASK_INTERRUPTIBLE,已经做好了最后的准备了,就剩最后的调度(休眠)了。
c.此时在3处发生了wake_up(几率很小),看看wake_up怎么做的-
- //wake_up默认调用的函数
- static int try_to_wake_up(struct task_struct *p, unsigned int state,
- int wake_flags)
- out_running:
- trace_sched_wakeup(rq, p, success);
- check_preempt_curr(rq, p, wake_flags);
-
- 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,最后希望写的东西能帮助你,共同努力,加了个油!!!!
|
|