vivi驱动中的等待队列wait_queue

内核有很多队列, 如等待队列, 工作队列等等。

 

所有的队列都是利用list机制做成一个双向链表/队列。

和内核种的一些模块自己使用的队列其实大同小异。

如usb的端点队列,  v4l2中vb2_buffer使用的queued_list和done_list。


以vivi.c驱动为例,  记录些等待队列的实现及应用。

* 相关结构体和函数

1. DECLARE_WAIT_QUEUE_HEAD

定义一个等待队列头

  54 #define __WAIT_QUEUE_HEAD_INITIALIZER(name) {›  ›   ›   ›   ›   \                                                                                                                                       
  55 ›   .lock›  ›   = __SPIN_LOCK_UNLOCKED(name.lock),› ›   ›   \                                                                                                                                           
  56 ›   .head›  ›   = { &(name).head, &(name).head } }                                                                                                                                                      
  57                                                                                                                                                                                                         
  58 #define DECLARE_WAIT_QUEUE_HEAD(name) \                                                                                                                                                                 
  59 ›   struct wait_queue_head name = __WAIT_QUEUE_HEAD_INITIALIZER(name)

即初始化一个静态/全局的等待队列头。

 

2. struct wait_queue_head结构体

  34 struct wait_queue_head {                                                                                                                                                                                
  35 ›   spinlock_t› ›   lock;                                                                                                                                                                               
  36 ›   struct list_head›   head;                                                                                                                                                                           
  37 };   

两个变量, 一个spinlock, 一个list_head

 

3. DECLARE_WAITQUEUE

  46 #define __WAITQUEUE_INITIALIZER(name, tsk) {›   ›   ›   ›   ›   \                                                                                                                                       
  47 ›   .private›   = tsk,› ›   ›   ›   ›   ›   ›   \                                                                                                                                                       
  48 ›   .func›  ›   = default_wake_function,›   ›   ›   ›   \                                                                                                                                               
  49 ›   .entry› ›   = { NULL, NULL } }                                                                                                                                                                      
  50                                                                                                                                                                                                         
  51 #define DECLARE_WAITQUEUE(name, tsk)›   ›   ›   ›   ›   ›   \                                                                                                                                           
  52 ›   struct wait_queue_entry name = __WAITQUEUE_INITIALIZER(name, tsk) 

定义一个等待队列entry, 

entry一般是翻译成入口的意思, 但放这里感觉不太合适...

比如list_entry函数

345 /**                                                                                                                                                                                                      
346  * list_entry - get the struct for this entry                                                                                                                                                            
347  * @ptr:›   the &struct list_head pointer.                                                                                                                                                               
348  * @type:›  the type of the struct this is embedded in.                                                                                                                                                  
349  * @member:›the name of the list_head within the struct.                                                                                                                                                 
350  */                                                                                                                                                                                                      
351 #define list_entry(ptr, type, member) \                                                                                                                                                                  
352 ›   container_of(ptr, type, member) 

所以我觉得这里entry翻译成元素, 条目一类的意思更为合适...

即list_head仅仅包含前后指针。

具体的条目内容本身需要另外定义一个结构体, 并通常把list_head结构体放最后。

不管怎样, DECLARE_WAITQUEUE定义了一个具体的等待队列条目/成员。 (可以放入等待队列中^^)

 

4. wait_queue_entry

  24 /*                                                                                                                                                                                                      
  25  * A single wait-queue entry structure:                                                                                                                                                                 
  26  */                                                                                                                                                                                                     
  27 struct wait_queue_entry {                                                                                                                                                                               
  28 ›   unsigned int›   ›   flags;                                                                                                                                                                          
  29 ›   void›   ›   ›   *private;                                                                                                                                                                           
  30 ›   wait_queue_func_t›  func;                                                                                                                                                                           
  31 ›   struct list_head›   entry;                                                                                                                                                                          
  32 };

 

4. add_wait_queue

17 void add_wait_queue(struct wait_queue_head *wq_head, struct wait_queue_entry *wq_entry)

