news 2026/9/10 13:28:04

Serenity OS 调度器系统调用:scheduler_set_parameters 与 scheduler_get_parameters 完全解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Serenity OS 调度器系统调用:scheduler_set_parameters 与 scheduler_get_parameters 完全解析

Serenity OS 调度器系统调用:scheduler_set_parameters 与 scheduler_get_parameters 完全解析

【免费下载链接】serenityThe Serenity Operating System 🐞项目地址: https://gitcode.com/GitHub_Trending/se/serenity

本文基于 Serenity OS 内核 man 页 scheduler_set_parameters.md 及配套内核源码,完整讲解scheduler_set_parametersscheduler_get_parameters这两个系统调用的参数结构、模式语义、权限规则与错误码,并结合 Kernel/Syscalls/sched.cpp 中的实现,展示 Serenity 如何用一套更通用的接口统一替代 POSIX 的sched_setparam/sched_getparam。读完后,你将能够:正确构造调用参数结构、理解进程级与线程级调度的差异、掌握 Serenity 的优先级取值范围(1–99)与权限模型,并能用 LibC 的sched_*/pthread_*封装完成实际的调度参数读写。

一、两个系统调用做什么

这两个系统调用用于修改或读取进程/线程的调度器参数,对应 man 页名称scheduler_set_parameters, scheduler_get_parameters - Set and get scheduler parameters for processes and threads

man 页特别强调一个行为特征:scheduler_set_parameters影响的是目标下一次被调度时的行为,因此调用后可能不会立刻观察到效果。这是典型的"参数生效于后续调度决策"语义——内核在设置参数时只是更新线程记录,真正体现优先级变化要等到下次 CPU 分派。

二、参数结构 SC_scheduler_parameters_params

两个系统调用共用同一个参数结构,man 页原文定义为:

struct SC_scheduler_parameters_params { pid_t pid_or_tid; SchedulerParametersMode mode; struct sched_param parameters; };

内核中的真实定义位于 Kernel/API/Syscall.h,逐字段对应:

enum class SchedulerParametersMode : bool { Process, Thread, }; struct SC_scheduler_parameters_params { pid_t pid_or_tid; SchedulerParametersMode mode; struct sched_param parameters; };

各字段含义:

  • mode:枚举,取值ProcessThread。决定系统调用处理的是整个进程的调度参数,还是线程级的调度参数。
  • pid_or_tid:指定要操作的进程或线程,具体解释方式取决于mode(见下一节)。
  • parameters:要读取/写入的实际调度参数,类型是 POSIX 的struct sched_param——即sched_setparam等 POSIX 接口使用的标准数据结构。man 页指出,当前可用的调度参数只有int sched_priority(调度优先级)一个

三、mode 语义:pid_or_tid 如何被解释

实现位于 Kernel/Syscalls/sched.cpp 的get_thread_from_pid_or_tid(),它把"进程或线程"统一归约成一个Thread指针,逻辑如下:

  • Thread 模式pid_or_tid == 0表示当前线程;否则按 tid 查找。注意权限限制写得很明确:注释说明"Only superuser can access other processes' threads"——非 root 进程如果目标线程不属于自己进程,直接返回EPERM
  • Process 模式pid_or_tid == 0表示当前进程;否则按 pid 查找,找不到则返回ESRCH。找到进程后,实现会遍历其线程列表,把tid 等于 pid 的主线程定位出来作为操作对象——注释标明"Main thread has tid == pid",这是 Serenity 中主线程的关键约定。

这里有一个值得注意的实现细节:两个系统调用在读取目标线程后,都先获取全局调度锁g_scheduler_lockSpinlockLocker lock(g_scheduler_lock)),保证在锁内完成凭据检查与优先级读/写,避免目标线程在被操作过程中退出或状态变化。

四、唯一参数 sched_priority:取值范围与内核映射

man 页声明当前唯一的调度参数是sched_priority。其合法范围由 POSIX 头文件 Kernel/API/POSIX/sched.h 定义:

#define THREAD_PRIORITY_MIN 1 #define THREAD_PRIORITY_MAX 99

内核在 sched.cpp 中做范围校验:

if (parameters.parameters.sched_priority < THREAD_PRIORITY_MIN || parameters.parameters.sched_priority > THREAD_PRIORITY_MAX) return EINVAL;

1(最低)到 99(最高),越界直接EINVAL

从 Kernel/Tasks/Scheduler.cpp 看,内核内部把该范围再映射成更少的就绪队列优先级桶:

