关于might_sleep的一点说明【转】

关于might_sleep的一点说明【转】

大家好,又见面了,我是全栈君。

转自:http://blog.csdn.net/chen_chuang_/article/details/48462575

这个函数我在看代码时基本上是直接忽略的(因为我知道它实际上不干什么事),不过因为内核中很多函数一开始就会用一下它,为了方便那些正在学习内核源码的网友,本帖专门讨论一下该函数到底被内核用来干什么。

简单地说,如果没有调试的需求(绝大多数下你平常跑的系统都是release版本的kernel),那么这个宏(或者函数,称谓并不重要)什么实质性的活都不干,内核只是用它来做一件事,就是提醒你,调用该函数的函数可能会sleep,这个跟其名字也是匹配的: The function calling might_sleep() might sleep。如果你想看源码,我把它列在下面:


点击(此处)折叠或打开

  1. # define might_resched() do { } while (0)
  2. # define might_sleep() do { might_resched(); } while (0)

看到没,啥事都没干。其实内核源码对此也有明确的注释:might_sleep – annotation for functions that can sleep。所以对于release版的kernel image而言,might_sleep的作用仅仅是一个annotation,提醒使用者,一个使用might_sleep的函数在其后的代码执行中可能会sleep。

不过如果有调试需求介入的话,比如你的系统莫名其妙地随机性地crash掉,在经过一段艰难的案情分析排查之后,最后你决定打开内核的CONFIG_DEBUG_ATOMIC_SLEEP选项,那么此时might_sleep对案情的进一步推进就可能产生贡献了。CONFIG_DEBUG_ATOMIC_SLEEP选项主要用来排查是否在一个ATOMIC操作的上下文中有函数发生sleep行为,关于什么是ATOMIC操作,内核源码在might_sleep函数前也有一段注释:
this macro will print a stack trace if it is executed in an atomic context (spinlock, irq-handler, …)

所以很明显,一个进程获得了spinlock之后它就进入了这里所谓的atomic context,或者是在一个irq-handler,也就是一个中断上下文中。这两种上下文中理论上不应该让当前的execution path进入sleep状态(虽然不是强制规定,换句话说,一个拥有spinlock的进程进入sleep并不必然意味着系统就一定会deadlock等,但是对内核编程而言,还是应该尽力避开这个雷区)。

在CONFIG_DEBUG_ATOMIC_SLEEP选项打开的情形下,might_sleep又有哪些特殊的功能呢?先看看内核中的源码:


点击(此处)折叠或打开

  1. void __might_sleep(const char *file, int line, int preempt_offset)
  2. {

  3.         static unsigned long prev_jiffy; /* ratelimiting */

  4.         if ((preempt_count_equals(preempt_offset) && !irqs_disabled()) ||
  5.             system_state != SYSTEM_RUNNING || oops_in_progress)
  6.                 return;
  7.         if (time_before(jiffies, prev_jiffy + HZ) && prev_jiffy)
  8.                 return;
  9.         prev_jiffy = jiffies;

  10.         printk(KERN_ERR
  11.                 “BUG: sleeping function called from invalid context at %s:%d\n”,
  12.                         file, line);
  13.         printk(KERN_ERR
  14.                 “in_atomic(): %d, irqs_disabled(): %d, pid: %d, name: %s\n”,
  15.                         in_atomic(), irqs_disabled(),
  16.                         current>pid, current>comm);

  17.         if (irqs_disabled())
  18.                 print_irqtrace_events(current);
  19.         dump_stack();
  20. }

上面的代码我进行了轻微的删减,去除了一些只有CONFIG_DEBUG_ATOMIC_SLEEP选项使能的情形下不干活的函数。


点击(此处)折叠或打开

  1. # define might_sleep() \
  2.         do { __might_sleep(__FILE__, __LINE__, 0); might_resched(); } while (0)

在当前CONFIG_DEBUG_ATOMIC_SLEEP选项使能的前提下, 可以看到__might_sleep还是干了不少事情的,最主要的工作是在第一个if语句那里,尤其是preempt_count_equals和 irqs_disabled,都是用来判断当前的上下文是否是一个atomic context,因为我们知道,只要进程获得了spin_lock的任一个变种形式的lock,那么无论是单处理器系统还是多处理器系统,都会导致preempt_count发生变化,而irq_disabled则是用来判断当前中断是否开启。__might_sleep正是根据这些信息来判断当前正在执行的代码上下文是否是个atomic,如果不是,那么函数就直接返回了,因为一切正常。如果是,那么代码下行。

