Sched ext回调1——init_task (linux 6.15.7)

struct sched_ext_ops代表了一个调度器,里面定义了很多回调函数,本文分析init_task这个hook,sched ext的部分hook如下:

系统中所有的task,都会触发init_task,不管是注册sched ext调度器时,已存在的task,还是后面新创建的task。

task在fork时会被加入到scx_tasks链表,注册sched ext调度器时,遍历scx_tasks链表,对这些已存在的task执行init_task。

注册sched ext调度器时,还会设置scx_ops_init_task_enabled标记为true,fork新task时,如果该标记为true,执行init_task。

一、新task触发init_task的调用栈

SYSCALL_DEFINE0(fork)

├─ kernel_clone

| ├─ copy_process()

| | ├─ dup_task_struct

| | | ├─ arch_dup_task_struct

| | | | └─ memcpy(dst, src, arch_task_struct_size) ← 继承父task名

| | | |

| | ├─ strscpy_pad(p->comm, args->name, sizeof(p->comm)) ← 内核线程设置task

| | ├─ sched_fork()

| | | └─ scx_pre_fork()

| | ├─ ...

| | |

| | ├─ sched_cgroup_fork()

| | | ├─ 设置 p->sched_task_group ← 设置cgroup

| | | ├─ __set_task_cpu()

| | | ├─ p->sched_class->task_fork() ← sched ext没有实现这个hook

| | | └─ scx_fork()

| | | └─ scx_ops_init_task() ← scx_ops_init_task_enabled为true时,有条件触发

| | └─ BPF_STRUCT_OPS(init_task)
| ├─ sched_post_fork

| | └─ scx_post_fork

| | └─ list_add_tail(&p->scx.tasks_node, &scx_tasks)

|

├─ wake_up_new_task

注册sched ext后,新创建的task都会触发init_task的调用链(注意,即使调度策略不是sched ext也会触发),见fork栈红字部分。

执行到init_task这个钩子函数时,用户态task有可能还是父task名称(取决于有没有pctl或者execv设置了task名),内核态task是自己真实名称。

另外,需注意wake_up_new_task的时间点。

二、已存在task触发init_task的调用栈

注册sched ext调度器前,已存在的task触发init_task稍微有点复杂,分2个步骤。

首先,fork task时,task加入到scx_tasks链表中,见fork调用链的蓝色部分。

接着,注册调度器时,遍历scx_tasks链表,对链表中的每个task执行init_task。

eBPF用户态程序通过执行SCX_OPS_ATTACH,注册sched ext调度器,把"已经通过 verifier 的 struct sched_ext_ops "注册到内核中,struct sched_ext_ops(见最文章开头图片)代表sched ext调度器。

SCX_OPS_ATTACH(...,numa_aware_ops, ...) ← numa_aware_ops是sched ext调度器

├─ bpf_map__attach_struct_ops

| ├─ bpf_link_create

| | └─ BPF_CALL_3(bpf_sys_bpf, int, cmd, union bpf_attr *, attr, u32, attr_size)

(进入内核态)

bpf_sys_bpf

├─ __sys_bpf(BPF_LINK_CREATE,...)

| ├─ link_create

| | ├─ bpf_struct_ops_link_create

| | | └─ st_map->st_ops_desc->st_ops->reg(st_map->kvalue.data, &link->link)

( 即 bpf_scx_reg )

bpf_scx_reg

├─ scx_ops_enable

| └─ scx_ops_init_task_enabled = true
|

| ------- scx_task_iter_start(&sti);

| 代 while ((p = scx_task_iter_next_locked(&sti))) {

| 码 ...

| 段 scx_ops_init_task ← 对scx_tasks中的每个task执行init_task

| ------ }

|

三、init_task中current task的名称是什么

bpf_get_current_task / bpf_get_current_comm获取到的进程名称分两种情况:

1)如果task是内核态的,获取到的是task自己真实的名称

2)如果task是用户态的,只有执行execve或者prctl设置名称后,task的名字才会更新成自己真实的名称。

用户态task被fork后,task继承父进程名称,见(一)调用栈。

exec修改用户态task名称调用栈如下:

SYSCALL_DEFINE3(execve,...

├─ do_execve

| └─ do_execveat_common

| ├─ alloc_bprm

| ├─ bprm_execve

| | ├─ exec_binprm

├─ search_binary_handler

| ├─ fmt->load_binary(bprm) ← 即 load_elf_binary

| ├─ begin_new_exec

| | └─ __set_task_comm

四、init_task与其他sched ext hook的并发性

fork调用栈中有个地方需要关注,执行完init_task后,才执行wake_up_new_task,所以针对这个task而言,init_task的执行时间点,一定优先于select_cpu、enqueue、dequeue、dispatch、tick、running、stopping这些hook。

相关推荐
小成202303202658 小时前
Linux高级02
linux·开发语言
mounter6258 小时前
【硬核前沿】CXL 深度解析:重塑数据中心架构的“高速公路”,Linux 内核如何应对挑战?-- CXL 协议详解与 LSF/MM 最新动态
linux·服务器·网络·架构·kernel
++==8 小时前
Linux 进程间通信与线程同步技术详解:IPC 机制、线程 API、同步工具与经典同步问题
linux
特长腿特长9 小时前
centos、ubantu系列机的用户和用户组的结构是什么?具体怎么配置?用户组权限怎么使用?这篇文章持续更新,帮助你复习linux的基础知识
linux·运维·centos
zzzyyy5389 小时前
Linux环境变量
linux·运维·服务器
pluvium279 小时前
记对 xonsh shell 的使用, 脚本编写, 迁移及调优
linux·python·shell·xonsh
无级程序员9 小时前
centos7 安装 llvm-toolset-7-clang出错的问题解决
linux·centos
CHHC188010 小时前
NetCore树莓派桌面应用程序
linux·运维·服务器
云栖梦泽11 小时前
Linux内核与驱动:9.Linux 驱动 API 封装
linux·c++
si莉亚12 小时前
ROS2安装EVO工具包
linux·开发语言·c++·开源