感谢支持
我们一直在努力

Linux源码分析:completion的解读


  1. /** 

  2.  * wait_for_completion: – waits for completion of a task 

  3.  * @x:  holds the state of this particular completion 

  4.  * 

  5.  * This waits to be signaled for completion of a specific task. It is NOT 

  6.  * interruptible and there is no timeout. 

  7.  * 

  8.  * See also similar routines (i.e. wait_for_completion_timeout()) with timeout 

  9.  * and interrupt capability. Also see complete(). 

  10.  */  

  11. void __sched wait_for_completion(struct completion *x)  

  12. {  

  13.     wait_for_common(x, MAX_SCHEDULE_TIMEOUT, TASK_UNINTERRUPTIBLE);  

  14. }  

[cpp]


  1. static long __sched  

  2. wait_for_common(struct completion *x, long timeout, int state)  

  3. {  

  4.     might_sleep();  

  5.   

  6.     spin_lock_irq(&x->wait.lock);  

  7.     timeout = do_wait_for_common(x, timeout, state);  

  8.     spin_unlock_irq(&x->wait.lock);  

  9.     return timeout;  

  10. }  

注意:spin_lock_irq(&x->wait.lock)和spin_unlock_irq(&x->wait.lock)并非真正对应的一对自旋锁,因为在自旋锁保护中是不允许休眠和调度的。与他们相对应的解锁和上锁操作在do_wait_for_common(x, timeout, state)函数内部。


[cpp]


  1. static inline long __sched  

  2. do_wait_for_common(struct completion *x, long timeout, int state)  

  3. {  

  4.     if (!x->done) {  

  5.         DECLARE_WAITQUEUE(wait, current);  

  6.   

  7.         wait.flags |= WQ_FLAG_EXCLUSIVE;  

  8.         __add_wait_queue_tail(&x->wait, &wait);  

  9.         do {  

  10.             if (signal_pending_state(state, current)) {  

  11.                 timeout = -ERESTARTSYS;  

  12.                 break;  

  13.             }  

  14.             __set_current_state(state);  

  15.             spin_unlock_irq(&x->wait.lock);  

  16.             timeout = schedule_timeout(timeout);  

  17.             spin_lock_irq(&x->wait.lock);  

  18.         } while (!x->done && timeout);  

  19.         __remove_wait_queue(&x->wait, &wait);  

  20.         if (!x->done)  

  21.             return timeout;  

  22.     }  

  23.     x->done–;  

  24.     return timeout ?: 1;  

  25. }  

函数完成的操作:声明等待队列,在队列末尾添加信号量,设置当前任务为TASK_UNINTERRUPTIBLE,释放自旋锁,进行任务调度,(任务被激活)获取自旋锁,移除等待队列。最后返回上一层函数,在上一层函数中释放自旋锁。


[cpp]


  1. /** 

  2.  * schedule_timeout – sleep until timeout 

  3.  * @timeout: timeout value in jiffies 

  4.  * 

  5.  * Make the current task sleep until @timeout jiffies have 

  6.  * elapsed. The routine will return immediately unless 

  7.  * the current task state has been set (see set_current_state()). 

  8.  * 

  9.  * You can set the task state as follows – 

  10.  * 

  11.  * %TASK_UNINTERRUPTIBLE – at least @timeout jiffies are guaranteed to 

  12.  * pass before the routine returns. The routine will return 0 

  13.  * 

  14.  * %TASK_INTERRUPTIBLE – the routine may return early if a signal is 

  15.  * delivered to the current task. In this case the remaining time 

  16.  * in jiffies will be returned, or 0 if the timer expired in time 

  17.  * 

  18.  * The current task state is guaranteed to be TASK_RUNNING when this 

  19.  * routine returns. 

  20.  * 

  21.  * Specifying a @timeout value of %MAX_SCHEDULE_TIMEOUT will schedule 

  22.  * the CPU away without a bound on the timeout. In this case the return 

  23.  * value will be %MAX_SCHEDULE_TIMEOUT. 

  24.  * 

  25.  * In all cases the return value is guaranteed to be non-negative. 

  26.  */  

  27. signed long __sched schedule_timeout(signed long timeout)  

  28. {  

  29.     struct timer_list timer;  

  30.     unsigned long expire;  

  31.   

  32.     switch (timeout)  

  33.     {  

  34.     case MAX_SCHEDULE_TIMEOUT:  

  35.         /* 

  36.          * These two special cases are useful to be comfortable 

  37.          * in the caller. Nothing more. We could take 

  38.          * MAX_SCHEDULE_TIMEOUT from one of the negative value 

  39.          * but I’ d like to return a valid offset (>=0) to allow 

  40.          * the caller to do everything it want with the retval. 

  41.          */  

  42.         schedule();  

  43.         goto out;  

  44.     default:  

  45.         /* 

  46.          * Another bit of PARANOID. Note that the retval will be 

  47.          * 0 since no piece of kernel is supposed to do a check 

  48.          * for a negative retval of schedule_timeout() (since it 

  49.          * should never happens anyway). You just have the printk() 

  50.          * that will tell you if something is gone wrong and where. 

  51.          */  

  52.         if (timeout < 0) {  

  53.             printk(KERN_ERR “schedule_timeout: wrong timeout “  

  54.                 “value %lx\n”, timeout);  

  55.             dump_stack();  

  56.             current->state = TASK_RUNNING;  

  57.             goto out;  

  58.         }  

  59.     }  

  60.   

  61.     expire = timeout + jiffies;  

  62.   

  63.     setup_timer_on_stack(&timer, process_timeout, (unsigned long)current);  

  64.     __mod_timer(&timer, expire, false, TIMER_NOT_PINNED);  

  65.     schedule();  

  66.     del_singleshot_timer_sync(&timer);  

  67.   

  68.     /* Remove the timer from the object tracker */  

  69.     destroy_timer_on_stack(&timer);  

  70.   

  71.     timeout = expire – jiffies;  

  72.   

  73.  out:  

  74.     return timeout < 0 ? 0 : timeout;  

  75. }  
