|
| 1 | +use std::marker::PhantomData; |
| 2 | + |
1 | 3 | use crate::syntax::{ast::App, Context};
|
2 | 4 | use crate::{analyze::Analysis, codegen::bindings::interrupt_mod, codegen::util};
|
3 | 5 | use proc_macro2::TokenStream as TokenStream2;
|
@@ -112,36 +114,6 @@ pub fn codegen(ctxt: Context, app: &App, analysis: &Analysis) -> TokenStream2 {
|
112 | 114 | let internal_context_name = util::internal_task_ident(name, "Context");
|
113 | 115 | let exec_name = util::internal_task_ident(name, "EXEC");
|
114 | 116 |
|
115 |
| - items.push(quote!( |
116 |
| - #(#cfgs)* |
117 |
| - /// Execution context |
118 |
| - #[allow(non_snake_case)] |
119 |
| - #[allow(non_camel_case_types)] |
120 |
| - pub struct #internal_context_name<'a> { |
121 |
| - #[doc(hidden)] |
122 |
| - __rtic_internal_p: ::core::marker::PhantomData<&'a ()>, |
123 |
| - #(#fields,)* |
124 |
| - } |
125 |
| - |
126 |
| - #(#cfgs)* |
127 |
| - impl<'a> #internal_context_name<'a> { |
128 |
| - #[inline(always)] |
129 |
| - #[allow(missing_docs)] |
130 |
| - pub unsafe fn new(#core) -> Self { |
131 |
| - #internal_context_name { |
132 |
| - __rtic_internal_p: ::core::marker::PhantomData, |
133 |
| - #(#values,)* |
134 |
| - } |
135 |
| - } |
136 |
| - } |
137 |
| - )); |
138 |
| - |
139 |
| - module_items.push(quote!( |
140 |
| - #(#cfgs)* |
141 |
| - #[doc(inline)] |
142 |
| - pub use super::#internal_context_name as Context; |
143 |
| - )); |
144 |
| - |
145 | 117 | if let Context::SoftwareTask(t) = ctxt {
|
146 | 118 | let spawnee = &app.software_tasks[name];
|
147 | 119 | let priority = spawnee.args.priority;
|
@@ -212,21 +184,112 @@ pub fn codegen(ctxt: Context, app: &App, analysis: &Analysis) -> TokenStream2 {
|
212 | 184 | }
|
213 | 185 | ));
|
214 | 186 |
|
215 |
| - if is_local_task { |
| 187 | + if !is_local_task { |
216 | 188 | module_items.push(quote!(
|
217 | 189 | #(#cfgs)*
|
218 | 190 | #[doc(inline)]
|
219 | 191 | pub use super::#internal_spawn_ident as spawn;
|
220 | 192 | ));
|
221 | 193 | }
|
222 | 194 |
|
| 195 | + let local_tasks_on_same_executor: Vec<_> = app |
| 196 | + .software_tasks |
| 197 | + .iter() |
| 198 | + //.filter(|(_, t)| t.args.is_local_task && t.args.priority == priority) |
| 199 | + .map(|(_, t)| t) |
| 200 | + .collect(); |
| 201 | + |
| 202 | + if !local_tasks_on_same_executor.is_empty() { |
| 203 | + fields.push(quote! { |
| 204 | + /// Used to spawn tasks on the same executor |
| 205 | + /// |
| 206 | + /// This is useful for tasks that take args which are !Send/!Sync. |
| 207 | + /// |
| 208 | + /// NOTE: This only works with tasks marked `is_local_task = true` |
| 209 | + /// and which have the same priority and thus will run on the |
| 210 | + /// same executor. |
| 211 | + pub local_spawner: LocalSpawner |
| 212 | + }); |
| 213 | + let tasks = local_tasks_on_same_executor |
| 214 | + .iter() |
| 215 | + .map(|task| { |
| 216 | + // Copied mostly from software_tasks.rs |
| 217 | + let context = &task.context; |
| 218 | + let attrs = &task.attrs; |
| 219 | + let cfgs = &task.cfgs; |
| 220 | + let inputs = &task.inputs; |
| 221 | + let lifetime = if task.is_bottom { |
| 222 | + quote!('static) |
| 223 | + } else { |
| 224 | + quote!('a) |
| 225 | + }; |
| 226 | + let generics = if task.is_bottom { |
| 227 | + quote!() |
| 228 | + } else { |
| 229 | + quote!(<'a>) |
| 230 | + }; |
| 231 | + let input_vals = inputs.iter().map(|i| &i.pat).collect::<Vec<_>>(); |
| 232 | + quote! { |
| 233 | + #(#attrs)* |
| 234 | + #(#cfgs)* |
| 235 | + #[allow(non_snake_case)] |
| 236 | + fn #name #generics(&self #(,#inputs)*) { |
| 237 | + // SAFETY: This is safe to call since this can only be called |
| 238 | + // from the same executor |
| 239 | + unsafe { #internal_spawn_ident(#(#input_vals,)*) } // <-- TODO strip the types |
| 240 | + } |
| 241 | + } |
| 242 | + }) |
| 243 | + .collect::<Vec<_>>(); |
| 244 | + values.push(quote!(local_spawner: LocalSpawner { _p: PhantomData })); |
| 245 | + module_items.push(quote! { |
| 246 | + struct LocalSpawner { |
| 247 | + _p: PhantomData<*mut ()>, |
| 248 | + } |
| 249 | + |
| 250 | + impl LocalSpawner { |
| 251 | + #(#tasks)* |
| 252 | + } |
| 253 | + }); |
| 254 | + } |
| 255 | + |
223 | 256 | module_items.push(quote!(
|
224 | 257 | #(#cfgs)*
|
225 | 258 | #[doc(inline)]
|
226 | 259 | pub use super::#internal_waker_ident as waker;
|
227 | 260 | ));
|
228 | 261 | }
|
229 | 262 |
|
| 263 | + items.push(quote!( |
| 264 | + #(#cfgs)* |
| 265 | + /// Execution context |
| 266 | + #[allow(non_snake_case)] |
| 267 | + #[allow(non_camel_case_types)] |
| 268 | + pub struct #internal_context_name<'a> { |
| 269 | + #[doc(hidden)] |
| 270 | + __rtic_internal_p: ::core::marker::PhantomData<&'a ()>, |
| 271 | + #(#fields,)* |
| 272 | + } |
| 273 | + |
| 274 | + #(#cfgs)* |
| 275 | + impl<'a> #internal_context_name<'a> { |
| 276 | + #[inline(always)] |
| 277 | + #[allow(missing_docs)] |
| 278 | + pub unsafe fn new(#core) -> Self { |
| 279 | + #internal_context_name { |
| 280 | + __rtic_internal_p: ::core::marker::PhantomData, |
| 281 | + #(#values,)* |
| 282 | + } |
| 283 | + } |
| 284 | + } |
| 285 | + )); |
| 286 | + |
| 287 | + module_items.push(quote!( |
| 288 | + #(#cfgs)* |
| 289 | + #[doc(inline)] |
| 290 | + pub use super::#internal_context_name as Context; |
| 291 | + )); |
| 292 | + |
230 | 293 | if items.is_empty() {
|
231 | 294 | quote!()
|
232 | 295 | } else {
|
|
0 commit comments