WIP: Replace ContextId with direct Arcs.

This commit is contained in:
4lDO2
2024-07-12 19:27:11 +02:00
parent 038ff03996
commit 80fe891c6e
30 changed files with 408 additions and 558 deletions
+1 -1
View File
@@ -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);
}
+1 -1
View File
@@ -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);
}
+10 -14
View File
@@ -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<RwLock<Process>>) -> Result<Context> {
pub fn new(pid: ProcessId, process: Arc<RwLock<Process>>) -> Result<Context> {
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<AddrSpaceWrapper>> {
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<Self> {
Ok(Self {
inner: Some(
context::current()?
context::current()
.write()
.syscall_head
.take()
@@ -486,7 +483,7 @@ impl BorrowedHtBuf {
pub fn tail() -> Result<Self> {
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;
};
-169
View File
@@ -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<ContextId, Arc<RwSpinlock<Context>>>,
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<RwSpinlock<Context>>> {
self.map.get(&id)
}
/// Get the current context.
pub fn current(&self) -> Option<&Arc<RwSpinlock<Context>>> {
self.map.get(&super::current_cid())
}
pub fn iter(
&self,
) -> ::alloc::collections::btree_map::Iter<ContextId, Arc<RwSpinlock<Context>>> {
self.map.iter()
}
pub fn range(
&self,
range: impl core::ops::RangeBounds<ContextId>,
) -> ::alloc::collections::btree_map::Range<'_, ContextId, Arc<RwSpinlock<Context>>> {
self.map.range(range)
}
pub(crate) fn insert_context_raw(
&mut self,
cid: ContextId,
pid: ProcessId,
process: Arc<RwLock<Process>>,
) -> Result<&Arc<RwSpinlock<Context>>> {
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<RwLock<Process>>,
) -> Result<&Arc<RwSpinlock<Context>>> {
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<RwLock<Process>>,
func: extern "C" fn(),
) -> Result<&Arc<RwSpinlock<Context>>> {
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::<crate::interrupt::InterruptStack>();
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::<InterruptStack>()).init();
}
}
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
unsafe {
if userspace_allowed {
stack_top = stack_top.sub(core::mem::size_of::<usize>());
stack_top
.cast::<usize>()
.write(crate::interrupt::syscall::enter_usermode as usize);
}
stack_top = stack_top.sub(core::mem::size_of::<usize>());
stack_top.cast::<usize>().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<Arc<RwSpinlock<Context>>> {
self.map.remove(&id)
}
}
+1 -1
View File
@@ -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 });
+137 -40
View File
@@ -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<ContextList> = RwLock::new(ContextList::new());
pub use self::arch::empty_cr3;
static KMAIN_PROCESS: Once<Arc<RwLock<Process>>> = Once::new();
// Set of weak references to all contexts available for scheduling. The only strong references are
// the context file descriptors.
static CONTEXTS: RwLock<BTreeSet<ContextRef>> = 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<ContextRef>> {
CONTEXTS.read()
}
/// Get the global schemes list, mutable
pub fn contexts_mut() -> RwLockWriteGuard<'static, ContextList> {
pub fn contexts_mut() -> RwLockWriteGuard<'static, BTreeSet<ContextRef>> {
CONTEXTS.write()
}
pub fn current_cid() -> ContextId {
PercpuBlock::current().switch_internals.current_cid()
pub fn current() -> Arc<RwSpinlock<Context>> {
PercpuBlock::current()
.switch_internals
.with_context(|context| Arc::clone(context))
}
pub fn current_pid() -> Result<ProcessId> {
Ok(current()?.read().pid)
pub fn is_current(context: &Arc<RwSpinlock<Context>>) -> bool {
PercpuBlock::current()
.switch_internals
.with_context(|current| Arc::ptr_eq(context, current))
}
pub fn current() -> Result<Arc<RwSpinlock<Context>>> {
contexts()
.current()
.ok_or(Error::new(ESRCH))
.map(Arc::clone)
pub fn current_pid() -> Result<ProcessId> {
Ok(current().read().pid)
}
pub struct ContextRef(pub Weak<RwSpinlock<Context>>);
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<core::cmp::Ordering> {
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<RwLock<Process>>,
func: extern "C" fn(),
) -> Result<Arc<RwSpinlock<Context>>> {
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::<crate::interrupt::InterruptStack>();
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::<InterruptStack>()).init();
}
}
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
unsafe {
if userspace_allowed {
stack_top = stack_top.sub(core::mem::size_of::<usize>());
stack_top
.cast::<usize>()
.write(crate::interrupt::syscall::enter_usermode as usize);
}
stack_top = stack_top.sub(core::mem::size_of::<usize>());
stack_top.cast::<usize>().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)
}
+1 -1
View File
@@ -91,7 +91,7 @@ pub fn ancestors(
}
pub fn current() -> Result<Arc<RwLock<Process>>> {
let pid = context::current()?.read().pid;
let pid = context::current().read().pid;
Ok(Arc::clone(
PROCESSES.read().get(&pid).ok_or(Error::new(ESRCH))?,
))
+2 -2
View File
@@ -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 {
+47 -29
View File
@@ -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<Option<SwitchResultInner>>,
pit_ticks: Cell<usize>,
/// Unique context ID of the currently running context.
current_cid: Cell<ContextId>,
current_ctxt: RefCell<Option<Arc<RwSpinlock<Context>>>>,
// The ID of the idle process
idle_id: Cell<ContextId>,
// The idle process
idle_ctxt: RefCell<Option<Arc<RwSpinlock<Context>>>>,
pub(crate) being_sigkilled: Cell<bool>,
}
impl ContextSwitchPercpu {
pub fn current_cid(&self) -> ContextId {
self.current_cid.get()
pub fn with_context<T>(&self, f: impl FnOnce(&Arc<RwSpinlock<Context>>) -> 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<RwSpinlock<Context>>) {
*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<RwSpinlock<Context>>) {
*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<RwSpinlock<Context>> {
Arc::clone(
self.idle_ctxt
.borrow()
.as_ref()
.expect("no idle context present"),
)
}
}
+4 -4
View File
@@ -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<usize> {
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(),
+18 -18
View File
@@ -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<Bootstrap> = spin::Once::new();
static INIT_THREAD: spin::Once<Arc<RwSpinlock<crate::context::Context>>> = 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);
}
+6 -8
View File
@@ -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));
}
}
+3 -9
View File
@@ -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<PtraceFlags> {
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)?;
+86 -172
View File
@@ -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<usize> {
dst.copy_common_bytes_from_slice(avail_src)
}
fn with_context<F, T>(pid: ContextId, callback: F) -> Result<T>
where
F: FnOnce(&Context) -> Result<T>,
{
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<F, T>(pid: ContextId, callback: F) -> Result<T>
where
F: FnOnce(&mut Context) -> Result<T>,
{
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<F, T>(pid: ContextId, callback: F) -> Result<T>
where
F: FnOnce(&mut Context) -> Result<T>,
{
if pid == context::current_cid() {
return Err(Error::new(EBADF));
fn try_stop_context<T>(
context_ref: Arc<RwSpinlock<Context>>,
callback: impl FnOnce(&mut Context) -> Result<T>,
) -> Result<T> {
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<Arc<RwSpinlock<Context>>> {
context::contexts()
.get(id)
.ok_or(Error::new(ENOENT))
.map(Arc::clone)
}
enum OpenTy {
Proc(ProcessId),
Ctxt(ContextId),
Ctxt(Arc<RwSpinlock<Context>>),
}
impl<const FULL: bool> ProcScheme<FULL> {
@@ -366,13 +336,7 @@ impl<const FULL: bool> ProcScheme<FULL> {
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<const FULL: bool> ProcScheme<FULL> {
.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<const FULL: bool> KernelScheme for ProcScheme<FULL> {
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<const FULL: bool> KernelScheme for ProcScheme<FULL> {
} 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<const FULL: bool> KernelScheme for ProcScheme<FULL> {
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<const FULL: bool> KernelScheme for ProcScheme<FULL> {
consume: bool,
) -> Result<usize> {
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<const FULL: bool> KernelScheme for ProcScheme<FULL> {
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<ContextId> {
fn new_thread() -> Result<Arc<RwSpinlock<Context>>> {
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<ContextId> {
let new_id = {
fn new_child() -> Result<Arc<RwSpinlock<Context>>> {
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<usize> {
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::<FloatRegisters>()? };
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::<IntRegisters>()? };
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::<EnvRegisters>()? };
let cid = context.read().cid;
write_env_regs(cid, regs)?;
write_env_regs(context, regs)?;
Ok(mem::size_of::<EnvRegisters>())
}
},
@@ -1511,35 +1442,28 @@ impl ContextHandle {
mem::size_of::<FloatRegisters>(),
)
}
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::<IntRegisters>()))
}
})?
}
RegsKind::Env => {
let cid = context.read().cid;
(
Output {
env: read_env_regs(cid)?,
},
mem::size_of::<EnvRegisters>(),
)
}
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::<IntRegisters>()))
}
})?,
RegsKind::Env => (
Output {
env: read_env_regs(context)?,
},
mem::size_of::<EnvRegisters>(),
),
};
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<RwSpinlock<Context>>, 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<RwSpinlock<Context>>, 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<RwSpinlock<Context>>, 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<EnvRegisters> {
fn read_env_regs(context: Arc<RwSpinlock<Context>>) -> Result<EnvRegisters> {
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<EnvRegisters> {
)
}
} 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<EnvRegisters> {
}
#[cfg(target_arch = "x86")]
fn read_env_regs(&self, info: &Info) -> Result<EnvRegisters> {
let (fsbase, gsbase) = if info.pid == context::context_id() {
fn read_env_regs(context: Arc<RwSpinlock<Context>>) -> Result<EnvRegisters> {
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<EnvRegisters> {
)
}
} 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<EnvRegisters> {
}
#[cfg(target_arch = "x86_64")]
fn read_env_regs(cid: ContextId) -> Result<EnvRegisters> {
fn read_env_regs(context: Arc<RwSpinlock<Context>>) -> Result<EnvRegisters> {
// 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<EnvRegisters> {
)
}
} else {
try_stop_context(cid, |context| {
try_stop_context(context, |context| {
Ok((context.arch.fsbase as u64, context.arch.gsbase as u64))
})?
};
+1 -5
View File
@@ -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);
+6 -2
View File
@@ -10,9 +10,13 @@ pub fn resource() -> Result<Vec<u8>> {
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,
));
}
}
+2 -2
View File
@@ -27,8 +27,8 @@ pub fn resource() -> Result<Vec<u8>> {
);
{
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
+1 -1
View File
@@ -3,7 +3,7 @@ use alloc::vec::Vec;
use crate::{context, syscall::error::Result};
pub fn resource() -> Result<Vec<u8>> {
Ok(context::current()?
Ok(context::current()
.read()
.name
.clone()
+7 -3
View File
@@ -9,9 +9,13 @@ pub fn resource() -> Result<Vec<u8>> {
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(),
));
}
}
+1 -5
View File
@@ -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<Vec<u8>> {
let scheme_ns = process::current()?.read().ens;
+1 -5
View File
@@ -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<Vec<u8>> {
let scheme_ns = process::current()?.read().ens;
+7 -3
View File
@@ -10,9 +10,13 @@ pub fn resource() -> Result<Vec<u8>> {
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(),
));
}
}
+11 -11
View File
@@ -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));
+20 -22
View File
@@ -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<Vec<Arc<RwSpinlock<Context>>>>,
contexts: Mutex<Vec<Weak<RwSpinlock<Context>>>>,
}
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<T>(&self, guard: MutexGuard<T>, 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(&current_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(&current_context_ref) {
contexts.remove(i);
waited = false;
break;
+12 -2
View File
@@ -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<usize>) {
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
+3 -3
View File
@@ -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<usize> {
pub fn iopl(level: usize) -> Result<usize> {
enforce_root()?;
context::current()?
context::current()
.write()
.set_userspace_io_allowed(level >= 3);
@@ -31,7 +31,7 @@ pub fn iopl(level: usize) -> Result<usize> {
pub fn virttophys(virtual_address: usize) -> Result<usize> {
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
+13 -16
View File
@@ -27,7 +27,7 @@ pub fn file_op_generic_ext<T>(
fd: FileHandle,
op: impl FnOnce(&dyn KernelScheme, Arc<RwLock<FileDescription>>, FileDescription) -> Result<T>,
) -> Result<T> {
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<FileHandle> {
};
//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<FileDescriptor> {
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<FileDescripto
pub fn dup(fd: FileHandle, buf: UserSliceRo) -> Result<FileHandle> {
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<File
let _ = close(new_fd);
let new_file = duplicate_file(fd, buf)?;
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();
context
.insert_file(new_fd, new_file)
@@ -241,7 +240,7 @@ pub fn sendfd(socket: FileHandle, fd: FileHandle, flags_raw: usize, arg: u64) ->
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<usize> {
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<usize> {
// 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<usize> {
// 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<usize> {
);
}
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;
+2 -2
View File
@@ -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)
+3 -6
View File
@@ -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<usize> {
}
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")
+1 -1
View File
@@ -30,7 +30,7 @@ pub fn nanosleep(req_buf: UserSliceRo, rem_buf_opt: Option<UserSliceWo>) -> 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();