Android内核wake_up源码分析

其他教程   发布日期:2023年08月01日   浏览次数:453

今天小编给大家分享一下Android内核wake_up源码分析的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。

    内核中通常用法:

    内核有个函数 wake_up 和 wake_up_interruptible 通常来说看到这俩函数调用就是唤醒等待队列上的线程。

    直到看了epoll的源码,发现并非如此。

    1. bool wakeup_condition;
    2. wait_queue_head_t wait_queue;
    3. init_waitqueue_head(&wait_queue);
    4. wait_queue_entry_t wq_entry
    5. // wait
    6. wait_event_interruptible(&wait_queue, wakeup_condition || kthread_should_stop());
    7. // 唤醒
    8. // 设置等待条件为true,并唤醒
    9. wakeup_condition = true;
    10. wake_up(&wait_queue);

    wake_up 的源码:

    1. // common/include/linux/wait.h
    2. #define TASK_NORMAL (TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE)
    3. #define wake_up(x) __wake_up(x, TASK_NORMAL, 1, NULL)
    4. #define wake_up_interruptible(x) __wake_up(x, TASK_INTERRUPTIBLE, 1, NULL)
    5. // common/kernel/sched/wait.c
    6. // wake_up 是个宏,展开后调用的是 __wake_up 函数
    7. // __wake_up(x, TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE, 1, NULL)
    8. int __wake_up(struct wait_queue_head *wq_head, unsigned int mode, int nr_exclusive, void *key)
    9. {
    10. return __wake_up_common_lock(wq_head, mode, nr_exclusive, 0, key);
    11. }
    12. EXPORT_SYMBOL(__wake_up);
    13. // __wake_up_common_lock(wq_head, TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE, 1, 0, NULL)
    14. static int __wake_up_common_lock(struct wait_queue_head *wq_head, unsigned int mode,
    15. int nr_exclusive, int wake_flags, void *key)
    16. {
    17. unsigned long flags;
    18. wait_queue_entry_t bookmark;
    19. int remaining = nr_exclusive;
    20. bookmark.flags = 0;
    21. bookmark.private = NULL;
    22. bookmark.func = NULL;
    23. INIT_LIST_HEAD(&bookmark.entry);//初始化链表: 链表的next和prev指针都指向链表自身地址
    24. do {
    25. spin_lock_irqsave(&wq_head->lock, flags);//自旋锁上锁,对队列上锁
    26. remaining = __wake_up_common(wq_head, mode, remaining, wake_flags, key, &bookmark);
    27. spin_unlock_irqrestore(&wq_head->lock, flags);//自旋锁解锁
    28. } while (bookmark.flags & WQ_FLAG_BOOKMARK);
    29. return nr_exclusive - remaining;//队列为空时,remaining=nr_exclusive ,此时 return 0;
    30. }
    31. // __wake_up_common(wq_head, TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE, 1, 0, NULL, &bookmark);
    32. static int __wake_up_common(struct wait_queue_head *wq_head, unsigned int mode,
    33. int nr_exclusive, int wake_flags, void *key,
    34. wait_queue_entry_t *bookmark)
    35. {
    36. wait_queue_entry_t *curr, *next;
    37. int cnt = 0;
    38. lockdep_assert_held(&wq_head->lock);
    39. // bookmark.flags = 0; WQ_FLAG_BOOKMARK = 0x04;
    40. if (bookmark && (bookmark->flags & WQ_FLAG_BOOKMARK)) {//不会进入此分支
    41. curr = list_next_entry(bookmark, entry);
    42. list_del(&bookmark->entry);
    43. bookmark->flags = 0;
    44. } else
    45. curr = list_first_entry(&wq_head->head, wait_queue_entry_t, entry);//获取wq_head队列的第一个元素
    46. if (&curr->entry == &wq_head->head)//队列为空时,直接返回传入的 nr_exclusive
    47. return nr_exclusive;
    48. list_for_each_entry_safe_from(curr, next, &wq_head->head, entry) {//遍历链表
    49. unsigned flags = curr->flags;
    50. int ret;
    51. if (flags & WQ_FLAG_BOOKMARK)
    52. continue;
    53. /*
    54. 调用 wait_queue_entry_t 中的回调函数 func
    55. // 这里依据func的类型会出现不同的结果。
    56. 使用 init_waitqueue_entry 初始化的 wait_queue_entry_t ,func = default_wake_function,这个函数会唤醒 curr->private 上的线程。
    57. 使用 init_waitqueue_func_entry 初始化的 wait_queue_entry_t,仅仅是做普通的函数调用。
    58. */
    59. ret = curr->func(curr, mode, wake_flags, key);
    60. if (ret < 0)
    61. break;
    62. if (ret && (flags & WQ_FLAG_EXCLUSIVE) && !--nr_exclusive)
    63. break;
    64. if (bookmark && (++cnt > WAITQUEUE_WALK_BREAK_CNT) &&
    65. (&next->entry != &wq_head->head)) {
    66. bookmark->flags = WQ_FLAG_BOOKMARK;
    67. list_add_tail(&bookmark->entry, &next->entry);
    68. break;
    69. }
    70. }
    71. return nr_exclusive;
    72. }

    func 赋值过程

    wait_queue_head 和 wait_queue_entry 数据结构

    1. //内核4.14以后
    2. // common/include/linux/wait.h
    3. struct wait_queue_head {// wait队列
    4. spinlock_t lock; // 自旋锁
    5. struct list_head head; // 添加到 wait 队列时,就是把wait_queue_entry.entry 加入这个 head 链表
    6. };
    7. /*
    8. * A single wait-queue entry structure:
    9. */
    10. struct wait_queue_entry {// wait队列的一个项
    11. unsigned int flags;
    12. void *private; // 私有数据,在init_waitqueue_entry中代表线程,在init_waitqueue_func_entry中为null
    13. wait_queue_func_t func; // 回调函数
    14. struct list_head entry; // 添加到 wait 队列时,就是把这个 entry 加入到 wait_queue_head.head 的链表
    15. };
    16. typedef struct wait_queue_head wait_queue_head_t; // wait_queue_head_t 同 wait_queue_head
    17. typedef struct wait_queue_entry wait_queue_entry_t; // wait_queue_entry_t 同 wait_queue_entry

    对于

    1. wait_queue_entry
    有两种常用的初始化方法
    1. init_waitqueue_entry
    1. init_waitqueue_func_entry

    两种等待任务 wait_queue_entry:线程 和 函数

    1. // common/include/linux/wait.h
    2. static inline void init_waitqueue_entry(struct wait_queue_entry *wq_entry, struct task_struct *p)
    3. {
    4. wq_entry-&gt;flags = 0;
    5. wq_entry-&gt;private = p; // 把需要唤醒的线程存储到 private 数据中
    6. // func 赋值为 default_wake_function 函数
    7. // 这个函数的作用是 唤醒等待队列上的线程
    8. wq_entry-&gt;func = default_wake_function; // 这函数作用是:唤醒线程 p
    9. }
    10. static inline void init_waitqueue_func_entry(struct wait_queue_entry *wq_entry, wait_queue_func_t func)
    11. {
    12. wq_entry-&gt;flags = 0;
    13. wq_entry-&gt;private = NULL;
    14. wq_entry-&gt;func = func; // 直接把传入的回调函数赋值给 wq_entry-&gt;func
    15. }

    default_wake_function 函数

    这个函数的作用基本等效于

    1. wake_up_process
    函数。
    1. int default_wake_function(wait_queue_entry_t *curr, unsigned mode, int wake_flags,
    2. void *key)
    3. {
    4. WARN_ON_ONCE(IS_ENABLED(CONFIG_SCHED_DEBUG) &amp;&amp; wake_flags &amp; ~WF_SYNC);
    5. //try_to_wake_up函数通过把进程状态设置为TASK_RUNNING, 并把该进程插入本地CPU运行队列rq来达到唤醒睡眠和停止的进程的目的.
    6. // curr-&gt;private 存储了需要唤醒的线程
    7. return try_to_wake_up(curr-&gt;private, mode, wake_flags);
    8. }
    9. EXPORT_SYMBOL(default_wake_function);

    综上:

    • wake_up ,可能是唤醒队列上的线程,也可能仅仅是触发一个回调而已

    wake_up的两种用法:

    1. bool wakeup_condition;
    2. wait_queue_head_t wait_queue;
    3. init_waitqueue_head(&wait_queue);
    4. wait_queue_entry_t wq_entry
    5. // wait
    6. 第一种用法:线程等待
    7. wait_event_interruptible(&wait_queue, wakeup_condition || kthread_should_stop());
    8. 第二种用法:添加一个回调到等待队列上
    9. init_waitqueue_func_entry(&wq_entry, callback);
    10. add_wait_queue(&wait_queue, &wq_entry);
    11. // 唤醒
    12. 设置等待条件为true,并唤醒
    13. wakeup_condition = true;
    14. // 内部遍历队列,调用每个 wait_queue_entry 的 func 函数,根据func不同为产生不同效果
    15. wake_up(&wait_queue);

    以上就是Android内核wake_up源码分析的详细内容,更多关于Android内核wake_up源码分析的资料请关注九品源码其它相关文章!