esp_wifi/preempt_builtin/
mod.rs
1#[cfg_attr(target_arch = "riscv32", path = "preempt_riscv.rs")]
2#[cfg_attr(target_arch = "xtensa", path = "preempt_xtensa.rs")]
3mod arch_specific;
4pub mod timer;
5
6use core::{ffi::c_void, mem::size_of};
7
8use arch_specific::*;
9use esp_hal::sync::Locked;
10use esp_wifi_sys::include::malloc;
11use timer::{disable_multitasking, setup_multitasking};
12pub(crate) use timer::{disable_timer, setup_timer};
13
14use crate::{compat::malloc::free, hal::trapframe::TrapFrame, memory_fence::memory_fence};
15
16#[repr(transparent)]
17struct ContextWrapper(*mut Context);
18
19unsafe impl Send for ContextWrapper {}
20
21static CTX_NOW: Locked<ContextWrapper> = Locked::new(ContextWrapper(core::ptr::null_mut()));
22
23static mut SCHEDULED_TASK_TO_DELETE: *mut Context = core::ptr::null_mut();
24
25use crate::preempt::Scheduler;
26
27struct BuiltinScheduler {}
28
29crate::scheduler_impl!(static SCHEDULER: BuiltinScheduler = BuiltinScheduler {});
30
31impl Scheduler for BuiltinScheduler {
32 fn enable(&self) {
33 allocate_main_task();
35 setup_multitasking();
36 }
37
38 fn disable(&self) {
39 disable_multitasking();
40 delete_all_tasks();
41
42 timer::TIMER.with(|timer| timer.take());
43 }
44
45 fn yield_task(&self) {
46 timer::yield_task()
47 }
48
49 fn task_create(
50 &self,
51 task: extern "C" fn(*mut c_void),
52 param: *mut c_void,
53 task_stack_size: usize,
54 ) -> *mut c_void {
55 arch_specific::task_create(task, param, task_stack_size) as *mut c_void
56 }
57
58 fn current_task(&self) -> *mut c_void {
59 current_task() as *mut c_void
60 }
61
62 fn schedule_task_deletion(&self, task_handle: *mut c_void) {
63 schedule_task_deletion(task_handle as *mut Context)
64 }
65
66 fn current_task_thread_semaphore(&self) -> *mut crate::binary::c_types::c_void {
67 unsafe {
68 &mut ((*current_task()).thread_semaphore) as *mut _
69 as *mut crate::binary::c_types::c_void
70 }
71 }
72}
73
74fn allocate_main_task() -> *mut Context {
75 CTX_NOW.with(|ctx_now| unsafe {
76 if !ctx_now.0.is_null() {
77 panic!("Tried to allocate main task multiple times");
78 }
79
80 let ptr = malloc(size_of::<Context>() as u32) as *mut Context;
81 core::ptr::write(ptr, Context::new());
82 (*ptr).next = ptr;
83 ctx_now.0 = ptr;
84 ptr
85 })
86}
87
88fn allocate_task() -> *mut Context {
89 CTX_NOW.with(|ctx_now| unsafe {
90 if ctx_now.0.is_null() {
91 panic!("Called `allocate_task` before allocating main task");
92 }
93
94 let ptr = malloc(size_of::<Context>() as u32) as *mut Context;
95 core::ptr::write(ptr, Context::new());
96 (*ptr).next = (*ctx_now.0).next;
97 (*ctx_now.0).next = ptr;
98 ptr
99 })
100}
101
102fn next_task() {
103 CTX_NOW.with(|ctx_now| unsafe {
104 ctx_now.0 = (*ctx_now.0).next;
105 });
106}
107
108fn delete_task(task: *mut Context) {
112 CTX_NOW.with(|ctx_now| unsafe {
113 let mut ptr = ctx_now.0;
114 let initial = ptr;
115 loop {
116 if (*ptr).next == task {
117 (*ptr).next = (*((*ptr).next)).next;
118
119 free((*task).allocated_stack as *mut u8);
120 free(task as *mut u8);
121 break;
122 }
123
124 ptr = (*ptr).next;
125
126 if ptr == initial {
127 break;
128 }
129 }
130
131 memory_fence();
132 });
133}
134
135fn delete_all_tasks() {
136 CTX_NOW.with(|ctx_now| unsafe {
137 let current_task = ctx_now.0;
138
139 if current_task.is_null() {
140 return;
141 }
142
143 let mut task_to_delete = current_task;
144
145 loop {
146 let next_task = (*task_to_delete).next;
147
148 free((*task_to_delete).allocated_stack as *mut u8);
149 free(task_to_delete as *mut u8);
150
151 if next_task == current_task {
152 break;
153 }
154
155 task_to_delete = next_task;
156 }
157
158 ctx_now.0 = core::ptr::null_mut();
159
160 memory_fence();
161 });
162}
163
164fn current_task() -> *mut Context {
165 CTX_NOW.with(|ctx_now| ctx_now.0)
166}
167
168fn schedule_task_deletion(task: *mut Context) {
169 unsafe {
170 SCHEDULED_TASK_TO_DELETE = task;
171 }
172
173 if task == current_task() {
174 loop {
175 timer::yield_task();
176 }
177 }
178}
179
180pub(crate) fn task_switch(trap_frame: &mut TrapFrame) {
181 save_task_context(current_task(), trap_frame);
182
183 unsafe {
184 if !SCHEDULED_TASK_TO_DELETE.is_null() {
185 delete_task(SCHEDULED_TASK_TO_DELETE);
186 SCHEDULED_TASK_TO_DELETE = core::ptr::null_mut();
187 }
188 }
189
190 next_task();
191 restore_task_context(current_task(), trap_frame);
192}