博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Linux源码-等待队列注释
阅读量:6278 次
发布时间:2019-06-22

本文共 5208 字,大约阅读时间需要 17 分钟。

等待队列

Linux中了等待队列的毒,代码中充斥着等待队列。不信你翻翻代码。

等待队列的唤醒我们这里叫激活。免得和线程唤醒混淆。

转载注明出处哦:http://www.cnblogs.com/stonehat/p/8627302.html

数据结构

  1. 头结点wait_queue_head_t的结构
struct __wait_queue_head {        // 自旋锁,用来做同步    spinlock_t lock;        // 链表,    struct list_head task_list;};// 熟悉的wait_queue_head_t实际上是struct __wait_queue_headtypedef struct __wait_queue_head wait_queue_head_t;
  1. 普通节点wait_queue_t的结构
typedef struct __wait_queue wait_queue_t;   //wait_queue_func_t的定义   typedef int (*wait_queue_func_t)(wait_queue_t *wait, unsigned mode, int sync, void *key);   //__wait_queue的定义   struct __wait_queue {       // 激活后是否继续激活下一个entry。候选值为WQ_FLAG_EXCLUSIVE。一般设置为0。       // 当等待队列所有entry的flags==0时,等待队列所有entry都会被激活。所以就会有惊群现象。    unsigned int flags;       // 排他性标志,调用wake_up时,可以传入参数,控制激活多少个排他性的entry就停止。   #define WQ_FLAG_EXCLUSIVE    0x01              //线程结构    struct task_struct * task;              // 函数指针。被激活时调用。    wait_queue_func_t func;              // listItem。内核链表如何做通用化的。就是靠特殊的宏操作。    struct list_head task_list;   };

函数

一、初始化

1. 头节点初始化

#define INIT_LIST_HEAD(ptr) do { \    (ptr)->next = (ptr); (ptr)->prev = (ptr); \} while (0)static inline void init_waitqueue_head(wait_queue_head_t *q){    // 初始化自旋锁    q->lock = SPIN_LOCK_UNLOCKED;    // 初始化链表    INIT_LIST_HEAD(&q->task_list);}

2. entry节点初始化

// 初始化一个等待队列entry// 这个entry在激活的时候直接会唤醒task_struct线程static inline void init_waitqueue_entry(wait_queue_t *q, struct task_struct *p)   {    //表示这个不是排他性的entry    q->flags = 0;        q->task = p;        // 默认给一个唤醒q->task的函数指针。    q->func = default_wake_function;   }// 初始化一个等待队列entry// 这个entry在激活的时候仅仅调用func.static inline void init_waitqueue_func_entry(wait_queue_t *q,                    wait_queue_func_t func)   {    q->flags = 0;    q->task = NULL;    q->func = func;   }

二、添加

extern void FASTCALL(add_wait_queue(wait_queue_head_t *q, wait_queue_t * wait));extern void FASTCALL(add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t * wait));

代码实现

void fastcall add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait){    unsigned long flags;    wait->flags &= ~WQ_FLAG_EXCLUSIVE;    spin_lock_irqsave(&q->lock, flags);    __add_wait_queue(q, wait);    spin_unlock_irqrestore(&q->lock, flags);}static inline void __add_wait_queue(wait_queue_head_t *head, wait_queue_t *new){    list_add(&new->task_list, &head->task_list);}static inline void list_add(struct list_head *new, struct list_head *head){    __list_add(new, head, head->next);}

简化代码看

