• kernel 等待队列


    Linux内核的sleep/wakeup机制非常重要,几乎贯穿了所有的内核子系统,值得注意的是,这里的sleep/wakeup依然采用了OO的思想,并没有限制睡眠的entry一定要是一个task,而是将睡眠的entry做了一层抽象,即:

    1. struct __wait_queue {
    2. unsigned int flags;
    3. // 至于这个private到底是什么,内核并不限制,它可以是task,也可以是别的。
    4. void *private;
    5. wait_queue_func_t func;
    6. struct list_head task_list; //挂在链表__wait_queue_head
    7. };
    8. typedef struct __wait_queue wait_queue_t;

    以上的这个entry,最终要睡眠在下面的数据结构实例化的一个链表上:

    1. struct __wait_queue_head {
    2. spinlock_t lock;
    3. struct list_head task_list;
    4. };
    5. typedef struct __wait_queue_head wait_queue_head_t;

    被等待的事件会提供链表wait_queue_head_t,等待事件的进程会初始化wait_queue_t,然后插入被等待事件的链表wait_queue_head_t后开始睡眠等待。
    当事件发生后,会遍历链表wait_queue_head_t上的wait_queue_t,执行其func函数default_wake_function将等待进程唤醒。

    entry初始化

    //调用此函数的一般是需要将调用进程睡眠等待事件发生
    //事件发生时调用default_wake_function来唤醒调用进程

    1. static inline void init_waitqueue_entry(wait_queue_t *q, struct task_struct *p)
    2. {
    3. q->flags = 0;
    4. q->private = p;
    5. q->func = default_wake_function;
    6. }

    //调用此函数的一般不会是打算唤醒进程,而是事件发生时,调用func来做其他事情,比如epoll_ctl添加监听目标

    1. static inline void
    2. init_waitqueue_func_entry(wait_queue_t *q, wait_queue_func_t func)
    3. {
    4. q->flags = 0;
    5. q->private = NULL;
    6. q->func = func;
    7. }

    将entry添加到等待队列

    有四个版本的添加函数用来将wait_queue_t添加到链表wait_queue_head_t
    a. 直接添加到队列头部

    1. static inline void __add_wait_queue(wait_queue_head_t *head, wait_queue_t *new)
    2. {
    3. list_add(&new->task_list, &head->task_list);
    4. }

    b. 设置exclusive标志,并添加到队列头部 //epoll_wait使用此函数

    1. /*
    2. * Used for wake-one threads:
    3. */
    4. static inline void
    5. __add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t *wait)
    6. {
    7. wait->flags |= WQ_FLAG_EXCLUSIVE;
    8. __add_wait_queue(q, wait);
    9. }

    c. 直接添加到队列尾部

    1. static inline void __add_wait_queue_tail(wait_queue_head_t *head,
    2. wait_queue_t *new)
    3. {
    4. list_add_tail(&new->task_list, &head->task_list);
    5. }

    d. 设置exclusive标志,并添加到队列尾部 //accept使用此函数

    1. static inline void
    2. __add_wait_queue_tail_exclusive(wait_queue_head_t *q, wait_queue_t *wait)
    3. {
    4. wait->flags |= WQ_FLAG_EXCLUSIVE;
    5. __add_wait_queue_tail(q, wait);
    6. }

    删除entry

    //将old entry从链表中删除

    1. static inline void
    2. __remove_wait_queue(wait_queue_head_t *head, wait_queue_t *old)
    3. {
    4. list_del(&old->task_list);
    5. }

    唤醒任务

    //将wait_queue_head_t 上的任务唤醒

    1. void __wake_up(wait_queue_head_t *q, unsigned int mode,
    2. int nr_exclusive, void *key)
    3. {
    4. unsigned long flags;
    5. spin_lock_irqsave(&q->lock, flags);
    6. __wake_up_common(q, mode, nr_exclusive, 0, key);
    7. spin_unlock_irqrestore(&q->lock, flags);
    8. }
    9. static void __wake_up_common(wait_queue_head_t *q, unsigned int mode,
    10. int nr_exclusive, int wake_flags, void *key)
    11. {
    12. wait_queue_t *curr, *next;
    13. list_for_each_entry_safe(curr, next, &q->task_list, task_list) {
    14. unsigned flags = curr->flags;
    15. //调用__pollwake或者default_wake_function将进程唤醒
    16. //如果设置了WQ_FLAG_EXCLUSIVE,则只唤醒nr_exclusive个任务
    17. if (curr->func(curr, mode, wake_flags, key) &&
    18. (flags & WQ_FLAG_EXCLUSIVE) && !--nr_exclusive)
    19. break;
    20. }
    21. }

    也可参考:https://www.jianshu.com/p/93a6b70542d0 

  • 相关阅读:
    qt creator 设置 项目依赖关系
    Redis——》实现分布式锁
    windows安装JDK与系统变量配置
    云原生架构之Spring Cloud+Kubernetes配置中心方案
    Python 3.12 目标:还可以更快!
    如何将项目打包上传到NuGet服务器(图文教程)?
    【23种设计模式】工厂方法模式(Factory Method Pattern) .Net Core实现
    机器人操作系统ROS(22)ROS安装opencv
    Qt模块、Qt开发应用程序类型、Qt未来主要市场、Qt6功能普及
    mongodb
  • 原文地址:https://blog.csdn.net/fengcai_ke/article/details/126563970