目录
1. 优先级设置触发方式
1.1 用户态接口
1.2 触发流程概览
2. 源码分析:普通进程优先级设置
2.1 系统调用入口(setpriority)
2.2 设置 Nice 值(set_user_nice)
2.3 动态优先级计算(effective_prio)
3. 源码分析:实时进程优先级设置
3.1 系统调用入口(sched_setscheduler)
3.2 更新调度类(__setscheduler_class)
4. 调度队列更新流程
4.1 重新入队任务(enqueue_task)
4.2 触发重新调度(resched_curr)
5. 权限与安全性处理
5.1 能力检查(capable(CAP_SYS_NICE))
5.2 实时优先级限制
6. 流程图解
7. 总结
普通进程优先级(Nice值):
命令:nice
、renice
。
系统调用:setpriority(PRIO_PROCESS, pid, nice_value)
。
实时进程优先级:
系统调用:sched_setscheduler(pid, policy, ¶m)
,其中 param.sched_priority
指定实时优先级。
用户发起请求:通过系统调用或工具修改优先级。
内核验证权限:检查用户是否具备 CAP_SYS_NICE
能力。
转换优先级值:将用户输入的优先级转换为内核内部表示。
更新任务结构:修改 task_struct
中的优先级字段。
调度队列调整:若任务在运行队列中,更新其在队列中的位置。
setpriority
)用户调用 setpriority
:修改进程的 Nice 值。
内核处理函数:kernel/sys.c
→ sys_setpriority()
→ do_setpriority()
.
// kernel/sys.c
SYSCALL_DEFINE3(setpriority, int, which, int, who, int, niceval) {
return do_setpriority(which, who, niceval);
}
static int do_setpriority(int which, int who, int niceval) {
// 1. 参数验证:niceval 必须在 [-20, 19] 范围内
if (niceval < MIN_NICE || niceval > MAX_NICE)
return -EINVAL;
// 2. 权限检查:需要 CAP_SYS_NICE 或目标进程属于当前用户
if (!capable(CAP_SYS_NICE)) {
if (cred->euid != pcred->uid && cred->euid != pcred->suid)
return -EPERM;
}
// 3. 设置静态优先级(static_prio)
set_user_nice(p, niceval);
return 0;
}
set_user_nice
)函数路径:kernel/sched/core.c
→ set_user_nice()
.
作用:将用户态 Nice 值转换为内核静态优先级(static_prio
),并更新动态优先级(prio
)。
void set_user_nice(struct task_struct *p, long nice) {
// 1. 转换 Nice 值到静态优先级(static_prio = 120 + nice)
int new_static_prio = NICE_TO_PRIO(nice);
p->static_prio = new_static_prio;
// 2. 更新动态优先级(prio)
p->prio = effective_prio(p);
// 3. 若任务在运行队列中,触发调度队列调整
if (task_queued(p)) {
enqueue_task(rq, p, ENQUEUE_UPDATE);
resched_curr(rq); // 可能触发重新调度
}
}
effective_prio
)函数路径:kernel/sched/core.c
→ effective_prio()
.
逻辑:普通进程的动态优先级基于静态优先级和调度策略计算。
static int effective_prio(struct task_struct *p) {
if (rt_task(p)) // 实时进程直接返回 rt_priority
return p->prio;
return normal_prio(p); // 普通进程:static_prio + 调度策略偏移
}
sched_setscheduler
)用户调用 sched_setscheduler
:设置实时调度策略(SCHED_FIFO
/SCHED_RR
)和优先级。
内核处理函数:kernel/sched/core.c
→ sched_setscheduler()
→ __sched_setscheduler()
.
SYSCALL_DEFINE3(sched_setscheduler, pid_t, pid, int, policy, struct sched_param __user *, param) {
struct sched_param lp;
copy_from_user(&lp, param, sizeof(struct sched_param));
return __sched_setscheduler(p, policy, &lp, true);
}
static int __sched_setscheduler(...) {
// 1. 验证实时优先级范围(0-99)
if (rt_policy(policy) && (param->sched_priority < 1 || param->sched_priority > 99))
return -EINVAL;
// 2. 权限检查:需要 CAP_SYS_NICE
if (!capable(CAP_SYS_NICE)) {
if (cred->euid != pcred->uid && cred->euid != pcred->suid)
return -EPERM;
}
// 3. 更新调度策略和优先级
p->policy = policy;
p->rt_priority = param->sched_priority;
// 4. 更新调度类(如从 CFS 切换到 RT)
__setscheduler_class(p, policy);
// 5. 若任务在运行队列中,重新入队以应用新策略
if (task_running(rq, p)) {
dequeue_task(rq, p, DEQUEUE_SAVE);
enqueue_task(rq, p, ENQUEUE_RESTORE | ENQUEUE_NOCLOCK);
resched_curr(rq);
}
}
__setscheduler_class
)函数路径:kernel/sched/core.c
→ __setscheduler_class()
.
逻辑:根据调度策略绑定对应的调度类(如 rt_sched_class
)。
static void __setscheduler_class(struct task_struct *p, int policy) {
switch (policy) {
case SCHED_NORMAL:
case SCHED_BATCH:
p->sched_class = &fair_sched_class; // 绑定到 CFS
break;
case SCHED_FIFO:
case SCHED_RR:
p->sched_class = &rt_sched_class; // 绑定到实时调度类
break;
// ...其他策略处理
}
}
enqueue_task
)当优先级或调度策略变更时,任务会被移出队列并重新插入,确保调度器按新优先级排序。
// kernel/sched/core.c
void enqueue_task(struct rq *rq, struct task_struct *p, int flags) {
p->sched_class->enqueue_task(rq, p, flags); // 调用调度类的入队方法
}
// 示例:CFS 的 enqueue_task_fair
static void enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags) {
enqueue_entity(cfs_rq, se, flags); // 插入红黑树(按 vruntime 排序)
update_load_avg(cfs_rq, se, UPDATE_TG); // 更新负载统计
}
resched_curr
)若当前任务优先级降低或被更高优先级任务抢占,设置 TIF_NEED_RESCHED
标志,触发调度。
void resched_curr(struct rq *rq) {
struct task_struct *curr = rq->curr;
set_tsk_need_resched(curr); // 设置 TIF_NEED_RESCHED
smp_send_reschedule(cpu); // 发送重新调度 IPI(多核)
}
capable(CAP_SYS_NICE)
)普通用户:只能修改自己进程的 Nice 值(范围受限),无法设置实时优先级。
Root 用户:拥有 CAP_SYS_NICE
能力,可修改任意进程的优先级。
默认配置:非 Root 用户无法设置实时优先级(需通过 /etc/security/limits.conf
解除限制)。
plaintext
复制
用户态触发 | v 系统调用入口(setpriority/sched_setscheduler) | v 参数验证(范围、权限) | v 转换优先级(Nice → static_prio,用户优先级 → rt_priority) | v 更新 task_struct(static_prio, rt_priority, sched_class) | v 重新入队任务(enqueue_task) → 触发重新调度(resched_curr) | v 调度器按新优先级选择任务执行
触发方式:
普通进程:通过 setpriority
修改 Nice 值(范围 -20~19)。
实时进程:通过 sched_setscheduler
设置策略和优先级(0~99)。
内核流程:
权限验证:检查 CAP_SYS_NICE
能力。
优先级转换:将用户输入转换为内核内部表示(如 static_prio = 120 + nice
)。
更新任务结构:修改 task_struct
的 static_prio
、rt_priority
和 sched_class
。
调度队列调整:重新入队任务,确保调度器按新优先级排序。
源码关键函数:
do_setpriority()
:处理普通进程优先级设置。
__sched_setscheduler()
:处理实时进程策略和优先级。
effective_prio()
:计算动态优先级。
enqueue_task()
:更新调度队列。
通过模块化的调度类设计(如 fair_sched_class
和 rt_sched_class
),Linux 内核实现了对不同优先级任务的高效管理,兼顾实时性和公平性。