// Converts the priority in the range of THREAD_PRIORITY_MIN...THREAD_PRIORITY_MAX VERIFY(thread_priority >= THREAD_PRIORITY_MIN && thread_priority <= THREAD_PRIORITY_MAX); constexpr u32 thread_priority_count = THREAD_PRIORITY_MAX - THREAD_PRIORITY_MIN + 1; auto priority_bucket = ((thread_priority_count - (thread_priority - THREAD_PRIORITY_MIN)) / thread_priority_count) * (ThreadReadyQueues::count - 1);

可以推断:用户空间看到 99 级细粒度优先级,内核就绪队列的桶数更少(ThreadReadyQueues::count),数值越大映射到越高的桶,即越先获得 CPU。内核自身线程也使用这套体系,例如 Kernel/Tasks/Scheduler.cpp 中 idle 线程被设置为THREAD_PRIORITY_MIN,而PowerStateSwitchTask使用THREAD_PRIORITY_HIGH(见 Kernel/Tasks/PowerStateSwitchTask.cpp)。

设置成功的写入点在 sched.cpp:

peer->set_priority((u32)parameters.parameters.sched_priority); // POSIX says that process scheduling parameters have precedence over thread scheduling parameters. // We don't track them separately, so overwrite the thread scheduling settings manually for now. if (parameters.mode == Syscall::SchedulerParametersMode::Process) { peer->process().for_each_thread(& { thread.set_priority((u32)parameters.parameters.sched_priority); }); }

这里体现了 POSIX 的一个规则:进程级调度参数优先于线程级参数。由于 Serenity 内核并不分开维护两套参数,进程模式的调用会直接把该值覆写到进程内所有线程上。set_priority()本身只是更新线程对象字段(Kernel/Tasks/Thread.h),所以下次调度才体现效果,与 man 页描述一致。

五、安全模型:proc promise 与权限规则

man 页的 Security 一节给出完整规则,两条系统调用都要求procpromise(源码中对应 sched.cpp 的TRY(require_promise(Pledge::proc)))。权限限制为:

  1. 超级用户可修改任何进程或线程的调度参数;
  2. 任意线程可修改其所属进程内所有线程以及该进程本身的调度参数;
  3. 任意进程可修改与它属于同一用户(有效用户 ID 与用户 ID 需匹配)的所有进程的调度参数,但不能修改其他进程内单个线程的参数。

内核实现的凭据检查(sched.cpp)与上述规则吻合:

auto credentials = this->credentials(); auto peer_credentials = peer->process().credentials(); if (!credentials->is_superuser() && credentials->euid() != peer_credentials->uid() && credentials->uid() != peer_credentials->uid()) return EPERM;

非 root 调用者必须与目标进程属主的 euid 或 uid 之一匹配,否则EPERM。Thread 模式下的"仅限本进程线程"约束则由get_thread_from_pid_or_tid()中的检查强制(其他进程线程只有 root 可访问)。

六、返回值与错误码

  • scheduler_get_parameters:读到的参数写回sched_param子结构(实现中经copy_to_user写回用户空间结构体)。
  • 两个系统调用:返回0表示成功,非零表示出错。

错误码及触发条件(man 页 Errors 一节,均可在源码中对应到返回点):

错误码含义源码触发点
EINVAL调度参数无效sched.cpp#L67-L68:sched_priority不在 1–99
EPERM无权访问目标进程/线程的调度参数sched.cpp#L75-L76:非 root 且 uid 不匹配
ESRCH给定的 pid/tid 不存在sched.cpp#L43-L44:按 pid/tid 查找落空
EFAULT参数结构体指针无效copy_typed_from_user/copy_from_user复制用户内存失败

七、历史演进:从 sched_setparam/sched_getparam 到统一接口

man 页 History 一节说明:scheduler_set_parametersscheduler_get_parameters取代了更不通用(less generic)的sched_setparamsched_getparam系统调用——后者只是 POSIX 库函数的镜像。新的统一接口用一个mode字段同时覆盖进程级与线程级两类操作,不再需要成对的专用系统调用。

用户空间的兼容层保留了 POSIX 面,全部收敛到新系统调用上:

  • 进程级:Userland/Libraries/LibC/sched.cpp 中sched_setparam(pid, param)sched_getparam(pid, param)都以mode = SchedulerParametersMode::Process构造参数结构后调用SC_scheduler_set_parameters/SC_scheduler_get_parameters
  • 线程级:Userland/Libraries/LibC/pthread.cpp 中pthread_getschedparam/pthread_setschedparammode = SchedulerParametersMode::Thread构造同一结构。
  • 附带地,sched.cpp 中sched_get_priority_min/max直接返回THREAD_PRIORITY_MIN(1)与THREAD_PRIORITY_MAX(99),与内核校验范围完全一致。

