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