__wake_up唤醒等待队列中的进程

等待队列头

struct __wait_queue_head 

{

     spinlock_t lock; //自旋锁用于保护自身资源(task_list链表)不被多个进程同时访问
     struct list_head task_list;//双向循环链表通过此字段连接成等待对列链表
};
typedef struct __wait_queue_head wait_queue_head_t;


等待队列项

struct __wait_queue

{

       //唤醒进程的方式 其中0是非互斥,WQ_FLAG_EXCLUSIVE(0×01)是互斥

     当一个等待队列入口有 WQ_FLAG_EXCLUSEVE 标志置位, 它被添加到等待队列的尾部. 没有这个标志的入口项, 相反, 添加        到开始
    当 wake_up 被在一个等待队列上调用, 它在唤醒第一个有 WQ_FLAG_EXCLUSIVE 标志的进程后停止

       unsigned int flags;

#define WQ_FLAG_EXCLUSIVE 0x01

        //私有指针变量,使用过程中会用来存放task_struct结构体
       void *private;

      //func是一个函数指针,指向用于唤醒队列中线程的函数。虽然提供了默认的唤醒函数default_wake_function,但也允许         灵活的设置队列的唤醒函数
      wait_queue_func_t func;

       //链表,用于将等待队列头、等待队列连接起来
       struct list_head task_list;
};
typedef struct __wait_queue wait_queue_t;


唤醒队列中处于特定状态的进程
void __wake_up(wait_queue_head_t *q,//等待队列头 
                         unsigned int mode,    //进程的状态  如TASK_NORMAL
                          int nr_exclusive,        //唤醒互斥进程的个数
                           void *key                //一般设置为NULL(传给唤醒回调函数的参数在default_wake_function并未使用)
                         )
{

unsigned long flags;

spin_lock_irqsave(&q->lock, flags);//自旋锁上锁
//下面函数中会调用唤醒的回调函数
__wake_up_common(q, mode, nr_exclusive, 0, key);
spin_unlock_irqrestore(&q->lock, flags);//自旋锁解锁
}

同步唤醒队列中处于特定状态的进程

void __wake_up_sync(wait_queue_head_t *q,

                                              unsigned int mode,

                                               int nr_exclusive)
{
    __wake_up_sync_key(q, mode, nr_exclusive, NULL);
}

void __wake_up_sync_key(wait_queue_head_t *q,

                                                      unsigned int mode,
                                                      int nr_exclusive,

                                                       void *key)
{
    unsigned long flags;
    int wake_flags = WF_SYNC;

    if (unlikely(!q))
        return;

    if (unlikely(!nr_exclusive))
        wake_flags = 0;

    spin_lock_irqsave(&q->lock, flags);
    __wake_up_common(q, mode, nr_exclusive, wake_flags, key);
    spin_unlock_irqrestore(&q->lock, flags);
}


static void __wake_up_common(wait_queue_head_t *q, //等待队列头
                                                  unsigned int mode, //进程的状态TASK_NORMAL
                                                  int nr_exclusive, //唤醒互斥进程的个数 
                                                  int wake_flags, //同步唤醒0 或异步唤醒1
                                                  void *key //一般设置为NULL(传给唤醒回调函数的参数在default_wake_function并未使用)
                                                 )
{

   wait_queue_t *curr, *next;

   //遍历等待队列中的数据项wait_queue_t类型

   list_for_each_entry_safe(curr, next, &q->task_list, task_list) 

   {

      unsigned flags = curr->flags;
       
         (1)对队列中的每一个元素,调用其回调函数func:default_wake_function
         (2)如果回调函数返回非0值,那么看队列元素的flag值,
           如果设置了WQ_FLAG_EXCLUSIVE(互斥)标志,那么停止遍历,不继续唤醒其它进程;否则继续唤醒下一个进程
         (3)如果设置了互斥进程唤醒个数nr_exclusive,则要唤醒nr_exclusive个互斥进程,若为<=0 则唤醒所有的

     if (curr->func(curr, mode, wake_flags, key)  &&  (flags & WQ_FLAG_EXCLUSIVE) && !--nr_exclusive)
           break;
  }

}

调用关系:

//例子 wakeup的使用

猜你喜欢

转载自blog.csdn.net/yldfree/article/details/81018845
今日推荐