Procházet zdrojové kódy

task: fix stackful waker implementation

The current implementation use the WokenUp object to detect whether the
stackful task is woken up somewhere. This is WRONG since we might lose
wakeups as the runtime have no idea what we have done. If someone wakes
us up, the task won't be enqueued so we will never have a second chance
to get to the foreground.

The fix is to use Arc<Task> to create a waker and check whether the task
is ready each time we get back to the stackful poll loop.

Signed-off-by: greatbridf <greatbridf@icloud.com>
greatbridf před 5 měsíci
rodič
revize
21b765092f

+ 4 - 0
crates/eonix_runtime/src/task.rs

@@ -93,6 +93,10 @@ impl Task {
             return rq;
         }
     }
+
+    pub fn is_ready(&self) -> bool {
+        self.state.is_ready()
+    }
 }
 
 impl Wake for Task {

+ 4 - 0
crates/eonix_runtime/src/task/task_state.rs

@@ -22,4 +22,8 @@ impl TaskState {
         self.0
             .fetch_update(Ordering::SeqCst, Ordering::SeqCst, func)
     }
+
+    pub(crate) fn is_ready(&self) -> bool {
+        self.0.load(Ordering::SeqCst) & Self::READY == Self::READY
+    }
 }

+ 4 - 20
src/kernel/task.rs

@@ -10,6 +10,7 @@ mod signal;
 mod thread;
 
 pub use clone::{do_clone, CloneArgs, CloneFlags};
+use eonix_runtime::task::Task;
 pub use futex::{futex_wait, futex_wake, parse_futexop, FutexFlags, FutexOp, RobustListHead};
 pub use kernel_stack::KernelStack;
 pub use loader::ProgramLoader;
@@ -18,7 +19,7 @@ pub use process_group::ProcessGroup;
 pub use process_list::ProcessList;
 pub use session::Session;
 pub use signal::SignalAction;
-pub use thread::{yield_now, Thread, ThreadBuilder};
+pub use thread::{yield_now, Thread, ThreadAlloc, ThreadBuilder};
 
 fn do_block_on<F>(mut future: core::pin::Pin<&mut F>) -> F::Output
 where
@@ -83,14 +84,10 @@ where
         interrupt::{default_fault_handler, default_irq_handler},
         timer::{should_reschedule, timer_interrupt},
     };
-    use alloc::sync::Arc;
-    use alloc::task::Wake;
     use core::cell::UnsafeCell;
     use core::future::Future;
     use core::pin::Pin;
     use core::ptr::NonNull;
-    use core::sync::atomic::AtomicBool;
-    use core::sync::atomic::Ordering;
     use core::task::Context;
     use core::task::Poll;
     use core::task::Waker;
@@ -108,27 +105,14 @@ where
     where
         F: Future,
     {
-        struct WokenUp(AtomicBool);
-
-        impl Wake for WokenUp {
-            fn wake(self: Arc<Self>) {
-                self.wake_by_ref();
-            }
-
-            fn wake_by_ref(self: &Arc<Self>) {
-                self.0.swap(true, Ordering::AcqRel);
-            }
-        }
-
-        let woken_up = Arc::new(WokenUp(AtomicBool::new(false)));
-        let waker = Waker::from(woken_up.clone());
+        let waker = Waker::from(Task::current().clone());
         let mut cx = Context::from_waker(&waker);
 
         let output = loop {
             match future.as_mut().poll(&mut cx) {
                 Poll::Ready(output) => break output,
                 Poll::Pending => {
-                    if woken_up.0.swap(false, Ordering::Acquire) {
+                    if Task::current().is_ready() {
                         continue;
                     }