diff --git a/risc_v/src/syscall.rs b/risc_v/src/syscall.rs index e192e38..5114693 100755 --- a/risc_v/src/syscall.rs +++ b/risc_v/src/syscall.rs @@ -7,7 +7,9 @@ use crate::{block::block_op, cpu::{dump_registers, TrapFrame}, minixfs, page::{virt_to_phys, Table}, - process::{delete_process, get_by_pid, set_sleeping, set_waiting}}; + process::{delete_process, get_by_pid, set_sleeping, set_waiting}}; + +use crate::process::{PROCESS_LIST_MUTEX, PROCESS_LIST, Process}; /// do_syscall is called from trap.rs to invoke a system call. No discernment is /// made here whether this is a U-mode, S-mode, or M-mode system call. @@ -41,6 +43,20 @@ pub unsafe fn do_syscall(mepc: usize, frame: *mut TrapFrame) -> usize { set_sleeping((*frame).pid as u16, (*frame).regs[10]); 0 }, + 11 => { + // Add process to the scheduler. This is obviously insecure and + // we wouldn't do this realistically. + let my_proc = (*frame).regs[10] as *const Process; + PROCESS_LIST_MUTEX.spin_lock(); + if let Some(mut pl) = PROCESS_LIST.take() { + // As soon as we push this process on the list, it'll be + // schedule-able. + pl.push_back(my_proc.read()); + PROCESS_LIST.replace(pl); + } + PROCESS_LIST_MUTEX.unlock(); + mepc + 4 + }, 63 => { // Read system call // This is an asynchronous call. This will get the @@ -184,6 +200,10 @@ pub fn syscall_sleep(duration: usize) { let _ = do_make_syscall(10, duration, 0, 0, 0, 0, 0); } + +pub fn syscall_add_process(process: Process) { + let _ = do_make_syscall(11, &process as *const Process as usize, 0, 0, 0, 0, 0); +} // These system call numbers come from libgloss so that we can use newlib // for our system calls. // Libgloss wants the system call number in A7 and arguments in A0..A6 diff --git a/risc_v/src/test.rs b/risc_v/src/test.rs index 441702e..466e4ea 100644 --- a/risc_v/src/test.rs +++ b/risc_v/src/test.rs @@ -13,11 +13,9 @@ use crate::{cpu::{build_satp, ProcessData, ProcessState, NEXT_PID, - PROCESS_LIST, - PROCESS_LIST_MUTEX, STACK_ADDR, STACK_PAGES}, - syscall::syscall_fs_read}; + syscall::{syscall_add_process, syscall_fs_read}}; /// Test block will load raw binaries into memory to execute them. This function /// will load ELF files and try to execute them. @@ -187,33 +185,13 @@ pub fn test_elf() { // now. Since we don't reuse PIDs, this means that we can only spawn // 65534 processes. satp_fence_asid(my_pid as usize); - // I took a different tact here than in process.rs. In there I created - // the process while holding onto the process list. It might - // matter since this is asynchronous--it is being ran as a kernel process. - unsafe { - PROCESS_LIST_MUTEX.spin_lock(); - } - if let Some(mut pl) = unsafe { PROCESS_LIST.take() } { - // As soon as we push this process on the list, it'll be - // schedule-able. - println!( - "Added user process to the scheduler...get ready \ - for take-off!" - ); - pl.push_back(my_proc); - unsafe { - PROCESS_LIST.replace(pl); - } - } - else { - println!("Unable to spawn process."); - // Since my_proc couldn't enter the process list, it - // will be dropped and all of the associated allocations - // will be deallocated through the process' Drop trait. - } - unsafe { - PROCESS_LIST_MUTEX.unlock(); - } + + // We will get a data race if we don't use the add process system call. This + // test process is being ran as a kernel process, which then competes with + // the scheduler due to the context switch timer. When we use a system call, + // it goes into an interrupt context so that the scheduler can safely + // receive our new process without preemption. + syscall_add_process(my_proc); println!(); }