Android 內(nèi)核代碼 wake_up源碼解析
內(nèi)核中通常用法:
內(nèi)核有個函數(shù) wake_up 和 wake_up_interruptible 通常來說看到這倆函數(shù)調(diào)用就是喚醒等待隊列上的線程。
直到看了epoll的源碼,發(fā)現(xiàn)并非如此。
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()); // 喚醒 // 設(shè)置等待條件為true,并喚醒 wakeup_condition = true; wake_up(&wait_queue);
wake_up 的源碼:
// 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 是個宏,展開后調(diào)用的是 __wake_up 函數(shù) // __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)) {//不會進(jìn)入此分支 curr = list_next_entry(bookmark, entry); list_del(&bookmark->entry); bookmark->flags = 0; } else curr = list_first_entry(&wq_head->head, wait_queue_entry_t, entry);//獲取wq_head隊列的第一個元素 if (&curr->entry == &wq_head->head)//隊列為空時,直接返回傳入的 nr_exclusive return 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; /* 調(diào)用 wait_queue_entry_t 中的回調(diào)函數(shù) func // 這里依據(jù)func的類型會出現(xiàn)不同的結(jié)果。 使用 init_waitqueue_entry 初始化的 wait_queue_entry_t ,func = default_wake_function,這個函數(shù)會喚醒 curr->private 上的線程。 使用 init_waitqueue_func_entry 初始化的 wait_queue_entry_t,僅僅是做普通的函數(shù)調(diào)用。 */ 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; }
func 賦值過程
wait_queue_head 和 wait_queue_entry 數(shù)據(jù)結(jié)構(gòu)
//內(nèi)核4.14以后 // common/include/linux/wait.h struct wait_queue_head {// wait隊列 spinlock_t lock; // 自旋鎖 struct list_head head; // 添加到 wait 隊列時,就是把wait_queue_entry.entry 加入這個 head 鏈表 }; /* * A single wait-queue entry structure: */ struct wait_queue_entry {// wait隊列的一個項 unsigned int flags; void *private; // 私有數(shù)據(jù),在init_waitqueue_entry中代表線程,在init_waitqueue_func_entry中為null wait_queue_func_t func; // 回調(diào)函數(shù) struct list_head entry; // 添加到 wait 隊列時,就是把這個 entry 加入到 wait_queue_head.head 的鏈表 }; typedef struct wait_queue_head wait_queue_head_t; // wait_queue_head_t 同 wait_queue_head typedef 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
兩種等待任務(wù) wait_queue_entry:線程 和 函數(shù)
// common/include/linux/wait.h static inline void init_waitqueue_entry(struct wait_queue_entry *wq_entry, struct task_struct *p) { wq_entry->flags = 0; wq_entry->private = p; // 把需要喚醒的線程存儲到 private 數(shù)據(jù)中 // func 賦值為 default_wake_function 函數(shù) // 這個函數(shù)的作用是 喚醒等待隊列上的線程 wq_entry->func = default_wake_function; // 這函數(shù)作用是:喚醒線程 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; // 直接把傳入的回調(diào)函數(shù)賦值給 wq_entry->func }
default_wake_function 函數(shù)
這個函數(shù)的作用基本等效于 wake_up_process
函數(shù)。
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函數(shù)通過把進(jìn)程狀態(tài)設(shè)置為TASK_RUNNING, 并把該進(jìn)程插入本地CPU運行隊列rq來達(dá)到喚醒睡眠和停止的進(jìn)程的目的. // curr->private 存儲了需要喚醒的線程 return try_to_wake_up(curr->private, mode, wake_flags); } EXPORT_SYMBOL(default_wake_function);
綜上:
- wake_up ,可能是喚醒隊列上的線程,也可能僅僅是觸發(fā)一個回調(diào)而已
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()); 第二種用法:添加一個回調(diào)到等待隊列上 init_waitqueue_func_entry(&wq_entry, callback); add_wait_queue(&wait_queue, &wq_entry); // 喚醒 設(shè)置等待條件為true,并喚醒 wakeup_condition = true; // 內(nèi)部遍歷隊列,調(diào)用每個 wait_queue_entry 的 func 函數(shù),根據(jù)func不同為產(chǎn)生不同效果 wake_up(&wait_queue);
注: 基于 內(nèi)核4.14 以后版本分析,更多關(guān)于Android內(nèi)核代碼wake_up的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Android學(xué)習(xí)教程之下拉刷新實現(xiàn)代碼(11)
這篇文章主要為大家詳細(xì)介紹了Android學(xué)習(xí)教程之下拉刷新實現(xiàn)代碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-11-11Android AutoCompleteTextView控件使用實例
AutoCompleteTextView這個控件用于輸入框的自動完成提示,非常適合搜索框等。它本質(zhì)上是個EditText,實際上它也是從EditText繼承的,使用起來也十分簡單2014-04-04Android自定義View之酷炫數(shù)字圓環(huán)
這篇文章主要為大家詳細(xì)介紹了Android自定義View之酷炫數(shù)字圓環(huán),實現(xiàn)效果很酷,,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-01-01