|
@@ -1,10 +1,11 @@
|
|
|
mod adapter;
|
|
mod adapter;
|
|
|
mod task_state;
|
|
mod task_state;
|
|
|
|
|
+mod wait_list;
|
|
|
|
|
|
|
|
use crate::{
|
|
use crate::{
|
|
|
context::ExecutionContext,
|
|
context::ExecutionContext,
|
|
|
executor::{ExecuteStatus, Executor, ExecutorBuilder, OutputHandle, Stack},
|
|
executor::{ExecuteStatus, Executor, ExecutorBuilder, OutputHandle, Stack},
|
|
|
- run::{Contexted, PinRun},
|
|
|
|
|
|
|
+ run::{Contexted, Run},
|
|
|
scheduler::Scheduler,
|
|
scheduler::Scheduler,
|
|
|
};
|
|
};
|
|
|
use alloc::{boxed::Box, sync::Arc, task::Wake};
|
|
use alloc::{boxed::Box, sync::Arc, task::Wake};
|
|
@@ -19,12 +20,11 @@ use intrusive_collections::RBTreeAtomicLink;
|
|
|
use task_state::TaskState;
|
|
use task_state::TaskState;
|
|
|
|
|
|
|
|
pub use adapter::TaskAdapter;
|
|
pub use adapter::TaskAdapter;
|
|
|
|
|
+pub use wait_list::TaskWait;
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
|
|
pub struct TaskId(u32);
|
|
pub struct TaskId(u32);
|
|
|
|
|
|
|
|
-pub struct UniqueWaker(Arc<Task>);
|
|
|
|
|
-
|
|
|
|
|
pub struct TaskHandle<Output>
|
|
pub struct TaskHandle<Output>
|
|
|
where
|
|
where
|
|
|
Output: Send,
|
|
Output: Send,
|
|
@@ -34,17 +34,40 @@ where
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/// A `Task` represents a schedulable unit.
|
|
/// A `Task` represents a schedulable unit.
|
|
|
|
|
+///
|
|
|
|
|
+/// ## Task Sleeping and Waking up
|
|
|
|
|
+///
|
|
|
|
|
+/// ### Waiters
|
|
|
|
|
+///
|
|
|
|
|
+/// lock => check condition no => save waker => set state sleep => unlock => return pending
|
|
|
|
|
+///
|
|
|
|
|
+/// executor check state -> if sleeping => goto scheduler => get rq lock => scheduler check state
|
|
|
|
|
+///
|
|
|
|
|
+/// -> if sleeping => on_rq = false
|
|
|
|
|
+///
|
|
|
|
|
+/// -> if running => enqueue
|
|
|
|
|
+///
|
|
|
|
|
+/// -> if running => poll again
|
|
|
|
|
+///
|
|
|
|
|
+/// ### Wakers
|
|
|
|
|
+///
|
|
|
|
|
+/// lock => set condition yes => get waker => unlock => if has waker
|
|
|
|
|
+///
|
|
|
|
|
+/// set state running => swap on_rq true => get rq lock => check on_rq true again => if false enqueue
|
|
|
pub struct Task {
|
|
pub struct Task {
|
|
|
/// Unique identifier of the task.
|
|
/// Unique identifier of the task.
|
|
|
pub id: TaskId,
|
|
pub id: TaskId,
|
|
|
- /// Whether the task is on some run queue.
|
|
|
|
|
|
|
+ /// Whether the task is on some run queue (a.k.a ready).
|
|
|
pub(crate) on_rq: AtomicBool,
|
|
pub(crate) on_rq: AtomicBool,
|
|
|
|
|
+ /// The last cpu that the task was executed on.
|
|
|
|
|
+ /// If `on_rq` is `false`, we can't assume that this task is still on the cpu.
|
|
|
|
|
+ pub(crate) cpu: AtomicU32,
|
|
|
|
|
+ /// Task state.
|
|
|
|
|
+ pub(crate) state: TaskState,
|
|
|
/// Task execution context.
|
|
/// Task execution context.
|
|
|
pub(crate) execution_context: ExecutionContext,
|
|
pub(crate) execution_context: ExecutionContext,
|
|
|
/// Executor object.
|
|
/// Executor object.
|
|
|
executor: AtomicUniqueRefCell<Option<Pin<Box<dyn Executor>>>>,
|
|
executor: AtomicUniqueRefCell<Option<Pin<Box<dyn Executor>>>>,
|
|
|
- /// Task state.
|
|
|
|
|
- state: TaskState,
|
|
|
|
|
/// Link in the global task list.
|
|
/// Link in the global task list.
|
|
|
link_task_list: RBTreeAtomicLink,
|
|
link_task_list: RBTreeAtomicLink,
|
|
|
}
|
|
}
|
|
@@ -62,7 +85,7 @@ impl Task {
|
|
|
pub fn new<S, R>(runnable: R) -> TaskHandle<R::Output>
|
|
pub fn new<S, R>(runnable: R) -> TaskHandle<R::Output>
|
|
|
where
|
|
where
|
|
|
S: Stack + 'static,
|
|
S: Stack + 'static,
|
|
|
- R: PinRun + Contexted + Send + 'static,
|
|
|
|
|
|
|
+ R: Run + Contexted + Send + 'static,
|
|
|
R::Output: Send + 'static,
|
|
R::Output: Send + 'static,
|
|
|
{
|
|
{
|
|
|
static ID: AtomicU32 = AtomicU32::new(0);
|
|
static ID: AtomicU32 = AtomicU32::new(0);
|
|
@@ -75,9 +98,10 @@ impl Task {
|
|
|
let task = Arc::new(Self {
|
|
let task = Arc::new(Self {
|
|
|
id: TaskId(ID.fetch_add(1, Ordering::Relaxed)),
|
|
id: TaskId(ID.fetch_add(1, Ordering::Relaxed)),
|
|
|
on_rq: AtomicBool::new(false),
|
|
on_rq: AtomicBool::new(false),
|
|
|
|
|
+ cpu: AtomicU32::new(0),
|
|
|
|
|
+ state: TaskState::new(TaskState::RUNNING),
|
|
|
executor: AtomicUniqueRefCell::new(Some(executor)),
|
|
executor: AtomicUniqueRefCell::new(Some(executor)),
|
|
|
execution_context,
|
|
execution_context,
|
|
|
- state: TaskState::new(TaskState::RUNNING),
|
|
|
|
|
link_task_list: RBTreeAtomicLink::new(),
|
|
link_task_list: RBTreeAtomicLink::new(),
|
|
|
});
|
|
});
|
|
|
|
|
|
|
@@ -87,41 +111,6 @@ impl Task {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- pub fn is_runnable(&self) -> bool {
|
|
|
|
|
- self.state.is_runnable()
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- pub(super) fn set_usleep(&self) {
|
|
|
|
|
- let prev_state = self.state.swap(TaskState::USLEEP);
|
|
|
|
|
- assert_eq!(
|
|
|
|
|
- prev_state,
|
|
|
|
|
- TaskState::RUNNING,
|
|
|
|
|
- "Trying to set task {} usleep that is not running",
|
|
|
|
|
- self.id.0
|
|
|
|
|
- );
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- pub fn usleep(self: &Arc<Self>) -> Arc<UniqueWaker> {
|
|
|
|
|
- // No need to dequeue. We have proved that the task is running so not in the queue.
|
|
|
|
|
- self.set_usleep();
|
|
|
|
|
-
|
|
|
|
|
- Arc::new(UniqueWaker(self.clone()))
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- pub fn isleep(self: &Arc<Self>) -> Arc<Self> {
|
|
|
|
|
- // No need to dequeue. We have proved that the task is running so not in the queue.
|
|
|
|
|
- let prev_state = self.state.cmpxchg(TaskState::RUNNING, TaskState::ISLEEP);
|
|
|
|
|
-
|
|
|
|
|
- assert_eq!(
|
|
|
|
|
- prev_state,
|
|
|
|
|
- TaskState::RUNNING,
|
|
|
|
|
- "Trying to sleep task {} that is not running",
|
|
|
|
|
- self.id.0
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- self.clone()
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
pub fn run(&self) -> ExecuteStatus {
|
|
pub fn run(&self) -> ExecuteStatus {
|
|
|
let mut executor_borrow = self.executor.borrow();
|
|
let mut executor_borrow = self.executor.borrow();
|
|
|
|
|
|
|
@@ -133,39 +122,33 @@ impl Task {
|
|
|
|
|
|
|
|
if let ExecuteStatus::Finished = executor.progress() {
|
|
if let ExecuteStatus::Finished = executor.progress() {
|
|
|
executor_borrow.take();
|
|
executor_borrow.take();
|
|
|
- self.set_usleep();
|
|
|
|
|
ExecuteStatus::Finished
|
|
ExecuteStatus::Finished
|
|
|
} else {
|
|
} else {
|
|
|
ExecuteStatus::Executing
|
|
ExecuteStatus::Executing
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-}
|
|
|
|
|
|
|
|
|
|
-impl Wake for Task {
|
|
|
|
|
- fn wake(self: Arc<Self>) {
|
|
|
|
|
- self.wake_by_ref();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- fn wake_by_ref(self: &Arc<Self>) {
|
|
|
|
|
- match self.state.cmpxchg(TaskState::ISLEEP, TaskState::RUNNING) {
|
|
|
|
|
- TaskState::RUNNING | TaskState::USLEEP => return,
|
|
|
|
|
- TaskState::ISLEEP => Scheduler::get().activate(self),
|
|
|
|
|
- state => panic!("Invalid transition from state {:?} to `Running`", state),
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ /// Temporary solution.
|
|
|
|
|
+ pub unsafe fn sleep(&self) {
|
|
|
|
|
+ self.state.swap(TaskState::SLEEPING);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-impl Wake for UniqueWaker {
|
|
|
|
|
|
|
+impl Wake for Task {
|
|
|
fn wake(self: Arc<Self>) {
|
|
fn wake(self: Arc<Self>) {
|
|
|
self.wake_by_ref();
|
|
self.wake_by_ref();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
fn wake_by_ref(self: &Arc<Self>) {
|
|
fn wake_by_ref(self: &Arc<Self>) {
|
|
|
- let Self(task) = &**self;
|
|
|
|
|
|
|
+ // TODO: Check the fast path where we're waking up current.
|
|
|
|
|
|
|
|
- let prev_state = task.state.swap(TaskState::RUNNING);
|
|
|
|
|
- assert_eq!(prev_state, TaskState::USLEEP);
|
|
|
|
|
|
|
+ // SAFETY: All the operations below should happen after we've read the sleeping state.
|
|
|
|
|
+ let old_state = self.state.swap(TaskState::RUNNING);
|
|
|
|
|
+ if old_state != TaskState::SLEEPING {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- Scheduler::get().activate(task);
|
|
|
|
|
|
|
+ // If we get here, we should be the only one waking up the task.
|
|
|
|
|
+ Scheduler::get().activate(self);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|