2017-03-03


很遗憾之前在介绍进程调度的文章中,虽然涉及到了内核抢占,但是却没有对其进行深入介绍,今天就稍微总结下内核抢占。

  内核抢占在一定程度上减少了对某种事件的响应延迟,这也是内核抢占被引入的目的。之前的内核中,除了显示调用系统调度器的某些点,内核其他地方是不允许中重新调度的,如果内核在做一些比较复杂的工作,就会造成某些急于处理的事得不到及时响应。针对内核抢占其实本质上也是对当前进程而言(不知道这么描述是否合适),因为内核是为用户程序提供服务,换言之,其本身不会主动的去执行某个动作。这里内核抢占,重点在于用户程序请求内核服务时,CPU切换到内核态在执行某个系统服务期间,被抢占。

  当然,即使支持内核抢占,也不是什么时候都可以的,还是要考虑对临界区的保护。类似于多处理器架构,如果进程A陷入到内核模式访问某个临界资源,而在访问期间,进程B也要访问临界区,如果这种抢占被允许,那么就发生了临界区被重入。所以,在访问临界资源时需要禁止内核抢占,在出临界区则要开启内核抢占。

  为了支持内核抢占,在进程结构体的thread_info结构中有个preempt_count字段,用以记录当前内核(活动)是否可以被抢占。当该值为0时,允许被抢占;否则,不允许。

  关于内核抢占有几个函数:
  

#define preempt_disable() \
do { \
inc_preempt_count(); \
barrier(); \
} while () #define preempt_enable() \
do { \
preempt_enable_no_resched(); \
barrier(); \
preempt_check_resched(); \
} while ()
#define inc_preempt_count() add_preempt_count(1)
#define dec_preempt_count() sub_preempt_count(1) # define add_preempt_count(val) do { preempt_count() += (val); } while (0)
# define sub_preempt_count(val) do { preempt_count() -= (val); } while (0)

上面两个函数是禁止和启用内核抢占。其实就是一个宏定义。禁止内核抢占本质上就是把当前进程的thread_info结构中的preempt_count字段加1,而启用内核抢占就是减1.注意这里启用内核抢占之后,调用了preempt_check_resched检查当前是否需要重新调度,这也是一个宏,实现如下:

#define preempt_check_resched() \
do { \
if (unlikely(test_thread_flag(TIF_NEED_RESCHED))) \
preempt_schedule(); \
} while ()

就是在开启内核抢占之后,检查下此时是否有比较重要的进程等待执行,如果有,则调用preempt_schedule函数执行调度,可见在显示开启内核抢占之后,是触发内核抢占的一个时机。而调度过程本身是不允许被抢占的。preempt_schedule函数如下

asmlinkage void __sched notrace preempt_schedule(void)
{
struct thread_info *ti = current_thread_info(); /*
* If there is a non-zero preempt_count or interrupts are disabled,
* we do not want to preempt the current task. Just return..
*/
if (likely(ti->preempt_count || irqs_disabled()))
return; do {
add_preempt_count_notrace(PREEMPT_ACTIVE);
__schedule();
sub_preempt_count_notrace(PREEMPT_ACTIVE); /*
* Check again in case we missed a preemption opportunity
* between schedule and now.
*/
barrier();
} while (need_resched());
}

如果抢占计数器不为0或者当前处于关闭硬件中断状态均是不可以被抢占的。

前面提到,在不支持内核抢占的内核中,内核态程序会一直执行,直到返回用户空间进程时,才会检查调度。在内核中执行期间,能打断当前执行的,只有中断,在硬件中断来了之后,处理器会根据情况着手处理硬件中断,在硬件中断处理完毕需要恢复现场时,若检查之前的状态是内核态,则不触发调度,只有之前状态是用户态时才会触发调度。而在支持内核抢占的内核中,在从硬件中断返回时,不管是返回用户态和内核态都会检查调度,若是返回内核态,检查当前线程调度标识和抢占标识,若都允许,则可进程调度。这是内核抢占下由增加的一个调度点。

参考资料:

1、linux 3.10.1内核

2、深入linux内核架构

