十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

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

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_parameters与scheduler_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枚举取值Process或Thread。决定系统调用处理的是整个进程的调度参数还是线程级的调度参数。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.cpppeer-set_priority((u32)parameters.parameters.sched_priority); // POSIX says that process scheduling parameters have precedence over thread scheduling parameters. // We dont 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))。权限限制为超级用户可修改任何进程或线程的调度参数任意线程可修改其所属进程内所有线程以及该进程本身的调度参数任意进程可修改与它属于同一用户有效用户 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-L68sched_priority不在 1–99EPERM无权访问目标进程/线程的调度参数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_parameters与scheduler_get_parameters取代了更不通用less generic的sched_setparam与sched_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_setschedparam以mode SchedulerParametersMode::Thread构造同一结构。附带地sched.cpp 中sched_get_priority_min/max直接返回THREAD_PRIORITY_MIN1与THREAD_PRIORITY_MAX99与内核校验范围完全一致。这意味着应用代码可以完全使用标准 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结构modeProcess/Threadpid_or_tid0 表示当前 POSIXsched_param当前唯一可读写参数是sched_priority范围 1–99内核将其映射到就绪队列优先级桶并在下次调度时生效权限模型procpromise root 全量权限 同进程线程自管 同属主进程级互改不可跨进程碰线程该接口以单一通用系统调用替代了旧的正向镜像式sched_setparam/sched_getparam系统调用用户空间 POSIX 层LibC 的sched.cpp与pthread.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),仅供参考
返回列表