日期
内核版本
CPU架构
作者
2019.04.06
Linux-5.0
PowerPC
LoneHugo
系列文章:https://blog.csdn.net/Vince_/article/details/89054330
调度实际上称为Porcess Scheduling,即进程调度,Linux对此作了封装,以调度实体(Schedule Entity)为单位进行调度。下面分别看一下Linux中与调度相关的数据结果或结构成员。
1. task_struct
task_struct为进程描述符,Linux上进程相关的所有信息都包含在其中,比如用户虚拟地址空间、打开的文件和进程内核栈等等。
定义:https://elixir.bootlin.com/linux/v5.0.7/source/include/linux/sched.h#L592
policy
又称为scheduling policy,表示一组用来决定何时以及如何选择下一个进程进行调度执行的规则。这组规则或者调度策略很好地解决了现在看似矛盾的问题:进程快速响应、后台进程高流量、进程饥饿以及优先级分配等。
policy可取值范围如下:
/*
* Scheduling policies
*/
#define SCHED_NORMAL 0 /* 普通调度类型CFS,采用fair_sched_class调度类 */
#define SCHED_FIFO 1 /* 先进先出,用于实时调度,采用rt_sched_class等调度类 */
#define SCHED_RR 2 /* 轮转Round Robin,用于实时调度,采用rt_sched_class等调度类 */
#define SCHED_BATCH 3 /* 普通调度,用于大流量消耗型进程组,采用rt_sched_class等调度类 */
/* SCHED_ISO: reserved but not implemented yet */
#define SCHED_IDLE 5 /* idle,空闲调度,优先级最低 */
#define SCHED_DEADLINE 6 /* deadline,紧急调度策略,优先级最高 */
state
表示进程当前的状态,取值范围如下:
/*
* Task state bitmask. NOTE! These bits are also
* encoded in fs/proc/array.c: get_task_state().
*
* We have two separate sets of flags: task->state
* is about runnability, while task->exit_state are
* about the task exiting. Confusing, but this way
* modifying one set can't modify the other one by
* mistake.
*/
/* Used in tsk->state: */
/* 进程处于可运行状态,正在运行或者排队等待运行,如果在等待,则调度器可以可以选择该进程调度 */
#define TASK_RUNNING 0x0000
/* 进程处于睡眠状态,等待信号或其他事件发生;如果接收到事件发生的信号,则会进入就绪状态TASK_RUNNING,继而可以被调度器选中调度 */
#define TASK_INTERRUPTIBLE 0x0001
/* 进程处于睡眠状态,正在等待其他事件;只有内核主动唤醒才会重新加入就绪队列被调度,不响应信号 */
#define TASK_UNINTERRUPTIBLE 0x0002
/* 进程因调试或者其他原因停止运行 */
#define __TASK_STOPPED 0x0004
/* 进程停止运行,因为被traced而停止 */
#define __TASK_TRACED 0x0008
/* Used in tsk->exit_state: */
/* 进程退出,但是还有multi其他进程以wait系统调用等待该进程退出 */
#define EXIT_DEAD 0x0010
/* 进程退出,但是父进程并未等待其退出,进程结构并未释放 */
#define EXIT_ZOMBIE 0x0020
#define EXIT_TRACE (EXIT_ZOMBIE | EXIT_DEAD)
/* Used in tsk->state again: */
#define TASK_PARKED 0x0040
#define TASK_DEAD 0x0080
#define TASK_WAKEKILL 0x0100
#define TASK_WAKING 0x0200
#define TASK_NOLOAD 0x0400
#define TASK_NEW 0x0800
#define TASK_STATE_MAX 0x1000
/* Convenience macros for the sake of set_current_state: */
/* 新引入的状态,在TASK_UNINTERRUPTIBLE基础之上会相应kill信号,可以被杀死,下面的状态类似 */
#define TASK_KILLABLE (TASK_WAKEKILL | TASK_UNINTERRUPTIBLE)
#define TASK_STOPPED (TASK_WAKEKILL | __TASK_STOPPED)
#define TASK_TRACED (TASK_WAKEKILL | __TASK_TRACED)
#define TASK_IDLE (TASK_UNINTERRUPTIBLE | TASK_NOLOAD)
/* Convenience macros for the sake of wake_up(): */
#define TASK_NORMAL (TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE)
/* get_task_state(): */
#define TASK_REPORT (TASK_RUNNING | TASK_INTERRUPTIBLE | \
TASK_UNINTERRUPTIBLE | __TASK_STOPPED | \
__TASK_TRACED | EXIT_DEAD | EXIT_ZOMBIE | \
TASK_PARKED)
进程状态转换
Running——正在运行
Waiting——等待运行,处于就绪状态,scheduler可以在下次调度时选择该进程调度运行
Sleeping——睡眠进程,等待外部事件,不可调度运行
进程分别在就绪队列rq和等待队列wq等待。rq中的进程等待被调度运行,下次调度过程调度器scheduler会选择一个进程执行;而wq有很多个,每个事件会有自己相应的等待队列,当事件发生时唤醒等待进程,将其加入rq等待调度。同样,运行中的进程可能因为请求某些资源等开始进入等待状态被调度器调度出去睡眠,或者简单地被放在rq上等待再次调度执行,如果进程完成工作退出,则会进入Stopped状态。
Zombie
这是一个需要特别考量的状态,在用户进程因SIGTERM或SIGKILL等信号而退出,但是并未被父进程通过wait4系统调用确认其退出时,进程会进入zombie状态,此时其占用的RAM等系统资源已经释放,但是进程表项信息还存在。除了占用少量内存资源之后,zombie对系统并无其他影响。
2. sched_class
定义:https://elixir.bootlin.com/linux/v5.0.7/source/kernel/sched/sched.h#L1630
3. task_group
定义:https://elixir.bootlin.com/linux/v5.0.7/source/kernel/sched/sched.h#L363