iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >Android内核wake_up源码分析
  • 720
分享到

Android内核wake_up源码分析

2023-07-05 10:07:53 720人浏览 独家记忆
摘要

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

    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;} 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;}

    func 赋值过程

    wait_queue_head 和 wait_queue_entry 数据结构

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

    两种等待任务 wait_queue_entry:线程 和 函数

    // common/include/linux/wait.hstatic 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源码分析”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注编程网精选频道。

    --结束END--

    本文标题: Android内核wake_up源码分析

    本文链接: https://www.lsjlt.com/news/351089.html(转载时请注明来源链接)

    有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

    本篇文章演示代码以及资料文档资料下载

    下载Word文档到电脑,方便收藏和打印~

    下载Word文档
    猜你喜欢
    • c#程序自启动怎么设置
      c# 程序的自启动方法有三种:注册表:在指定注册表项下创建新值,并将其设置为程序可执行文件路径。任务计划程序:创建一个新任务,并在触发器和动作部分分别指定登录时或特定时间触发,以及启动程...
      99+
      2024-05-14
      c#
    • c#怎么调用dll文件
      可在 c# 中轻松调用 dll 文件:引用 dll(使用 dllimport 特性)定义与 dll 函数签名匹配的函数原型调用 dll 函数(如同 c# 函数)附加技巧:使用 chars...
      99+
      2024-05-14
      c#
    • 如何构建 Golang RESTful API,并实现 CRUD 操作?
      通过创建 golang 项目并安装必要的包,我们可以构建一个功能齐全的 restful api。它使用 mysql 数据库进行 crud 操作:1. 创建和连接数据库;2. 定义数据结构...
      99+
      2024-05-14
      go crud mysql git golang
    • c#怎么添加类文件
      在c#中添加类文件的步骤:1. 创建新项目,2. 添加新类,3. 为类添加代码,4. 在另一个类中引用新类。using语句引用类文件所在的命名空间;new运算符创建类的新实例;点运算符访...
      99+
      2024-05-14
      c#
    • 使用 C++ 构建高性能服务器架构的最佳实践
      遵循 c++++ 中构建高性能服务器架构的最佳实践可以创建可扩展、可靠且可维护的系统:使用线程池以重用线程,提高性能。利用协程减少上下文切换和内存开销,提升性能。通过智能指针和引用计数优...
      99+
      2024-05-14
      c++ 高性能服务器架构 数据访问
    • c#怎么添加字段
      在 c# 中添加字段包括以下步骤:声明字段:在类或结构中使用 字段类型 字段名; 语法声明字段。访问修饰符:用于限制对字段的访问,如 private、public、protected 和...
      99+
      2024-05-14
      c#
    • c#中怎么添加引用
      c# 中添加引用的方法有四种:使用 nuget 包管理器添加软件包。添加项目引用以包含其他项目。手动编辑项目文件 (.csproj) 以添加引用。从编译器命令行使用 /reference...
      99+
      2024-05-14
      c#
    • c#怎么创建文本文件
      在 c# 中创建文本文件的方法包括:创建 filestream 对象以打开或创建文件。使用 streamwriter 写入文本至文件。关闭 streamwriter 对象释放资源。关闭 ...
      99+
      2024-05-14
      c#
    • c#怎么定义属性
      如何在 c# 中定义属性 属性是一种编程构造,它包含一个 get 访问器和一个 set 访问器,允许以一种类属性的方式访问字段。它们提供了一种安全且封装的方式来访问和修改类的内部数据。 ...
      99+
      2024-05-14
      c#
    • 基于 C++ 的服务器架构的安全性考虑因素
      在设计基于 c++++ 的服务器架构时,安全考虑至关重要:使用 std::string 或 std::vector 避免缓冲区溢出。使用正则表达式或库函数验证用户输入。采用输出转义防止跨...
      99+
      2024-05-14
      安全性 关键词: c++ 服务器架构 c++ lsp
    软考高级职称资格查询
    编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
    • 官方手机版

    • 微信公众号

    • 商务合作