Linux下的内核抢占
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下的内核抢占的更多相关文章
- Linux下查看内核、CPU、内存及各组件版本的命令和方法
Linux下查看内核.CPU.内存及各组件版本的命令和方法 Linux查看内核版本: uname -a more /etc/*release ...
- Linux下编译内核配置选项简介
Code maturity level options代码成熟度选项 Prompt for development and/or incomplete code/drivers 显示尚在开发中或尚未完 ...
- Linux 下 Oracle 内核参数优化
数据库的性能优化涉及到整个数据库运行环境的方方面面,诸如操作系统,Oracle自身,存储,网络等等几个大块.而操作系统则是Oracle稳定运行与最大化性能的基石.本文主要描述基于Linux系统下 Or ...
- 优化Linux下的内核TCP参数以提高系统性能
内核的优化跟服务器的优化一样,应本着稳定安全的原则.下面以64位的Centos5.5下的Squid服务器为例来说明,待客户端与服务器端建立 TCP/IP连接后就会关闭SOCKET,服务器端连接的端口状 ...
- 优化Linux下的内核TCP参数来提高服务器负载能力
http://blog.renhao.org/2010/07/setup-linux-kernel-tcp-settings/ /proc/sys/net目录 所有的TCP/IP参数都位于/proc/ ...
- Linux下的内核测试工具——perf使用简介
Perf是Linux kernel自带的系统性能优化工具.Perf的优势在于与Linux Kernel的紧密结合,它可以最先应用到加入Kernel的new feature.pef可以用于查看热点函数, ...
- linux下删除内核
一.概述 笔者的Ubuntu系统刚安装成功后,就不知道怎么会有多个内核,但实际上默认运行的只有一个.在grub启动界面多余的启动项和多余内核占用的存储空间迫使我产生了铲除多余内核的冲动. 最近,自己从 ...
- 在linux下查看内核版本、gcc版本、操作系统多少位等参数
1. 查看linux版本 cat /etc/issue Ubuntu 11.04 \n \l 2. 查看内核版本 1)cat /proc/version Linux version 2.6.38-13 ...
- linux下改动内核參数进行Tcp性能调优 -- 高并发
前言: Tcp/ip协议对网络编程的重要性,进行过网络开发的人员都知道,我们所编写的网络程序除了硬件,结构等限制,通过改动Tcp/ip内核參数也能得到非常大的性能提升, 以下就列举一些Tcp/ip内核 ...
随机推荐
- python操作word
python教程(百度经验) Python 操作Word(Excel.PPT等通用) import win32comfrom win32com.client import Dispatch, co ...
- [Eth]Mac/Phy/mdio/Rgmii
转自:http://www.cnblogs.com/zxc2man/p/3769777.html 1. MDIO(Management Data Input/Output),对G比特以太网而言,串行通 ...
- PHP——分页显示的完善(加查询,用类简化sql语句)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- 深入分析DDR(转载)
深入分析:我们为何需要DDR2内存技术 http://www.cnblogs.com/thx-bj/archive/2008/04/02/1134040.html 文/IT168评测室特约 Myddn ...
- C++ new delete操作符
//new delete操作符 #define _CRT_SECURE_NO_WARNINGS #include<iostream> using namespace std; /* 1.n ...
- jQuery补充,基于jQuery的bxslider轮播器插件
基于jQuery的bxslider轮播器插件 html <!DOCTYPE html> <html lang="zh-cn"> <head> & ...
- 视图矩阵的推导-opengl应用
把物体从世界坐标系转化到视点坐标系的矩阵称为视图矩阵. 下面我们先看下opengl视图矩阵的推导过程: 假设视点或camera的局部坐标系为UVN,UVN分别指向右方.上方和后方从而构成右手坐标系,视 ...
- Window发声函数Beep、MessageBeep
C++ Code 1234567891011 WINBASEAPI BOOL WINAPI Beep(__in DWORD dwFreq, __in DWORD dwDuration ...
- Maven的Settings.xml配置文件解释
该配置用于单用户配置和全局配置, 单用户配置默认存放于 ${user.home}/.m2/目录中. 全局配置默认存放于Maven安装目录下面的conf目录中. 这两个默认的位置都可以修改. <? ...
- VC中的学习点滴
1. __stdcall 和 __cdecl __cdecl 是C Declaration的缩写(declaration,声明),表示C语言默认的函数调用方法:所有参数从右到左依次入栈,由调用者负责 ...