1use alloc::{boxed::Box, sync::Arc, vec::Vec};
5use core::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
6use rt::sync::SpinLock;
7
8pub const THR_MAX: usize = 64;
10#[derive(Clone, Copy, Debug, PartialEq, Eq)]
12pub struct Cancelled;
13
14pub struct JobCtl {
16 count: usize,
17 done: AtomicUsize,
18 cancel: AtomicBool,
19 running: AtomicBool,
20}
21impl JobCtl {
22 fn new(count: usize) -> Self {
23 Self {
24 count,
25 done: AtomicUsize::new(0),
26 cancel: AtomicBool::new(false),
27 running: AtomicBool::new(false),
28 }
29 }
30 pub fn cancel(&self) {
32 self.cancel.store(true, Ordering::Relaxed);
33 }
34 pub fn cancelled(&self) -> bool {
36 self.cancel.load(Ordering::Relaxed)
37 }
38 pub fn count(&self) -> u64 {
40 self.count as u64
41 }
42 pub fn items_done(&self) -> u64 {
44 self.done.load(Ordering::Relaxed) as u64
45 }
46}
47
48struct Record {
49 ctl: JobCtl,
50 function: Option<Box<dyn Fn(usize, &JobCtl) + Send + Sync>>,
51}
52static QUEUE: SpinLock<Vec<Arc<Record>>> = SpinLock::new(Vec::new());
53
54fn step(record: &Record) -> bool {
55 let ctl = &record.ctl;
56 if !ctl.running.load(Ordering::Relaxed) {
57 return false;
58 }
59 let i = ctl.done.load(Ordering::Relaxed);
60 if i >= ctl.count || ctl.cancelled() || record.function.is_none() {
61 ctl.running.store(false, Ordering::Relaxed);
62 crate::wake();
63 return false;
64 }
65 if let Some(function) = &record.function {
66 function(i, ctl);
67 }
68 ctl.done.store(i + 1, Ordering::Relaxed);
69 if i + 1 >= ctl.count || ctl.cancelled() {
70 ctl.running.store(false, Ordering::Relaxed);
71 crate::wake();
72 }
73 true
74}
75
76pub fn pump_jobs(items: usize) {
78 for _ in 0..items {
79 let record = {
80 let mut q = QUEUE.lock();
81 if q.is_empty() {
82 None
83 } else {
84 Some(q.remove(0))
85 }
86 };
87 let Some(record) = record else {
88 break;
89 };
90 let _ = step(&record);
91 if record.ctl.running.load(Ordering::Relaxed) {
92 QUEUE.lock().push(record);
93 }
94 }
95}
96
97pub fn thr_init(_count: u32) -> u32 {
99 0
100}
101pub fn thr_count() -> u32 {
103 0
104}
105pub fn thr_shutdown() {
107 let queue = core::mem::take(&mut *QUEUE.lock());
108 for record in queue {
109 record.ctl.cancel();
110 let _ = step(&record);
111 }
112}
113pub fn thr_self() -> usize {
115 0
116}
117pub fn parallel_for(count: usize, f: &(dyn Fn(usize, &JobCtl) + Sync)) -> Result<(), Cancelled> {
119 let ctl = JobCtl::new(count);
120 for i in 0..count {
121 if ctl.cancelled() {
122 break;
123 }
124 f(i, &ctl);
125 ctl.done.store(i + 1, Ordering::Relaxed);
126 }
127 if ctl.cancelled() {
128 Err(Cancelled)
129 } else {
130 Ok(())
131 }
132}
133
134pub struct Job {
136 record: Arc<Record>,
137}
138impl Default for Job {
139 fn default() -> Self {
140 Self::new()
141 }
142}
143impl Job {
144 pub fn new() -> Self {
146 Self {
147 record: Arc::new(Record {
148 ctl: JobCtl::new(0),
149 function: None,
150 }),
151 }
152 }
153 pub fn set(&mut self, count: u64, f: impl Fn(usize, &JobCtl) + Send + Sync + 'static) -> bool {
155 if !self.done() || count > usize::MAX as u64 {
156 return false;
157 }
158 self.record = Arc::new(Record {
159 ctl: JobCtl::new(count as usize),
160 function: Some(Box::new(f)),
161 });
162 true
163 }
164 pub fn set_count(&mut self, count: u64) -> bool {
166 if !self.done() || count > usize::MAX as u64 {
167 return false;
168 }
169 QUEUE.lock().retain(|r| !Arc::ptr_eq(r, &self.record));
171 let Some(record) = Arc::get_mut(&mut self.record) else {
172 return false;
173 };
174 record.ctl.count = count as usize;
175 true
176 }
177 pub fn start(&self) -> bool {
179 if !self.done() {
180 return false;
181 }
182 let ctl = &self.record.ctl;
183 ctl.done.store(0, Ordering::Relaxed);
184 ctl.cancel.store(false, Ordering::Relaxed);
185 QUEUE.lock().retain(|r| !Arc::ptr_eq(r, &self.record));
186 if ctl.count == 0 || self.record.function.is_none() {
187 crate::wake();
188 return true;
189 }
190 ctl.running.store(true, Ordering::Relaxed);
191 QUEUE.lock().push(self.record.clone());
192 crate::wake();
193 true
194 }
195 pub fn wait(&self) -> Result<(), Cancelled> {
197 while step(&self.record) {}
198 if self.record.ctl.cancelled() {
199 Err(Cancelled)
200 } else {
201 Ok(())
202 }
203 }
204 pub fn cancel(&self) {
206 self.record.ctl.cancel();
207 }
208 pub fn done(&self) -> bool {
210 !self.record.ctl.running.load(Ordering::Relaxed)
211 }
212 pub fn items_done(&self) -> u64 {
214 self.record.ctl.items_done()
215 }
216 pub fn count(&self) -> u64 {
218 self.record.ctl.count()
219 }
220}
221impl Drop for Job {
222 fn drop(&mut self) {
223 self.cancel();
224 let _ = self.wait();
225 }
226}