diff --git a/rtic-macros/CHANGELOG.md b/rtic-macros/CHANGELOG.md index 86b051b695fc..6b583b8cbd07 100644 --- a/rtic-macros/CHANGELOG.md +++ b/rtic-macros/CHANGELOG.md @@ -7,6 +7,8 @@ For each category, *Added*, *Changed*, *Fixed* add new entries at the top! ## [Unreleased] +- Added `waker` getter to software tasks + ## [v2.1.1] - 2024-12-06 ### Changed diff --git a/rtic-macros/src/codegen/module.rs b/rtic-macros/src/codegen/module.rs index a8700c5bafb9..1d2f90a6928b 100644 --- a/rtic-macros/src/codegen/module.rs +++ b/rtic-macros/src/codegen/module.rs @@ -158,6 +158,7 @@ pub fn codegen(ctxt: Context, app: &App, analysis: &Analysis) -> TokenStream2 { }; let internal_spawn_ident = util::internal_task_ident(name, "spawn"); + let internal_waker_ident = util::internal_task_ident(name, "waker"); let from_ptr_n_args = util::from_ptr_n_args_ident(spawnee.inputs.len()); let (input_args, input_tupled, input_untupled, input_ty) = util::regroup_inputs(&spawnee.inputs); @@ -184,11 +185,36 @@ pub fn codegen(ctxt: Context, app: &App, analysis: &Analysis) -> TokenStream2 { } )); + // Waker + items.push(quote!( + #(#cfgs)* + /// Gives waker to the task + #[allow(non_snake_case)] + #[doc(hidden)] + pub fn #internal_waker_ident() -> ::core::task::Waker { + // SAFETY: #exec_name is a valid pointer to an executor. + unsafe { + let exec = rtic::export::executor::AsyncTaskExecutor::#from_ptr_n_args(#name, &#exec_name); + exec.waker(|| { + let exec = rtic::export::executor::AsyncTaskExecutor::#from_ptr_n_args(#name, &#exec_name); + exec.set_pending(); + #pend_interrupt + }) + } + } + )); + module_items.push(quote!( #(#cfgs)* #[doc(inline)] pub use super::#internal_spawn_ident as spawn; )); + + module_items.push(quote!( + #(#cfgs)* + #[doc(inline)] + pub use super::#internal_waker_ident as waker; + )); } if items.is_empty() { diff --git a/rtic/CHANGELOG.md b/rtic/CHANGELOG.md index faefaeb8edae..5bad996ec795 100644 --- a/rtic/CHANGELOG.md +++ b/rtic/CHANGELOG.md @@ -20,6 +20,8 @@ Example: ## [Unreleased] +- Added public `waker` constructor to the executor. + ## [v2.1.2] - 2024-12-06 ### Changed diff --git a/rtic/src/export/executor.rs b/rtic/src/export/executor.rs index 8d42c4153fa8..b82dfe97f770 100644 --- a/rtic/src/export/executor.rs +++ b/rtic/src/export/executor.rs @@ -192,11 +192,16 @@ impl AsyncTaskExecutor { self.set_pending(); } + #[inline(always)] + pub const fn waker(&self, wake: fn()) -> Waker { + unsafe { Waker::from_raw(RawWaker::new(wake as *const (), &WAKER_VTABLE)) } + } + /// Poll the future in the executor. #[inline(always)] pub fn poll(&self, wake: fn()) { if self.is_running() && self.check_and_clear_pending() { - let waker = unsafe { Waker::from_raw(RawWaker::new(wake as *const (), &WAKER_VTABLE)) }; + let waker = self.waker(wake); let mut cx = Context::from_waker(&waker); let future = unsafe { Pin::new_unchecked(&mut *(self.task.get() as *mut F)) };