ok, 该函数就是将等待队列条目挂载到等待队列中。 (是结尾还是开头??需要看内部实现。。。)

 154 static inline void __add_wait_queue(struct wait_queue_head *wq_head, struct wait_queue_entry *wq_entry)                                                                                                 
 155 {                                                                                                                                                                                                       
 156 ›   list_add(&wq_entry->entry, &wq_head->head);                                                                                                                                                         
 157 }   

内部调用的是list_add, 所以是加载等待队列的头部。 (wait_queue_head的后一个)

ok, 该函数仅仅做了一个入队列的动作... 具体如何触发等待... 需要其他函数介入。

 

5. schedule_timeout_interruptible

/*
 * We can use __set_current_state() here because schedule_timeout() calls
 * schedule() unconditionally.
 */
signed long __sched schedule_timeout_interruptible(signed long timeout)
{
	__set_current_state(TASK_INTERRUPTIBLE);
	return schedule_timeout(timeout);
}

以上函数就是为了让当前线程进入睡眠。

依赖的方式为两个步骤,

1). __set_current_state(TASK_INTERRUPTIBLE)

     设置当前状态为可中断

2). schedule_timeout

     相比schedule, 多了个timeout超时机制。 具体后面再看。

     schedule() 函数就会让当前线程挂起/睡眠, 让出cpu, 让cpu去调度其他线程。

 

*具体调度器的代码一下子看不懂... 先贴点源码注释, 后面慢慢分析吧...

2743 /*                                                                                                                                                                 
2744  * __schedule() is the main scheduler function.                                                                                                                    
2745  *                                                                                                                                                                 
2746  * The main means of driving the scheduler and thus entering this function are:                                                                                    
2747  *                                                                                                                                                                 
2748  *   1. Explicit blocking: mutex, semaphore, waitqueue, etc.                                                                                                       
2749  *                                                                                                                                                                 
2750  *   2. TIF_NEED_RESCHED flag is checked on interrupt and userspace return                                                                                         
2751  *      paths. For example, see arch/x86/entry_64.S.                                                                                                               
2752  *                                                                                                                                                                 
2753  *      To drive preemption between tasks, the scheduler sets the flag in timer                                                                                    
2754  *      interrupt handler scheduler_tick().                                                                                                                        
2755  *                                                                                                                                                                 
2756  *   3. Wakeups don't really cause entry into schedule(). They add a                                                                                               
2757  *      task to the run-queue and that's it.                                                                                                                       
2758  *                                                                                                                                                                 
2759  *      Now, if the new task added to the run-queue preempts the current                                                                                           
2760  *      task, then the wakeup sets TIF_NEED_RESCHED and schedule() gets                                                                                            
2761  *      called on the nearest possible occasion:                                                                                                                   
2762  *                                                                                                                                                                 
2763  *       - If the kernel is preemptible (CONFIG_PREEMPT=y):                                                                                                        
2764  *                                                                                                                                                                 
2765  *         - in syscall or exception context, at the next outmost                                                                                                  
2766  *           preempt_enable(). (this might be as soon as the wake_up()'s                                                                                           
2767  *           spin_unlock()!)                                                                                                                                       
2768  *                                                                                                                                                                 
2769  *         - in IRQ context, return from interrupt-handler to                                                                                                      
2770  *           preemptible context                                                                                                                                   
2771  *                                                                                                                                                                 
2772  *       - If the kernel is not preemptible (CONFIG_PREEMPT is not set)                                                                                            
2773  *         then at the next:                                                                                                                                       
2774  *                                                                                                                                                                 
2775  *          - cond_resched() call                                                                                                                                  
2776  *          - explicit schedule() call                                                                                                                             
2777  *          - return from syscall or exception to user-space                                                                                                       
2778  *          - return from interrupt-handler to user-space                                                                                                          
2779  */                                                                                                                                                                
2780 static void __sched __schedule(void)

 

6. wake_up_interruptible

一看名字, 就是唤醒等待队列中的睡眠线程的。

