【精通内核】Linux内核抢占原理

578 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第7天,点击查看活动详情

前言

📫作者简介小明java问道之路,专注于研究 Java/ Liunx内核/ C++及汇编/计算机底层原理/源码,就职于大型金融公司后端高级工程师,擅长交易领域的高安全/可用/并发/性能的架构设计与演进、系统优化与稳定性建设。

📫热衷分享,喜欢原创~ 关注我会给你带来一些不一样的认知和成长

🏆InfoQ签约作者、CSDN专家博主/后端领域优质创作者/内容合伙人、阿里云专家/签约博主、51CTO专家🏆

🔥如果此文还不错的话,还请👍关注 、点赞 、收藏三连支持👍一下博主~


本文导读

内核抢占就是允许正在内核中执行的任务抢占另一个正在内核中执行的任务。本文详解Linux内核抢占原理以及内核源码实现过程。

一、Linux内核抢占原理

何为内核抢占呢?就是允许正在内核中执行的任务抢占另一个正在内核中执行的任务。

在 Linux 内核 2.6 版本之前,陷入内核执行的任务无法被抢占,即使有比它优先级高的任务也无被抢占,只能设置重调度标记位,在退出内核空间时才能抢占它。

二、内核抢占原理

这样做的结果就是极大地降低了的性能,于是在Linux 内核2.6版本开始支持内核抢占。这就显著地提高了性能,并且大幅提升响应能力。当内核处理中断和异常或者打开内核强占时,将会响应内核强占,此时会调用调度器 preempt schedule 方法完成强占动作。下面看看内核抢占的相关操作。

三、Linux内核抢占源码解析

可以看到,一个任务是否可以被抢占是通过一个preempt_count变量来控制的,并且在scheduler 调度器中提供了preempt schedule()抢占调度操作。

首先在每个任务的thread_info里维护了一个preemptcount,当它等于0时是可以被抢占的。

增加 preempt_count和减少preempt_count,如果启用了内核抢占机制,那么以下宏定义生效,设置当前任务禁止被抢占,设置当前任务禁止被抢占以及设置当前任务可以被抢占。

抢占调度,设置当前任务可以被抢占且马上尝试抢占调度,如果没有配置内核抢占,这些操作默认为空操作。

// 在每个任务的thread_info里维护了一个preemptcount,当它等于0时是可以被抢占的
#define preempt_count()(currentthread info()->preemptcount)

// 增加 preempt_count
#define inc_preempt_count() 
do {
    preempt_count()++;
} while (0)

// 减少preempt_count
#define dec_preempt_count()
do {
    preempt_count()--;
} while (0)

// 如果启用了内核抢占机制,那么以下宏定义生效
#ifdef CONFIG PREEMPT
extern void preempt_schedule(void);

// 设置当前任务禁止被抢占
#define preempt_disable() 
do {
    inc_preempt_count(); 
    barrier();
} while (0)

// 设置当前任务可以被抢占
#define preempt enable_no resched() 
do {
    barrier();
    dec_preempt_count();
} while (0)

// 抢占调度
#define preempt_check_resched() 
do{
    if (unlikely(test_thread_flag(TIF_NEED_RESCHED)))
        preempt_schedule();
} while (0)

// 设置当前任务可以被抢占且马上尝试抢占调度
#define preempt_enable() 
do {
    preempt_enable_no_resched();
    preempt_check_resched();
} while (0)

// 如果没有配置内核抢占,这些操作默认为空操作
#else
#define preempt_disable()	do { } while (0)	
#define preempt_enable_no_resched() do{}while(0)
#define preempt_enable()	do {} while (0)	
#define preempt_check_resched()	do { } while (0)	
#endif
#endif