Forráskód Böngészése

task, thread: working version of threads

We've got everything done in order to make the system run.

Add Thread::contexted to load the context needed for the thread to run.
Wrap the Thread::real_run() with contexted(stackful(...)) in
Thread::run().

We would use this for now. Later, we will make the thread completely
asynchronous. This way we don't have to change its interface then.

Signed-off-by: greatbridf <greatbridf@icloud.com>
greatbridf 5 hónapja
szülő
commit
9c900be225
4 módosított fájl, 109 hozzáadás és 51 törlés
  1. 66 22
      src/kernel/task.rs
  2. 2 2
      src/kernel/task/clone.rs
  3. 39 25
      src/kernel/task/thread.rs
  4. 2 2
      src/lib.rs

+ 66 - 22
src/kernel/task.rs

@@ -79,29 +79,68 @@ pub async fn stackful<F>(mut future: F) -> F::Output
 where
     F: core::future::Future,
 {
+    use crate::kernel::{
+        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;
     use eonix_hal::traits::fault::Fault;
     use eonix_hal::traits::trap::RawTrapContext;
     use eonix_hal::traits::trap::TrapReturn;
+    use eonix_hal::traits::trap::TrapType;
     use eonix_hal::trap::TrapContext;
-    use eonix_log::println_debug;
+    use eonix_preempt::assert_preempt_enabled;
     use eonix_runtime::executor::Stack;
-
-    use crate::kernel::{
-        interrupt::{default_fault_handler, default_irq_handler},
-        timer::{should_reschedule, timer_interrupt},
-    };
+    use thread::wait_for_wakeups;
 
     let stack = KernelStack::new();
 
-    fn execute<F>(
-        future: core::pin::Pin<&mut F>,
-        output_ptr: core::ptr::NonNull<Option<F::Output>>,
-    ) -> !
+    fn execute<F>(mut future: Pin<&mut F>, output_ptr: NonNull<Option<F::Output>>) -> !
     where
-        F: core::future::Future,
+        F: Future,
     {
-        let output = do_block_on(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 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) {
+                        continue;
+                    }
+
+                    assert_preempt_enabled!("Blocking in stackful futures is not allowed.");
+
+                    unsafe {
+                        core::arch::asm!("ebreak");
+                    }
+                }
+            }
+        };
 
         unsafe {
             output_ptr.write(Some(output));
@@ -115,7 +154,7 @@ where
     }
 
     let sp = stack.get_bottom();
-    let output = UnsafeCell::new(None);
+    let mut output = UnsafeCell::new(None);
 
     let mut trap_ctx = TrapContext::new();
 
