WIP: Replace ContextId with direct Arcs.
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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))?,
|
||||
))
|
||||
|
||||
@@ -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
@@ -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"),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user