这意味着应用代码可以完全使用标准 POSIX 接口(<sched.h>/<pthread.h>),无需直接接触系统调用号。

八、实操示例

在 Serenity 用户空间编译以下示例即可完整演示一次"读取—修改—读回"进程调度参数(需 pledgeproc能力由 LibC 调用环境决定;对非 root 用户,仅能操作同属主进程):

#include <sched.h> #include <stdio.h> #include <stdlib.h> int main(void) { struct sched_param param; param.sched_priority = 50; /* 合法范围 1..99 */ if (sched_getparam(0, &param) == -1) perror("sched_getparam"); printf("before: priority = %d\n", param.sched_priority); param.sched_priority = 80; if (sched_setparam(0, &param) == -1) perror("sched_setparam"); if (sched_getparam(0, &param) == -1) perror("sched_getparam(2)"); printf("after: priority = %d\n", param.sched_priority); return 0; }

线程级场景改用pthread_setschedparam(pthread_self(), 0, &param)/pthread_getschedparampolicy参数在 Serenity 的封装中未参与内核决策(内核只读sched_priority)。注意两点适用前提:

  • sched_priority必须落在sched_get_priority_min(policy)(1)与sched_get_priority_max(policy)(99)之间,否则内核返回EINVAL
  • 修改进程级参数会使该值覆盖进程内所有线程的优先级(见第四节源码注释),因此线程级调整应在线程自身上下文或以 Thread 模式进行。

九、小结

  • 两个系统调用共享SC_scheduler_parameters_params结构:mode(Process/Thread)+pid_or_tid(0 表示当前)+ POSIXsched_param
  • 当前唯一可读写参数是sched_priority,范围 1–99,内核将其映射到就绪队列优先级桶,并在下次调度时生效;
  • 权限模型:procpromise + root 全量权限 + 同进程线程自管 + 同属主进程级互改(不可跨进程碰线程);
  • 该接口以单一通用系统调用替代了旧的正向镜像式sched_setparam/sched_getparam系统调用,用户空间 POSIX 层(LibC 的sched.cpppthread.cpp)均已迁移到它之上。

延伸阅读:man 页源码 Base/usr/share/man/man2/scheduler_set_parameters.md、系统调用实现 Kernel/Syscalls/sched.cpp、参数定义 Kernel/API/Syscall.h、优先级常量 Kernel/API/POSIX/sched.h。

【免费下载链接】serenityThe Serenity Operating System 🐞项目地址: https://gitcode.com/GitHub_Trending/se/serenity

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/10 13:27:15

DeepSeek V4.1 Flash 今日上线:Flash 系列再降价,开发者该算哪笔账

这两天 AI 圈被一条消息刷了不少屏&#xff1a;DeepSeek 开放平台发公告&#xff0c;计划于北京时间 2026 年 9 月 10 日前后正式发布 V4.1 Flash 模型&#xff0c;官方称它在性能、费用、速度、总用时等指标上全面超过此前的 V4 Pro&#xff1b;同时宣布自 9 月 10 日 12:00 起…

作者头像 李华
网站建设 2026/9/10 13:23:08

用Python复刻我的世界小游戏:体素引擎与区块存储实战

简介&#xff1a;这是一套基于Python和Pygame库实现的‘我的世界’风格二维沙盒小游戏源码&#xff0c;面向已经掌握Python基础语法、希望真正进入游戏开发领域的初学者。项目借助窗口创建、事件监听、方块绘制、碰撞检测与帧速率控制等机制&#xff0c;完整展示像素化沙盒游戏…

作者头像 李华
网站建设 2026/9/10 13:22:01

YOLOv5双目测距毕设实战:标定、视差与三维映射全链路解析

简介&#xff1a;本资源是一套完整的毕业设计级项目方案&#xff0c;面向计算机视觉方向的本科生与初学者&#xff0c;解决目标检测与三维空间距离测量的融合实践问题。项目基于YOLOv5实现高效目标识别&#xff0c;并结合双目摄像头标定与视差计算完成实时距离估计&#xff0c;…

作者头像 李华
网站建设 2026/9/10 13:21:56

OpenVoice即时语音克隆:10秒参考音频,让它用你的声音说话

OpenVoice即时语音克隆&#xff1a;10秒参考音频&#xff0c;让它用你的声音说话 【免费下载链接】OpenVoice Instant voice cloning by MIT and MyShell. Audio foundation model. 项目地址: https://gitcode.com/GitHub_Trending/op/OpenVoice OpenVoice 是 MIT 与 My…

作者头像 李华