Stop using #[thread_local] on x86_*.

This commit is contained in:
4lDO2
2023-07-11 16:01:46 +02:00
parent bdd5c954dc
commit a78d6e42f8
10 changed files with 92 additions and 107 deletions
+1 -2
View File
@@ -1,7 +1,6 @@
use alloc::sync::Arc;
use alloc::collections::BTreeMap;
use core::{iter, mem};
use core::sync::atomic::Ordering;
use spin::RwLock;
@@ -39,7 +38,7 @@ impl ContextList {
/// Get the current context.
pub fn current(&self) -> Option<&Arc<RwLock<Context>>> {
self.map.get(&super::CONTEXT_ID.load(Ordering::SeqCst))
self.map.get(&super::context_id())
}
pub fn iter(&self) -> ::alloc::collections::btree_map::Iter<ContextId, Arc<RwLock<Context>>> {
+6 -12
View File
@@ -1,7 +1,6 @@
//! # Context management
//!
//! For resources on contexts, please consult [wikipedia](https://en.wikipedia.org/wiki/Context_switch) and [osdev](https://wiki.osdev.org/Context_Switching)
use core::sync::atomic::Ordering;
use alloc::borrow::Cow;
use alloc::sync::Arc;
@@ -9,6 +8,7 @@ use alloc::sync::Arc;
use spin::{RwLock, RwLockReadGuard, RwLockWriteGuard};
use crate::paging::{RmmA, RmmArch, TableKind};
use crate::percpu::PercpuBlock;
use crate::syscall::error::{Error, ESRCH, Result};
pub use self::context::{BorrowedHtBuf, Context, ContextId, ContextSnapshot, Status, WaitpidKey};
@@ -59,9 +59,6 @@ pub const CONTEXT_MAX_FILES: usize = 65_536;
/// Contexts list
static CONTEXTS: RwLock<ContextList> = RwLock::new(ContextList::new());
#[thread_local]
static CONTEXT_ID: context::AtomicContextId = context::AtomicContextId::default();
pub use self::arch::empty_cr3;
pub fn init() {
@@ -77,7 +74,10 @@ pub fn init() {
context.status = Status::Runnable;
context.running = true;
context.cpu_id = Some(crate::cpu_id());
CONTEXT_ID.store(context.id, Ordering::SeqCst);
unsafe {
PercpuBlock::current().switch_internals.set_context_id(context.id);
}
}
/// Get the global schemes list, const
@@ -91,13 +91,7 @@ pub fn contexts_mut() -> RwLockWriteGuard<'static, ContextList> {
}
pub fn context_id() -> ContextId {
// Thread local variables can and should only be modified using Relaxed. This is to prevent a
// hardware thread from racing with itself, for example if there is an interrupt. Orderings
// stronger than Relaxed are only necessary for inter-processor synchronization.
let id = CONTEXT_ID.load(Ordering::Relaxed);
// Prevent the compiler from reordering subsequent loads and stores to before this load.
core::sync::atomic::compiler_fence(Ordering::Acquire);
id
PercpuBlock::current().switch_internals.context_id()
}
pub fn current() -> Result<Arc<RwLock<Context>>> {
+33 -15
View File
@@ -7,13 +7,15 @@ use alloc::sync::Arc;
use spin::{RwLock, RwLockWriteGuard};
use crate::context::signal::signal_handler;
use crate::context::{arch, contexts, Context, CONTEXT_ID};
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
use crate::context::{arch, contexts, Context};
use crate::gdt;
use crate::interrupt;
use crate::percpu::PercpuBlock;
use crate::ptrace;
use crate::time;
use super::ContextId;
unsafe fn update_runnable(context: &mut Context, cpu_id: usize) -> bool {
// Ignore already running contexts
if context.running {
@@ -87,16 +89,12 @@ struct SwitchResult {
next_lock: Arc<RwLock<Context>>,
}
#[thread_local]
static SWITCH_RESULT: Cell<Option<SwitchResult>> = Cell::new(None);
//resets to 0 in context::switch()
#[thread_local]
pub static PIT_TICKS: Cell<usize> = Cell::new(0);
pub fn tick() {
let new_ticks = PIT_TICKS.get() + 1;
PIT_TICKS.set(new_ticks);
let ticks_cell = &PercpuBlock::current().switch_internals.pit_ticks;
let new_ticks = ticks_cell.get() + 1;
ticks_cell.set(new_ticks);
// Switch after 3 ticks (about 6.75 ms)
if new_ticks >= 3 {
@@ -105,7 +103,7 @@ pub fn tick() {
}
pub unsafe extern "C" fn switch_finish_hook() {
if let Some(SwitchResult { prev_lock, next_lock }) = SWITCH_RESULT.take() {
if let Some(SwitchResult { prev_lock, next_lock }) = PercpuBlock::current().switch_internals.switch_result.take() {
prev_lock.force_write_unlock();
next_lock.force_write_unlock();
} else {
@@ -121,11 +119,13 @@ pub unsafe extern "C" fn switch_finish_hook() {
///
/// Do not call this while holding locks!
pub unsafe fn switch() -> bool {
// TODO: Better memory orderings?
let percpu = PercpuBlock::current();
//set PIT Interrupt counter to 0, giving each process same amount of PIT ticks
PIT_TICKS.set(0);
percpu.switch_internals.pit_ticks.set(0);
// Set the global lock to avoid the unsafe operations below from causing issues
// TODO: Better memory orderings?
while arch::CONTEXT_SWITCH_LOCK.compare_exchange_weak(false, true, Ordering::SeqCst, Ordering::Relaxed).is_err() {
interrupt::pause();
}
@@ -190,7 +190,8 @@ pub unsafe fn switch() -> bool {
gdt::set_tss_stack(stack.as_ptr() as usize + stack.len());
}
}
CONTEXT_ID.store(next_context.id, Ordering::SeqCst);
let percpu = PercpuBlock::current();
percpu.switch_internals.context_id.set(next_context.id);
if next_context.ksig.is_none() {
//TODO: Allow nested signals
@@ -204,7 +205,7 @@ pub unsafe fn switch() -> bool {
}
}
SWITCH_RESULT.set(Some(SwitchResult {
percpu.switch_internals.switch_result.set(Some(SwitchResult {
prev_lock: prev_context_lock,
next_lock: next_context_lock,
}));
@@ -223,3 +224,20 @@ pub unsafe fn switch() -> bool {
false
}
}
#[derive(Default)]
pub struct ContextSwitchPercpu {
switch_result: Cell<Option<SwitchResult>>,
pit_ticks: Cell<usize>,
/// Unique ID of the currently running context.
context_id: Cell<ContextId>,
}
impl ContextSwitchPercpu {
pub fn context_id(&self) -> ContextId {
self.context_id.get()
}
pub unsafe fn set_context_id(&self, new: ContextId) {
self.context_id.set(new)
}
}