pubfnfork(context: &mut ProcessContext) { x86_64::instructions::interrupts::without_interrupts(|| { letmanager = get_process_manager(); // FIXME: save_current as parent letparent_pid = manager.current().pid(); manager.save_current(context); // FIXME: fork to get child manager.fork(); // FIXME: push to child & parent to ready queue manager.push_ready(parent_pid); // FIXME: switch to next process manager.switch_next(context); }) }
pkg/kernel/src/proc/manager.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14
implProcessManager { pubfnfork(&self) { // FIXME: get current process letcurrent = self.current(); // FIXME: fork to get child letchild = current.fork(); // FIXME: add child to process list letchild_pid = child.pid(); self.add_proc(child_pid, child); self.push_ready(child_pid); // FOR DBG: maybe print the process ready queue? debug!("Ready queue: {:?}", self.ready_queue.lock()); } }
implProcess { pubfnfork(self: &Arc<Self>) -> Arc<Self> { // FIXME: lock inner as write letmut inner = self.inner.write(); // FIXME: inner fork with parent weak ref letchild_inner = inner.fork(Arc::downgrade(self)); letchild_pid = ProcessId::new(); // FOR DBG: maybe print the child process info // e.g. parent, name, pid, etc. debug!("fork: parrent is {}#{}, child is {}#{}.", inner.name, self.pid, child_inner.name, child_pid); // FIXME: make the arc of child letchild = Arc::new(Self { pid: child_pid, inner: Arc::new(RwLock::new(child_inner)), }); // FIXME: add child to current process's children list inner.children.push(child.clone()); // FIXME: set fork ret value for parent with `context.set_rax` inner.context.set_rax(child.pid.0asusize);
// FIXME: mark the child as ready & return it inner.pause(); // !!!!!!!! actually, mark the parent as ready here child } }
implProcessInner { pubfnfork(&mutself, parent: Weak<Process>) -> ProcessInner { // FIXME: get current process's stack info letstack_info = self.stack_segment.unwrap(); // FIXME: clone the process data struct letchild_proc_data = self.proc_data.clone().unwrap(); // FIXME: clone the page table context (see instructions) letchild_page_table = self.page_table.as_ref().unwrap().fork(); // FIXME: alloc & map new stack for child (see instructions) letframe_allocator = &mut *get_frame_alloc_for_sure(); letmapper = &mutself.page_table.as_ref().unwrap().mapper(); letparent_stack_base = stack_info.start.start_address().as_u64(); letparent_stack_top = stack_info.end.start_address().as_u64(); letmut child_stack_base = parent_stack_base - (self.children.len() asu64 + 1)* STACK_MAX_SIZE; while elf::map_range(child_stack_base, stack_info.count() asu64, mapper, frame_allocator, true, true).is_err(){ trace!("Map thread stack to {:#x} failed.", child_stack_base); child_stack_base -= STACK_MAX_SIZE; }; debug!("map child stack to {:#x} succeed", child_stack_base); // FIXME: copy the *entire stack* from parent to child ProcessInner::clone_range(parent_stack_base, child_stack_base, stack_info.count()); //debug!("finished clone range"); // FIXME: update child's context with new *stack pointer* // > update child's stack to new base letmut child_context = self.context; child_context.set_stack_offset(child_stack_base - parent_stack_base); // > keep lower bits of *rsp*, update the higher bits // > also update the stack record in process data letmut child_proc_data = self.proc_data.clone().unwrap(); letchild_stack_top = child_stack_base + stack_info.count() asu64 * Size4KiB::SIZE; letchild_stack = Page::range( Page::containing_address(VirtAddr::new_truncate(child_stack_base)), Page::containing_address(VirtAddr::new_truncate(child_stack_top)) ); child_proc_data.stack_segment = Some(child_stack); child_proc_data.set_max_stack(VirtAddr::new(child_stack_top-STACK_MAX_SIZE), STACK_MAX_PAGES); // FIXME: set the return value 0 for child with `context.set_rax` child_context.set_rax(0); // FIXME: construct the child process inner Self { name: self.name.clone(), parent: Some(parent), children: Vec::new(), ticks_passed: 0, status: ProgramStatus::Ready, exit_code: None, context: child_context, page_table: Some(child_page_table), proc_data: Some(child_proc_data) } // NOTE: return inner because there's no pid record in inner } /// Clone a range of memory /// /// - `src_addr`: the address of the source memory /// - `dest_addr`: the address of the target memory /// - `size`: the count of pages to be cloned fnclone_range(src_addr: u64, dest_addr: u64, size: usize) { trace!("Clone range: {:#x} -> {:#x}", src_addr, dest_addr); unsafe { copy_nonoverlapping::<u8>( src_addr as *mutu8, dest_addr as *mutu8, size * Size4KiB::SIZE asusize, ); } } }
pubfnacquire(&self) { // FIXME: acquire the lock, spin if the lock is not available whileself.bolt.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed).is_err() { spin_loop(); } }
implSemaphore { /// Create a new semaphore pubfnnew(value: usize) ->Self { Self { count: value, wait_queue: VecDeque::new(), } }
/// Wait the semaphore (acquire/down/proberen) /// /// if the count is 0, then push the process into the wait queue /// else decrease the count and return Ok pubfnwait(&mutself, pid: ProcessId) -> SemaphoreResult { // FIXME: if the count is 0, then push pid into the wait queue // return Block(pid) ifself.count == 0 { self.wait_queue.push_back(pid); return SemaphoreResult::Block(pid); }else{ self.count -= 1; return SemaphoreResult::Ok; } // FIXME: else decrease the count and return Ok }
/// Signal the semaphore (release/up/verhogen) /// /// if the wait queue is not empty, then pop a process from the wait queue /// else increase the count pubfnsignal(&mutself) -> SemaphoreResult { // FIXME: if the wait queue is not empty // pop a process from the wait queue // return WakeUp(pid) // FIXME: else increase the count and return Ok if !self.wait_queue.is_empty() { letpid = self.wait_queue.pop_front().unwrap(); return SemaphoreResult::WakeUp(pid); } else{ self.count += 1; return SemaphoreResult::Ok; } } }
// FIXME: insert a new semaphore into the sems // use `insert(/* ... */).is_none()` self.sems.insert(SemaphoreId::new(key), Mutex::new(Semaphore::new(value))).is_none() }
// FIXME: try get the semaphore from the sems // then do it's operation matchself.sems.get(&sid) { Some(sem) => { letmut sem = sem.lock(); sem.wait(pid) }, None => SemaphoreResult::NotExist, } // FIXME: return NotExist if the semaphore is not exist }
/// Signal the semaphore (release/up/verhogen) pubfnsignal(&self, key: u32) -> SemaphoreResult { letsid = SemaphoreId::new(key);
// FIXME: try get the semaphore from the sems // then do it's operation matchself.sems.get(&sid) { Some(sem)=>{ letmut sem = sem.lock(); sem.signal() }, None => SemaphoreResult::NotExist, } // FIXME: return NotExist if the semaphore is not exist } }
/// Increment the counter /// /// this function simulate a critical section by delay /// DO NOT MODIFY THIS FUNCTION fninc_counter() { unsafe { delay(); letmut val = COUNTER; delay(); val += 1; delay(); COUNTER = val; } }
pubstructProcessManager { //... wait_queue: Mutex<BTreeMap<ProcessId, BTreeSet<ProcessId>>>, } implProcessManager { //... pubfnkill(&self, pid: ProcessId, ret: isize) { //... ifletSome(pids) = self.wait_queue.lock().remove(&pid) { forpidin pids { self.wait_pid_wake_up(pid, Some(ret)); } } //... } //... pubfnwait_pid(&self, pid: ProcessId) { letmut wait_queue = self.wait_queue.lock(); // FIXME: push the current process to the wait queue // `processor::current_pid()` is waiting for `pid` letk = wait_queue.entry(pid).or_insert(BTreeSet::new()); k.insert(self.current().pid()); } /// Wake up the process with the given pid /// /// If `ret` is `Some`, set the return value of the process pubfnwait_pid_wake_up(&self, pid: ProcessId, ret: Option<isize>) { ifletSome(proc) = self.get_proc(&pid) { letmut inner = proc.write(); ifletSome(ret) = ret { // FIXME: set the return value of the process // like `context.set_rax(ret as usize)` inner.set_rax(ret asusize); } // FIXME: set the process as ready inner.pause(); // FIXME: push to ready queue self.push_ready(pid); } } }
用户库侧:
pkg/lib/src/syscall.rs
1 2 3 4 5 6 7
#[inline(always)] pubfnsys_wait_pid(pid: u16) ->isize { // FIXME: try to get the return value for process // loop until the process is finished letstatus: isize = syscall!(Syscall::WaitPid, pid asu64) asisize; status }