mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-18 20:16:42 +00:00
Enable check of atomic mode
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
4231645c02
commit
32a1a53ee7
@ -30,6 +30,8 @@
|
|||||||
#![feature(linked_list_retain)]
|
#![feature(linked_list_retain)]
|
||||||
#![register_tool(component_access_control)]
|
#![register_tool(component_access_control)]
|
||||||
|
|
||||||
|
use core::sync::atomic::Ordering;
|
||||||
|
|
||||||
use ostd::{
|
use ostd::{
|
||||||
arch::qemu::{exit_qemu, QemuExitCode},
|
arch::qemu::{exit_qemu, QemuExitCode},
|
||||||
boot,
|
boot,
|
||||||
@ -80,6 +82,7 @@ pub fn main() {
|
|||||||
ostd::early_println!("[kernel] OSTD initialized. Preparing components.");
|
ostd::early_println!("[kernel] OSTD initialized. Preparing components.");
|
||||||
component::init_all(component::parse_metadata!()).unwrap();
|
component::init_all(component::parse_metadata!()).unwrap();
|
||||||
init();
|
init();
|
||||||
|
ostd::IN_BOOTSTRAP_CONTEXT.store(false, Ordering::Relaxed);
|
||||||
Thread::spawn_kernel_thread(ThreadOptions::new(init_thread));
|
Thread::spawn_kernel_thread(ThreadOptions::new(init_thread));
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
|
@ -44,6 +44,8 @@ pub mod task;
|
|||||||
pub mod trap;
|
pub mod trap;
|
||||||
pub mod user;
|
pub mod user;
|
||||||
|
|
||||||
|
use core::sync::atomic::AtomicBool;
|
||||||
|
|
||||||
pub use ostd_macros::main;
|
pub use ostd_macros::main;
|
||||||
pub use ostd_pod::Pod;
|
pub use ostd_pod::Pod;
|
||||||
|
|
||||||
@ -96,6 +98,9 @@ pub unsafe fn init() {
|
|||||||
invoke_ffi_init_funcs();
|
invoke_ffi_init_funcs();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Indicates whether the kernel is in bootstrap context.
|
||||||
|
pub static IN_BOOTSTRAP_CONTEXT: AtomicBool = AtomicBool::new(true);
|
||||||
|
|
||||||
/// Invoke the initialization functions defined in the FFI.
|
/// Invoke the initialization functions defined in the FFI.
|
||||||
/// The component system uses this function to call the initialization functions of
|
/// The component system uses this function to call the initialization functions of
|
||||||
/// the components.
|
/// the components.
|
||||||
|
46
ostd/src/task/atomic_mode.rs
Normal file
46
ostd/src/task/atomic_mode.rs
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
//! Atomic Mode
|
||||||
|
//!
|
||||||
|
//! Multitasking, while powerful, can sometimes lead to undesirable
|
||||||
|
//! or catastrophic consequences if being misused.
|
||||||
|
//! For instance, a user of OSTD might accidentally write an IRQ handler
|
||||||
|
//! that relies on mutexes,
|
||||||
|
//! which could attempt to sleep within an interrupt context---something that must be avoided.
|
||||||
|
//! Another common mistake is
|
||||||
|
//! acquiring a spinlock in a task context and then attempting to yield or sleep,
|
||||||
|
//! which can easily lead to deadlocks.
|
||||||
|
//!
|
||||||
|
//! To mitigate the risks associated with improper multitasking,
|
||||||
|
//! we introduce the concept of atomic mode.
|
||||||
|
//! Kernel code is considered to be running in atomic mode
|
||||||
|
//! if one of the following conditions is met:
|
||||||
|
//!
|
||||||
|
//! 1. Task preemption is disabled, such as when a spinlock is held.
|
||||||
|
//! 2. Local IRQs are disabled, such as during interrupt context.
|
||||||
|
//!
|
||||||
|
//! While in atomic mode,
|
||||||
|
//! any attempt to perform "sleep-like" actions will trigger a panic:
|
||||||
|
//!
|
||||||
|
//! 1. Switching to another task.
|
||||||
|
//! 2. Switching to user space.
|
||||||
|
//!
|
||||||
|
//! This module provides API to detect such "sleep-like" actions.
|
||||||
|
|
||||||
|
use core::sync::atomic::Ordering;
|
||||||
|
|
||||||
|
/// Marks a function as one that might sleep.
|
||||||
|
///
|
||||||
|
/// This function will panic if it is executed in atomic mode.
|
||||||
|
pub fn might_sleep() {
|
||||||
|
let preempt_count = super::preempt::cpu_local::get_guard_count();
|
||||||
|
let is_local_irq_enabled = crate::arch::irq::is_local_enabled();
|
||||||
|
if (preempt_count != 0 || !is_local_irq_enabled)
|
||||||
|
&& !crate::IN_BOOTSTRAP_CONTEXT.load(Ordering::Relaxed)
|
||||||
|
{
|
||||||
|
panic!(
|
||||||
|
"This function might break atomic mode (preempt_count = {}, is_local_irq_enabled = {})",
|
||||||
|
preempt_count, is_local_irq_enabled
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
//! Tasks are the unit of code execution.
|
//! Tasks are the unit of code execution.
|
||||||
|
|
||||||
|
pub(crate) mod atomic_mode;
|
||||||
mod preempt;
|
mod preempt;
|
||||||
mod processor;
|
mod processor;
|
||||||
pub mod scheduler;
|
pub mod scheduler;
|
||||||
|
@ -2,10 +2,7 @@
|
|||||||
|
|
||||||
use alloc::sync::Arc;
|
use alloc::sync::Arc;
|
||||||
|
|
||||||
use super::{
|
use super::task::{context_switch, Task, TaskContext};
|
||||||
preempt::cpu_local,
|
|
||||||
task::{context_switch, Task, TaskContext},
|
|
||||||
};
|
|
||||||
use crate::cpu_local_cell;
|
use crate::cpu_local_cell;
|
||||||
|
|
||||||
cpu_local_cell! {
|
cpu_local_cell! {
|
||||||
@ -46,18 +43,7 @@ pub(super) fn current_task() -> Option<Arc<Task>> {
|
|||||||
/// This function will panic if called while holding preemption locks or with
|
/// This function will panic if called while holding preemption locks or with
|
||||||
/// local IRQ disabled.
|
/// local IRQ disabled.
|
||||||
pub(super) fn switch_to_task(next_task: Arc<Task>) {
|
pub(super) fn switch_to_task(next_task: Arc<Task>) {
|
||||||
let guard_count = cpu_local::get_guard_count();
|
super::atomic_mode::might_sleep();
|
||||||
if guard_count != 0 {
|
|
||||||
panic!(
|
|
||||||
"Switching task with preemption disabled (nesting depth: {})",
|
|
||||||
guard_count
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
assert!(
|
|
||||||
crate::arch::irq::is_local_enabled(),
|
|
||||||
"Switching task with local IRQ disabled"
|
|
||||||
);
|
|
||||||
|
|
||||||
let irq_guard = crate::trap::disable_local();
|
let irq_guard = crate::trap::disable_local();
|
||||||
|
|
||||||
|
@ -140,6 +140,7 @@ impl<'a> UserMode<'a> {
|
|||||||
F: FnMut() -> bool,
|
F: FnMut() -> bool,
|
||||||
{
|
{
|
||||||
debug_assert!(Arc::ptr_eq(&self.current, &Task::current().unwrap()));
|
debug_assert!(Arc::ptr_eq(&self.current, &Task::current().unwrap()));
|
||||||
|
crate::task::atomic_mode::might_sleep();
|
||||||
self.context.execute(has_kernel_event)
|
self.context.execute(has_kernel_event)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user