1use core::{hint, sync::atomic::Ordering};
7
8use alloc::sync::Arc;
9
10use crate::{
11 arch::{intr::disable_interrupts, trap::restore},
12 kernel::{
13 SCHEDULER, TaskState,
14 cpu::current_cpu,
15 scheduler::Scheduler,
16 task::{TASK_MANAGER, TaskStruct, task_manager::TaskManagerTrait},
17 },
18 mm::{
19 frame_allocator::{alloc_contig_frames, alloc_frame},
20 memory_space::MemorySpace,
21 },
22 sync::SpinLock,
23};
24
25#[allow(dead_code)]
40pub fn kthread_spawn(entry_point: fn()) -> u32 {
41 let tid = TASK_MANAGER.lock().allocate_tid();
42 let (pid, ppid, signal_handlers, blocked, signal, uts, rlimit, fd_table, fs) = {
43 let cur_cpu = current_cpu().lock();
44 let cur_task = cur_cpu.current_task.as_ref().unwrap();
45 let cur_task = cur_task.lock();
46 (
47 cur_task.pid,
48 cur_task.ppid,
49 cur_task.signal_handlers.clone(),
50 cur_task.blocked,
51 cur_task.shared_pending.clone(),
52 cur_task.uts_namespace.clone(),
53 cur_task.rlimit.clone(),
54 cur_task.fd_table.clone(),
55 cur_task.fs.clone(),
56 )
57 };
58
59 let kstack_tracker = alloc_contig_frames(4).expect("kthread_spawn: failed to alloc kstack");
60 let trap_frame_tracker = alloc_frame().expect("kthread_spawn: failed to alloc trap_frame");
61
62 let task = TaskStruct::ktask_create(
64 tid,
65 pid,
66 ppid,
67 TaskStruct::empty_children(),
68 kstack_tracker,
69 trap_frame_tracker,
70 signal_handlers,
71 blocked,
72 signal,
73 uts,
74 rlimit,
75 fd_table,
76 fs,
77 );
78
79 let tf = task.trap_frame_ptr.load(Ordering::SeqCst);
80 unsafe {
82 (*tf).set_kernel_trap_frame(
83 entry_point as usize,
84 super::terminate_task as usize,
85 task.kstack_base,
86 );
87 }
88 let tid = task.tid;
89 let task = task.into_shared();
90
91 TASK_MANAGER.lock().add_task(task.clone());
93 SCHEDULER.lock().add_task(task);
94
95 tid
96}
97
98pub unsafe fn kthread_join(tid: u32, return_value_ptr: Option<usize>) -> i32 {
111 loop {
112 let task_opt = TASK_MANAGER.lock().get_task(tid);
113 if let Some(task) = task_opt {
114 let t = task.lock();
115 if t.state == TaskState::Zombie {
116 if let Some(rv) = t.exit_code {
117 unsafe {
119 if let Some(ptr) = return_value_ptr {
120 let ptr = ptr as *mut usize;
121 ptr.write_volatile(rv as usize);
122 }
123 }
124 }
125 TASK_MANAGER.lock().release_task(task.clone());
126 return 0; }
128 } else {
129 return -1; }
131 hint::spin_loop();
133 }
134}
135
136pub fn kernel_execve(path: &str, argv: &[&str], envp: &[&str]) -> ! {
143 crate::pr_info!("[kernel_execve] Loading: {}", path);
145 let data = crate::vfs::vfs_load_elf(path).expect("kernel_execve: file not found");
146 crate::pr_info!("[kernel_execve] Loaded {} bytes", data.len());
147
148 let (space, entry, sp, phdr_addr, phnum, phent) = MemorySpace::from_elf(&data)
150 .expect("kernel_execve: failed to create memory space from ELF");
151 crate::pr_info!("[kernel_execve] Created memory space, entry=0x{:x}", entry);
152
153 let space = Arc::new(SpinLock::new(space));
155 current_cpu().lock().switch_space(space.clone());
157
158 let task = {
159 let cpu = current_cpu().lock();
160 cpu.current_task.as_ref().unwrap().clone()
161 };
162 unsafe { disable_interrupts() };
167 {
168 let mut t = task.lock();
169 t.execve(space, entry, sp, argv, envp, phdr_addr, phnum, phent);
170 }
171 crate::pr_info!("[kernel_execve] Switching to user mode");
172
173 let tfp = task.lock().trap_frame_ptr.load(Ordering::SeqCst);
174 unsafe {
177 restore(&*tfp);
178 }
179 unreachable!("kernel_execve: should not return");
180}
181
182#[cfg(test)]
183mod tests {
184 #![allow(dead_code)]
186 use super::*;
189 use crate::{
190 kassert,
191 kernel::task::{SharedTask, TASK_MANAGER},
192 test_case,
193 };
194 fn dummy_thread() {}
198
199 fn mk_task(tid: u32) -> SharedTask {
200 TaskStruct::new_dummy_task(tid).into_shared()
201 }
202
203 test_case!(test_kthread_spawn_basic, {
205 current_cpu().lock().current_task = Some(mk_task(1));
206 let tid = kthread_spawn(dummy_thread);
207 kassert!(tid != 0);
208 let task_opt = TASK_MANAGER.lock().get_task(tid);
209 kassert!(task_opt.is_some());
210 let t = task_opt.unwrap();
211 let g = t.lock();
212 kassert!(g.tid == tid);
213 kassert!(g.is_kernel_thread());
214 });
215
216 test_case!(test_kthread_join_not_found, {
252 let missing_tid = 0xFFFF_FFFFu32;
254 kassert!(TASK_MANAGER.lock().get_task(missing_tid).is_none());
255 let rc = unsafe { kthread_join(missing_tid, None) };
256 kassert!(rc == -1);
257 });
258}