Linux下的内核抢占的更多相关文章

  1. Linux下查看内核、CPU、内存及各组件版本的命令和方法

    Linux下查看内核.CPU.内存及各组件版本的命令和方法 Linux查看内核版本: uname -a                        more /etc/*release       ...

  2. Linux下编译内核配置选项简介

    Code maturity level options代码成熟度选项 Prompt for development and/or incomplete code/drivers 显示尚在开发中或尚未完 ...

  3. Linux 下 Oracle 内核参数优化

    数据库的性能优化涉及到整个数据库运行环境的方方面面,诸如操作系统,Oracle自身,存储,网络等等几个大块.而操作系统则是Oracle稳定运行与最大化性能的基石.本文主要描述基于Linux系统下 Or ...

  4. 优化Linux下的内核TCP参数以提高系统性能

    内核的优化跟服务器的优化一样,应本着稳定安全的原则.下面以64位的Centos5.5下的Squid服务器为例来说明,待客户端与服务器端建立 TCP/IP连接后就会关闭SOCKET,服务器端连接的端口状 ...

  5. 优化Linux下的内核TCP参数来提高服务器负载能力

    http://blog.renhao.org/2010/07/setup-linux-kernel-tcp-settings/ /proc/sys/net目录 所有的TCP/IP参数都位于/proc/ ...

  6. Linux下的内核测试工具——perf使用简介

    Perf是Linux kernel自带的系统性能优化工具.Perf的优势在于与Linux Kernel的紧密结合,它可以最先应用到加入Kernel的new feature.pef可以用于查看热点函数, ...

  7. linux下删除内核

    一.概述 笔者的Ubuntu系统刚安装成功后,就不知道怎么会有多个内核,但实际上默认运行的只有一个.在grub启动界面多余的启动项和多余内核占用的存储空间迫使我产生了铲除多余内核的冲动. 最近,自己从 ...

  8. 在linux下查看内核版本、gcc版本、操作系统多少位等参数

    1. 查看linux版本 cat /etc/issue Ubuntu 11.04 \n \l 2. 查看内核版本 1)cat /proc/version Linux version 2.6.38-13 ...

  9. linux下改动内核參数进行Tcp性能调优 -- 高并发

    前言: Tcp/ip协议对网络编程的重要性,进行过网络开发的人员都知道,我们所编写的网络程序除了硬件,结构等限制,通过改动Tcp/ip内核參数也能得到非常大的性能提升, 以下就列举一些Tcp/ip内核 ...

随机推荐

  1. Windows Phone 修改系统定义的资源颜色

    [问题的背景] 相信有些经验的WP研发同学都会遇到下面的问题: 系统控件以及WPToolkit中大量使用了PhoneAccentBrush这个画刷(这个画刷定义的是系统的强调色,即用户选择的主题颜色) ...

  2. OpenERP 7 picking order 继承需要注意的地方

    stock.picking.out  和 stock.picking.in 都是继承自stock.picking 新添加columns时需要注意,在stock.picking.out和stock.pi ...

  3. linux udhcpc 后无法自动设置网卡ip

    arm 主板用 udhcpc 获取租赁的空闲的ip后,并没有直接设置在网卡上. 查了一下相关原因,是因为虽然已经获取了ip, 但是并没有通过脚本去设置这个IP. 在 busybox 里面有相关的脚本要 ...

  4. UASCO Wormholes 解析 and C 语言实现

    题目大意: 农场有N个洞(2<=N<=12,N为偶数),且组成N/2个连接对.每一个洞的给出平面坐标(x,y). 假设A和B相连,则进入A会从B出来,进入B会从A出来.有仅仅会沿着x轴正方 ...

  5. 重启oracle方法一二三

    startup nomount alter database mount alter database open Linux:方法1 用root以ssh登录到linux,打开终端输入以下命令: cd ...

  6. CMake Error at cmake/boost.cmake:76 (MESSAGE):

    编译mysql5.7.9的时候报错 CMake Error at cmake/boost.cmake:76 (MESSAGE): You can download it with -DDOWNLOAD ...

  7. 绑定QQ登录 PHP OAuth详解(转)

    越来越多的网站开始采用 第三方账号登录 如qq 微博 开心网 等诸多流行的社交平台,利用第三方账号登录,可以更好地省去用户的注册时间,并且极大地提高用户体验,吸引更多的潜在用户. 让用户拥有 一个号码 ...

  8. 【wikioi】3160 最长公共子串(后缀自动机)

    http://codevs.cn/problem/3160/ sam的裸题...(之前写了spoj上另一题sam的题目,但是spoj被卡评测现在还没评测完QAQ打算写那题题解时再来详细介绍sam的.. ...

  9. hdu 1022:Train Problem I(数据结构,栈,递归,dfs)

    Train Problem I Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)T ...

  10. jQuery监控文本框事件并作相应处理的方法

    本文实例讲述了jQuery监控文本框事件并作相应处理的方法.分享给大家供大家参考.具体如下: //事情委托 $(document)  .on('input propertychange', '#que ...