task.rs 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. mod clone;
  2. mod futex;
  3. mod kernel_stack;
  4. mod loader;
  5. mod process;
  6. mod process_group;
  7. mod process_list;
  8. mod session;
  9. mod signal;
  10. mod thread;
  11. mod user_tls;
  12. pub use clone::{do_clone, CloneArgs, CloneFlags};
  13. use eonix_hal::symbol_addr;
  14. pub use futex::{
  15. futex_exec, futex_exit, futex_wait, futex_wake, parse_futexop, FutexFlags,
  16. FutexOp, RobustListHead,
  17. };
  18. pub use kernel_stack::KernelStack;
  19. pub use loader::ProgramLoader;
  20. pub use process::{
  21. alloc_pid, Process, ProcessBuilder, WaitId, WaitObject, WaitType,
  22. };
  23. pub use process_group::ProcessGroup;
  24. pub use process_list::ProcessList;
  25. pub use session::Session;
  26. pub use signal::SignalAction;
  27. pub use thread::{yield_now, Thread, ThreadAlloc, ThreadBuilder};
  28. pub use user_tls::{UserTLS, UserTLSDescriptor};
  29. fn do_block_on<F>(mut future: core::pin::Pin<&mut F>) -> F::Output
  30. where
  31. F: core::future::Future,
  32. {
  33. let waker = core::task::Waker::noop();
  34. let mut cx = core::task::Context::from_waker(&waker);
  35. loop {
  36. match future.as_mut().poll(&mut cx) {
  37. core::task::Poll::Ready(output) => return output,
  38. core::task::Poll::Pending => {}
  39. }
  40. }
  41. }
  42. /// Constantly poll the given future until it is ready, blocking the current thread.
  43. ///
  44. /// # Warning
  45. /// This function will block the current thread and should not be used in async
  46. /// contexts as it might cause infinite blocking or deadlocks. The following is
  47. /// a bad example:
  48. ///
  49. /// ```ignore
  50. /// block_on(async {
  51. /// // This will block the current thread forever.
  52. /// loop {
  53. /// println_debug!("This will never end!");
  54. /// }
  55. /// });
  56. ///
  57. /// // The code below will never be reached.
  58. /// println_debug!("You'll never see this message!");
  59. /// ```
  60. ///
  61. /// Use [`stackful`] instead to run async (or computational) code in a separate
  62. /// stackful (and preemptive) context or `RUNTIME.spawn` to run async code in
  63. /// the runtime's executor.
  64. pub fn block_on<F>(future: F) -> F::Output
  65. where
  66. F: core::future::Future,
  67. {
  68. do_block_on(core::pin::pin!(future))
  69. }
  70. /// Run the given future in a stackful context, allowing it to be preempted by
  71. /// timer interrupts.
  72. ///
  73. /// ```ignore
  74. /// RUNTIME.spawn(stackful(async {
  75. /// // Some simulated computation heavy task.
  76. /// loop {
  77. /// println_debug!("Hello from stackful future!");
  78. /// }
  79. /// }));
  80. /// ```
  81. pub async fn stackful<F>(mut future: F) -> F::Output
  82. where
  83. F: core::future::Future,
  84. {
  85. use alloc::sync::Arc;
  86. use alloc::task::Wake;
  87. use core::cell::UnsafeCell;
  88. use core::future::Future;
  89. use core::pin::Pin;
  90. use core::ptr::NonNull;
  91. use core::sync::atomic::{AtomicBool, Ordering};
  92. use core::task::{Context, Poll, Waker};
  93. use eonix_hal::traits::trap::{RawTrapContext, TrapReturn, TrapType};
  94. use eonix_hal::trap::TrapContext;
  95. use eonix_preempt::assert_preempt_enabled;
  96. use eonix_runtime::executor::Stack;
  97. use eonix_runtime::task::Task;
  98. use thread::wait_for_wakeups;
  99. use crate::kernel::interrupt::{
  100. default_fault_handler, default_irq_handler,
  101. };
  102. use crate::kernel::timer::{should_reschedule, timer_interrupt};
  103. let stack = KernelStack::new();
  104. fn execute<F>(
  105. mut future: Pin<&mut F>, output_ptr: NonNull<Option<F::Output>>,
  106. ) -> !
  107. where
  108. F: Future,
  109. {
  110. struct WakeSaver {
  111. task: Arc<Task>,
  112. woken: AtomicBool,
  113. }
  114. impl Wake for WakeSaver {
  115. fn wake_by_ref(self: &Arc<Self>) {
  116. // SAFETY: If we read true below in the loop, we must have been
  117. // woken up and acquired our waker's work by the runtime.
  118. self.woken.store(true, Ordering::Relaxed);
  119. self.task.wake_by_ref();
  120. }
  121. fn wake(self: Arc<Self>) {
  122. self.wake_by_ref();
  123. }
  124. }
  125. let wake_saver = Arc::new(WakeSaver {
  126. task: Task::current().clone(),
  127. woken: AtomicBool::new(false),
  128. });
  129. let waker = Waker::from(wake_saver.clone());
  130. let mut cx = Context::from_waker(&waker);
  131. let output = loop {
  132. match future.as_mut().poll(&mut cx) {
  133. Poll::Ready(output) => break output,
  134. Poll::Pending => {
  135. assert_preempt_enabled!(
  136. "Blocking in stackful futures is not allowed."
  137. );
  138. if Task::current().is_ready() {
  139. continue;
  140. }
  141. // SAFETY: The runtime must have ensured that we can see the
  142. // work done by the waker.
  143. if wake_saver.woken.swap(false, Ordering::Relaxed) {
  144. continue;
  145. }
  146. unsafe {
  147. #[cfg(target_arch = "riscv64")]
  148. core::arch::asm!("ebreak");
  149. #[cfg(target_arch = "loongarch64")]
  150. core::arch::asm!("break 1");
  151. }
  152. }
  153. }
  154. };
  155. drop(cx);
  156. drop(waker);
  157. drop(wake_saver);
  158. unsafe {
  159. output_ptr.write(Some(output));
  160. }
  161. unsafe {
  162. #[cfg(target_arch = "riscv64")]
  163. core::arch::asm!("ebreak");
  164. #[cfg(target_arch = "loongarch64")]
  165. core::arch::asm!("break 1");
  166. }
  167. unreachable!()
  168. }
  169. let sp = stack.get_bottom();
  170. let mut output = UnsafeCell::new(None);
  171. let mut trap_ctx = TrapContext::new();
  172. trap_ctx.set_user_mode(false);
  173. trap_ctx.set_interrupt_enabled(true);
  174. let _ = trap_ctx.set_user_call_frame(
  175. symbol_addr!(execute::<F>),
  176. Some(sp.addr().get()),
  177. None,
  178. &[(&raw mut future) as usize, output.get() as usize],
  179. |_, _| Ok::<(), u32>(()),
  180. );
  181. loop {
  182. unsafe {
  183. trap_ctx.trap_return();
  184. }
  185. match trap_ctx.trap_type() {
  186. TrapType::Syscall { .. } => {}
  187. TrapType::Fault(fault) => {
  188. default_fault_handler(fault, &mut trap_ctx)
  189. }
  190. TrapType::Irq { callback } => callback(default_irq_handler),
  191. TrapType::Timer { callback } => {
  192. callback(timer_interrupt);
  193. if eonix_preempt::count() == 0 && should_reschedule() {
  194. yield_now().await;
  195. }
  196. }
  197. TrapType::Breakpoint => {
  198. if let Some(output) = output.get_mut().take() {
  199. break output;
  200. } else {
  201. wait_for_wakeups().await;
  202. }
  203. #[cfg(target_arch = "riscv64")]
  204. trap_ctx
  205. .set_program_counter(trap_ctx.get_program_counter() + 2);
  206. #[cfg(target_arch = "loongarch64")]
  207. trap_ctx
  208. .set_program_counter(trap_ctx.get_program_counter() + 4);
  209. }
  210. }
  211. }
  212. }