函数直接进去MAX_SCHEDULE_TIMEOUT的情况,调用schedule()


[cpp]


  1. /* 

  2.  * schedule() is the main scheduler function. 

  3.  */  

  4. asmlinkage void __sched schedule(void)  

  5. {  

  6.     struct task_struct *prev, *next;  

  7.     unsigned long *switch_count;  

  8.     struct rq *rq;  

  9.     int cpu;  

  10.   

  11. need_resched:  

  12.     preempt_disable();  

  13.     cpu = smp_processor_id();  

  14.     rq = cpu_rq(cpu);  

  15.     rcu_sched_qs(cpu);  

  16.     prev = rq->curr;  

  17.     switch_count = &prev->nivcsw;  

  18.   

  19.     release_kernel_lock(prev);  

  20. need_resched_nonpreemptible:  

  21.   

  22.     schedule_debug(prev);  

  23.   

  24.     if (sched_feat(HRTICK))  

  25.         hrtick_clear(rq);  

  26.   

  27.     spin_lock_irq(&rq->lock);  

  28.     update_rq_clock(rq);  

  29.     clear_tsk_need_resched(prev);  

  30.   

  31.     if (prev->state && !(preempt_count() & PREEMPT_ACTIVE)) {  

  32.         if (unlikely(signal_pending_state(prev->state, prev)))  

  33.             prev->state = TASK_RUNNING;  

  34.         else  

  35.             deactivate_task(rq, prev, 1);  

  36.         switch_count = &prev->nvcsw;  

  37.     }  

  38.   

  39.     pre_schedule(rq, prev);  

  40.   

  41.     if (unlikely(!rq->nr_running))  

  42.         idle_balance(cpu, rq);  

  43.   

  44.     put_prev_task(rq, prev);  

  45.     next = pick_next_task(rq);  

  46.   

  47.     if (likely(prev != next)) {  

  48.         sched_info_switch(prev, next);  

  49.         perf_event_task_sched_out(prev, next, cpu);  

  50.   

  51.         rq->nr_switches++;  

  52.         rq->curr = next;  

  53.         ++*switch_count;  

  54.   

  55.         context_switch(rq, prev, next); /* unlocks the rq */  

  56.         /* 

  57.          * the context switch might have flipped the stack from under 

  58.          * us, hence refresh the local variables. 

  59.          */  

  60.         cpu = smp_processor_id();  

  61.         rq = cpu_rq(cpu);  

  62.     } else  

  63.         spin_unlock_irq(&rq->lock);  

  64.   

  65.     post_schedule(rq);  

  66.   

  67.     if (unlikely(reacquire_kernel_lock(current) < 0))  

  68.         goto need_resched_nonpreemptible;  

  69.   

  70.     preempt_enable_no_resched();  

  71.     if (need_resched())  

  72.         goto need_resched;  

  73. }  

赞(0) 打赏
转载请注明出处:服务器评测 » Linux源码分析:completion的解读
分享到: 更多 (0)

听说打赏我的人,都进福布斯排行榜啦!

支付宝扫一扫打赏

微信扫一扫打赏