void fastcall add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait){    unsigned long flags;    wait->flags &= ~WQ_FLAG_EXCLUSIVE;    //加锁保护,保存中断    spin_lock_irqsave(&q->lock, flags);        q->task_list->pre=wait->task_list;    wait->task_list->next=q->task_list;    wait->task_list->pre=q->task_list->next;    q->task_list->next = wait->task_list;        __add_wait_queue(q, wait);    //解锁。    spin_unlock_irqrestore(&q->lock, flags);}

三、删除

extern void FASTCALL(remove_wait_queue(wait_queue_head_t *q, wait_queue_t * wait));

//忽略

四、队列激活

#define wake_up(x)          __wake_up(x, TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, 1, NULL)#define wake_up_nr(x, nr)       __wake_up(x, TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, nr, NULL)#define wake_up_all(x)          __wake_up(x, TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, 0, NULL)#define wake_up_interruptible(x)    __wake_up(x, TASK_INTERRUPTIBLE, 1, NULL)#define wake_up_interruptible_nr(x, nr) __wake_up(x, TASK_INTERRUPTIBLE, nr, NULL)#define wake_up_interruptible_all(x)    __wake_up(x, TASK_INTERRUPTIBLE, 0, NULL)#define wake_up_locked(x)       __wake_up_locked((x), TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE)#define wake_up_interruptible_sync(x)   __wake_up_sync((x),TASK_INTERRUPTIBLE, 1)/** * 激活等待队列. * @q: the waitqueue * @mode: which threads * @nr_exclusive: 最多激活多少个WQ_FLAG_EXCLUSIVE属性的entry。0表示都不限制。 */void fastcall __wake_up(wait_queue_head_t *q, unsigned int mode,                int nr_exclusive, void *key){    unsigned long flags;    spin_lock_irqsave(&q->lock, flags);    __wake_up_common(q, mode, nr_exclusive, 0, key);    spin_unlock_irqrestore(&q->lock, flags);}/* * 激活核心代码。遍历所有task_list,取出wait_queue_t结构(宏操作取出),执行里面的func。 * nr_exclusive表示要执行多少个WQ_FLAG_EXCLUSIVE属性的entry。 */static void __wake_up_common(wait_queue_head_t *q, unsigned int mode,                 int nr_exclusive, int sync, void *key){    struct list_head *tmp, *next;    list_for_each_safe(tmp, next, &q->task_list) {        wait_queue_t *curr;        unsigned flags;        curr = list_entry(tmp, wait_queue_t, task_list);        flags = curr->flags;        if (curr->func(curr, mode, sync, key) &&            (flags & WQ_FLAG_EXCLUSIVE) &&            !--nr_exclusive)            break;    }}

巧妙的宏

在等待队列中,队列其实是由list_head构成的,而在遍历激活entry的时候,可以取出对应的wait_queue_t结构体。如何做到的?

看下wait_queue_t结构。

struct __wait_queue {       unsigned int flags;#define WQ_FLAG_EXCLUSIVE   0x01        struct task_struct * task;        wait_queue_func_t func;        // list_head在结构体内部。    struct list_head task_list;};

我们一般是从外部去取内部成员,而内核链表是通过内部成员去取外部结构体指针。有什么好处?这样可以做通用的链表结构,而不用担心内部单元类型。

那如何从内部成员获得外部结构体指针呢?以wait_queue_t 的变量a为例,内部task_list地址记为b。

b- &( ( (wait_queue_t *) 0 )->task_list)可以获得wait_queue_t a的地址。

转载于:https://www.cnblogs.com/stonehat/p/8627302.html

你可能感兴趣的文章
JAVA IO BIO NIO AIO
查看>>
input checkbox 复选框大小修改
查看>>
网吧维护工具
查看>>
BOOT.INI文件参数
查看>>
vmstat详解
查看>>
新年第一镖
查看>>
unbtu使用笔记
查看>>
OEA 中 WPF 树型表格虚拟化设计方案
查看>>
Android程序开发初级教程(一) 开始 Hello Android
查看>>
使用Gradle打RPM包
查看>>
“我意识到”的意义
查看>>
淘宝天猫上新辅助工具-新品填表
查看>>
再学 GDI+[43]: 文本输出 - 获取已安装的字体列表
查看>>
nginx反向代理
查看>>
操作系统真实的虚拟内存是什么样的(一)
查看>>
hadoop、hbase、zookeeper集群搭建
查看>>
python中一切皆对象------类的基础(五)
查看>>
modprobe
查看>>
android中用ExpandableListView实现三级扩展列表
查看>>
%Error opening tftp://255.255.255.255/cisconet.cfg
查看>>