esp_wifi/
preempt.rs

1//! This module allows hooking `esp-wifi` into an external scheduler, instead
2//! of using the integrated one as provided by the `preempt` module.
3//!
4//! In order to hook up an external scheduler, enable the `preempt-extern`
5//! feature, implement the `Scheduler` trait for a struct, and create the
6//! necessary `extern` functions using the `scheduler_impl!()` macro.
7//!
8//! Example:
9//!
10//! ```ignore
11//! use esp_wifi::preempt::Scheduler;
12//!
13//! struct MyScheduler {}
14//!
15//! impl Scheduler for MyScheduler {
16//!     // impl goes here
17//! }
18//!
19//! esp_wifi::scheduler_impl!(static SCHEDULER: MyScheduler = MyScheduler {});
20//! ```
21use core::ffi::c_void;
22
23pub trait Scheduler: Send + Sync + 'static {
24    /// This function is called by `esp-wifi` when starting up the WiFi stack.
25    fn enable(&self);
26
27    /// This function is called by `esp-wifi` when shutting down the WiFi stack.
28    fn disable(&self);
29
30    /// This function is called by threads and should switch to the next thread.
31    fn yield_task(&self);
32
33    /// This function is called by threads and should return an opaque handle
34    /// for the calling thread. The same handle will be passed to
35    /// `esp_wifi_preempt_schedule_task_deletion`.
36    fn current_task(&self) -> *mut c_void;
37
38    /// This function is used to create threads.
39    /// It should allocate the stack.
40    fn task_create(
41        &self,
42        task: extern "C" fn(*mut c_void),
43        param: *mut c_void,
44        task_stack_size: usize,
45    ) -> *mut c_void;
46
47    /// This function is called to let the scheduler know this thread is not
48    /// needed anymore and should be deleted. After this function is called,
49    /// the thread should not be scheduled anymore. The thread stack can be
50    /// free'ed.
51    fn schedule_task_deletion(&self, task_handle: *mut c_void);
52
53    /// This function should return an opaque per-thread pointer to an
54    /// usize-sized memory location, which will be used to store a pointer
55    /// to a semaphore for this thread.
56    fn current_task_thread_semaphore(&self) -> *mut c_void;
57}
58
59extern "Rust" {
60    fn esp_wifi_preempt_enable();
61    fn esp_wifi_preempt_disable();
62    fn esp_wifi_preempt_yield_task();
63    fn esp_wifi_preempt_current_task() -> *mut c_void;
64    fn esp_wifi_preempt_task_create(
65        task: extern "C" fn(*mut c_void),
66        param: *mut c_void,
67        task_stack_size: usize,
68    ) -> *mut c_void;
69    fn esp_wifi_preempt_schedule_task_deletion(task_handle: *mut c_void);
70    fn esp_wifi_preempt_current_task_thread_semaphore() -> *mut c_void;
71}
72
73pub(crate) fn enable() {
74    unsafe { esp_wifi_preempt_enable() }
75}
76
77pub(crate) fn disable() {
78    unsafe { esp_wifi_preempt_disable() }
79}
80
81pub(crate) fn yield_task() {
82    unsafe { esp_wifi_preempt_yield_task() }
83}
84
85pub(crate) fn current_task() -> *mut c_void {
86    unsafe { esp_wifi_preempt_current_task() }
87}
88
89pub(crate) fn task_create(
90    task: extern "C" fn(*mut c_void),
91    param: *mut c_void,
92    task_stack_size: usize,
93) -> *mut c_void {
94    unsafe { esp_wifi_preempt_task_create(task, param, task_stack_size) }
95}
96
97pub(crate) fn schedule_task_deletion(task_handle: *mut c_void) {
98    unsafe { esp_wifi_preempt_schedule_task_deletion(task_handle) }
99}
100
101pub(crate) fn current_task_thread_semaphore() -> *mut c_void {
102    unsafe { esp_wifi_preempt_current_task_thread_semaphore() }
103}
104
105/// Set the Scheduler implementation.
106///
107/// See the module documentation for an example.
108#[macro_export]
109macro_rules! scheduler_impl {
110    (static $name:ident: $t: ty = $val:expr) => {
111        static $name: $t = $val;
112
113        #[no_mangle]
114        fn esp_wifi_preempt_enable() {
115            <$t as $crate::preempt::Scheduler>::enable(&$name)
116        }
117        #[no_mangle]
118        fn esp_wifi_preempt_disable() {
119            <$t as $crate::preempt::Scheduler>::disable(&$name)
120        }
121        #[no_mangle]
122        fn esp_wifi_preempt_yield_task() {
123            <$t as $crate::preempt::Scheduler>::yield_task(&$name)
124        }
125        #[no_mangle]
126        fn esp_wifi_preempt_current_task() -> *mut c_void {
127            <$t as $crate::preempt::Scheduler>::current_task(&$name)
128        }
129        #[no_mangle]
130        fn esp_wifi_preempt_task_create(
131            task: extern "C" fn(*mut c_void),
132            param: *mut c_void,
133            task_stack_size: usize,
134        ) -> *mut c_void {
135            <$t as $crate::preempt::Scheduler>::task_create(&$name, task, param, task_stack_size)
136        }
137        #[no_mangle]
138        fn esp_wifi_preempt_schedule_task_deletion(task_handle: *mut c_void) {
139            <$t as $crate::preempt::Scheduler>::schedule_task_deletion(&$name, task_handle)
140        }
141        #[no_mangle]
142        fn esp_wifi_preempt_current_task_thread_semaphore() -> *mut c_void {
143            <$t as $crate::preempt::Scheduler>::current_task_thread_semaphore(&$name)
144        }
145    };
146}