@@ -135,21 +174,26 @@ where
         }
 
         match trap_ctx.trap_type() {
-            eonix_hal::traits::trap::TrapType::Syscall { .. } => {}
-            eonix_hal::traits::trap::TrapType::Fault(fault) => {
+            TrapType::Syscall { .. } => {}
+            TrapType::Fault(fault) => {
                 // Breakpoint
                 if let Fault::Unknown(3) = &fault {
-                    println_debug!("Breakpoint hit, returning output");
-                    break output.into_inner().unwrap();
+                    if let Some(output) = output.get_mut().take() {
+                        break output;
+                    } else {
+                        wait_for_wakeups().await;
+                    }
+
+                    trap_ctx.set_program_counter(trap_ctx.get_program_counter() + 2);
+                } else {
+                    default_fault_handler(fault, &mut trap_ctx)
                 }
-
-                default_fault_handler(fault, &mut trap_ctx)
             }
-            eonix_hal::traits::trap::TrapType::Irq { callback } => callback(default_irq_handler),
-            eonix_hal::traits::trap::TrapType::Timer { callback } => {
+            TrapType::Irq { callback } => callback(default_irq_handler),
+            TrapType::Timer { callback } => {
                 callback(timer_interrupt);
 
-                if should_reschedule() {
+                if eonix_preempt::count() == 0 && should_reschedule() {
                     yield_now().await;
                 }
             }

+ 2 - 2
src/kernel/task/clone.rs

@@ -1,4 +1,4 @@
-use super::{block_on, stackful};
+use super::block_on;
 use crate::{
     kernel::{
         syscall::procops::parse_user_tls,
@@ -164,7 +164,7 @@ pub fn do_clone(thread: &Thread, clone_args: CloneArgs) -> KResult<u32> {
         UserPointerMut::new(parent_tid_ptr as *mut u32)?.write(new_pid)?
     }
 
-    RUNTIME.spawn(stackful(new_thread.run()));
+    RUNTIME.spawn(new_thread.run());
 
     Ok(new_pid)
 }

+ 39 - 25
src/kernel/task/thread.rs

@@ -1,6 +1,6 @@
 use super::{
     signal::{RaiseResult, SignalList},
-    Process, ProcessList, WaitType,
+    stackful, Process, ProcessList, WaitType,
 };
 use crate::{
     kernel::{
@@ -16,8 +16,8 @@ use crate::{
 use alloc::sync::Arc;
 use atomic_unique_refcell::AtomicUniqueRefCell;
 use core::{
-    future::Future,
-    pin::{pin, Pin},
+    future::{poll_fn, Future},
+    pin::Pin,
     ptr::NonNull,
     sync::atomic::{AtomicBool, Ordering},
     task::{Context, Poll},
@@ -28,9 +28,9 @@ use eonix_hal::{
     traits::{
         fault::Fault,
         fpu::RawFpuState as _,
-        trap::{IrqState as _, RawTrapContext, TrapReturn, TrapType},
+        trap::{RawTrapContext, TrapReturn, TrapType},
     },
-    trap::{disable_irqs_save, TrapContext},
+    trap::TrapContext,
 };
 use eonix_mm::address::{Addr as _, VAddr};
 use eonix_sync::AsProofMut as _;
@@ -415,36 +415,39 @@ impl Thread {
         }
     }
 
-    pub fn run(self: Arc<Thread>) -> impl Future<Output = ()> + Send + 'static {
-        async fn real_run_with_context(me: &Arc<Thread>) {
-            let mut future = pin!(me.real_run());
+    async fn contexted<F>(&self, future: F) -> F::Output
+    where
+        F: Future,
+    {
+        let mut future = core::pin::pin!(future);
 
-            core::future::poll_fn(|cx| {
-                me.process.mm_list.activate();
+        core::future::poll_fn(|cx| {
+            self.process.mm_list.activate();
 
-                CURRENT_THREAD.set(NonNull::new(Arc::as_ptr(me) as *mut _));
+            CURRENT_THREAD.set(NonNull::new(&raw const *self as *mut _));
 
-                unsafe {
-                    // SAFETY: Preemption is disabled.
-                    me.load_thread_area32();
-                }
+            unsafe {
+                eonix_preempt::disable();
 
-                let irq_state = disable_irqs_save();
+                // SAFETY: Preemption is disabled.
+                self.load_thread_area32();
 
-                let result = future.as_mut().poll(cx);
+                eonix_preempt::enable();
+            }
 
-                irq_state.restore();
+            let result = future.as_mut().poll(cx);
 
-                me.process.mm_list.deactivate();
+            self.process.mm_list.deactivate();
 
-                CURRENT_THREAD.set(None);
+            CURRENT_THREAD.set(None);
 
-                result
-            })
-            .await
-        }
+            result
+        })
+        .await
+    }
 
-        async move { real_run_with_context(&self).await }
+    pub fn run(self: Arc<Thread>) -> impl Future<Output = ()> + Send + 'static {
+        async move { self.contexted(stackful(self.real_run())).await }
     }
 }
 
@@ -469,3 +472,14 @@ pub async fn yield_now() {
 
     Yield { yielded: false }.await;
 }
+
+pub fn wait_for_wakeups() -> impl Future<Output = ()> {
+    let mut waited = false;
+    poll_fn(move |_| match waited {
+        true => Poll::Ready(()),
+        false => {
+            waited = true;
+            Poll::Pending
+        }
+    })
+}

+ 2 - 2
src/lib.rs

@@ -37,7 +37,7 @@ use eonix_mm::address::PRange;
 use eonix_runtime::{executor::Stack, scheduler::RUNTIME};
 use kernel::{
     mem::GlobalPageAlloc,
-    task::{stackful, KernelStack, ProcessBuilder, ProcessList, ProgramLoader, ThreadBuilder},
+    task::{KernelStack, ProcessBuilder, ProcessList, ProgramLoader, ThreadBuilder},
     vfs::{
         dentry::Dentry,
         mount::{do_mount, MS_NOATIME, MS_NODEV, MS_NOSUID, MS_RDONLY},
@@ -272,5 +272,5 @@ async fn init_process(early_kstack: PRange) {
     // TODO!!!: Remove this.
     thread.files.open_console();
 
-    RUNTIME.spawn(stackful(thread.run()));
+    RUNTIME.spawn(thread.run());
 }