diff --git a/src/context/arch/x86.rs b/src/context/arch/x86.rs index d4f9eb858e..17520cbf26 100644 --- a/src/context/arch/x86.rs +++ b/src/context/arch/x86.rs @@ -104,7 +104,7 @@ impl super::Context { pub fn set_userspace_io_allowed(&mut self, allowed: bool) { self.arch.userspace_io_allowed = allowed; - if self.id == super::context_id() { + if self.is_current_context() { unsafe { crate::gdt::set_userspace_io_allowed(allowed); } diff --git a/src/context/arch/x86_64.rs b/src/context/arch/x86_64.rs index 4a8f2251b8..8ea07fc74a 100644 --- a/src/context/arch/x86_64.rs +++ b/src/context/arch/x86_64.rs @@ -114,7 +114,7 @@ impl super::Context { pub fn set_userspace_io_allowed(&mut self, allowed: bool) { self.arch.userspace_io_allowed = allowed; - if self.cid == super::current_cid() { + if self.is_current_context() { unsafe { crate::gdt::set_userspace_io_allowed(crate::gdt::pcr(), allowed); } diff --git a/src/context/context.rs b/src/context/context.rs index db9a394ae1..cf5a0db98c 100644 --- a/src/context/context.rs +++ b/src/context/context.rs @@ -21,15 +21,11 @@ use crate::{ use crate::syscall::error::{Error, Result, EAGAIN, ESRCH}; -/// Unique identifier for a context (i.e. `pid`). -use ::core::sync::atomic::AtomicUsize; - use super::{ empty_cr3, memory::{AddrSpaceWrapper, GrantFileRef}, process::{Process, ProcessId}, }; -int_like!(ContextId, AtomicContextId, usize, AtomicUsize); /// The status of a context - used for scheduling /// See `syscall::process::waitpid` and the `sync` module for examples of usage @@ -131,8 +127,6 @@ impl Eq for WaitpidKey {} /// A context, which identifies either a process or a thread #[derive(Debug)] pub struct Context { - /// The internal context ID of this context - pub cid: ContextId, /// The process ID of this context pub pid: ProcessId, /// Process state shared with other threads @@ -207,9 +201,8 @@ pub struct SignalState { } impl Context { - pub fn new(cid: ContextId, pid: ProcessId, process: Arc>) -> Result { + pub fn new(pid: ProcessId, process: Arc>) -> Result { let this = Context { - cid, pid, process, sig: None, @@ -362,6 +355,10 @@ impl Context { } } + pub fn is_current_context(&self) -> bool { + self.running && self.cpu_id == Some(crate::cpu_id()) + } + pub fn addr_space(&self) -> Result<&Arc> { self.addr_space.as_ref().ok_or(Error::new(ESRCH)) } @@ -375,7 +372,7 @@ impl Context { return addr_space; }; - if self.cid == super::current_cid() { + if self.is_current_context() { // TODO: Share more code with context::arch::switch_to. let this_percpu = PercpuBlock::current(); @@ -474,7 +471,7 @@ impl BorrowedHtBuf { pub fn head() -> Result { Ok(Self { inner: Some( - context::current()? + context::current() .write() .syscall_head .take() @@ -486,7 +483,7 @@ impl BorrowedHtBuf { pub fn tail() -> Result { Ok(Self { inner: Some( - context::current()? + context::current() .write() .syscall_tail .take() @@ -545,9 +542,8 @@ impl BorrowedHtBuf { } impl Drop for BorrowedHtBuf { fn drop(&mut self) { - let Ok(context) = context::current() else { - return; - }; + let context = context::current(); + let Some(inner) = self.inner.take() else { return; }; diff --git a/src/context/list.rs b/src/context/list.rs deleted file mode 100644 index 65ac2c4b07..0000000000 --- a/src/context/list.rs +++ /dev/null @@ -1,169 +0,0 @@ -use alloc::{collections::BTreeMap, sync::Arc}; -use spin::RwLock; - -use spinning_top::RwSpinlock; - -use super::{ - context::{Context, ContextId, Kstack}, - memory::AddrSpaceWrapper, - process::{new_process, Process, ProcessId, ProcessInfo}, -}; -use crate::{ - interrupt::InterruptStack, - scheme::SchemeNamespace, - syscall::error::{Error, Result, EAGAIN}, -}; - -/// Context list type -pub struct ContextList { - // Using a BTreeMap for it's range method - map: BTreeMap>>, - next_id: usize, -} - -impl ContextList { - /// Create a new context list. - pub const fn new() -> Self { - ContextList { - map: BTreeMap::new(), - next_id: 1, - } - } - - /// Get the nth context. - pub fn get(&self, id: ContextId) -> Option<&Arc>> { - self.map.get(&id) - } - - /// Get the current context. - pub fn current(&self) -> Option<&Arc>> { - self.map.get(&super::current_cid()) - } - - pub fn iter( - &self, - ) -> ::alloc::collections::btree_map::Iter>> { - self.map.iter() - } - - pub fn range( - &self, - range: impl core::ops::RangeBounds, - ) -> ::alloc::collections::btree_map::Range<'_, ContextId, Arc>> { - self.map.range(range) - } - - pub(crate) fn insert_context_raw( - &mut self, - cid: ContextId, - pid: ProcessId, - process: Arc>, - ) -> Result<&Arc>> { - assert!(self - .map - // TODO - .insert( - cid, - Arc::new(RwSpinlock::new(Context::new(cid, pid, process)?)) - ) - .is_none()); - - Ok(self - .map - .get(&cid) - .expect("Failed to insert new context. ID is out of bounds.")) - } - - /// Create a new context. - pub fn new_context( - &mut self, - process: Arc>, - ) -> Result<&Arc>> { - let pid = process.read().pid; - - // Zero is not a valid context ID, therefore add 1. - // - // FIXME: Ensure the number of CPUs can't switch between new_context calls. - let min = crate::cpu_count() as usize + 1; - - self.next_id = core::cmp::max(self.next_id, min); - - if self.next_id >= super::CONTEXT_MAX_CONTEXTS { - self.next_id = min; - } - - while self.map.contains_key(&ContextId::from(self.next_id)) { - self.next_id += 1; - } - - if self.next_id >= super::CONTEXT_MAX_CONTEXTS { - return Err(Error::new(EAGAIN)); - } - - let id = ContextId::from(self.next_id); - self.next_id += 1; - - self.insert_context_raw(id, pid, process) - } - - /// Spawn a context from a function. - pub fn spawn( - &mut self, - userspace_allowed: bool, - process: Arc>, - func: extern "C" fn(), - ) -> Result<&Arc>> { - let stack = Kstack::new()?; - - let context_lock = self.new_context(Arc::clone(&process))?; - process.write().threads.push(Arc::downgrade(&context_lock)); - { - let mut context = context_lock.write(); - let _ = context.set_addr_space(Some(AddrSpaceWrapper::new()?)); - - let mut stack_top = stack.initial_top(); - - const INT_REGS_SIZE: usize = core::mem::size_of::(); - - if userspace_allowed { - unsafe { - // Zero-initialize InterruptStack registers. - stack_top = stack_top.sub(INT_REGS_SIZE); - stack_top.write_bytes(0_u8, INT_REGS_SIZE); - (&mut *stack_top.cast::()).init(); - } - } - #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - unsafe { - if userspace_allowed { - stack_top = stack_top.sub(core::mem::size_of::()); - stack_top - .cast::() - .write(crate::interrupt::syscall::enter_usermode as usize); - } - - stack_top = stack_top.sub(core::mem::size_of::()); - stack_top.cast::().write(func as usize); - } - - #[cfg(target_arch = "aarch64")] - unsafe { - context - .arch - .set_lr(crate::interrupt::syscall::enter_usermode as usize); - context.arch.set_x28(func as usize); - context.arch.set_context_handle(); - } - - context.arch.set_stack(stack_top as usize); - - context.kstack = Some(stack); - context.userspace = userspace_allowed; - } - Ok(context_lock) - } - - pub fn remove(&mut self, id: ContextId) -> Option>> { - self.map.remove(&id) - } -} diff --git a/src/context/memory.rs b/src/context/memory.rs index b048faec3f..fa14b57256 100644 --- a/src/context/memory.rs +++ b/src/context/memory.rs @@ -2712,7 +2712,7 @@ fn correct_inner<'l>( .request_fmap(scheme_number, offset, 1, flags) .unwrap(); - let context_lock = super::current().map_err(|_| PfError::NonfatalInternalError)?; + let context_lock = crate::context::current(); context_lock .write() .hard_block(HardBlockedReason::AwaitingMmap { file_ref }); diff --git a/src/context/mod.rs b/src/context/mod.rs index 46dad92aeb..6f6e7f9481 100644 --- a/src/context/mod.rs +++ b/src/context/mod.rs @@ -2,23 +2,33 @@ //! //! For resources on contexts, please consult [wikipedia](https://en.wikipedia.org/wiki/Context_switch) and [osdev](https://wiki.osdev.org/Context_Switching) -use alloc::{borrow::Cow, sync::Arc, vec::Vec}; +use alloc::{ + borrow::Cow, + collections::BTreeSet, + sync::{Arc, Weak}, + vec::Vec, +}; -use spin::{RwLock, RwLockReadGuard, RwLockWriteGuard}; +use spin::{Once, RwLock, RwLockReadGuard, RwLockWriteGuard}; use spinning_top::RwSpinlock; +use syscall::ENOMEM; use crate::{ + context::memory::AddrSpaceWrapper, cpu_set::LogicalCpuSet, + interrupt::InterruptStack, paging::{RmmA, RmmArch, TableKind}, percpu::PercpuBlock, sync::WaitMap, - syscall::error::{Error, Result, ESRCH}, + syscall::error::{Error, Result}, }; -use self::process::{Process, ProcessId, ProcessInfo}; +use self::{ + context::Kstack, + process::{Process, ProcessId, ProcessInfo}, +}; pub use self::{ - context::{BorrowedHtBuf, Context, ContextId, Status, WaitpidKey}, - list::ContextList, + context::{BorrowedHtBuf, Context, Status, WaitpidKey}, switch::switch, }; @@ -37,9 +47,6 @@ mod arch; /// Context struct pub mod context; -/// Context list -mod list; - /// Context switch function pub mod switch; @@ -60,32 +67,29 @@ pub mod timeout; pub use self::switch::switch_finish_hook; -/// Limit on number of contexts -pub const CONTEXT_MAX_CONTEXTS: usize = (isize::max_value() as usize) - 1; - /// Maximum context files pub const CONTEXT_MAX_FILES: usize = 65_536; -/// Contexts list -static CONTEXTS: RwLock = RwLock::new(ContextList::new()); - pub use self::arch::empty_cr3; +static KMAIN_PROCESS: Once>> = Once::new(); + +// Set of weak references to all contexts available for scheduling. The only strong references are +// the context file descriptors. +static CONTEXTS: RwLock> = RwLock::new(BTreeSet::new()); + pub fn init() { - let mut contexts = contexts_mut(); - let id = ContextId::from(crate::cpu_id().get() as usize + 1); - let pid = ProcessId::new(0); - let process = Arc::new(RwLock::new(Process { - info: ProcessInfo::default(), - waitpid: Arc::new(WaitMap::new()), - threads: Vec::new(), - })); + let process = KMAIN_PROCESS.call_once(|| { + Arc::new(RwLock::new(Process { + info: ProcessInfo::default(), + waitpid: Arc::new(WaitMap::new()), + threads: Vec::new(), + })) + }); - let context_lock = contexts - .insert_context_raw(id, pid, process) - .expect("could not initialize first context"); - let mut context = context_lock.write(); + let mut context = + Context::new(pid, Arc::clone(process)).expect("failed to create kmain context"); context.sched_affinity = LogicalCpuSet::empty(); context.sched_affinity.atomic_set(crate::cpu_id()); context.name = Cow::Borrowed("kmain"); @@ -96,33 +100,126 @@ pub fn init() { context.running = true; context.cpu_id = Some(crate::cpu_id()); + let context_lock = Arc::new(RwSpinlock::new(context)); + + CONTEXTS + .write() + .insert(ContextRef(Arc::downgrade(&context_lock))); + unsafe { let percpu = PercpuBlock::current(); - percpu.switch_internals.set_current_cid(context.cid); - percpu.switch_internals.set_idle_id(context.cid); + percpu + .switch_internals + .set_current_context(Arc::clone(&context_lock)); + percpu.switch_internals.set_idle_context(context_lock); } } /// Get the global schemes list, const -pub fn contexts() -> RwLockReadGuard<'static, ContextList> { +pub fn contexts() -> RwLockReadGuard<'static, BTreeSet> { CONTEXTS.read() } /// Get the global schemes list, mutable -pub fn contexts_mut() -> RwLockWriteGuard<'static, ContextList> { +pub fn contexts_mut() -> RwLockWriteGuard<'static, BTreeSet> { CONTEXTS.write() } -pub fn current_cid() -> ContextId { - PercpuBlock::current().switch_internals.current_cid() +pub fn current() -> Arc> { + PercpuBlock::current() + .switch_internals + .with_context(|context| Arc::clone(context)) } -pub fn current_pid() -> Result { - Ok(current()?.read().pid) +pub fn is_current(context: &Arc>) -> bool { + PercpuBlock::current() + .switch_internals + .with_context(|current| Arc::ptr_eq(context, current)) } -pub fn current() -> Result>> { - contexts() - .current() - .ok_or(Error::new(ESRCH)) - .map(Arc::clone) +pub fn current_pid() -> Result { + Ok(current().read().pid) +} + +pub struct ContextRef(pub Weak>); + +impl Ord for ContextRef { + fn cmp(&self, other: &Self) -> core::cmp::Ordering { + Ord::cmp(&self.0.as_ptr(), &other.0.as_ptr()) + } +} +impl PartialOrd for ContextRef { + fn partial_cmp(&self, other: &Self) -> Option { + Some(Ord::cmp(self, other)) + } +} +impl PartialEq for ContextRef { + fn eq(&self, other: &Self) -> bool { + Ord::cmp(self, other) == core::cmp::Ordering::Equal + } +} +impl Eq for ContextRef {} + +/// Spawn a context from a function. +pub fn spawn( + userspace_allowed: bool, + process: Arc>, + func: extern "C" fn(), +) -> Result>> { + let stack = Kstack::new()?; + + let context_lock = Arc::try_new(RwSpinlock::new(Context::new( + process.read().pid, + Arc::clone(&process), + )?)) + .map_err(|_| Error::new(ENOMEM))?; + + CONTEXTS + .write() + .insert(ContextRef(Arc::downgrade(&context_lock))); + + process.write().threads.push(Arc::downgrade(&context_lock)); + { + let mut context = context_lock.write(); + let _ = context.set_addr_space(Some(AddrSpaceWrapper::new()?)); + + let mut stack_top = stack.initial_top(); + + const INT_REGS_SIZE: usize = core::mem::size_of::(); + + if userspace_allowed { + unsafe { + // Zero-initialize InterruptStack registers. + stack_top = stack_top.sub(INT_REGS_SIZE); + stack_top.write_bytes(0_u8, INT_REGS_SIZE); + (&mut *stack_top.cast::()).init(); + } + } + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + unsafe { + if userspace_allowed { + stack_top = stack_top.sub(core::mem::size_of::()); + stack_top + .cast::() + .write(crate::interrupt::syscall::enter_usermode as usize); + } + + stack_top = stack_top.sub(core::mem::size_of::()); + stack_top.cast::().write(func as usize); + } + + #[cfg(target_arch = "aarch64")] + unsafe { + context + .arch + .set_lr(crate::interrupt::syscall::enter_usermode as usize); + context.arch.set_x28(func as usize); + context.arch.set_context_handle(); + } + + context.arch.set_stack(stack_top as usize); + + context.kstack = Some(stack); + context.userspace = userspace_allowed; + } + Ok(context_lock) } diff --git a/src/context/process.rs b/src/context/process.rs index ed9808b9a6..fe63d07114 100644 --- a/src/context/process.rs +++ b/src/context/process.rs @@ -91,7 +91,7 @@ pub fn ancestors( } pub fn current() -> Result>> { - let pid = context::current()?.read().pid; + let pid = context::current().read().pid; Ok(Arc::clone( PROCESSES.read().get(&pid).ok_or(Error::new(ESRCH))?, )) diff --git a/src/context/signal.rs b/src/context/signal.rs index 35be3c0a44..78828c0a09 100644 --- a/src/context/signal.rs +++ b/src/context/signal.rs @@ -6,7 +6,7 @@ use crate::{ }; pub fn signal_handler() { - let context_lock = context::current().expect("running signal handler outside of context"); + let context_lock = context::current(); let mut context = context_lock.write(); let context = &mut *context; @@ -71,7 +71,7 @@ pub fn signal_handler() { ); } pub fn excp_handler(_signal: usize) { - let current = context::current().expect("CPU exception but not inside of context!"); + let current = context::current(); let context = current.write(); let Some(_eh) = context.sig.as_ref().and_then(|s| s.excp_handler) else { diff --git a/src/context/switch.rs b/src/context/switch.rs index ac9cbcfbe9..6754a50a48 100644 --- a/src/context/switch.rs +++ b/src/context/switch.rs @@ -1,7 +1,12 @@ -use core::{cell::Cell, mem, ops::Bound, sync::atomic::Ordering}; +use core::{ + cell::{Cell, RefCell}, + mem, + ops::Bound, + sync::atomic::Ordering, +}; use alloc::sync::Arc; -use spinning_top::guard::ArcRwSpinlockWriteGuard; +use spinning_top::{guard::ArcRwSpinlockWriteGuard, RwSpinlock}; use syscall::PtraceFlags; use crate::{ @@ -12,7 +17,7 @@ use crate::{ ptrace, time, }; -use super::ContextId; +use super::ContextRef; enum UpdateResult { CanSwitch, @@ -116,31 +121,32 @@ pub fn switch() -> SwitchResult { let contexts = contexts(); // Lock previous context - let prev_context_lock = contexts - .current() - .expect("context::switch: not inside of context"); + let prev_context_lock = crate::context::current(); let prev_context_guard = prev_context_lock.write_arc(); - let idle_id = percpu.switch_internals.idle_id(); + let idle_context = percpu.switch_internals.idle_context(); let mut skip_idle = true; // Locate next context - for (cid, next_context_lock) in contexts + for next_context_lock in contexts // Include all contexts with IDs greater than the current... - .range((Bound::Excluded(prev_context_guard.cid), Bound::Unbounded)) + .range(( + Bound::Excluded(ContextRef(Arc::downgrade(&prev_context_lock))), + Bound::Unbounded, + )) .chain( contexts // ... and all contexts with IDs less than the current... - .range((Bound::Unbounded, Bound::Excluded(prev_context_guard.cid))), - ) - .chain( - contexts - // ... and finally the idle ID - .range((Bound::Included(idle_id), Bound::Included(idle_id))), + .range(( + Bound::Unbounded, + Bound::Excluded(ContextRef(Arc::downgrade(&prev_context_lock))), + )), ) + .filter_map(|r| r.0.upgrade()) + .chain(Some(Arc::clone(&idle_context))) // ... but not the current context, which is already locked { - if cid == &idle_id && skip_idle { + if Arc::ptr_eq(&next_context_lock, &idle_context) && skip_idle { // Skip idle process the first time it shows up skip_idle = false; continue; @@ -178,7 +184,11 @@ pub fn switch() -> SwitchResult { next_context.switch_time = switch_time; let percpu = PercpuBlock::current(); - percpu.switch_internals.current_cid.set(next_context.cid); + unsafe { + percpu.switch_internals.set_current_context(Arc::clone( + ArcRwSpinlockWriteGuard::rwlock(&next_context_guard), + )); + } // FIXME set th switch result in arch::switch_to instead let prev_context = @@ -245,25 +255,33 @@ pub struct ContextSwitchPercpu { switch_result: Cell>, pit_ticks: Cell, - /// Unique context ID of the currently running context. - current_cid: Cell, + current_ctxt: RefCell>>>, - // The ID of the idle process - idle_id: Cell, + // The idle process + idle_ctxt: RefCell>>>, pub(crate) being_sigkilled: Cell, } impl ContextSwitchPercpu { - pub fn current_cid(&self) -> ContextId { - self.current_cid.get() + pub fn with_context(&self, f: impl FnOnce(&Arc>) -> T) -> T { + f(&*self + .current_ctxt + .borrow() + .as_ref() + .expect("not inside of context")) } - pub unsafe fn set_current_cid(&self, new: ContextId) { - self.current_cid.set(new) + pub unsafe fn set_current_context(&self, new: Arc>) { + *self.current_ctxt.borrow_mut() = Some(new); } - pub fn idle_id(&self) -> ContextId { - self.idle_id.get() + pub unsafe fn set_idle_context(&self, new: Arc>) { + *self.idle_ctxt.borrow_mut() = Some(new); } - pub unsafe fn set_idle_id(&self, new: ContextId) { - self.idle_id.set(new) + pub fn idle_context(&self) -> Arc> { + Arc::clone( + self.idle_ctxt + .borrow() + .as_ref() + .expect("no idle context present"), + ) } } diff --git a/src/event.rs b/src/event.rs index a8506f25a5..6727401014 100644 --- a/src/event.rs +++ b/src/event.rs @@ -9,7 +9,7 @@ use crate::{ sync::WaitQueue, syscall::{ data::Event, - error::{Error, Result, EBADF, ESRCH}, + error::{Error, Result, EBADF}, flag::EventFlags, usercopy::UserSliceWo, }, @@ -37,9 +37,9 @@ impl EventQueue { pub fn write(&self, events: &[Event]) -> Result { for event in events { let file = { - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; - let context = context_lock.read(); + let context_ref = context::current(); + let context = context_ref.read(); + let files = context.files.read(); match files.get(event.id).ok_or(Error::new(EBADF))? { Some(file) => file.clone(), diff --git a/src/main.rs b/src/main.rs index 03f9029212..b0de6880fb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -117,6 +117,8 @@ mod externs; /// Logging mod log; use ::log::info; +use alloc::sync::Arc; +use spinning_top::RwSpinlock; /// Memory management mod memory; @@ -183,6 +185,7 @@ struct Bootstrap { env: &'static [u8], } static BOOTSTRAP: spin::Once = spin::Once::new(); +static INIT_THREAD: spin::Once>> = spin::Once::new(); /// This is the kernel entry point for the primary CPU. The arch crate is responsible for calling this fn kmain(cpu_count: u32, bootstrap: Bootstrap) -> ! { @@ -218,15 +221,18 @@ fn kmain(cpu_count: u32, bootstrap: Bootstrap) -> ! { }) .expect("failed to create init process"); - match context::contexts_mut().spawn(true, process, userspace_init) { + match context::spawn(true, process, userspace_init) { Ok(context_lock) => { - let mut context = context_lock.write(); - context.status = context::Status::Runnable; - context.name = "bootstrap".into(); + { + let mut context = context_lock.write(); + context.status = context::Status::Runnable; + context.name = "bootstrap".into(); - let mut process = context.process.write(); - process.rns = SchemeNamespace::from(1); - process.ens = SchemeNamespace::from(1); + let mut process = context.process.write(); + process.rns = SchemeNamespace::from(1); + process.ens = SchemeNamespace::from(1); + } + INIT_THREAD.call_once(move || context_lock); } Err(err) => { panic!("failed to spawn userspace_init: {:?}", err); @@ -282,18 +288,12 @@ fn run_userspace() -> ! { /// Allow exception handlers to send signal to arch-independent kernel pub fn ksignal(signal: usize) { - info!( - "SIGNAL {}, CPU {}, PID {:?}", - signal, - cpu_id(), - context::current_cid() - ); + let current = context::current(); + + info!("SIGNAL {signal}, CPU {}, PID {current:p}", cpu_id(),); { - let contexts = context::contexts(); - if let Some(context_lock) = contexts.current() { - let context = context_lock.read(); - info!("NAME {}", context.name); - } + let context = current.read(); + info!("NAME {}", context.name); } crate::context::signal::excp_handler(signal); } diff --git a/src/panic.rs b/src/panic.rs index 0e555b6e16..92cb9879f2 100644 --- a/src/panic.rs +++ b/src/panic.rs @@ -12,19 +12,17 @@ fn rust_begin_unwind(info: &PanicInfo) -> ! { unsafe { interrupt::stack_trace(); } + let context_lock = context::current(); - println!("CPU {}, CID {:?}", cpu_id(), context::current_cid()); + println!("CPU {}, CID {:p}", cpu_id(), context_lock); // This could deadlock, but at this point we are going to halt anyways { - let contexts = context::contexts(); - if let Some(context_lock) = contexts.current() { - let context = context_lock.read(); - println!("NAME: {}", context.name); + let context = context_lock.read(); + println!("NAME: {}", context.name); - if let Some([a, b, c, d, e, f]) = context.current_syscall() { - println!("SYSCALL: {}", syscall::debug::format_call(a, b, c, d, e, f)); - } + if let Some([a, b, c, d, e, f]) = context.current_syscall() { + println!("SYSCALL: {}", syscall::debug::format_call(a, b, c, d, e, f)); } } diff --git a/src/ptrace.rs b/src/ptrace.rs index b44faade6d..3cbc12c347 100644 --- a/src/ptrace.rs +++ b/src/ptrace.rs @@ -171,12 +171,7 @@ fn proc_trigger_event(file_id: usize, flags: EventFlags) { /// the tracer to wake up and poll for events. Returns Some(()) if an /// event was sent. pub fn send_event(event: PtraceEvent) -> Option<()> { - let id = { - let contexts = context::contexts(); - let context = contexts.current()?; - let context = context.read(); - context.pid - }; + let id = context::current().read().pid; let sessions = sessions(); let session = sessions.get(&id)?; @@ -290,9 +285,8 @@ pub fn breakpoint_callback( /// Obtain the next breakpoint flags for the current process. This is used for /// detecting whether or not the tracer decided to use sysemu mode. pub fn next_breakpoint() -> Option { - let contexts = context::contexts(); - let context = contexts.current()?; - let context = context.read(); + let context_lock = context::current(); + let context = context_lock.read(); let sessions = sessions(); let session = sessions.get(&context.pid)?; diff --git a/src/scheme/proc.rs b/src/scheme/proc.rs index 060513f240..49aafd62d7 100644 --- a/src/scheme/proc.rs +++ b/src/scheme/proc.rs @@ -3,11 +3,10 @@ use crate::{ context::{ self, context::{HardBlockedReason, SignalState}, - contexts, file::{FileDescriptor, InternalFlags}, memory::{handle_notify_files, AddrSpaceWrapper, Grant, PageSpan}, process::{self, Process, ProcessId, ProcessInfo}, - Context, ContextId, Status, + Context, Status, }, memory::PAGE_SIZE, ptrace, @@ -49,40 +48,18 @@ fn read_from(dst: UserSliceWo, src: &[u8], offset: u64) -> Result { dst.copy_common_bytes_from_slice(avail_src) } -fn with_context(pid: ContextId, callback: F) -> Result -where - F: FnOnce(&Context) -> Result, -{ - let contexts = context::contexts(); - let context = contexts.get(pid).ok_or(Error::new(ESRCH))?; - let context = context.read(); - if let Status::Exited(_) = context.status { - return Err(Error::new(ESRCH)); - } - callback(&context) -} -fn with_context_mut(pid: ContextId, callback: F) -> Result -where - F: FnOnce(&mut Context) -> Result, -{ - let contexts = context::contexts(); - let context = contexts.get(pid).ok_or(Error::new(ESRCH))?; - let mut context = context.write(); - if let Status::Exited(_) = context.status { - return Err(Error::new(ESRCH)); - } - callback(&mut context) -} -fn try_stop_context(pid: ContextId, callback: F) -> Result -where - F: FnOnce(&mut Context) -> Result, -{ - if pid == context::current_cid() { - return Err(Error::new(EBADF)); +fn try_stop_context( + context_ref: Arc>, + callback: impl FnOnce(&mut Context) -> Result, +) -> Result { + if context::is_current(&context_ref) { + return callback(&mut *context_ref.write()); } // Stop process - let (prev_status, mut running) = with_context_mut(pid, |context| { - Ok(( + let (prev_status, mut running) = { + let mut context = context_ref.write(); + + ( core::mem::replace( &mut context.status, context::Status::HardBlocked { @@ -90,28 +67,27 @@ where }, ), context.running, - )) - })?; + ) + }; // Wait until stopped while running { context::switch(); - running = with_context(pid, |context| Ok(context.running))?; + running = context_ref.read().running; } - with_context_mut(pid, |context| { - assert!( - !context.running, - "process can't have been restarted, we stopped it!" - ); + let mut context = context_ref.write(); + assert!( + !context.running, + "process can't have been restarted, we stopped it!" + ); - let ret = callback(context); + let ret = callback(&mut *context); - context.status = prev_status; + context.status = prev_status; - ret - }) + ret } #[derive(Clone, Copy, PartialEq, Eq)] @@ -257,15 +233,9 @@ fn new_handle((handle, fl): (Handle, InternalFlags)) -> Result<(usize, InternalF Ok((id, fl)) } -fn get_context(id: ContextId) -> Result>> { - context::contexts() - .get(id) - .ok_or(Error::new(ENOENT)) - .map(Arc::clone) -} enum OpenTy { Proc(ProcessId), - Ctxt(ContextId), + Ctxt(Arc>), } impl ProcScheme { @@ -366,13 +336,7 @@ impl ProcScheme { let processes = process::PROCESSES.read(); Arc::clone(processes.get(&pid).ok_or(Error::new(ESRCH))?) } - OpenTy::Ctxt(cid) => Arc::clone( - &context::contexts() - .get(cid) - .ok_or(Error::new(ESRCH))? - .read() - .process, - ), + OpenTy::Ctxt(ref context) => Arc::clone(&context.read().process), }; let operation_name = operation_str.ok_or(Error::new(EINVAL))?; @@ -394,9 +358,7 @@ impl ProcScheme { .ok_or(Error::new(ESRCH))? .upgrade() .ok_or(Error::new(ESRCH))?, - OpenTy::Ctxt(ctxt) => { - Arc::clone(contexts().get(ctxt).ok_or(Error::new(ESRCH))?) - } + OpenTy::Ctxt(ref ctxt) => Arc::clone(&ctxt), }; if let Some((kind, positioned)) = self.openat_context(operation_name, Arc::clone(&context))? @@ -522,7 +484,7 @@ impl KernelScheme for ProcScheme { let pid_str = parts.next().ok_or(Error::new(ENOENT))?; let pid = if pid_str == "current" { - OpenTy::Ctxt(context::current_cid()) + OpenTy::Ctxt(context::current()) } else if pid_str == "new" || pid_str == "new-child" { OpenTy::Ctxt(new_child()?) } else if pid_str == "new-thread" { @@ -530,7 +492,7 @@ impl KernelScheme for ProcScheme { } else if !FULL { return Err(Error::new(EACCES)); } else { - OpenTy::Ctxt(ContextId::new( + OpenTy::Proc(ProcessId::new( pid_str.parse().map_err(|_| Error::new(ENOENT))?, )) }; @@ -568,15 +530,7 @@ impl KernelScheme for ProcScheme { new_ip, }, } => { - let cid = context.read().cid; - - let stop_context = if cid == context::current_cid() { - with_context_mut - } else { - try_stop_context - }; - - let _ = stop_context(cid, |context: &mut Context| { + let _ = try_stop_context(context, |context: &mut Context| { let regs = context.regs_mut().ok_or(Error::new(EBADFD))?; regs.set_instr_pointer(new_ip); regs.set_stack_pointer(new_sp); @@ -631,7 +585,7 @@ impl KernelScheme for ProcScheme { consume: bool, ) -> Result { let handle = HANDLES.read().get(&id).ok_or(Error::new(EBADF))?.clone(); - let Handle::Context { context, kind } = handle else { + let Handle::Context { kind, .. } = handle else { return Err(Error::new(EBADF)); }; @@ -841,10 +795,9 @@ impl KernelScheme for ProcScheme { let (uid, gid) = match &*process::current()?.read() { process => (process.euid, process.egid), }; - let cid = context.read().cid; return self .open_inner( - OpenTy::Ctxt(cid), + OpenTy::Ctxt(context), Some(core::str::from_utf8(buf).map_err(|_| Error::new(EINVAL))?) .filter(|s| !s.is_empty()), O_RDWR | O_CLOEXEC, @@ -943,53 +896,40 @@ extern "C" fn clone_handler() { // usermode. } -fn new_thread() -> Result { +fn new_thread() -> Result>> { let current_process = process::current()?; - let new_context = - Arc::clone(context::contexts_mut().spawn(true, current_process, clone_handler)?); - let cid = new_context.read().cid; - Ok(cid) + context::spawn(true, current_process, clone_handler) } -fn new_child() -> Result { - let new_id = { +fn new_child() -> Result>> { + let new_context = { let current_process_info = process::current()?.read().info; let new_process = process::new_process(|new_pid| ProcessInfo { pid: new_pid, ppid: current_process_info.pid, ..current_process_info })?; - let new_context_lock = - Arc::clone(context::contexts_mut().spawn(true, new_process, clone_handler)?); - let new_context = new_context_lock.read(); - - new_context.cid + context::spawn(true, new_process, clone_handler)? }; if ptrace::send_event(crate::syscall::ptrace_event!( PTRACE_EVENT_CLONE, - new_id.into() + new_context.read().pid.into() )) .is_some() { // Freeze the clone, allow ptrace to put breakpoints // to it before it starts - let contexts = context::contexts(); - let context = contexts - .get(new_id) - .expect("Newly created context doesn't exist??"); - let mut context = context.write(); + let mut context = new_context.write(); context.status = context::Status::HardBlocked { reason: HardBlockedReason::PtraceStop, }; } - Ok(new_id) + Ok(new_context) } fn extract_scheme_number(fd: usize) -> Result<(KernelSchemes, usize)> { - let (scheme_id, number) = match &*context::contexts() - .current() - .ok_or(Error::new(ESRCH))? + let (scheme_id, number) = match &*context::current() .read() .get_file(FileHandle::from(fd)) .ok_or(Error::new(EBADF))? @@ -1052,9 +992,7 @@ impl ProcHandle { .threads .first() .and_then(|f| f.upgrade()) - .ok_or(Error::new(ESRCH))? - .read() - .cid; + .ok_or(Error::new(ESRCH))?; if op.contains(PTRACE_STOP_SINGLESTEP) { try_stop_context(first, |context| match context.regs_mut() { @@ -1140,11 +1078,7 @@ impl ProcHandle { read_flags: u32, ) -> Result { match self { - Self::Static { bytes, .. } => { - let mut handles = HANDLES.write(); - let handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; - read_from(buf, &bytes, offset) - } + Self::Static { bytes, .. } => read_from(buf, &bytes, offset), Self::Trace { pid, clones, .. } => { // Wait for event if (read_flags as usize) & O_NONBLOCK != O_NONBLOCK { @@ -1277,8 +1211,7 @@ impl ContextHandle { RegsKind::Float => { let regs = unsafe { buf.read_exact::()? }; - let cid = context.read().cid; - try_stop_context(cid, |context| { + try_stop_context(context, |context| { // NOTE: The kernel will never touch floats // Ignore the rare case of floating point @@ -1291,8 +1224,7 @@ impl ContextHandle { RegsKind::Int => { let regs = unsafe { buf.read_exact::()? }; - let cid = context.read().cid; - try_stop_context(cid, |context| match context.regs_mut() { + try_stop_context(context, |context| match context.regs_mut() { None => { println!( "{}:{}: Couldn't read registers from stopped process", @@ -1310,8 +1242,7 @@ impl ContextHandle { } RegsKind::Env => { let regs = unsafe { buf.read_exact::()? }; - let cid = context.read().cid; - write_env_regs(cid, regs)?; + write_env_regs(context, regs)?; Ok(mem::size_of::()) } }, @@ -1511,35 +1442,28 @@ impl ContextHandle { mem::size_of::(), ) } - RegsKind::Int => { - let cid = context.read().cid; - try_stop_context(cid, |context| match context.regs() { - None => { - assert!(!context.running, "try_stop_context is broken, clearly"); - println!( - "{}:{}: Couldn't read registers from stopped process", - file!(), - line!() - ); - Err(Error::new(ENOTRECOVERABLE)) - } - Some(stack) => { - let mut regs = IntRegisters::default(); - stack.save(&mut regs); - Ok((Output { int: regs }, mem::size_of::())) - } - })? - } - RegsKind::Env => { - let cid = context.read().cid; - - ( - Output { - env: read_env_regs(cid)?, - }, - mem::size_of::(), - ) - } + RegsKind::Int => try_stop_context(context, |context| match context.regs() { + None => { + assert!(!context.running, "try_stop_context is broken, clearly"); + println!( + "{}:{}: Couldn't read registers from stopped process", + file!(), + line!() + ); + Err(Error::new(ENOTRECOVERABLE)) + } + Some(stack) => { + let mut regs = IntRegisters::default(); + stack.save(&mut regs); + Ok((Output { int: regs }, mem::size_of::())) + } + })?, + RegsKind::Env => ( + Output { + env: read_env_regs(context)?, + }, + mem::size_of::(), + ), }; let src_buf = @@ -1604,16 +1528,16 @@ impl ContextHandle { } } #[cfg(target_arch = "aarch64")] -fn write_env_regs(&self, info: &Info, regs: EnvRegisters) -> Result<()> { +fn write_env_regs(context: Arc>, regs: EnvRegisters) -> Result<()> { use crate::device::cpu::registers::control_regs; - if info.pid == context::context_id() { + if context::is_current(&context) { unsafe { control_regs::tpidr_el0_write(regs.tpidr_el0 as u64); control_regs::tpidrro_el0_write(regs.tpidrro_el0 as u64); } } else { - try_stop_context(info.pid, |context| { + try_stop_context(context, |context| { context.arch.tpidr_el0 = regs.tpidr_el0; context.arch.tpidrro_el0 = regs.tpidrro_el0; Ok(()) @@ -1623,24 +1547,19 @@ fn write_env_regs(&self, info: &Info, regs: EnvRegisters) -> Result<()> { } #[cfg(target_arch = "x86")] -fn write_env_regs(&self, info: &Info, regs: EnvRegisters) -> Result<()> { +fn write_env_regs(context: Arc>, regs: EnvRegisters) -> Result<()> { if !(RmmA::virt_is_valid(VirtualAddress::new(regs.fsbase as usize)) && RmmA::virt_is_valid(VirtualAddress::new(regs.gsbase as usize))) { return Err(Error::new(EINVAL)); } - if info.pid == context::context_id() { + if context::is_current(&context) { unsafe { (&mut *crate::gdt::pcr()).gdt[crate::gdt::GDT_USER_FS].set_offset(regs.fsbase); (&mut *crate::gdt::pcr()).gdt[crate::gdt::GDT_USER_GS].set_offset(regs.gsbase); - match context::contexts() - .current() - .ok_or(Error::new(ESRCH))? - .write() - .arch - { + match context.write().arch { ref mut arch => { arch.fsbase = regs.fsbase as usize; arch.gsbase = regs.gsbase as usize; @@ -1648,7 +1567,7 @@ fn write_env_regs(&self, info: &Info, regs: EnvRegisters) -> Result<()> { } } } else { - try_stop_context(info.pid, |context| { + try_stop_context(context, |context| { context.arch.fsbase = regs.fsbase as usize; context.arch.gsbase = regs.gsbase as usize; Ok(()) @@ -1658,26 +1577,21 @@ fn write_env_regs(&self, info: &Info, regs: EnvRegisters) -> Result<()> { } #[cfg(target_arch = "x86_64")] -fn write_env_regs(cid: ContextId, regs: EnvRegisters) -> Result<()> { +fn write_env_regs(context: Arc>, regs: EnvRegisters) -> Result<()> { if !(RmmA::virt_is_valid(VirtualAddress::new(regs.fsbase as usize)) && RmmA::virt_is_valid(VirtualAddress::new(regs.gsbase as usize))) { return Err(Error::new(EINVAL)); } - if cid == context::current_cid() { + if context::is_current(&context) { unsafe { x86::msr::wrmsr(x86::msr::IA32_FS_BASE, regs.fsbase as u64); // We have to write to KERNEL_GSBASE, because when the kernel returns to // userspace, it will have executed SWAPGS first. x86::msr::wrmsr(x86::msr::IA32_KERNEL_GSBASE, regs.gsbase as u64); - match context::contexts() - .current() - .ok_or(Error::new(ESRCH))? - .write() - .arch - { + match context::current().write().arch { ref mut arch => { arch.fsbase = regs.fsbase as usize; arch.gsbase = regs.gsbase as usize; @@ -1685,7 +1599,7 @@ fn write_env_regs(cid: ContextId, regs: EnvRegisters) -> Result<()> { } } } else { - try_stop_context(cid, |context| { + try_stop_context(context, |context| { context.arch.fsbase = regs.fsbase as usize; context.arch.gsbase = regs.gsbase as usize; Ok(()) @@ -1694,10 +1608,10 @@ fn write_env_regs(cid: ContextId, regs: EnvRegisters) -> Result<()> { Ok(()) } #[cfg(target_arch = "aarch64")] -fn read_env_regs(&self, info: &Info) -> Result { +fn read_env_regs(context: Arc>) -> Result { use crate::device::cpu::registers::control_regs; - let (tpidr_el0, tpidrro_el0) = if info.pid == context::context_id() { + let (tpidr_el0, tpidrro_el0) = if context::is_current(&context) { unsafe { ( control_regs::tpidr_el0() as usize, @@ -1705,7 +1619,7 @@ fn read_env_regs(&self, info: &Info) -> Result { ) } } else { - try_stop_context(info.pid, |context| { + try_stop_context(context, |context| { Ok((context.arch.tpidr_el0, context.arch.tpidrro_el0)) })? }; @@ -1716,8 +1630,8 @@ fn read_env_regs(&self, info: &Info) -> Result { } #[cfg(target_arch = "x86")] -fn read_env_regs(&self, info: &Info) -> Result { - let (fsbase, gsbase) = if info.pid == context::context_id() { +fn read_env_regs(context: Arc>) -> Result { + let (fsbase, gsbase) = if context::is_current(&context) { unsafe { ( (&*crate::gdt::pcr()).gdt[crate::gdt::GDT_USER_FS].offset() as u64, @@ -1725,7 +1639,7 @@ fn read_env_regs(&self, info: &Info) -> Result { ) } } else { - try_stop_context(info.pid, |context| { + try_stop_context(context, |context| { Ok((context.arch.fsbase as u64, context.arch.gsbase as u64)) })? }; @@ -1736,9 +1650,9 @@ fn read_env_regs(&self, info: &Info) -> Result { } #[cfg(target_arch = "x86_64")] -fn read_env_regs(cid: ContextId) -> Result { +fn read_env_regs(context: Arc>) -> Result { // TODO: Avoid rdmsr if fsgsbase is not enabled, if this is worth optimizing for. - let (fsbase, gsbase) = if cid == context::current_cid() { + let (fsbase, gsbase) = if context::is_current(&context) { unsafe { ( x86::msr::rdmsr(x86::msr::IA32_FS_BASE), @@ -1746,7 +1660,7 @@ fn read_env_regs(cid: ContextId) -> Result { ) } } else { - try_stop_context(cid, |context| { + try_stop_context(context, |context| { Ok((context.arch.fsbase as u64, context.arch.gsbase as u64)) })? }; diff --git a/src/scheme/root.rs b/src/scheme/root.rs index 5e5d991f66..08a2fa1c69 100644 --- a/src/scheme/root.rs +++ b/src/scheme/root.rs @@ -77,11 +77,7 @@ impl KernelScheme for RootScheme { return Err(Error::new(EINVAL)); } - let context = { - let contexts = context::contexts(); - let context = contexts.current().ok_or(Error::new(ESRCH))?; - Arc::downgrade(context) - }; + let context = Arc::downgrade(&context::current()); let id = self.next_id.fetch_add(1, Ordering::Relaxed); diff --git a/src/scheme/sys/block.rs b/src/scheme/sys/block.rs index b792cf02fb..cd281eb99a 100644 --- a/src/scheme/sys/block.rs +++ b/src/scheme/sys/block.rs @@ -10,9 +10,13 @@ pub fn resource() -> Result> { let mut rows = Vec::new(); { let contexts = context::contexts(); - for (id, context_lock) in contexts.iter() { + for context_lock in contexts.iter().filter_map(|r| r.0.upgrade()) { let context = context_lock.read(); - rows.push((*id, context.name.clone(), context.status_reason)); + rows.push(( + context.pid.get(), + context.name.clone(), + context.status_reason, + )); } } diff --git a/src/scheme/sys/context.rs b/src/scheme/sys/context.rs index 80cd3cabc9..3d5fdc2441 100644 --- a/src/scheme/sys/context.rs +++ b/src/scheme/sys/context.rs @@ -27,8 +27,8 @@ pub fn resource() -> Result> { ); { let contexts = context::contexts(); - for (_id, context_lock) in contexts.iter() { - let context = context_lock.read(); + for context_ref in contexts.iter().filter_map(|r| r.0.upgrade()) { + let context = context_ref.read(); let mut stat_string = String::new(); // TODO: All user programs must have some grant in order for executable memory to even diff --git a/src/scheme/sys/exe.rs b/src/scheme/sys/exe.rs index bbf2d35a49..e917f93b9b 100644 --- a/src/scheme/sys/exe.rs +++ b/src/scheme/sys/exe.rs @@ -3,7 +3,7 @@ use alloc::vec::Vec; use crate::{context, syscall::error::Result}; pub fn resource() -> Result> { - Ok(context::current()? + Ok(context::current() .read() .name .clone() diff --git a/src/scheme/sys/iostat.rs b/src/scheme/sys/iostat.rs index 557baf1a72..e98a63c15d 100644 --- a/src/scheme/sys/iostat.rs +++ b/src/scheme/sys/iostat.rs @@ -9,9 +9,13 @@ pub fn resource() -> Result> { let mut rows = Vec::new(); { let contexts = context::contexts(); - for (id, context_lock) in contexts.iter() { - let context = context_lock.read(); - rows.push((*id, context.name.clone(), context.files.read().clone())); + for context_ref in contexts.iter().filter_map(|r| r.0.upgrade()) { + let context = context_ref.read(); + rows.push(( + context.pid, + context.name.clone(), + context.files.read().clone(), + )); } } diff --git a/src/scheme/sys/scheme.rs b/src/scheme/sys/scheme.rs index 461cbb14a3..2386b76e90 100644 --- a/src/scheme/sys/scheme.rs +++ b/src/scheme/sys/scheme.rs @@ -1,10 +1,6 @@ use alloc::vec::Vec; -use crate::{ - context::process, - scheme, - syscall::error::{Error, Result}, -}; +use crate::{context::process, scheme, syscall::error::Result}; pub fn resource() -> Result> { let scheme_ns = process::current()?.read().ens; diff --git a/src/scheme/sys/scheme_num.rs b/src/scheme/sys/scheme_num.rs index eefce66cd0..880ef80e97 100644 --- a/src/scheme/sys/scheme_num.rs +++ b/src/scheme/sys/scheme_num.rs @@ -1,10 +1,6 @@ use alloc::vec::Vec; -use crate::{ - context::process, - scheme, - syscall::error::{Error, Result, ESRCH}, -}; +use crate::{context::process, scheme, syscall::error::Result}; pub fn resource() -> Result> { let scheme_ns = process::current()?.read().ens; diff --git a/src/scheme/sys/syscall.rs b/src/scheme/sys/syscall.rs index 53b20d800d..52f7d8ce2f 100644 --- a/src/scheme/sys/syscall.rs +++ b/src/scheme/sys/syscall.rs @@ -10,9 +10,13 @@ pub fn resource() -> Result> { let mut rows = Vec::new(); { let contexts = context::contexts(); - for (id, context_lock) in contexts.iter() { - let context = context_lock.read(); - rows.push((*id, context.name.clone(), context.current_syscall())); + for context_ref in contexts.iter().filter_map(|r| r.0.upgrade()) { + let context = context_ref.read(); + rows.push(( + context.pid.get(), + context.name.clone(), + context.current_syscall(), + )); } } diff --git a/src/scheme/user.rs b/src/scheme/user.rs index 64919b3826..c4425272ba 100644 --- a/src/scheme/user.rs +++ b/src/scheme/user.rs @@ -122,7 +122,7 @@ impl ParsedCqe { log::warn!( "Unknown scheme -> kernel message {} from {}", packet.a, - context::current().unwrap().read().name + context::current().read().name ); // Some schemes don't implement cancellation properly yet, so we temporarily @@ -276,7 +276,7 @@ impl UserInner { return Err(Error::new(ENODEV)); } - let current_context = context::current()?; + let current_context = context::current(); { let mut states = self.states.lock(); @@ -295,7 +295,7 @@ impl UserInner { context::switch(); let eintr_if_sigkill = || { - if context::current()?.read().being_sigkilled { + if context::current().read().being_sigkilled { // EINTR directly if SIGKILL was found without waiting for scheme. Data loss // doesn't matter. Err(Error::new(EINTR)) @@ -317,7 +317,7 @@ impl UserInner { *o = old_state; drop(states); eintr_if_sigkill()?; - context::current()?.write().block("UserInner::call"); + context::current().write().block("UserInner::call"); } // spurious wakeup State::Waiting { @@ -342,7 +342,7 @@ impl UserInner { ..Default::default() }); event::trigger(self.root_id, self.handle_id, EVENT_READ); - context::current()?.write().block("UserInner::call"); + context::current().write().block("UserInner::call"); } // invalid state @@ -830,7 +830,7 @@ impl UserInner { let tag = self.next_id()?; let mut states = self.states.lock(); - states[tag as usize] = State::Fmap(Arc::downgrade(&context::current()?)); + states[tag as usize] = State::Fmap(Arc::downgrade(&context::current())); /*self.todo.send(Packet { id: packet_id, @@ -855,7 +855,7 @@ impl UserInner { 0, uid_gid_hack_merge(current_uid_gid()?), ], - caller: context::current()?.read().pid.get() as u64, + caller: context::current().read().pid.get() as u64, }); event::trigger(self.root_id, self.handle_id, EVENT_READ); @@ -869,7 +869,7 @@ impl UserInner { ParsedCqe::ResponseWithFd { tag, fd } => self.respond( tag, Response::Fd( - context::current()? + context::current() .read() .remove_file(FileHandle::from(fd)) .ok_or(Error::new(EINVAL))? @@ -894,7 +894,7 @@ impl UserInner { // FIXME: Description can leak if context::current() fails, or if there is no // additional file table space. if flags.contains(FobtainFdFlags::MANUAL_FD) { - context::current()?.read().insert_file( + context::current().read().insert_file( FileHandle::from(dst_fd_or_ptr), FileDescriptor { description, @@ -902,7 +902,7 @@ impl UserInner { }, ); } else { - let fd = context::current()? + let fd = context::current() .read() .add_file(FileDescriptor { description, @@ -1089,7 +1089,7 @@ impl UserInner { } let (pid, desc) = { - let context_lock = context::current()?; + let context_lock = context::current(); let context = context_lock.read(); // TODO: Faster, cleaner mechanism to get descriptor let mut desc_res = Err(Error::new(EBADF)); diff --git a/src/sync/wait_condition.rs b/src/sync/wait_condition.rs index 91b05a6582..cf5d58306a 100644 --- a/src/sync/wait_condition.rs +++ b/src/sync/wait_condition.rs @@ -1,4 +1,7 @@ -use alloc::{sync::Arc, vec::Vec}; +use alloc::{ + sync::{Arc, Weak}, + vec::Vec, +}; use spin::{Mutex, MutexGuard}; use spinning_top::RwSpinlock; @@ -6,7 +9,7 @@ use crate::context::{self, Context}; #[derive(Debug)] pub struct WaitCondition { - contexts: Mutex>>>, + contexts: Mutex>>>, } impl WaitCondition { @@ -20,8 +23,10 @@ impl WaitCondition { pub fn notify(&self) -> usize { let mut contexts = self.contexts.lock(); let len = contexts.len(); - while let Some(context_lock) = contexts.pop() { - context_lock.write().unblock(); + while let Some(context_weak) = contexts.pop() { + if let Some(context_ref) = context_weak.upgrade() { + context_ref.write().unblock(); + } } len } @@ -30,34 +35,31 @@ impl WaitCondition { pub unsafe fn notify_signal(&self) -> usize { let contexts = self.contexts.lock(); let len = contexts.len(); - for context_lock in contexts.iter() { - context_lock.write().unblock(); + for context_weak in contexts.iter() { + if let Some(context_ref) = context_weak.upgrade() { + context_ref.write().unblock(); + } } len } // Wait until notified. Unlocks guard when blocking is ready. Returns false if resumed by a signal or the notify_signal function pub fn wait(&self, guard: MutexGuard, reason: &'static str) -> bool { - let cid; + let current_context_ref = context::current(); { - let context_lock = { - let contexts = context::contexts(); - let context_lock = contexts.current().expect("WaitCondition::wait: no context"); - Arc::clone(context_lock) - }; - { - let mut context = context_lock.write(); + let mut context = current_context_ref.write(); if let Some((control, _, _)) = context.sigcontrol() && control.currently_pending_unblocked() != 0 { return false; } - cid = context.cid; context.block(reason); } - self.contexts.lock().push(context_lock); + self.contexts + .lock() + .push(Arc::downgrade(¤t_context_ref)); drop(guard); } @@ -69,14 +71,10 @@ impl WaitCondition { { let mut contexts = self.contexts.lock(); + // TODO: retain let mut i = 0; while i < contexts.len() { - let remove = { - let context = contexts[i].read(); - context.cid == cid - }; - - if remove { + if Weak::as_ptr(&contexts[i]) == Arc::as_ptr(¤t_context_ref) { contexts.remove(i); waited = false; break; diff --git a/src/syscall/debug.rs b/src/syscall/debug.rs index c9dac9a2d0..aaed92ab6a 100644 --- a/src/syscall/debug.rs +++ b/src/syscall/debug.rs @@ -243,7 +243,12 @@ pub fn debug_start([a, b, c, d, e, f]: [usize; 6]) { let contexts = crate::context::contexts(); if let Some(context_lock) = contexts.current() { let context = context_lock.read(); - print!("{} ({}/{}): ", context.name, context.pid.get(), context.cid.get()); + print!( + "{} ({}/{}): ", + context.name, + context.pid.get(), + context.cid.get() + ); } // Do format_call outside print! so possible exception handlers cannot reentrantly @@ -279,7 +284,12 @@ pub fn debug_end([a, b, c, d, e, f]: [usize; 6], result: Result) { let contexts = crate::context::contexts(); if let Some(context_lock) = contexts.current() { let context = context_lock.read(); - print!("{} ({}/{}): ", context.name, context.pid.get(), context.cid.get()); + print!( + "{} ({}/{}): ", + context.name, + context.pid.get(), + context.cid.get() + ); } // Do format_call outside print! so possible exception handlers cannot reentrantly diff --git a/src/syscall/driver.rs b/src/syscall/driver.rs index dcc1523d26..5ee5375b30 100644 --- a/src/syscall/driver.rs +++ b/src/syscall/driver.rs @@ -3,7 +3,7 @@ use alloc::sync::Arc; use crate::{ context::{self, process}, paging::VirtualAddress, - syscall::error::{Error, Result, EFAULT, EPERM, ESRCH}, + syscall::error::{Error, Result, EFAULT, EPERM}, }; fn enforce_root() -> Result<()> { if process::current()?.read().euid != 0 { @@ -21,7 +21,7 @@ pub fn iopl(level: usize) -> Result { pub fn iopl(level: usize) -> Result { enforce_root()?; - context::current()? + context::current() .write() .set_userspace_io_allowed(level >= 3); @@ -31,7 +31,7 @@ pub fn iopl(level: usize) -> Result { pub fn virttophys(virtual_address: usize) -> Result { enforce_root()?; - let addr_space = Arc::clone(context::current()?.read().addr_space()?); + let addr_space = Arc::clone(context::current().read().addr_space()?); let addr_space = addr_space.acquire_read(); match addr_space diff --git a/src/syscall/fs.rs b/src/syscall/fs.rs index 37c02957b8..19fe8a78eb 100644 --- a/src/syscall/fs.rs +++ b/src/syscall/fs.rs @@ -27,7 +27,7 @@ pub fn file_op_generic_ext( fd: FileHandle, op: impl FnOnce(&dyn KernelScheme, Arc>, FileDescription) -> Result, ) -> Result { - let file = context::current()? + let file = context::current() .read() .get_file(fd) .ok_or(Error::new(EBADF))?; @@ -101,7 +101,7 @@ pub fn open(raw_path: UserSliceRo, flags: usize) -> Result { }; //drop(path_buf); - context::current()? + context::current() .read() .add_file(FileDescriptor { description, @@ -160,7 +160,7 @@ pub fn unlink(raw_path: UserSliceRo) -> Result<()> { /// Close syscall pub fn close(fd: FileHandle) -> Result<()> { let file = { - let context_lock = context::current()?; + let context_lock = context::current(); let context = context_lock.read(); context.remove_file(fd).ok_or(Error::new(EBADF))? }; @@ -170,7 +170,7 @@ pub fn close(fd: FileHandle) -> Result<()> { fn duplicate_file(fd: FileHandle, user_buf: UserSliceRo) -> Result { let caller_ctx = process::current()?.read().caller_ctx(); - let file = context::current()? + let file = context::current() .read() .get_file(fd) .ok_or(Error::new(EBADF))?; @@ -214,7 +214,7 @@ fn duplicate_file(fd: FileHandle, user_buf: UserSliceRo) -> Result Result { let new_file = duplicate_file(fd, buf)?; - context::current()? + context::current() .read() .add_file(new_file) .ok_or(Error::new(EMFILE)) @@ -228,9 +228,8 @@ pub fn dup2(fd: FileHandle, new_fd: FileHandle, buf: UserSliceRo) -> Result let requested_flags = SendFdFlags::from_bits(flags_raw).ok_or(Error::new(EINVAL))?; let (scheme, number, desc_to_send) = { - let current_lock = context::current()?; + let current_lock = context::current(); let current = current_lock.read(); // TODO: Ensure deadlocks can't happen @@ -287,7 +286,7 @@ pub fn sendfd(socket: FileHandle, fd: FileHandle, flags_raw: usize, arg: u64) -> /// File descriptor controls pub fn fcntl(fd: FileHandle, cmd: usize, arg: usize) -> Result { - let file = context::current()? + let file = context::current() .read() .get_file(fd) .ok_or(Error::new(EBADF))?; @@ -298,8 +297,7 @@ pub fn fcntl(fd: FileHandle, cmd: usize, arg: usize) -> Result { // Not in match because 'files' cannot be locked let new_file = duplicate_file(fd, UserSlice::empty())?; - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; + let context_lock = context::current(); let context = context_lock.read(); return context @@ -320,8 +318,7 @@ pub fn fcntl(fd: FileHandle, cmd: usize, arg: usize) -> Result { // Perform kernel operation if scheme agrees { - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; + let context_lock = context::current(); let context = context_lock.read(); let mut files = context.files.write(); @@ -364,7 +361,7 @@ pub fn frename(fd: FileHandle, raw_path: UserSliceRo) -> Result<()> { process.ens, ), }; - let file = context::current()? + let file = context::current() .read() .get_file(fd) .ok_or(Error::new(EBADF))?; @@ -433,7 +430,7 @@ pub fn funmap(virtual_address: usize, length: usize) -> Result { ); } - let addr_space = Arc::clone(context::current()?.read().addr_space()?); + let addr_space = Arc::clone(context::current().read().addr_space()?); let span = PageSpan::validate_nonempty(VirtualAddress::new(virtual_address), length_aligned) .ok_or(Error::new(EINVAL))?; let unpin = false; diff --git a/src/syscall/futex.rs b/src/syscall/futex.rs index e9be1df888..5e1af7a5a1 100644 --- a/src/syscall/futex.rs +++ b/src/syscall/futex.rs @@ -89,7 +89,7 @@ pub fn futex(addr: usize, op: usize, val: usize, val2: usize, _addr2: usize) -> { let mut futexes = FUTEXES.write(); - let context_lock = context::current()?; + let context_lock = context::current(); let (fetched, expected) = if op == FUTEX_WAIT { // Must be aligned, otherwise it could cross a page boundary and mess up the @@ -162,7 +162,7 @@ pub fn futex(addr: usize, op: usize, val: usize, val2: usize, _addr2: usize) -> context::switch(); if timeout_opt.is_some() { - context::current()?.write().wake = None; + context::current().write().wake = None; Err(Error::new(ETIMEDOUT)) } else { Ok(0) diff --git a/src/syscall/process.rs b/src/syscall/process.rs index 65ddee4fb5..667771f6b2 100644 --- a/src/syscall/process.rs +++ b/src/syscall/process.rs @@ -35,7 +35,7 @@ pub fn exit(status: usize) -> ! { ); { - let context_lock = context::current().expect("exit failed to find context"); + let context_lock = context::current(); let close_files; let addrspace_opt; @@ -175,7 +175,7 @@ pub fn kill(pid: ProcessId, sig: usize, parent_sigchld: bool) -> Result { } let mut send = |context: &mut context::Context, proc: &ProcessInfo| -> SendResult { - let is_self = context.cid == context::current_cid(); + let is_self = context.is_current_context(); // Non-root users cannot kill arbitrarily. if euid != 0 && euid != proc.ruid && ruid != proc.ruid { @@ -640,9 +640,7 @@ pub unsafe fn usermode_bootstrap(bootstrap: &Bootstrap) { { let addr_space = Arc::clone( - context::contexts() - .current() - .expect("expected a context to exist when executing init") + context::current() .read() .addr_space() .expect("expected bootstrap context to have an address space"), @@ -689,7 +687,6 @@ pub unsafe fn usermode_bootstrap(bootstrap: &Bootstrap) { // Start in a minimal environment without any stack. match context::current() - .expect("bootstrap was not running inside any context") .write() .regs_mut() .expect("bootstrap needs registers to be available") diff --git a/src/syscall/time.rs b/src/syscall/time.rs index 2a7d33f51c..8052fa654b 100644 --- a/src/syscall/time.rs +++ b/src/syscall/time.rs @@ -30,7 +30,7 @@ pub fn nanosleep(req_buf: UserSliceRo, rem_buf_opt: Option) -> Resu let start = time::monotonic(); let end = start + (req.tv_sec as u128 * time::NANOS_PER_SEC) + (req.tv_nsec as u128); - let current_context = context::current()?; + let current_context = context::current(); { let mut context = current_context.write();