Add ForceSync

This commit is contained in:
Ruihan Li
2024-11-03 22:46:51 +08:00
committed by Tate, Hongliang Tian
parent 85a7d94da7
commit 51db2da151
2 changed files with 48 additions and 8 deletions

View File

@ -7,12 +7,17 @@ mod kernel_stack;
mod preempt;
mod processor;
pub mod scheduler;
mod utils;
use core::{any::Any, cell::SyncUnsafeCell};
use core::{
any::Any,
cell::{Cell, SyncUnsafeCell},
};
use kernel_stack::KernelStack;
pub(crate) use preempt::cpu_local::reset_preempt_info;
use processor::current_task;
use utils::ForceSync;
pub use self::{
preempt::{disable_preempt, DisabledPreemptGuard},
@ -28,7 +33,8 @@ use crate::{prelude::*, user::UserSpace};
/// execute user code. Multiple tasks can share a single user space.
#[derive(Debug)]
pub struct Task {
func: SyncUnsafeCell<Option<Box<dyn FnOnce() + Send + Sync>>>,
#[allow(clippy::type_complexity)]
func: ForceSync<Cell<Option<Box<dyn FnOnce() + Send>>>>,
data: Box<dyn Any + Send + Sync>,
user_space: Option<Arc<UserSpace>>,
ctx: SyncUnsafeCell<TaskContext>,
@ -104,7 +110,7 @@ impl Task {
/// Options to create or spawn a new task.
pub struct TaskOptions {
func: Option<Box<dyn FnOnce() + Send + Sync>>,
func: Option<Box<dyn FnOnce() + Send>>,
data: Option<Box<dyn Any + Send + Sync>>,
user_space: Option<Arc<UserSpace>>,
}
@ -125,7 +131,7 @@ impl TaskOptions {
/// Sets the function that represents the entry point of the task.
pub fn func<F>(mut self, func: F) -> Self
where
F: Fn() + Send + Sync + 'static,
F: Fn() + Send + 'static,
{
self.func = Some(Box::new(func));
self
@ -153,9 +159,10 @@ impl TaskOptions {
extern "C" fn kernel_task_entry() -> ! {
let current_task = current_task()
.expect("no current task, it should have current task in kernel task entry");
// SAFETY: The scheduler will ensure that the task is only accessed
// by one CPU.
let task_func = unsafe { &mut *current_task.func.get() };
// SAFETY: The `func` field will only be accessed by the current task in the task
// context, so the data won't be accessed concurrently.
let task_func = unsafe { current_task.func.get() };
let task_func = task_func
.take()
.expect("task function is `None` when trying to run");
@ -186,7 +193,7 @@ impl TaskOptions {
ctx.get_mut().set_stack_pointer(kstack.end_vaddr() - 16);
let new_task = Task {
func: SyncUnsafeCell::new(self.func),
func: ForceSync::new(Cell::new(self.func)),
data: self.data.unwrap(),
user_space: self.user_space,
ctx,

33
ostd/src/task/utils.rs Normal file
View File

@ -0,0 +1,33 @@
// SPDX-License-Identifier: MPL-2.0
use alloc::fmt;
/// Always [`Sync`], but unsafe to reference the data.
pub(super) struct ForceSync<T>(T);
impl<T> fmt::Debug for ForceSync<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ForceSync").finish_non_exhaustive()
}
}
// SAFETY: The caller of the `ForceSync::get` method must ensure that the underlying data is not
// concurrently accessed if the underlying type is not `Sync`.
unsafe impl<T> Sync for ForceSync<T> {}
impl<T> ForceSync<T> {
/// Creates an instance with `data` as the inner data.
pub(super) fn new(data: T) -> Self {
Self(data)
}
/// Returns a reference to the inner data.
///
/// # Safety
///
/// If the data type is not [`Sync`], the caller must ensure that the data is not accessed
/// concurrently.
pub(super) unsafe fn get(&self) -> &T {
&self.0
}
}