LINUX软中断-完全理解

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

前言

关于linux的软中断的文章在网上可以找到很多但总觉着讲的都不够深入打算自己写一下

软中断的感性认识

中断一旦被触发本地cpu正在运行的不管是什么程序都要让路让中断程序执行并且执行过程中不能被打断。在linux下符合这种情景的中断有两种

  1. 硬中断
    即硬件机制GIC产生一个中断后通知cpucpu硬件会跳到特定的地址去执行程序不能被打断, 这个程序就是中断服务程序。
  2. 软中断
    用软件编程的方式来模拟硬件中断的特性当触发软中断任务执行时此任务是不能被本core上的其他任务抢占运行优先级最高软中断任务执行结束后才能执行其他任务类似于硬中断的行为。但是毕竟是软件模拟的行为所以软中断任务在执行的过程中是可以接收硬中断并优先执行中断服务程序硬中断是老大优先处理。

那问题来了软中断是如何做到不被本core上的其他任务抢占呢?我们先要说一下其他方面的知识

运行上下文

大家都知道在linux内核里用current_thread_info来表示本core上当前所运行程序的信息。

union thread_union {
	struct thread_info thread_info;
	unsigned long stack[THREAD_SIZE/sizeof(long)];
};
static inline struct thread_info *current_thread_info(void) __attribute_const__;

static inline struct thread_info *current_thread_info(void)
{
	register unsigned long sp asm ("sp");
	return (struct thread_info *)(sp & ~(THREAD_SIZE - 1));
}

从上面的定义可以看出thread_info与栈共同占用一个pagethread_info从低地址开始存放而栈从高地址往低地址增长。由于页对齐的缘故栈指针sp & ~(THREAD_SIZE - 1)就是thread_info。
其次内核程序在运行的过程中需要有一个变量(preempt_count)

//#define preempt_count()	(current_thread_info()->preempt_count)
current_thread_info()->preempt_count

来标明目前此程序正在运行的环境即上下文在linux中用不同的整数来代表不同的上下文。

//这里的 PREEMPT_SHIFT 是什么值就不做讨论了。
#define PREEMPT_OFFSET	(1UL << PREEMPT_SHIFT)
#define SOFTIRQ_OFFSET	(1UL << SOFTIRQ_SHIFT)
#define HARDIRQ_OFFSET	(1UL << HARDIRQ_SHIFT)
#define NMI_OFFSET	(1UL << NMI_SHIFT)

比如来了个中断当前任务被打断那么这时候此任务应该被标识为正在运行在中断上下文中
比如来个硬中断

//# define add_preempt_count(val)	do { preempt_count() += (val); } while (0)
//# define sub_preempt_count(val)	do { preempt_count() -= (val); } while (0)
add_preempt_count(HARDIRQ_OFFSET);

即把 preempt_count变量加上 HARDIRQ_OFFSET后的值就表示当前current正运行在中断上下文。
随之而来的问题就出现了preempt_count存在的意义是什么呢?仅仅就是为了标识当前程序所运行的上下文吗?

linux的抢占调度

上面的问题跟linux的调度器有关关于linux的调度其实分成两个阶段

  1. check点
    即找出要执行抢占的程序

  2. 抢占点
    即switch到抢占的程序执行

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: linux