os/kernel/task/
task_struct.rs

1//! 任务结构体定义
2//!
3//! 包含任务的核心信息,如上下文、状态、内存空间等
4#![allow(dead_code)]
5use core::sync::atomic::{AtomicPtr, Ordering};
6
7use alloc::{sync::Arc, vec::Vec};
8
9use crate::{
10    arch::{
11        kernel::{context::Context, task::setup_stack_layout},
12        trap::TrapFrame,
13    },
14    ipc::{SignalHandlerTable, SignalPending},
15    kernel::{
16        WaitQueue,
17        task::{forkret, task_state::TaskState},
18    },
19    mm::{
20        address::{ConvertablePaddr, PageNum, UsizeConvert},
21        frame_allocator::{FrameRangeTracker, FrameTracker},
22        memory_space::MemorySpace,
23    },
24    pr_debug,
25    sync::SpinLock,
26    uapi::{
27        resource::RlimitStruct,
28        signal::{SignalFlags, SignalStack},
29        uts_namespace::UtsNamespace,
30    },
31    vfs::{Dentry, FDTable},
32};
33
34/// 共享任务句柄
35/// 用于在多个地方引用同一个任务实例
36pub type SharedTask = Arc<SpinLock<Task>>;
37
38/// 任务
39/// 存放任务的核心信息
40/// 其中的信息可以分为几大类:
41/// 1. 调度运行相关的信息,如上下文、状态、优先级等
42/// 2. 任务标识信息,如 tid、pid、ppid、子任务等
43/// 3. 任务资源信息,如内核栈、TrapFrame、内存空间等
44/// 表示进程的任务与表示线程的任务由本结构体统一表征
45/// 其区别仅在于:
46/// 1. 进程的 pid 等于 tid,线程的 pid 不等于 tid
47/// 2. 进程的返回值通过 exit_code 字段传递,线程的返回值通过 return_value 字段传递
48/// 3. 对于所有3.类信息,均通过引用计数共享。创建时任务,进程需传入新的`Arc<T>`,而线程则共享父任务的资源。
49/// 注意:线程拥有自己独立的运行栈,和一套寄存器上下文。
50///      TrapFrame,Context结构可以保证所有线程切换时保存和恢复寄存器状态。
51///      每个任务的内核栈独立分配,互不干扰。内核线程只使用内核栈。
52///      但是上层必须自己保证创建的用户线程在用户态运行时拥有独立的用户栈空间。
53/// OPTIMIZE: 简单起见目前的设计中,Task 结构体包含了所有信息,包括调度相关的信息和资源管理相关的信息。
54///           未来可以考虑将其拆分为 TaskInfo 和 TaskStruct 两个部分,以提高访问效率和模块化程度。
55#[derive(Debug)]
56pub struct Task {
57    /// 任务的上下文信息,用于任务切换
58    pub context: Context,
59    /// 任务的抢占计数器,表示当前任务被禁止抢占的次数
60    /// 当该值大于0时,表示任务处于不可抢占状态。暂未使用
61    pub preempt_count: usize,
62    /// 任务的优先级,数值越小优先级越高。暂未使用
63    pub priority: u8,
64    /// 任务所在的处理器id。暂未使用
65    pub processor_id: usize,
66    /// 任务当前的状态
67    pub state: TaskState,
68    /// 任务的id
69    pub tid: u32,
70    /// 任务的所属进程id
71    /// NOTE: 由于采用了统一的任务模型,一个任务组内任务的 pid 是相同的,等于父任务的 pid 而父任务的 pid 等于自己的 tid
72    pub pid: u32,
73    /// 父任务的id
74    pub ppid: u32,
75    /// 任务的进程组id
76    pub pgid: u32,
77    /// 任务的子任务列表
78    pub children: Arc<SpinLock<Vec<SharedTask>>>,
79    /// 任务的等待队列
80    pub wait_child: Arc<SpinLock<WaitQueue>>,
81    /// 内核栈基址
82    pub kstack_base: usize,
83    /// 中断上下文。指向当前任务内核栈上的 TrapFrame,仅在任务被中断时有效。
84    pub trap_frame_ptr: AtomicPtr<TrapFrame>,
85    /// 任务的内存空间
86    /// 对于内核任务,该字段为 None
87    pub memory_space: Option<Arc<SpinLock<MemorySpace>>>,
88    /// 退出码
89    /// 存储任务退出时的状态码,通常用于表示任务的执行结果
90    /// 由 exit 接口设置
91    /// 对应于 waitpid 的 exit_status
92    pub exit_code: Option<i32>,
93    /// 内核栈跟踪器
94    kstack_tracker: FrameRangeTracker,
95    /// 任务的 TrapFrame 跟踪器
96    trap_frame_tracker: FrameTracker,
97    /// 信号屏蔽字
98    pub blocked: SignalFlags,
99    /// 私有待处理信号集合
100    pub pending: SignalPending,
101    /// 待处理信号队列
102    pub shared_pending: Arc<SpinLock<SignalPending>>,
103    /// 信号处理动作表
104    pub signal_handlers: Arc<SpinLock<SignalHandlerTable>>,
105    /// 备用信号栈信息
106    pub signal_stack: Arc<SpinLock<SignalStack>>,
107    /// 退出信号, 当任务退出时发送给父任务的信号
108    pub exit_signal: u8,
109    /// UTS 命名空间
110    pub uts_namespace: Arc<SpinLock<UtsNamespace>>,
111    /// 资源限制结构体
112    pub rlimit: Arc<SpinLock<RlimitStruct>>,
113    /// 健壮列表头地址及其大小
114    pub robust_list: Option<usize>,
115    /// 线程ID地址
116    pub set_child_tid: usize,
117    /// 线程退出时清除的线程ID地址
118    pub clear_child_tid: usize,
119
120    // === 权限和凭证 ===
121    /// 任务凭证(用户、组、能力)
122    pub credential: super::Credential,
123    /// 文件创建掩码
124    pub umask: u32,
125
126    // === 文件系统 ===
127    /// 文件描述符表
128    pub fd_table: Arc<FDTable>,
129    /// 文件系统信息
130    pub fs: Arc<SpinLock<FsStruct>>,
131}
132
133/// 文件系统信息相关结构体
134#[derive(Debug, Clone)]
135pub struct FsStruct {
136    /// 当前工作目录
137    pub cwd: Option<Arc<Dentry>>,
138    /// 根目录
139    pub root: Option<Arc<Dentry>>,
140}
141
142impl FsStruct {
143    pub fn new(cwd: Option<Arc<Dentry>>, root: Option<Arc<Dentry>>) -> Self {
144        Self { cwd, root }
145    }
146}
147
148impl Task {
149    /// 为内核线程初始化任务上下文
150    /// # 参数
151    /// * `tid`: 任务ID
152    /// * `pid`: 进程ID
153    /// * `ppid`: 父任务ID
154    /// * `kstack_tracker`: 内核栈的帧跟踪器
155    /// * `trap_frame_tracker`: TrapFrame 的帧跟踪器
156    /// * `entry`: 任务的入口地址
157    /// # 返回值
158    /// 新创建的任务
159    /// 注意:调用者必须自己初始化TrapFrame内容
160    pub fn ktask_create(
161        tid: u32,
162        pid: u32,
163        ppid: u32,
164        children: Arc<SpinLock<Vec<Arc<SpinLock<Task>>>>>,
165        kstack_tracker: FrameRangeTracker,
166        trap_frame_tracker: FrameTracker,
167        signal_handlers: Arc<SpinLock<SignalHandlerTable>>,
168        blocked: SignalFlags,
169        signal: Arc<SpinLock<SignalPending>>,
170        uts_namespace: Arc<SpinLock<UtsNamespace>>,
171        rlimit: Arc<SpinLock<RlimitStruct>>,
172        fd_table: Arc<FDTable>,
173        fs: Arc<SpinLock<FsStruct>>,
174    ) -> Self {
175        let mut task = Self::new(
176            tid,
177            pid,
178            ppid,
179            tid, // 内核线程不属于常规意义的进程组
180            children,
181            kstack_tracker,
182            trap_frame_tracker,
183            None,
184            signal_handlers,
185            blocked,
186            signal,
187            Arc::new(SpinLock::new(SignalStack::default())), // 内核线程通常不使用备用信号栈
188            0,                                               // 内核线程退出不通过IPC发送信号
189            uts_namespace,
190            rlimit,
191            fd_table,
192            fs,
193        );
194        task.context
195            .set_init_context(forkret as usize, task.kstack_base);
196        task
197    }
198
199    /// 创建一个新的用户任务
200    /// # 参数
201    /// * `ppid`: 父任务ID
202    /// * `memory_space`: 任务的内存空间
203    /// # 返回值
204    /// 新创建的任务
205    /// 注意:调用者必须自己初始化TrapFrame内容
206    pub fn utask_create(
207        tid: u32,
208        pid: u32,
209        ppid: u32,
210        pgid: u32,
211        children: Arc<SpinLock<Vec<Arc<SpinLock<Task>>>>>,
212        kstack_tracker: FrameRangeTracker,
213        trap_frame_tracker: FrameTracker,
214        memory_space: Arc<SpinLock<MemorySpace>>,
215        signal_handlers: Arc<SpinLock<SignalHandlerTable>>,
216        blocked: SignalFlags,
217        signal: Arc<SpinLock<SignalPending>>,
218        signal_stack: Arc<SpinLock<SignalStack>>,
219        exit_signal: u8,
220        uts_namespace: Arc<SpinLock<UtsNamespace>>,
221        rlimit: Arc<SpinLock<RlimitStruct>>,
222        fd_table: Arc<FDTable>,
223        fs: Arc<SpinLock<FsStruct>>,
224    ) -> Self {
225        let mut task = Self::new(
226            tid,
227            pid,
228            ppid,
229            pgid,
230            children,
231            kstack_tracker,
232            trap_frame_tracker,
233            Some(memory_space),
234            signal_handlers,
235            blocked,
236            signal,
237            signal_stack,
238            exit_signal,
239            uts_namespace,
240            rlimit,
241            fd_table,
242            fs,
243        );
244        task.context
245            .set_init_context(forkret as usize, task.kstack_base);
246        task
247    }
248
249    /// 执行 execve 操作,替换当前任务的内存空间和上下文
250    /// # 参数
251    /// * `new_memory_space`: 新的内存空间
252    /// * `entry_point`: 新程序的入口地址
253    /// * `sp`: 新程序的栈指针
254    /// * `argv`: 传递给新程序的参数列表
255    /// * `envp`: 传递给新程序的环境变量列表
256    pub fn execve(
257        &mut self,
258        new_memory_space: Arc<SpinLock<MemorySpace>>,
259        entry_point: usize,
260        sp_high: usize,
261        argv: &[&str],
262        envp: &[&str],
263        phdr_addr: usize,
264        phnum: usize,
265        phent: usize,
266    ) {
267        // 1. 切换任务的地址空间对象
268        self.memory_space = Some(new_memory_space);
269
270        // 2. 处理文件描述符:取消共享并关闭 CLOEXEC 文件
271        // execve 应该让当前进程拥有独立的 FD 表(如果之前是共享的)
272        // 并且关闭所有标记为 FD_CLOEXEC 的文件
273        let new_fd_table = self.fd_table.clone_table();
274        new_fd_table.close_exec();
275        self.fd_table = Arc::new(new_fd_table);
276
277        let tf_ptr = self.trap_frame_ptr.load(Ordering::SeqCst);
278
279        // 注意:以下拷贝时对sp进行的操作均要求已经可以访问用户栈空间
280        //      也就是说,new_memory_space 已经被激活(切换 satp)
281        //      否则必须实现类似 copy_to_user 的函数来完成拷贝,不然会引发页错误
282        // 3. 设置用户栈布局,包含命令行参数和环境变量
283        let (new_sp, argc, argv_vec_ptr, envp_vec_ptr) =
284            setup_stack_layout(sp_high, argv, envp, phdr_addr, phnum, phent, entry_point);
285
286        // 4. 配置 TrapFrame (新的上下文)
287        // SAFETY: tfptr 指向的内存已经被分配且可写,并由 task 拥有
288        unsafe {
289            // 清零整个 TrapFrame,避免旧值泄漏到用户态
290            core::ptr::write_bytes(tf_ptr, 0, 1);
291            (*tf_ptr).set_exec_trap_frame(
292                entry_point,
293                new_sp,
294                self.kstack_base,
295                argc,
296                argv_vec_ptr,
297                envp_vec_ptr,
298            );
299        }
300    }
301
302    /// 检查是否有满足条件的子任务
303    /// # 参数
304    /// * `cond`: 用于检查子任务的条件闭包
305    /// * `remove`: 是否在找到后从子任务列表中移除该僵尸子任务(如果是)
306    /// # 返回值
307    /// 如果有,返回该子任务的共享句柄. 如果没有,返回 None
308    /// 注意:此函数不阻塞,调用者需持有锁
309    pub fn check_child(
310        &mut self,
311        cond: impl FnMut(&SharedTask) -> bool,
312        remove: bool,
313    ) -> Option<SharedTask> {
314        let mut children_guard = self.children.lock();
315        if let Some(idx) = children_guard.iter().position(cond) {
316            let child = children_guard[idx].clone();
317            if remove && child.lock().state == TaskState::Zombie {
318                children_guard.remove(idx);
319            }
320            return Some(child);
321        }
322        None
323    }
324
325    pub fn notify_child_exit(&mut self) {
326        self.wait_child.lock().wake_up_one();
327    }
328
329    /// 判断该任务是否为内核线程
330    pub fn is_kernel_thread(&self) -> bool {
331        self.memory_space.is_none()
332    }
333
334    /// 判断该任务是否为进程 / 主线程
335    /// 对于进程,其 pid 等于 tid
336    pub fn is_process(&self) -> bool {
337        self.pid == self.tid
338    }
339
340    /// 把已初始化的 TaskStruct 包装为共享任务句柄
341    /// 返回值: 包装后的 SharedTask
342    pub fn into_shared(self) -> SharedTask {
343        Arc::new(SpinLock::new(self))
344    }
345
346    /// 返回一个空的子任务列表
347    /// 用于创建新任务时初始化 children 字段
348    pub fn empty_children() -> Arc<SpinLock<Vec<SharedTask>>> {
349        Arc::new(SpinLock::new(Vec::new()))
350    }
351
352    fn new(
353        tid: u32,
354        pid: u32,
355        ppid: u32,
356        pgid: u32,
357        children: Arc<SpinLock<Vec<SharedTask>>>,
358        kstack_tracker: FrameRangeTracker,
359        trap_frame_tracker: FrameTracker,
360        memory_space: Option<Arc<SpinLock<MemorySpace>>>,
361        signal_handlers: Arc<SpinLock<SignalHandlerTable>>,
362        blocked: SignalFlags,
363        shared_pending: Arc<SpinLock<SignalPending>>,
364        signal_stack: Arc<SpinLock<SignalStack>>,
365        exit_signal: u8,
366        uts_namespace: Arc<SpinLock<UtsNamespace>>,
367        rlimit: Arc<SpinLock<RlimitStruct>>,
368        fd_table: Arc<FDTable>,
369        fs: Arc<SpinLock<FsStruct>>,
370    ) -> Self {
371        let trap_frame_ptr = trap_frame_tracker.ppn().start_addr().to_vaddr().as_usize();
372        let kstack_base = kstack_tracker.end_ppn().start_addr().to_vaddr().as_usize();
373
374        Task {
375            context: Context::zero_init(),
376            preempt_count: 0,
377            priority: 0,
378            processor_id: 0,
379            state: TaskState::Running,
380            tid,
381            pid,
382            ppid,
383            pgid,
384            children,
385            wait_child: Arc::new(SpinLock::new(WaitQueue::new())),
386            kstack_base,
387            kstack_tracker,
388            trap_frame_tracker,
389            trap_frame_ptr: AtomicPtr::new(trap_frame_ptr as *mut TrapFrame),
390            memory_space,
391            exit_code: None,
392            signal_handlers,
393            signal_stack,
394            exit_signal,
395            uts_namespace,
396            rlimit,
397            blocked,
398            pending: SignalPending::empty(),
399            shared_pending,
400            robust_list: None,
401            set_child_tid: 0,
402            clear_child_tid: 0,
403            credential: super::Credential::root(),
404            umask: 0o022,
405            fd_table,
406            fs,
407        }
408    }
409
410    #[cfg(test)]
411    pub fn new_dummy_task(tid: u32) -> Self {
412        use crate::{
413            mm::frame_allocator::{alloc_contig_frames, alloc_frame},
414            uapi::resource::INIT_RLIMITS,
415        };
416        let kstack_tracker =
417            alloc_contig_frames(1).expect("new_dummy_task: failed to alloc kstack");
418        let trap_frame_tracker = alloc_frame().expect("new_dummy_task: failed to alloc trap_frame");
419        Self::new(
420            tid,
421            tid,
422            0,
423            0,
424            Task::empty_children(),
425            kstack_tracker,
426            trap_frame_tracker,
427            None,
428            Arc::new(SpinLock::new(SignalHandlerTable::new())),
429            SignalFlags::empty(),
430            Arc::new(SpinLock::new(SignalPending::empty())),
431            Arc::new(SpinLock::new(SignalStack::default())),
432            0,
433            Arc::new(SpinLock::new(UtsNamespace::default())),
434            Arc::new(SpinLock::new(RlimitStruct::new(INIT_RLIMITS))),
435            Arc::new(FDTable::new()),
436            Arc::new(SpinLock::new(FsStruct::new(None, None))),
437        )
438    }
439}
440
441impl Drop for Task {
442    fn drop(&mut self) {
443        pr_debug!("Dropping Task {}", self.tid);
444    }
445}
446// /// 关于任务的管理信息
447// /// 存放与调度器、任务状态、队列相关的、需要高频访问和修改的数据。
448// /// 主要由调度器子系统使用。
449// pub struct TaskInfo {}
450
451// /// 关于任务的资源信息
452// /// 存放与进程资源、内存管理、I/O 权限、用户 ID 等相关的、相对稳定或低频访问的数据。
453// /// 主要由内存管理子系统和权限管理子系统使用。
454// #[allow(dead_code)]
455// pub struct TaskStruct {}
456
457#[cfg(test)]
458mod tests {
459    use super::*;
460    use crate::{kassert, test_case};
461
462    // // 创建内核任务的基本属性检查
463    // test_case!(test_ktask_create, {
464    //     let kstack_tracker = alloc_contig_frames(4).expect("kthread_spawn: failed to alloc kstack");
465    //     let trap_frame_tracker = alloc_frame().expect("kthread_spawn: failed to alloc trap_frame");
466    //     let t = Task::ktask_create(
467    //         1,
468    //         1,
469    //         0,
470    //         Task::empty_children(),
471    //         kstack_tracker,
472    //         trap_frame_tracker,
473    //         Arc::new(SpinLock::new(SignalHandlerTable::new())),
474    //         SignalFlags::empty(),
475    //         Arc::new(SpinLock::new(UtsNamespace::default())),
476    //         Arc::new(SpinLock::new(RlimitStruct::new(INIT_RLIMITS))),
477    //         Arc::new(FDTable::new()),
478    //     );
479    //     kassert!(t.tid == 1);
480    //     kassert!(t.pid == t.tid);
481    //     kassert!(t.is_kernel_thread());
482    //     kassert!(t.is_process());
483    //     kassert!(t.kstack_base != 0);
484    //     kassert!(t.trap_frame_ptr.load(Ordering::SeqCst) as usize != 0);
485    // });
486
487    // new_dummy_task:应为内核线程,pid=tid,初始状态为 Running
488    test_case!(test_dummy_task_basic, {
489        let t = Task::new_dummy_task(7);
490        kassert!(t.tid == 7);
491        kassert!(t.pid == 7);
492        kassert!(t.is_kernel_thread());
493        kassert!(t.is_process());
494        kassert!(matches!(t.state, TaskState::Running));
495    });
496
497    // // is_process 与 is_kernel_thread 区分:人为创建一个“线程” pid!=tid
498    // test_case!(test_is_process_vs_thread, {
499    //     let kstack_tracker = alloc_contig_frames(2).expect("alloc kstack");
500    //     let trap_frame_tracker = alloc_frame().expect("alloc trap_frame");
501    //     // 传入 pid 与 tid 不同模拟同进程内的线程
502    //     let t = Task::ktask_create(
503    //         10,
504    //         5,
505    //         5,
506    //         Task::empty_children(),
507    //         kstack_tracker,
508    //         trap_frame_tracker,
509    //         Arc::new(SpinLock::new(SignalHandlerTable::new())),
510    //         SignalFlags::empty(),
511    //         Arc::new(SpinLock::new(UtsNamespace::default())),
512    //         Arc::new(SpinLock::new(RlimitStruct::new(INIT_RLIMITS))),
513    //     );
514    //     kassert!(t.tid == 10);
515    //     kassert!(t.pid == 5);
516    //     kassert!(!t.is_process());
517    //     kassert!(t.is_kernel_thread()); // 仍是内核线程(没有用户地址空间)
518    // });
519
520    // // init_user_trapframe_and_context:验证重新定位 trap_frame 指针与入口设置
521    // test_case!(test_init_user_trapframe_and_context, {
522    //     let mut t = Task::new_dummy_task(3);
523    //     let original_tf_ptr = t.trap_frame_ptr.load(Ordering::SeqCst) as usize;
524    //     let user_entry = 0x5555_8888usize;
525    //     let trampoline = 0xFFFF_FFC0_8020_9000usize;
526    //     unsafe {
527    //         t.init_user_trapframe_and_context(user_entry, trampoline);
528    //     }
529    //     let new_tf_ptr = t.trap_frame_ptr.load(Ordering::SeqCst) as usize;
530    //     // 新 trap_frame 应位于内核栈顶下方 size_of::<TrapFrame>()
531    //     let expect_ptr = t.kstack_base - size_of::<TrapFrame>();
532    //     kassert!(new_tf_ptr == expect_ptr);
533    //     kassert!(new_tf_ptr != original_tf_ptr);
534    //     // 校验写入的 sepc
535    //     let tf = unsafe { &*t.trap_frame_ptr.load(Ordering::SeqCst) };
536    //     kassert!(tf.sepc == user_entry);
537    //     // Context 设置
538    //     kassert!(t.context.sp == t.kstack_base);
539    //     kassert!(t.context.ra == trampoline);
540    // });
541
542    // // execve 前后的 TrapFrame 基本字段(不访问用户空间,只验证写入逻辑)
543    // test_case!(test_execve_basic_trapframe_setup, {
544    //     // 构造内核任务再模拟成为用户任务:直接插入一个空的 MemorySpace(若出现 API 变化需调整)
545    //     // 使用 zeroed MemorySpace 仅用于测试 trap_frame 字段写入,不触发实际页表操作
546    //     let mut t = Task::new_dummy_task(11);
547    //     // 伪造用户地址空间(测试目的:Some 即视为用户进程)
548    //     // SAFETY: 仅在测试中使用,MemorySpace 零值不会被真正激活
549    //     let dummy_space: Arc<MemorySpace> = unsafe { core::mem::zeroed() };
550    //     t.memory_space = Some(dummy_space);
551
552    //     let tf_ptr = t.trap_frame_ptr.load(Ordering::SeqCst);
553    //     let entry = 0x1234_5678usize;
554    //     let user_sp_high = t.kstack_base & !0xFF; // 构造一个“高地址”作为栈顶
555    //     let argv = ["prog", "arg1"];
556    //     let envp = ["KEY=VALUE"];
557    //     // 调用 execve(由于 dummy_space 不会映射,不能访问用户页,仅验证不崩溃及字段设置)
558    //     // 为避免实际用户页访问,这里将字符串数组长度设小,且不真正触发用户空间写(dummy 空页表会使 SUM 写失败时 panic,若失败则跳过此测试)
559    //     // 如果出现页错误,可根据真实 MemorySpace API 替换为可映射测试空间。
560    //     t.execve(unsafe { core::mem::zeroed() }, entry, user_sp_high, &argv, &envp);
561    //     let tf_after = unsafe { &*tf_ptr };
562    //     kassert!(tf_after.sepc == entry);
563    //     kassert!(tf_after.x10_a0 == argv.len());
564    //     kassert!(tf_after.x1_ra == 0);
565    // });
566}