所以让CONFIG_DEBUG_ATOMIC_SLEEP选项打开,可以捕捉到在一个atomic context中是否发生了sleep,如果你的代码不小心在某处的确出现了这种情形,那么might_sleep会通过后续的printk以及dump_stack来协助你发现这种情形。

至于__might_sleep函数中的system_state,它是一个全局性的enum型变量,主要用来记录当前系统的状态:

点击(此处)折叠或打开

  1. enum system_states system_state __read_mostly;
  2. EXPORT_SYMBOL(system_state);

注意system_state已经被export出来,所以内核模块可以直接读该值来判断当前系统的运行状态,常见的状态包括:

点击(此处)折叠或打开

  1. extern enum system_states {

  2.     SYSTEM_BOOTING,
  3.     SYSTEM_RUNNING,
  4.     SYSTEM_HALT,
  5.     SYSTEM_POWER_OFF,
  6.     SYSTEM_RESTART,
  7.     SYSTEM_SUSPEND_DISK,
  8. } system_state;

最常见的状态当然是SYSTEM_RUNNING了,你的系统正常起来之后就处于这个状态。因为跟当前的话题没有直接的关联,这里只提一下好了。

阅读(1) | 评论(0) | 转发(0) |

0

上一篇:proc函数

下一篇:linux程序设计—多线程

评论热议

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/108302.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • pycharm安装CV2,tensorflow[通俗易懂]

    pycharm安装CV2,tensorflow[通俗易懂]在pycharm中导入importcv2时不能正常使用,需要安装cv2库,但是我们在pycharm中安装库时没有找到CV2,就需要安装opencv库,我采用的是以下的方式:1、首先看下pycharm中的环境,我现在用的环境是anaconda下的PyCharmproject2、在菜单栏中打开anacondaprompt(anaconda3)3、刚开始进入时环境是4、切换环境为pycharm中环境activatePyCharmproject5、已经下好了opencv的whl文件,我下到了3

    2022年8月26日
    9
  • Modbus通讯协议详细解释

    Modbus通讯协议详细解释Modbus一个工业上常用的通讯协议、一种通讯约定。Modbus协议包括RTU、ASCII、TCP。其中MODBUS-RTU最常用,比较简单,在单片机上很容易实现。先来简单分析一条MODBUS-RTU报文,例如:0106000100179804010600010017

    2022年7月12日
    15
  • pcep协议什么意思_什么是SDN「建议收藏」

    pcep协议什么意思_什么是SDN「建议收藏」传统网络设备部署模式来说,基于整个网络状态的决策都要由每台网络设备独立承担,如果执行控制平面功能的模块的处理能力达到了设备极限,即便数据平面带宽仍有富余,也可能会出现瓶颈。此外,如果控制平面决策进程涉及多个节点的信息,如RSVP(ResourceReservationProtocol,资源预留协议)应用场景,那么就需要在节点之间执行额外的通信操作以收集相关信息,进而给设备带来不必要的开销负担。…

    2022年9月7日
    1
  • java 除法取商_java除法怎样取小数部分「建议收藏」

    java 除法取商_java除法怎样取小数部分「建议收藏」2016-09-0100:30最佳答案C++的优先级优先级操作符结合性1::左2.->[]()左3++–~!-+&*()sizeofnewdeletecastname_cast单目操作符右4.*->*左5*/%左6+-左7<<>>左8<<=>>=…

    2022年5月30日
    57
  • 电压转电流电路

    电压转电流电路图1 电压转电流原理图   如图 1是输入输出无偏置型电压转电流信号调理的典型电路。其中运放A、电阻R13、三极管Q10构成压控电流源电路;电阻R9、R11、运放B、三极管Q8、Q9构成电流放大电路。   当电压信号加在运放A同向输入时,由运放特性:虚短、虚断可知反向输入端电压跟随同向输入端电压信号,此时在电阻R13支路上产生电流流过三极管Q10,三极管Q10基极受运放A输出端

    2022年6月2日
    38
  • Ubuntu安装Redis及使用「建议收藏」

    Ubuntu安装Redis及使用「建议收藏」NoSQL简介NoSQL,全名为NotOnlySQL,指的是非关系型的数据库随着访问量的上升,网站的数据库性能出现了问题,于是nosql被设计出来优点/缺点优点:高可扩展性分布式计算低成本架构的灵活性,半结构化数据没有复杂的关系缺点:没有标准化有限的查询功能(到目前为止)最终一致是不直观的程序分类类型部分代表特点列存储H…

    2022年9月14日
    5

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号