165 #define wake_up_interruptible(x)›   __wake_up(x, TASK_INTERRUPTIBLE, 1, NULL) 

 78 /**                                                                                                                                                                 
 79  * __wake_up - wake up threads blocked on a waitqueue.                                                                                                              
 80  * @q: the waitqueue                                                                                                                                                
 81  * @mode: which threads                                                                                                                                             
 82  * @nr_exclusive: how many wake-one or wake-many threads to wake up                                                                                                 
 83  * @key: is directly passed to the wakeup function                                                                                                                  
 84  *                                                                                                                                                                  
 85  * It may be assumed that this function implies a write memory barrier before                                                                                       
 86  * changing the task state if and only if any tasks are woken up.                                                                                                   
 87  */                                                                                                                                                                 
 88 void __wake_up(wait_queue_head_t *q, unsigned int mode,                                                                                                             
 89 ›   ›   ›   int nr_exclusive, void *key)                                                                                                                            
 90 {                                                                                                                                                                   
 91 ›   unsigned long flags;                                                                                                                                            
 92                                                                                                                                                                     
 93 ›   spin_lock_irqsave(&q->lock, flags);                                                                                                                             
 94 ›   __wake_up_common(q, mode, nr_exclusive, 0, key);                                                                                                                
 95 ›   spin_unlock_irqrestore(&q->lock, flags);                                                                                                                        
 96 }

 55 /*                                                                                                                                                                  
 56  * The core wakeup function. Non-exclusive wakeups (nr_exclusive == 0) just                                                                                         
 57  * wake everything up. If it's an exclusive wakeup (nr_exclusive == small +ve                                                                                       
 58  * number) then we wake all the non-exclusive tasks and one exclusive task.                                                                                         
 59  *                                                                                                                                                                  
 60  * There are circumstances in which we can try to wake a task which has already                                                                                     
 61  * started to run but is not in state TASK_RUNNING. try_to_wake_up() returns                                                                                        
 62  * zero in this (rare) case, and we handle it by continuing to scan the queue.                                                                                      
 63  */                                                                                                                                                                 
 64 static void __wake_up_common(wait_queue_head_t *q, unsigned int mode,                                                                                               
 65 ›   ›   ›   int nr_exclusive, int wake_flags, void *key)                                                                                                            
 66 {                                                                                                                                                                   
 67 ›   wait_queue_t *curr, *next;                                                                                                                                      
 68                                                                                                                                                                     
 69 ›   list_for_each_entry_safe(curr, next, &q->task_list, task_list) {                                                                                                
 70 ›   ›   unsigned flags = curr->flags;                                                                                                                               
 71                                                                                                                                                                     
 72 ›   ›   if (curr->func(curr, mode, wake_flags, key) &&                                                                                                              
 73 ›   ›   ›   ›   (flags & WQ_FLAG_EXCLUSIVE) && !--nr_exclusive)                                                                                                     
 74 ›   ›   ›   break;                                                                                                                                                  
 75 ›   }                                                                                                                                                               
 76 } 

这个函数还挺容易看,

就是拿出等待队列中对应要唤醒的条目, 调用func回调函数。


可惜关于调用的哪个回调函数...又没这么简单了...

 47 #define __WAITQUEUE_INITIALIZER(name, tsk) {›   ›   ›   ›   \                                                                                                                                            
 48 ›   .private›   = tsk,› ›   ›   ›   ›   ›   \                                                                                                                                                            
 49 ›   .func›  ›   = default_wake_function,›   ›   ›   \                                                                                                                                                    
 50 ›   .task_list› = { NULL, NULL } }   
