欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android 內(nèi)核代碼 wake_up源碼解析

 更新時間:2023年03月08日 10:49:34   作者:拉普  
這篇文章主要為大家介紹了Android 內(nèi)核代碼 wake_up源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

內(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_entryinit_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-&gt;flags		= 0;
	wq_entry-&gt;private	= p; // 把需要喚醒的線程存儲到 private 數(shù)據(jù)中
    // func 賦值為 default_wake_function 函數(shù)
    // 這個函數(shù)的作用是 喚醒等待隊列上的線程
	wq_entry-&gt;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-&gt;flags		= 0;
	wq_entry-&gt;private	= NULL;
	wq_entry-&gt;func		= func; // 直接把傳入的回調(diào)函數(shù)賦值給 wq_entry-&gt;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) &amp;&amp; wake_flags &amp; ~WF_SYNC);
    //try_to_wake_up函數(shù)通過把進(jìn)程狀態(tài)設(shè)置為TASK_RUNNING, 并把該進(jìn)程插入本地CPU運行隊列rq來達(dá)到喚醒睡眠和停止的進(jìn)程的目的.
    // curr-&gt;private 存儲了需要喚醒的線程
	return try_to_wake_up(curr-&gt;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)

    Android學(xué)習(xí)教程之下拉刷新實現(xiàn)代碼(11)

    這篇文章主要為大家詳細(xì)介紹了Android學(xué)習(xí)教程之下拉刷新實現(xiàn)代碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-11-11
  • Android實現(xiàn)圖片輪播效果的兩種方法

    Android實現(xiàn)圖片輪播效果的兩種方法

    android圖片輪播效果非常漂亮,在程序開發(fā)中也經(jīng)常用到,本文給大家分享android實現(xiàn)圖片輪播效果的幾種方法,對android實現(xiàn)圖片輪播相關(guān)知識感興趣的朋友一起學(xué)習(xí)吧
    2015-12-12
  • Android開發(fā)之關(guān)于項目

    Android開發(fā)之關(guān)于項目

    本文是此系列文章的第二篇,給大家介紹的是項目相關(guān)的內(nèi)容,非常的細(xì)致全面,有需要的小伙伴可以參考下
    2016-02-02
  • Android中HTTP請求中文亂碼解決辦法

    Android中HTTP請求中文亂碼解決辦法

    這篇文章主要介紹了Android中HTTP請求中文亂碼解決辦法的相關(guān)資料,希望通過本文能幫助到大家,讓大家解決中文亂碼的問題,需要的朋友可以參考下
    2017-09-09
  • Android讀取服務(wù)器圖片的三種方法

    Android讀取服務(wù)器圖片的三種方法

    這篇文章主要為大家詳細(xì)介紹了Android讀取服務(wù)器圖片的三種方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-05-05
  • Android AutoCompleteTextView控件使用實例

    Android AutoCompleteTextView控件使用實例

    AutoCompleteTextView這個控件用于輸入框的自動完成提示,非常適合搜索框等。它本質(zhì)上是個EditText,實際上它也是從EditText繼承的,使用起來也十分簡單
    2014-04-04
  • 使用UITextField限制輸入金額是正確小數(shù)

    使用UITextField限制輸入金額是正確小數(shù)

    通過我們使用正則表達(dá)式和textfield的方法判斷輸入金額是否為正確的金額,今天小編給大家使用UITextField限制輸入金額是正確小數(shù),有需要的朋友可以參考下
    2016-05-05
  • Android無需root實現(xiàn)apk的靜默安裝

    Android無需root實現(xiàn)apk的靜默安裝

    這篇文章主要介紹了Android無需root實現(xiàn)apk的靜默安裝 的相關(guān)資料,需要的朋友可以參考下
    2016-01-01
  • android藍(lán)牙控制PC端代碼分享

    android藍(lán)牙控制PC端代碼分享

    這篇文章主要為大家分享了android藍(lán)牙控制PC端的詳細(xì)代碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-07-07
  • Android自定義View之酷炫數(shù)字圓環(huán)

    Android自定義View之酷炫數(shù)字圓環(huán)

    這篇文章主要為大家詳細(xì)介紹了Android自定義View之酷炫數(shù)字圓環(huán),實現(xiàn)效果很酷,,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-01-01

最新評論