1use proc_macro::TokenStream;
2use quote::quote;
3use syn::{
4 FnArg, ItemFn, Lit, Meta, Token, parse::Parse, parse::ParseStream, parse_macro_input,
5 punctuated::Punctuated,
6};
7
8struct TaskArgs {
9 priority: String,
10 affinity: String,
11 kind: String,
12 stack: String,
13 switcher: String,
14}
15
16impl Parse for TaskArgs {
17 fn parse(input: ParseStream) -> syn::Result<Self> {
18 let vars = Punctuated::<Meta, Token![,]>::parse_terminated(input)?;
19 let mut priority = "Normal".to_string();
20 let mut affinity = "SameCore".to_string();
21 let mut kind = "Compute".to_string();
22 let mut stack = "2M".to_string();
23 let mut switcher = "CrossThreadFloat".to_string();
24
25 for var in vars {
26 if let Meta::NameValue(nv) = var {
27 if nv.path.is_ident("priority") {
28 if let syn::Expr::Lit(syn::ExprLit {
29 lit: Lit::Str(s), ..
30 }) = nv.value
31 {
32 priority = s.value();
33 }
34 } else if nv.path.is_ident("affinity") {
35 if let syn::Expr::Lit(syn::ExprLit {
36 lit: Lit::Str(s), ..
37 }) = nv.value
38 {
39 affinity = s.value();
40 }
41 } else if nv.path.is_ident("kind") {
42 if let syn::Expr::Lit(syn::ExprLit {
43 lit: Lit::Str(s), ..
44 }) = nv.value
45 {
46 kind = s.value();
47 }
48 } else if nv.path.is_ident("stack") {
49 if let syn::Expr::Lit(syn::ExprLit {
50 lit: Lit::Str(s), ..
51 }) = nv.value
52 {
53 stack = s.value();
54 }
55 } else if nv.path.is_ident("switcher")
56 && let syn::Expr::Lit(syn::ExprLit {
57 lit: Lit::Str(s), ..
58 }) = nv.value
59 {
60 switcher = s.value();
61 }
62 }
63 }
64
65 Ok(TaskArgs {
66 priority,
67 affinity,
68 kind,
69 stack,
70 switcher,
71 })
72 }
73}
74
75#[proc_macro_attribute]
76pub fn task(args: TokenStream, item: TokenStream) -> TokenStream {
77 let args = parse_macro_input!(args as TaskArgs);
78 let mut input = parse_macro_input!(item as ItemFn);
79
80 let fn_name = &input.sig.ident;
81 let priority = &args.priority;
82 let affinity = &args.affinity;
83 let kind = &args.kind;
84 let stack = &args.stack;
85
86 let metadata_mod = syn::Ident::new(&format!("dtact_metadata_{}", fn_name), fn_name.span());
87 let priority_ident = syn::Ident::new(priority, fn_name.span());
88 let affinity_ident = syn::Ident::new(affinity, fn_name.span());
89 let kind_ident = syn::Ident::new(kind, fn_name.span());
90 let switcher = &args.switcher;
91 let switcher_ident = syn::Ident::new(switcher, fn_name.span());
92
93 let return_type = match &input.sig.output {
94 syn::ReturnType::Default => quote! { () },
95 syn::ReturnType::Type(_, ty) => quote! { #ty },
96 };
97
98 input.sig.asyncness = None;
99 input.sig.output = syn::parse2(quote! {
100 -> dtact::api::TaskFuture<impl std::future::Future<Output = #return_type> + Send + 'static, dtact::#switcher_ident>
101 }).unwrap();
102
103 let vis = &input.vis;
104 let attrs = &input.attrs;
105 let sig = &input.sig;
106 let body = &input.block;
107
108 let expanded = quote! {
109 #(#attrs)*
110 #vis #sig {
111 let fut = async move #body;
112 dtact::api::TaskFuture {
113 future: fut,
114 priority: dtact::Priority::#priority_ident,
115 affinity: dtact::topology::Affinity::#affinity_ident,
116 kind: dtact::WorkloadKind::#kind_ident,
117 _marker: std::marker::PhantomData,
118 }
119 }
120
121 pub mod #metadata_mod {
122 pub const PRIORITY: dtact::Priority = dtact::Priority::#priority_ident;
123 pub const AFFINITY: dtact::topology::Affinity = dtact::topology::Affinity::#affinity_ident;
124 pub const KIND: dtact::WorkloadKind = dtact::WorkloadKind::#kind_ident;
125 pub const STACK_SIZE: &'static str = #stack;
126 pub type SWITCHER = dtact::#switcher_ident;
127 }
128 };
129
130 TokenStream::from(expanded)
131}
132
133#[proc_macro_attribute]
134pub fn export_async(_args: TokenStream, item: TokenStream) -> TokenStream {
135 let input = parse_macro_input!(item as ItemFn);
136 let fn_name = &input.sig.ident;
137 let wrapper_name = syn::Ident::new(&format!("dtact_export_{}", fn_name), fn_name.span());
138
139 let mut c_params = Vec::new();
140 let mut call_args = Vec::new();
141
142 for input in &input.sig.inputs {
143 if let FnArg::Typed(pat_type) = input {
144 let pat = &pat_type.pat;
145 let ty = &pat_type.ty;
146 c_params.push(quote! { #pat: #ty });
147 call_args.push(quote! { #pat });
148 } else {
149 panic!("export_async does not support 'self' parameters");
150 }
151 }
152
153 let expanded = quote! {
154 #input
155
156 #[unsafe(no_mangle)]
157 pub extern "C" fn #wrapper_name(#(#c_params),*) -> dtact::dtact_handle_t {
158 dtact::spawn(#fn_name(#(#call_args),*))
159 }
160 };
161
162 TokenStream::from(expanded)
163}
164
165#[proc_macro_attribute]
166pub fn export_fiber(_args: TokenStream, item: TokenStream) -> TokenStream {
167 let input = parse_macro_input!(item as ItemFn);
168 let fn_name = &input.sig.ident;
169 let wrapper_name = syn::Ident::new(&format!("dtact_export_fiber_{}", fn_name), fn_name.span());
170
171 let mut c_params = Vec::new();
172 let mut call_args = Vec::new();
173
174 for input in &input.sig.inputs {
175 if let FnArg::Typed(pat_type) = input {
176 let pat = &pat_type.pat;
177 let ty = &pat_type.ty;
178 c_params.push(quote! { #pat: #ty });
179 call_args.push(quote! { #pat });
180 } else {
181 panic!("export_fiber does not support 'self' parameters");
182 }
183 }
184
185 let expanded = quote! {
186 #input
187
188 #[unsafe(no_mangle)]
189 pub extern "C" fn #wrapper_name(#(#c_params),*) -> dtact::dtact_handle_t {
190 dtact::api::fiber::spawn_with_stack("2M", move || {
191 #fn_name(#(#call_args),*);
192 })
193 }
194 };
195
196 TokenStream::from(expanded)
197}
198
199struct InitArgs {
200 topology: String,
201 safety: String,
202 workers: usize,
203 capacity: u32,
204 stack: usize,
205 numa: usize,
206}
207
208impl Parse for InitArgs {
209 fn parse(input: ParseStream) -> syn::Result<Self> {
210 let vars = Punctuated::<Meta, Token![,]>::parse_terminated(input)?;
211 let mut topology = "P2PMesh".to_string();
212 let mut safety = "Safety1".to_string();
213 let mut workers = 0;
214 let mut capacity = 4096;
215 let mut stack = 512 * 1024;
216 let mut numa = 0;
217
218 for var in vars {
219 if let Meta::NameValue(nv) = var {
220 if nv.path.is_ident("topology") {
221 if let syn::Expr::Lit(syn::ExprLit {
222 lit: Lit::Str(s), ..
223 }) = &nv.value
224 {
225 topology = s.value();
226 }
227 } else if nv.path.is_ident("safety") {
228 if let syn::Expr::Lit(syn::ExprLit {
229 lit: Lit::Str(s), ..
230 }) = &nv.value
231 {
232 safety = s.value();
233 }
234 } else if nv.path.is_ident("workers") {
235 if let syn::Expr::Lit(syn::ExprLit {
236 lit: Lit::Int(i), ..
237 }) = &nv.value
238 {
239 workers = i.base10_parse()?;
240 }
241 } else if nv.path.is_ident("capacity") {
242 if let syn::Expr::Lit(syn::ExprLit {
243 lit: Lit::Int(i), ..
244 }) = &nv.value
245 {
246 capacity = i.base10_parse()?;
247 }
248 } else if nv.path.is_ident("stack") {
249 if let syn::Expr::Lit(syn::ExprLit {
250 lit: Lit::Int(i), ..
251 }) = &nv.value
252 {
253 stack = i.base10_parse()?;
254 }
255 } else if nv.path.is_ident("numa")
256 && let syn::Expr::Lit(syn::ExprLit {
257 lit: Lit::Int(i), ..
258 }) = &nv.value
259 {
260 numa = i.base10_parse()?;
261 }
262 }
263 }
264 Ok(InitArgs {
265 topology,
266 safety,
267 workers,
268 capacity,
269 stack,
270 numa,
271 })
272 }
273}
274
275#[proc_macro_attribute]
276pub fn dtact_init(args: TokenStream, item: TokenStream) -> TokenStream {
277 let args = parse_macro_input!(args as InitArgs);
278 let input = parse_macro_input!(item as ItemFn);
279
280 let topology = &args.topology;
281 let safety = &args.safety;
282 let workers = args.workers;
283 let capacity = args.capacity;
284 let stack = args.stack;
285 let numa = args.numa;
286
287 let topology_ident = syn::Ident::new(topology, input.sig.ident.span());
288 let safety_ident = syn::Ident::new(safety, input.sig.ident.span());
289 let autostart_fn_name = syn::Ident::new("dtact_autostart", input.sig.ident.span());
290
291 let attrs = &input.attrs;
292 let vis = &input.vis;
293 let sig = &input.sig;
294 let block = &input.block;
295
296 let expanded = quote! {
297 #[unsafe(no_mangle)]
298 extern "C" fn #autostart_fn_name() {
299 let runtime = dtact::GLOBAL_RUNTIME.get_or_init(|| {
300 let mut workers_count = #workers;
301 if workers_count == 0 {
302 workers_count = std::thread::available_parallelism().map(|n| n.get()).unwrap_or(1);
303 }
304
305 let scheduler = dtact::dta_scheduler::DtaScheduler::new(
306 workers_count,
307 dtact::dta_scheduler::TopologyMode::#topology_ident
308 );
309
310 let pool = dtact::memory_management::ContextPool::new(
311 #capacity,
312 #stack,
313 dtact::memory_management::SafetyLevel::#safety_ident,
314 #numa
315 ).expect("DTA-V3 Hardware Initialization Failed");
316
317 dtact::Runtime {
318 scheduler,
319 pool,
320 started: core::sync::atomic::AtomicBool::new(false),
321 shutdown: core::sync::atomic::AtomicBool::new(false),
322 }
323 });
324 runtime.start();
325 }
326
327 #(#attrs)* #vis #sig {
328 #autostart_fn_name();
329 #block
330 }
331 };
332
333 TokenStream::from(expanded)
334}
335
336struct IoInitArgs {
343 workers: usize,
344 buffer_pool_size: usize,
345 chunk_size: usize,
346 pin_cpus: Vec<usize>,
347 ring_depth: u32,
348}
349
350impl Parse for IoInitArgs {
351 fn parse(input: ParseStream) -> syn::Result<Self> {
352 let vars = Punctuated::<Meta, Token![,]>::parse_terminated(input)?;
353 let mut workers = 1;
354 let mut buffer_pool_size = 65536;
355 let mut chunk_size = 4096;
356 let mut pin_cpus = Vec::new();
357 let mut ring_depth = 256;
358
359 for var in vars {
360 if let Meta::NameValue(nv) = var {
361 if nv.path.is_ident("workers") {
362 if let syn::Expr::Lit(syn::ExprLit {
363 lit: Lit::Int(i), ..
364 }) = &nv.value
365 {
366 workers = i.base10_parse()?;
367 }
368 } else if nv.path.is_ident("buffer_pool_size") {
369 if let syn::Expr::Lit(syn::ExprLit {
370 lit: Lit::Int(i), ..
371 }) = &nv.value
372 {
373 buffer_pool_size = i.base10_parse()?;
374 }
375 } else if nv.path.is_ident("chunk_size") {
376 if let syn::Expr::Lit(syn::ExprLit {
377 lit: Lit::Int(i), ..
378 }) = &nv.value
379 {
380 chunk_size = i.base10_parse()?;
381 }
382 } else if nv.path.is_ident("ring_depth") {
383 if let syn::Expr::Lit(syn::ExprLit {
384 lit: Lit::Int(i), ..
385 }) = &nv.value
386 {
387 ring_depth = i.base10_parse()?;
388 }
389 } else if nv.path.is_ident("pin_cpus")
390 && let syn::Expr::Array(syn::ExprArray { elems, .. }) = &nv.value
391 {
392 for elem in elems {
393 if let syn::Expr::Lit(syn::ExprLit {
394 lit: Lit::Int(i), ..
395 }) = elem
396 {
397 pin_cpus.push(i.base10_parse()?);
398 }
399 }
400 }
401 }
402 }
403 Ok(IoInitArgs {
404 workers,
405 buffer_pool_size,
406 chunk_size,
407 pin_cpus,
408 ring_depth,
409 })
410 }
411}
412
413#[proc_macro_attribute]
421pub fn dtact_io_init(args: TokenStream, item: TokenStream) -> TokenStream {
422 let args = parse_macro_input!(args as IoInitArgs);
423 let input = parse_macro_input!(item as ItemFn);
424
425 let workers = args.workers;
426 let buffer_pool_size = args.buffer_pool_size;
427 let chunk_size = args.chunk_size;
428 let ring_depth = args.ring_depth;
429 let pin_cpus = &args.pin_cpus;
430
431 let attrs = &input.attrs;
432 let vis = &input.vis;
433 let sig = &input.sig;
434 let block = &input.block;
435
436 let expanded = quote! {
437 #(#attrs)* #vis #sig {
438 dtact_util::init_runtime(
439 #workers,
440 #ring_depth,
441 #buffer_pool_size,
442 #chunk_size,
443 &[#(#pin_cpus),*],
444 );
445 #block
446 }
447 };
448
449 TokenStream::from(expanded)
450}
451
452#[proc_macro_attribute]
460pub fn fs_init(args: TokenStream, item: TokenStream) -> TokenStream {
461 let args = parse_macro_input!(args as IoInitArgs);
462 let input = parse_macro_input!(item as ItemFn);
463
464 let workers = args.workers;
465 let buffer_pool_size = args.buffer_pool_size;
466 let chunk_size = args.chunk_size;
467 let ring_depth = args.ring_depth;
468 let pin_cpus = &args.pin_cpus;
469
470 let attrs = &input.attrs;
471 let vis = &input.vis;
472 let sig = &input.sig;
473 let block = &input.block;
474
475 let expanded = quote! {
476 #(#attrs)* #vis #sig {
477 dtact_util::fs::init_fs(
478 #workers,
479 #ring_depth,
480 #buffer_pool_size,
481 #chunk_size,
482 &[#(#pin_cpus),*],
483 );
484 #block
485 }
486 };
487
488 TokenStream::from(expanded)
489}
490
491#[proc_macro_attribute]
499pub fn process_init(args: TokenStream, item: TokenStream) -> TokenStream {
500 let args = parse_macro_input!(args as IoInitArgs);
501 let input = parse_macro_input!(item as ItemFn);
502
503 let workers = args.workers;
504 let buffer_pool_size = args.buffer_pool_size;
505 let chunk_size = args.chunk_size;
506 let ring_depth = args.ring_depth;
507 let pin_cpus = &args.pin_cpus;
508
509 let attrs = &input.attrs;
510 let vis = &input.vis;
511 let sig = &input.sig;
512 let block = &input.block;
513
514 let expanded = quote! {
515 #(#attrs)* #vis #sig {
516 dtact_util::process::init_process(
517 #workers,
518 #ring_depth,
519 #buffer_pool_size,
520 #chunk_size,
521 &[#(#pin_cpus),*],
522 );
523 #block
524 }
525 };
526
527 TokenStream::from(expanded)
528}