1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
// Copyright (c) 2020 Alex Chi // // This software is released under the MIT License. // https://opensource.org/licenses/MIT //! Process and scheduling mod trapframe; pub use trapframe::*; mod cpu; pub use cpu::*; mod process; pub use process::*; mod context; pub use context::*; mod schedule; pub use schedule::*; use crate::symbols::*; use crate::spinlock::Mutex; use crate::arch; use alloc::boxed::Box; use core::mem::MaybeUninit; use core::borrow::BorrowMut; use crate::arch::hart_id; /// An array holding all CPU information static mut CPUS: [CPU; NCPUS] = [CPU::zero(); NCPUS]; /// Enum describing a process in process pool /// /// `NoProc`: No process associated with this pid /// /// `Scheduled`: This process is scheduled on one CPU /// /// `Pooling`: This process is not being scheduled /// /// `BeingSlept`: This process holds a sleep lock and is to be put back pub enum ProcInPool { NoProc, Scheduled, Pooling(Box<Process>), BeingSlept, } /// An array holding all process information. /// /// # Examples /// /// ``` /// let pool = PROCS_POOL.lock(); /// let p = &mut pool[0]; /// if p.0 == false { /// println!("This pid is not occupied by any process."); /// } /// if p.0 == true { /// if p.1.is_none() { /// println!("The process is running on one CPU."); /// } else { /// println!("The process is to be scheduled."); /// assert_eq!(p.1.pid, 0); // process of PID x is stored at PROCS_POOL[x] /// } /// } /// ``` pub static PROCS_POOL: Mutex<[ProcInPool; NMAXPROCS]> = Mutex::new([ProcInPool::NoProc; NMAXPROCS], "proc pool"); pub unsafe fn init() {} /// Get CPU object of current hart. pub fn my_cpu() -> &'static mut CPU { unsafe { &mut CPUS[arch::hart_id()] } } /// Get reference to current running process on current hart. /// /// Note that this reference is always valid no matter /// which hart this process is scheduled. /// On the contrary, `&mut my_cpu().process` can't /// be moved between harts. /// /// ## Examples /// /// ``` /// use crate::{arch, process}; /// let p = process::my_proc(); /// arch::intr_on(); /// // There may be timer interrupt at any time, and context /// // of this process in kernel may be scheduled to another /// // hart. /// p.trapframe.epc += 4; /// ``` /// /// On the contrary, the following code may cause problems. /// /// ``` /// use crate::{arch, process}; /// let p = &mut my_cpu().process.unwrap(); /// arch::intr_on(); /// // After this kernel context is scheduled on another /// // hart, p is no longer valid, as previous hart may /// // have scheduled a different process, or there is /// // no process running at all. /// p.trapframe.epc += 4; // Load page fault /// ``` pub fn my_proc() -> &'static mut Process { let proc_cpu = my_cpu(); proc_cpu.process.as_mut().unwrap() } use crate::println; pub fn debug() { for i in 0..NCPUS { match unsafe { &CPUS[i].process } { Some(x) => { println!("{} running on hart {}", x.pid, i); } _ => {} } } let pool = unsafe { PROCS_POOL.get() }; for i in 0..NMAXPROCS { match &pool[i] { ProcInPool::Pooling(x) => { println!("{} pooling with state {:?}", x.pid, x.state); } ProcInPool::BeingSlept => { println!("{} being slept", i); } _ => {} } } }