long_screen/kernels/
pool.rs1pub fn helpers() -> usize {
18 imp::helpers()
19}
20
21pub fn par_for<F: Fn(usize) + Sync>(chunks: usize, body: F) {
23 imp::par_for(chunks, &body)
24}
25
26#[inline]
29pub fn split(len: usize, parts: usize, i: usize) -> usize {
30 len * i / parts.max(1)
31}
32
33pub fn chunks_for(len: usize, min: usize) -> usize {
36 let threads = helpers() + 1;
37 if threads == 1 || len == 0 {
38 return 1;
39 }
40 (len / min.max(1)).clamp(1, threads * 4)
41}
42
43#[derive(Clone, Copy)]
45pub struct SyncPtr<T>(pub *mut T);
46unsafe impl<T> Sync for SyncPtr<T> {}
48unsafe impl<T> Send for SyncPtr<T> {}
49impl<T> SyncPtr<T> {
50 #[inline]
51 pub fn get(self) -> *mut T {
52 self.0
53 }
54}
55
56pub fn worker_loop() -> ! {
58 imp::worker_loop()
59}
60
61#[cfg(target_feature = "atomics")]
62mod imp {
63 use core::arch::wasm32::{memory_atomic_notify, memory_atomic_wait32};
64 use core::sync::atomic::{AtomicBool, AtomicU32, AtomicUsize, Ordering::SeqCst};
65
66 static EPOCH: AtomicU32 = AtomicU32::new(0);
68 static HELPERS: AtomicUsize = AtomicUsize::new(0);
69 static ACTIVE: AtomicUsize = AtomicUsize::new(0);
71 static BUSY: AtomicBool = AtomicBool::new(false);
72 static JOB_DATA: AtomicUsize = AtomicUsize::new(0);
73 static JOB_CALL: AtomicUsize = AtomicUsize::new(0);
74 static JOB_CHUNKS: AtomicUsize = AtomicUsize::new(0);
75 static NEXT: AtomicUsize = AtomicUsize::new(0);
76 static PENDING: AtomicUsize = AtomicUsize::new(0);
77
78 pub fn helpers() -> usize {
79 HELPERS.load(SeqCst)
80 }
81
82 unsafe fn trampoline<F: Fn(usize) + Sync>(data: usize, i: usize) {
83 (*(data as *const F))(i)
84 }
85
86 fn run_chunks(data: usize, call: usize, chunks: usize) {
87 let f: unsafe fn(usize, usize) = unsafe { core::mem::transmute(call) };
89 loop {
90 let i = NEXT.fetch_add(1, SeqCst);
91 if i >= chunks {
92 return;
93 }
94 unsafe { f(data, i) };
95 PENDING.fetch_sub(1, SeqCst);
96 }
97 }
98
99 pub fn par_for<F: Fn(usize) + Sync>(chunks: usize, body: &F) {
100 if chunks <= 1 || HELPERS.load(SeqCst) == 0 || BUSY.swap(true, SeqCst) {
101 (0..chunks).for_each(body);
102 return;
103 }
104 EPOCH.fetch_add(1, SeqCst);
106 while ACTIVE.load(SeqCst) != 0 {
107 core::hint::spin_loop();
108 }
109 let data = body as *const F as usize;
110 let call = trampoline::<F> as unsafe fn(usize, usize) as usize;
111 JOB_DATA.store(data, SeqCst);
112 JOB_CALL.store(call, SeqCst);
113 JOB_CHUNKS.store(chunks, SeqCst);
114 PENDING.store(chunks, SeqCst);
115 NEXT.store(0, SeqCst);
116 EPOCH.fetch_add(1, SeqCst);
117 unsafe { memory_atomic_notify(EPOCH.as_ptr() as *mut i32, u32::MAX) };
118 run_chunks(data, call, chunks);
119 while PENDING.load(SeqCst) != 0 {
120 core::hint::spin_loop();
121 }
122 BUSY.store(false, SeqCst);
123 }
124
125 pub fn worker_loop() -> ! {
126 HELPERS.fetch_add(1, SeqCst);
127 let mut seen = EPOCH.load(SeqCst);
128 loop {
129 let e = EPOCH.load(SeqCst);
130 if e == seen || e & 1 == 1 {
131 unsafe { memory_atomic_wait32(EPOCH.as_ptr() as *mut i32, e as i32, -1) };
133 continue;
134 }
135 ACTIVE.fetch_add(1, SeqCst);
136 if EPOCH.load(SeqCst) == e {
137 seen = e;
138 run_chunks(
139 JOB_DATA.load(SeqCst),
140 JOB_CALL.load(SeqCst),
141 JOB_CHUNKS.load(SeqCst),
142 );
143 }
144 ACTIVE.fetch_sub(1, SeqCst);
145 }
146 }
147}
148
149#[cfg(all(feature = "rayon", not(target_feature = "atomics")))]
150mod imp {
151 use rayon::prelude::*;
152
153 pub fn helpers() -> usize {
154 rayon::current_num_threads().saturating_sub(1)
155 }
156 pub fn par_for<F: Fn(usize) + Sync>(chunks: usize, body: &F) {
157 if chunks <= 1 {
158 (0..chunks).for_each(body);
159 } else {
160 (0..chunks).into_par_iter().for_each(body);
161 }
162 }
163 pub fn worker_loop() -> ! {
164 panic!("worker_loop is the threaded wasm build's; native helpers are rayon's threads")
165 }
166}
167
168#[cfg(all(not(feature = "rayon"), not(target_feature = "atomics")))]
169mod imp {
170 pub fn helpers() -> usize {
171 0
172 }
173 pub fn par_for<F: Fn(usize) + Sync>(chunks: usize, body: &F) {
174 (0..chunks).for_each(body)
175 }
176 pub fn worker_loop() -> ! {
177 panic!("worker_loop requires the threaded core build")
178 }
179}