1650 /**                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
1651  * try_to_wake_up - wake up a thread                                                                                                                                                                                                                                                                                                                                                                                                                                                     
1652  * @p: the thread to be awakened                                                                                                                                                                                                                                                                                                                                                                                                                                                         
1653  * @state: the mask of task states that can be woken                                                                                                                                                                                                                                                                                                                                                                                                                                     
1654  * @wake_flags: wake modifier flags (WF_*)                                                                                                                                                                                                                                                                                                                                                                                                                                               
1655  *                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       
1656  * Put it on the run-queue if it's not already there. The "current"                                                                                                                                                                                                                                                                                                                                                                                                                      
1657  * thread is always on the run-queue (except when the actual                                                                                                                                                                                                                                                                                                                                                                                                                             
1658  * re-schedule is in progress), and as such you're allowed to do                                                                                                                                                                                                                                                                                                                                                                                                                         
1659  * the simpler "current->state = TASK_RUNNING" to mark yourself                                                                                                                                                                                                                                                                                                                                                                                                                          
1660  * runnable without the overhead of this.                                                                                                                                                                                                                                                                                                                                                                                                                                                
1661  *                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       
1662  * Return: %true if @p was woken up, %false if it was already running.                                                                                                                                                                                                                                                                                                                                                                                                                   
1663  * or @state didn't match @p's state.                                                                                                                                                                                                                                                                                                                                                                                                                                                    
1664  */                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
1665 static int                                                                                                                                                                                                                                                                                                                                                                                                                                                                               
1666 try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags)                                                                                                                                                                                                                                                                                                                                                                                                                
1667 {                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        
1668 ›   unsigned long flags;                                                                                                                                                                                                                                                                                                                                                                                                                                                                 
1669 ›   int cpu, success = 0;                                                                                                                                                                                                                                                                                                                                                                                                                                                                
1670                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
1671 ›   /*                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   
1672 ›    * If we are going to wake up a thread waiting for CONDITION we                                                                                                                                                                                                                                                                                                                                                                                                                      
1673 ›    * need to ensure that CONDITION=1 done by the caller can not be                                                                                                                                                                                                                                                                                                                                                                                                                     
1674 ›    * reordered with p->state check below. This pairs with mb() in                                                                                                                                                                                                                                                                                                                                                                                                                      
1675 ›    * set_current_state() the waiting thread does.                                                                                                                                                                                                                                                                                                                                                                                                                                      
1676 ›    */                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  
1677 ›   smp_mb__before_spinlock();                                                                                                                                                                                                                                                                                                                                                                                                                                                           
1678 ›   raw_spin_lock_irqsave(&p->pi_lock, flags);                                                                                                                                                                                                                                                                                                                                                                                                                                           
1679 ›   if (!(p->state & state))                                                                                                                                                                                                                                                                                                                                                                                                                                                             
1680 ›   ›   goto out;                                                                                                                                                                                                                                                                                                                                                                                                                                                                        
1681                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
1682 ›   success = 1; /* we're going to change ->state */                                                                                                                                                                                                                                                                                                                                                                                                                                     
1683 ›   cpu = task_cpu(p);                                                                                                                                                                                                                                                                                                                                                                                                                                                                   
1684                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
1685 ›   /*                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   
1686 ›    * Ensure we load p->on_rq _after_ p->state, otherwise it would                                                                                                                                                                                                                                                                                                                                                                                                                      
1687 ›    * be possible to, falsely, observe p->on_rq == 0 and get stuck                                                                                                                                                                                                                                                                                                                                                                                                                      
1688 ›    * in smp_cond_load_acquire() below.                                                                                                                                                                                                                                                                                                                                                                                                                                                 
1689 ›    *                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   
1690 ›    * sched_ttwu_pending()                 try_to_wake_up()                                                                                                                                                                                                                                                                                                                                                                                                                             
1691 ›    *   [S] p->on_rq = 1;                  [L] P->state                                                                                                                                                                                                                                                                                                                                                                                                                                 
1692 ›    *       UNLOCK rq->lock  -----.                                                                                                                                                                                                                                                                                                                                                                                                                                                     
1693 ›    *                              \                                                                                                                                                                                                                                                                                                                                                                                                                                                    
1694 ›    *› ›   ›   ›    +---   RMB                                                                                                                                                                                                                                                                                                                                                                                                                                                          
1695 ›    * schedule()                   /                                                                                                                                                                                                                                                                                                                                                                                                                                                    
1696 ›    *       LOCK rq->lock    -----'                                                                                                                                                                                                                                                                                                                                                                                                                                                     
1697 ›    *       UNLOCK rq->lock                                                                                                                                                                                                                                                                                                                                                                                                                                                             
1698 ›    *                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   
1699 ›    * [task p]                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
1700 ›    *   [S] p->state = UNINTERRUPTIBLE     [L] p->on_rq                                                                                                                                                                                                                                                                                                                                                                                                                                 
1701 ›    *                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   
1702 ›    * Pairs with the UNLOCK+LOCK on rq->lock from the                                                                                                                                                                                                                                                                                                                                                                                                                                   
1703 ›    * last wakeup of our task and the schedule that got our task                                                                                                                                                                                                                                                                                                                                                                                                                        
1704 ›    * current.                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
1705 ›    */                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  
1706 ›   smp_rmb();                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
1707 ›   if (p->on_rq && ttwu_remote(p, wake_flags))                                                                                                                                                                                                                                                                                                                                                                                                                                          
1708 ›   ›   goto stat;                                                                                                                                                                                                                                                                                                                                                                                                                                                                       
1709                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
1710 #ifdef CONFIG_SMP                                                                                                                                                                                                                                                                                                                                                                                                                                                                        
1711 ›   /*                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   
1712 ›    * If the owning (remote) cpu is still in the middle of schedule() with                                                                                                                                                                                                                                                                                                                                                                                                              
1713 ›    * this task as prev, wait until its done referencing the task.                                                                                                                                                                                                                                                                                                                                                                                                                      
1714 ›    */                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  
1715 ›   while (p->on_cpu)                                                                                                                                                                                                                                                                                                                                                                                                                                                                    
1716 ›   ›   cpu_relax();                                                                                                                                                                                                                                                                                                                                                                                                                                                                     
1717 ›   /*                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   
1718 ›    * Pairs with the smp_wmb() in finish_lock_switch().                                                                                                                                                                                                                                                                                                                                                                                                                                 
1719 ›    */                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  
1720 ›   smp_rmb();                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
1721                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
1722 ›   p->sched_contributes_to_load = !!task_contributes_to_load(p);                                                                                                                                                                                                                                                                                                                                                                                                                        
1723 ›   p->state = TASK_WAKING;                                                                                                                                                                                                                                                                                                                                                                                                                                                              
1724                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
1725 ›   if (p->sched_class->task_waking)                                                                                                                                                                                                                                                                                                                                                                                                                                                     
1726 ›   ›   p->sched_class->task_waking(p);                                                                                                                                                                                                                                                                                                                                                                                                                                                  
1727                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
1728 ›   cpu = select_task_rq(p, p->wake_cpu, SD_BALANCE_WAKE, wake_flags);                                                                                                                                                                                                                                                                                                                                                                                                                   
1729 ›   if (task_cpu(p) != cpu) {                                                                                                                                                                                                                                                                                                                                                                                                                                                            
1730 ›   ›   wake_flags |= WF_MIGRATED;                                                                                                                                                                                                                                                                                                                                                                                                                                                       
1731 ›   ›   set_task_cpu(p, cpu);                                                                                                                                                                                                                                                                                                                                                                                                                                                            
1732 ›   }                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    
1733 #endif /* CONFIG_SMP */                                                                                                                                                                                                                                                                                                                                                                                                                                                                  
1734                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
1735 ›   ttwu_queue(p, cpu);                                                                                                                                                                                                                                                                                                                                                                                                                                                                  
1736 stat:                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    
1737 ›   ttwu_stat(p, cpu, wake_flags);                                                                                                                                                                                                                                                                                                                                                                                                                                                       
1738 out:                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     
1739 ›   raw_spin_unlock_irqrestore(&p->pi_lock, flags);                                                                                                                                                                                                                                                                                                                                                                                                                                      
1740                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
1741 ›   return success;                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
1742 }

回调函数默认是一个通用的函数, default_wake_function, 会调用try_to_wake_up唤醒对应线程。

一下子也不好理解, 反正只要知道他是唤醒线程(根据常识设计肯定是从当时挂起的下一条指令开始执行)


ok, 先知其然吧...

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值