中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Android內核wake_up源碼分析

發布時間:2023-03-08 11:27:54 來源:億速云 閱讀:114 作者:iii 欄目:開發技術

今天小編給大家分享一下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);

    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 是個宏,展開后調用的是 __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;
    }

    func 賦值過程

    wait_queue_head 和 wait_queue_entry 數據結構

    //內核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_entryinit_waitqueue_func_entry

    兩種等待任務 wait_queue_entry:線程 和 函數

    // 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 數據中
        // func 賦值為 default_wake_function 函數
        // 這個函數的作用是 喚醒等待隊列上的線程
    	wq_entry-&gt;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-&gt;flags		= 0;
    	wq_entry-&gt;private	= NULL;
    	wq_entry-&gt;func		= func; // 直接把傳入的回調函數賦值給 wq_entry-&gt;func
    }

    default_wake_function 函數

    這個函數的作用基本等效于 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) &amp;&amp; wake_flags &amp; ~WF_SYNC);
        //try_to_wake_up函數通過把進程狀態設置為TASK_RUNNING, 并把該進程插入本地CPU運行隊列rq來達到喚醒睡眠和停止的進程的目的.
        // curr-&gt;private 存儲了需要喚醒的線程
    	return try_to_wake_up(curr-&gt;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源碼分析”這篇文章的所有內容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關注億速云行業資訊頻道。

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    黎川县| 池州市| 永康市| 讷河市| 双辽市| 冀州市| 阿荣旗| 疏勒县| 德阳市| 四会市| 正定县| 汝城县| 吴忠市| 崇左市| 尚义县| 河南省| 库车县| 霍林郭勒市| 文安县| 砀山县| 新密市| 德庆县| 彭山县| 镇坪县| 牡丹江市| 东山县| 洪江市| 镇远县| 浪卡子县| 灯塔市| 塘沽区| 德兴市| 连南| 威远县| 界首市| 治县。| 赤峰市| 金秀| 临城县| 军事| 惠州市|