<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
核心有個函數 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; } 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; /* 呼叫 wait_queue_entry_t 中的回撥函數 func // 這裡依據func的型別會出現不同的結果。 使用 init_waitqueue_entry 初始化的 wait_queue_entry_t ,func = default_wake_function,這個函數會喚醒 curr->private 上的執行緒。 使用 init_waitqueue_func_entry 初始化的 wait_queue_entry_t,僅僅是做普通的函數呼叫。 */ 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.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; // 私有資料,在init_waitqueue_entry中代表執行緒,在init_waitqueue_func_entry中為null wait_queue_func_t func; // 回撥函數 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
// 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 資料中 // 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的兩種用法:
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);
注: 基於 核心4.14 以後版本分析,更多關於Android核心程式碼wake_up的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45