Support the wait queue that allows sleeping

This commit is contained in:
Chuandong Li 2023-07-03 00:29:59 +08:00 committed by Tate, Hongliang Tian
parent 9edcbe743d
commit fba4a9405e
5 changed files with 19 additions and 15 deletions

View File

@ -4,7 +4,7 @@ use super::SpinLock;
use alloc::{collections::VecDeque, sync::Arc};
use bitflags::bitflags;
use crate::task::schedule;
use crate::task::{add_task, current_task, schedule, Task, TaskStatus};
/// A wait queue.
///
@ -85,7 +85,6 @@ impl WaitQueue {
}
}
#[derive(Debug)]
struct Waiter {
/// Whether the
is_woken_up: AtomicBool,
@ -93,6 +92,8 @@ struct Waiter {
flag: WaiterFlag,
/// if the wait condition is ture, then the waiter is finished and can be removed from waitqueue
wait_finished: AtomicBool,
/// The `Task` held by the waiter.
task: Arc<Task>,
}
impl Waiter {
@ -101,16 +102,18 @@ impl Waiter {
is_woken_up: AtomicBool::new(false),
flag: WaiterFlag::empty(),
wait_finished: AtomicBool::new(false),
task: current_task().unwrap(),
}
}
/// make self into wait status until be called wake up
pub fn wait(&self) {
self.is_woken_up.store(false, Ordering::SeqCst);
self.task.inner_exclusive_access().task_status = TaskStatus::Sleeping;
while !self.is_woken_up.load(Ordering::SeqCst) {
// yield the execution, to allow other task to continue
schedule();
}
self.task.inner_exclusive_access().task_status = TaskStatus::Runnable;
}
pub fn is_woken_up(&self) -> bool {
@ -119,6 +122,7 @@ impl Waiter {
pub fn wake_up(&self) {
self.is_woken_up.store(true, Ordering::SeqCst);
add_task(self.task.clone());
}
pub fn set_finished(&self) {

View File

@ -5,6 +5,6 @@ mod scheduler;
#[allow(clippy::module_inception)]
mod task;
pub use self::processor::schedule;
pub use self::scheduler::{set_scheduler, Scheduler};
pub use self::processor::{current_task, schedule};
pub use self::scheduler::{add_task, set_scheduler, Scheduler};
pub use self::task::{Task, TaskAdapter, TaskStatus};

View File

@ -71,8 +71,10 @@ pub fn switch_to_task(next_task: Arc<Task>) {
PROCESSOR.lock().get_idle_task_cx_ptr()
} else {
current_task = current_task_option.unwrap();
if current_task.status() != TaskStatus::Exited {
GLOBAL_SCHEDULER.lock().enqueue(current_task.clone());
if current_task.status() == TaskStatus::Runnable {
GLOBAL_SCHEDULER
.lock_irq_disabled()
.enqueue(current_task.clone());
}
&mut current_task.inner_exclusive_access().ctx as *mut TaskContext
};

View File

@ -1,12 +1,12 @@
use crate::prelude::*;
use crate::sync::SpinLock;
use crate::task::Task;
use lazy_static::lazy_static;
use spin::Mutex;
lazy_static! {
pub(crate) static ref GLOBAL_SCHEDULER: Mutex<GlobalScheduler> =
Mutex::new(GlobalScheduler { scheduler: None });
pub(crate) static ref GLOBAL_SCHEDULER: SpinLock<GlobalScheduler> =
SpinLock::new(GlobalScheduler { scheduler: None });
}
/// A scheduler for tasks.
@ -43,13 +43,13 @@ impl GlobalScheduler {
///
/// This must be called before invoking `Task::spawn`.
pub fn set_scheduler(scheduler: &'static dyn Scheduler) {
GLOBAL_SCHEDULER.lock().scheduler = Some(scheduler);
GLOBAL_SCHEDULER.lock_irq_disabled().scheduler = Some(scheduler);
}
pub fn fetch_task() -> Option<Arc<Task>> {
GLOBAL_SCHEDULER.lock().dequeue()
GLOBAL_SCHEDULER.lock_irq_disabled().dequeue()
}
pub fn add_task(task: Arc<Task>) {
GLOBAL_SCHEDULER.lock().enqueue(task);
GLOBAL_SCHEDULER.lock_irq_disabled().enqueue(task);
}

View File

@ -216,8 +216,6 @@ impl Task {
pub enum TaskStatus {
/// The task is runnable.
Runnable,
/// The task is running.
Running,
/// The task is sleeping.
Sleeping,
/// The task has exited.