今天小编给大家分享一下Android内核wake_up源码分析的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。内核中通常用法:
今天小编给大家分享一下Android内核wake_up源码分析的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。
内核有个函数 wake_up 和 wake_up_interruptible 通常来说看到这俩函数调用就是唤醒等待队列上的线程。
直到看了epoll的源码,发现并非如此。
bool wakeup_condition; wait_queue_head_t wait_queue; init_waitqueue_head(&wait_queue); wait_queue_entry_t wq_entry// wait wait_event_interruptible(&wait_queue, wakeup_condition || kthread_should_stop());// 唤醒// 设置等待条件为true,并唤醒 wakeup_condition = true; wake_up(&wait_queue);
// common/include/linux/wait.h#define TASK_NORMAL(TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE)#define wake_up(x) __wake_up(x, TASK_NORMAL, 1, NULL)#define wake_up_interruptible(x)__wake_up(x, TASK_INTERRUPTIBLE, 1, NULL)// common/kernel/sched/wait.c// wake_up 是个宏,展开后调用的是 __wake_up 函数// __wake_up(x, TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE, 1, NULL)int __wake_up(struct wait_queue_head *wq_head, unsigned int mode, int nr_exclusive, void *key){return __wake_up_common_lock(wq_head, mode, nr_exclusive, 0, key);}EXPORT_SYMBOL(__wake_up);// __wake_up_common_lock(wq_head, TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE, 1, 0, NULL)static int __wake_up_common_lock(struct wait_queue_head *wq_head, unsigned int mode,int nr_exclusive, int wake_flags, void *key){unsigned long flags;wait_queue_entry_t bookmark;int remaining = nr_exclusive;bookmark.flags = 0;bookmark.private = NULL;bookmark.func = NULL;INIT_LIST_HEAD(&bookmark.entry);//初始化链表: 链表的next和prev指针都指向链表自身地址do {spin_lock_irqsave(&wq_head->lock, flags);//自旋锁上锁,对队列上锁remaining = __wake_up_common(wq_head, mode, remaining, wake_flags, key, &bookmark);spin_unlock_irqrestore(&wq_head->lock, flags);//自旋锁解锁} while (bookmark.flags & WQ_FLAG_BOOKMARK);return nr_exclusive - remaining;//队列为空时,remaining=nr_exclusive ,此时 return 0;}// __wake_up_common(wq_head, TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE, 1, 0, NULL, &bookmark);static int __wake_up_common(struct wait_queue_head *wq_head, unsigned int mode,int nr_exclusive, int wake_flags, void *key,wait_queue_entry_t *bookmark){wait_queue_entry_t *curr, *next;int cnt = 0;lockdep_assert_held(&wq_head->lock); // bookmark.flags = 0; WQ_FLAG_BOOKMARK = 0x04;if (bookmark && (bookmark->flags & WQ_FLAG_BOOKMARK)) {//不会进入此分支curr = list_next_entry(bookmark, entry);list_del(&bookmark->entry);bookmark->flags = 0;} elsecurr = list_first_entry(&wq_head->head, wait_queue_entry_t, entry);//获取wq_head队列的第一个元素if (&curr->entry == &wq_head->head)//队列为空时,直接返回传入的 nr_exclusivereturn nr_exclusive;list_for_each_entry_safe_from(curr, next, &wq_head->head, entry) {//遍历链表unsigned flags = curr->flags;int ret;if (flags & WQ_FLAG_BOOKMARK)continue;ret = curr->func(curr, mode, wake_flags, key);if (ret < 0)break;if (ret && (flags & WQ_FLAG_EXCLUSIVE) && !--nr_exclusive)break;if (bookmark && (++cnt > WAITQUEUE_WALK_BREAK_CNT) &&(&next->entry != &wq_head->head)) {bookmark->flags = WQ_FLAG_BOOKMARK;list_add_tail(&bookmark->entry, &next->entry);break;}}return nr_exclusive;}
//内核4.14以后// common/include/linux/wait.hstruct wait_queue_head {// wait队列spinlock_tlock; // 自旋锁struct list_headhead; // 添加到 wait 队列时,就是把wait_queue_entry.entry 加入这个 head 链表};struct wait_queue_entry {// wait队列的一个项unsigned intflags;void*private; // 私有数据,在init_waitqueue_entry中代表线程,在init_waitqueue_func_entry中为nullwait_queue_func_tfunc; // 回调函数struct list_headentry; // 添加到 wait 队列时,就是把这个 entry 加入到 wait_queue_head.head 的链表};typedef struct wait_queue_head wait_queue_head_t; // wait_queue_head_t 同 wait_queue_headtypedef struct wait_queue_entry wait_queue_entry_t; // wait_queue_entry_t 同 wait_queue_entry
对于 wait_queue_entry
有两种常用的初始化方法 init_waitqueue_entry
和 init_waitqueue_func_entry
// common/include/linux/wait.hstatic inline void init_waitqueue_entry(struct wait_queue_entry *wq_entry, struct task_struct *p){wq_entry->flags= 0;wq_entry->private= p; // 把需要唤醒的线程存储到 private 数据中 // func 赋值为 default_wake_function 函数 // 这个函数的作用是 唤醒等待队列上的线程wq_entry->func= default_wake_function; // 这函数作用是:唤醒线程 p}static inline void init_waitqueue_func_entry(struct wait_queue_entry *wq_entry, wait_queue_func_t func){wq_entry->flags= 0;wq_entry->private= NULL;wq_entry->func= func; // 直接把传入的回调函数赋值给 wq_entry->func}
这个函数的作用基本等效于 wake_up_process
函数。
int default_wake_function(wait_queue_entry_t *curr, unsigned mode, int wake_flags, void *key){WARN_ON_ONCE(IS_ENABLED(CONFIG_SCHED_DEBUG) && wake_flags & ~WF_SYNC); //try_to_wake_up函数通过把进程状态设置为TASK_RUNNING, 并把该进程插入本地CPU运行队列rq来达到唤醒睡眠和停止的进程的目的. // curr->private 存储了需要唤醒的线程return try_to_wake_up(curr->private, mode, wake_flags);}EXPORT_SYMBOL(default_wake_function);
wake_up ,可能是唤醒队列上的线程,也可能仅仅是触发一个回调而已
wake_up的两种用法:
bool wakeup_condition; wait_queue_head_t wait_queue; init_waitqueue_head(&wait_queue); wait_queue_entry_t wq_entry// wait第一种用法:线程等待 wait_event_interruptible(&wait_queue, wakeup_condition || kthread_should_stop());第二种用法:添加一个回调到等待队列上 init_waitqueue_func_entry(&wq_entry, callback); add_wait_queue(&wait_queue, &wq_entry);// 唤醒 设置等待条件为true,并唤醒 wakeup_condition = true;// 内部遍历队列,调用每个 wait_queue_entry 的 func 函数,根据func不同为产生不同效果 wake_up(&wait_queue);
以上就是“Android内核wake_up源码分析”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注编程网精选频道。
--结束END--
本文标题: Android内核wake_up源码分析
本文链接: https://www.lsjlt.com/news/351089.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
下载Word文档到电脑,方便收藏和打印~
2024-05-14
2024-05-14
2024-05-14
2024-05-14
2024-05-14
2024-05-14
2024-05-14
2024-05-14
2024-05-14
2024-05-14
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0