孙浩宇 closed issue #11: 实现 prctl syscall 的 PR_SET_NAME / PR_GET_NAME 子命令 at Nam...

孙浩宇
2026-04-05T12:37:27Z

背景

prctl (process control) 是一个多功能 syscall，通过第一个参数选择不同的操作。目前是 stub 直接返回 0：

// kernel/src/syscall/mod.rs:404
SYS_PRCTL => self.unimplemented("prctl", Ok(0)),

最常用的子命令是 PR_SET_NAME（设置线程名）和 PR_GET_NAME（获取线程名）。许多程序（如多线程应用、busybox）会用它来设置线程名，方便调试。/proc/self/comm 也依赖此值。

目标

实现 prctl 的 PR_SET_NAME 和 PR_GET_NAME 子命令，其余子命令暂时返回 0 或 EINVAL。

prctl 语义

int prctl(int option, unsigned long arg2, ...);

PR_SET_NAME (15): 将当前线程名设为 arg2 指向的字符串（最长 16 字节，含 \0）

PR_GET_NAME (16): 将当前线程名写入 arg2 指向的缓冲区（至少 16 字节）

实现指引

1. 在 ThreadInner 中添加线程名字段

文件：kernel/src/process/thread.rs（约第 65 行）

pub struct ThreadInner {
// ... 已有字段 ...
/// 线程名（最长 16 字节，含 \0）
pub name: [u8; 16],
}

初始化时可以从进程的 exec_path 中取文件名作为默认线程名。

2. 实现 syscall

在 kernel/src/syscall/proc.rs 或 misc.rs 中添加：

const PR_SET_NAME: usize = 15;
const PR_GET_NAME: usize = 16;

pub fn sys_prctl(&mut self, option: usize, arg2: usize) -> SysResult {
info!("prctl: option={}, arg2={:#x}", option, arg2);
match option {
PR_SET_NAME => {
// 从用户空间读取最多 16 字节的线程名
let name = unsafe {
let ptr = arg2 as *const u8;
let mut buf = [0u8; 16];
for i in 0..16 {
let byte = *ptr.add(i); // 需要用安全的用户空间读取方式
buf[i] = byte;
if byte == 0 { break; }
}
buf
};
// 设置到当前线程
self.thread.inner.lock().name = name;
Ok(0)
}
PR_GET_NAME => {
// 将线程名写入用户空间缓冲区
let name = self.thread.inner.lock().name;
// 写入用户空间（需要用安全的方式）
unsafe {
let ptr = arg2 as *mut u8;
for i in 0..16 {
*ptr.add(i) = name[i];
}
}
Ok(0)
}
_ => {
warn!("prctl: unhandled option {}", option);
Ok(0) // 未实现的子命令暂时返回成功
}
}
}

注意：上面的用户空间内存访问只是示意。实际应使用项目中已有的 UserPtr 机制（kernel/src/syscall/user.rs）来安全地读写用户空间内存。请参考其他 syscall 中使用 UserInPtr / UserOutPtr 的方式。

3. 在 syscall 分发表中注册

将 kernel/src/syscall/mod.rs 中的：

SYS_PRCTL => self.unimplemented("prctl", Ok(0)),

改为：

SYS_PRCTL => self.sys_prctl(args[0], args[1]),

涉及的 Rust 知识

match 模式匹配（核心模式 — prctl 本身就是一个大 match）

数组 [u8; 16] 和字节操作

unsafe 块（用户空间指针访问）

常量定义 (const)

Result / 错误处理

难度

⭐⭐ 进阶级 — 需要理解用户/内核空间内存边界，学会使用 UserPtr

验证方式

多线程程序通过 prctl(PR_SET_NAME, "worker") 设置线程名后，prctl(PR_GET_NAME, buf) 应能正确读回 "worker"。

后续（可选）

可以继续实现其他常用的 prctl 子命令：

PR_SET_NO_NEW_PRIVS (38) — 安全相关，很多程序会调用

PR_GET_DUMPABLE / PR_SET_DUMPABLE — coredump 控制