xref: /relibc/src/platform/pte.rs (revision a2f2484e4559206922b0fcc16217598a6867c8a2)
1 #![allow(non_snake_case)]
2 
3 use alloc::{boxed::Box, collections::BTreeMap};
4 use core::{
5     intrinsics, ptr,
6     sync::atomic::{AtomicU32, Ordering},
7 };
8 
9 use crate::{
10     header::{sys_mman, time::timespec},
11     ld_so::{
12         linker::Linker,
13         tcb::{Master, Tcb},
14     },
15     platform::{
16         types::{c_int, c_uint, c_void, pid_t, size_t},
17         Pal, Sys,
18     },
19     sync::Mutex,
20 };
21 
22 pub struct Semaphore {
23     lock: Mutex<()>,
24     count: i32,
25 }
26 
27 type pte_osThreadHandle = pid_t;
28 type pte_osMutexHandle = *mut Mutex<()>;
29 type pte_osSemaphoreHandle = *mut Semaphore;
30 type pte_osThreadEntryPoint = unsafe extern "C" fn(params: *mut c_void) -> *mut c_void;
31 
32 #[repr(C)]
33 #[derive(Eq, PartialEq)]
34 #[allow(dead_code)]
35 pub enum pte_osResult {
36     PTE_OS_OK = 0,
37     PTE_OS_NO_RESOURCES,
38     PTE_OS_GENERAL_FAILURE,
39     PTE_OS_TIMEOUT,
40     PTE_OS_INTERRUPTED,
41     PTE_OS_INVALID_PARAM,
42 }
43 
44 use self::pte_osResult::*;
45 
46 static mut pid_mutexes: Option<BTreeMap<pte_osThreadHandle, pte_osMutexHandle>> = None;
47 static mut pid_mutexes_lock: Mutex<()> = Mutex::new(());
48 
49 static mut pid_stacks: Option<BTreeMap<pte_osThreadHandle, (*mut c_void, size_t)>> = None;
50 static mut pid_stacks_lock: Mutex<()> = Mutex::new(());
51 
52 #[thread_local]
53 static mut LOCALS: *mut BTreeMap<c_uint, *mut c_void> = ptr::null_mut();
54 
55 static NEXT_KEY: AtomicU32 = AtomicU32::new(0);
56 
57 unsafe fn locals() -> &'static mut BTreeMap<c_uint, *mut c_void> {
58     if LOCALS.is_null() {
59         LOCALS = Box::into_raw(Box::new(BTreeMap::new()));
60     }
61     &mut *LOCALS
62 }
63 
64 // pte_osResult pte_osInit(void)
65 #[no_mangle]
66 pub unsafe extern "C" fn pte_osInit() -> pte_osResult {
67     PTE_OS_OK
68 }
69 
70 /// A shim to wrap thread entry points in logic to set up TLS, for example
71 unsafe extern "C" fn pte_osThreadShim(
72     entryPoint: pte_osThreadEntryPoint,
73     argv: *mut c_void,
74     mutex: pte_osMutexHandle,
75     tls_size: usize,
76     tls_masters_ptr: *mut Master,
77     tls_masters_len: usize,
78     tls_linker_ptr: *const Mutex<Linker>,
79 ) {
80     // The kernel allocated TLS does not have masters set, so do not attempt to copy it.
81     // It will be copied by the kernel.
82     if !tls_masters_ptr.is_null() {
83         let tcb = Tcb::new(tls_size).unwrap();
84         tcb.masters_ptr = tls_masters_ptr;
85         tcb.masters_len = tls_masters_len;
86         tcb.linker_ptr = tls_linker_ptr;
87         tcb.copy_masters().unwrap();
88         tcb.activate();
89     }
90 
91     // Wait until pte_osThreadStart
92     pte_osMutexLock(mutex);
93     entryPoint(argv);
94     pte_osThreadExit();
95 }
96 
97 #[no_mangle]
98 pub unsafe extern "C" fn pte_osThreadCreate(
99     entryPoint: pte_osThreadEntryPoint,
100     stackSize: c_int,
101     _initialPriority: c_int,
102     argv: *mut c_void,
103     ppte_osThreadHandle: *mut pte_osThreadHandle,
104 ) -> pte_osResult {
105     // Create a locked mutex, unlocked by pte_osThreadStart
106     let mutex: pte_osMutexHandle = Box::into_raw(Box::new(Mutex::locked(())));
107 
108     let stack_size = if stackSize == 0 {
109         1024 * 1024
110     } else {
111         stackSize as usize
112     };
113     let stack_base = sys_mman::mmap(
114         ptr::null_mut(),
115         stack_size,
116         sys_mman::PROT_READ | sys_mman::PROT_WRITE,
117         sys_mman::MAP_SHARED | sys_mman::MAP_ANONYMOUS,
118         -1,
119         0,
120     );
121     if stack_base as isize == -1 {
122         return PTE_OS_GENERAL_FAILURE;
123     }
124     ptr::write_bytes(stack_base as *mut u8, 0, stack_size);
125     let stack_end = stack_base.add(stack_size);
126     let mut stack = stack_end as *mut usize;
127     {
128         let mut push = |value: usize| {
129             stack = stack.offset(-1);
130             *stack = value;
131         };
132 
133         // Stack must be 128-bit aligned for SSE
134         push(0);
135 
136         if let Some(tcb) = Tcb::current() {
137             push(tcb.linker_ptr as usize);
138             push(tcb.masters_len);
139             push(tcb.masters_ptr as usize);
140             push(tcb.tls_len);
141         } else {
142             push(0);
143             push(0);
144             push(0);
145             push(0);
146         }
147 
148         push(mutex as usize);
149 
150         push(argv as usize);
151         push(entryPoint as usize);
152 
153         push(pte_osThreadShim as usize);
154     }
155 
156     let id = Sys::pte_clone(stack);
157     if id < 0 {
158         return PTE_OS_GENERAL_FAILURE;
159     }
160 
161     pte_osMutexLock(&mut pid_mutexes_lock);
162     if pid_mutexes.is_none() {
163         pid_mutexes = Some(BTreeMap::new());
164     }
165     pid_mutexes.as_mut().unwrap().insert(id, mutex);
166     pte_osMutexUnlock(&mut pid_mutexes_lock);
167 
168     pte_osMutexLock(&mut pid_stacks_lock);
169     if pid_stacks.is_none() {
170         pid_stacks = Some(BTreeMap::new());
171     }
172     pid_stacks
173         .as_mut()
174         .unwrap()
175         .insert(id, (stack_base, stack_size));
176     pte_osMutexUnlock(&mut pid_stacks_lock);
177 
178     *ppte_osThreadHandle = id;
179 
180     PTE_OS_OK
181 }
182 
183 #[no_mangle]
184 pub unsafe extern "C" fn pte_osThreadStart(handle: pte_osThreadHandle) -> pte_osResult {
185     let mut ret = PTE_OS_GENERAL_FAILURE;
186     pte_osMutexLock(&mut pid_mutexes_lock);
187     if let Some(ref mutexes) = pid_mutexes {
188         if let Some(mutex) = mutexes.get(&handle) {
189             pte_osMutexUnlock(*mutex);
190             ret = PTE_OS_OK;
191         }
192     }
193     pte_osMutexUnlock(&mut pid_mutexes_lock);
194     ret
195 }
196 
197 #[no_mangle]
198 pub unsafe extern "C" fn pte_osThreadExit() {
199     Sys::exit(0);
200 }
201 
202 #[no_mangle]
203 pub unsafe extern "C" fn pte_osThreadExitAndDelete(handle: pte_osThreadHandle) -> pte_osResult {
204     let res = pte_osThreadDelete(handle);
205     if res != PTE_OS_OK {
206         return res;
207     }
208     pte_osThreadExit();
209     PTE_OS_OK
210 }
211 
212 #[no_mangle]
213 pub unsafe extern "C" fn pte_osThreadDelete(handle: pte_osThreadHandle) -> pte_osResult {
214     pte_osMutexLock(&mut pid_mutexes_lock);
215     if let Some(ref mut mutexes) = pid_mutexes {
216         if let Some(mutex) = mutexes.remove(&handle) {
217             Box::from_raw(mutex);
218         }
219     }
220     pte_osMutexUnlock(&mut pid_mutexes_lock);
221 
222     pte_osMutexLock(&mut pid_stacks_lock);
223     if let Some(ref mut stacks) = pid_stacks {
224         if let Some((stack_base, stack_size)) = stacks.remove(&handle) {
225             sys_mman::munmap(stack_base, stack_size);
226         }
227     }
228     pte_osMutexUnlock(&mut pid_stacks_lock);
229 
230     PTE_OS_OK
231 }
232 
233 #[no_mangle]
234 pub unsafe extern "C" fn pte_osThreadWaitForEnd(handle: pte_osThreadHandle) -> pte_osResult {
235     let mut status = 0;
236     Sys::waitpid(handle, &mut status, 0);
237     PTE_OS_OK
238 }
239 
240 #[no_mangle]
241 pub unsafe extern "C" fn pte_osThreadCancel(handle: pte_osThreadHandle) -> pte_osResult {
242     //TODO: allow cancel of thread
243     PTE_OS_OK
244 }
245 
246 #[no_mangle]
247 pub unsafe extern "C" fn pte_osThreadCheckCancel(handle: pte_osThreadHandle) -> pte_osResult {
248     PTE_OS_OK
249 }
250 
251 #[no_mangle]
252 pub unsafe extern "C" fn pte_osThreadSleep(msecs: c_uint) {
253     let tm = timespec {
254         tv_sec: msecs as i64 / 1000,
255         tv_nsec: (msecs % 1000) as i64 * 1000000,
256     };
257     Sys::nanosleep(&tm, ptr::null_mut());
258 }
259 
260 #[no_mangle]
261 pub unsafe extern "C" fn pte_osThreadGetHandle() -> pte_osThreadHandle {
262     Sys::gettid()
263 }
264 
265 #[no_mangle]
266 pub unsafe extern "C" fn pte_osThreadGetPriority(threadHandle: pte_osThreadHandle) -> c_int {
267     // XXX Shouldn't Redox support priorities?
268     1
269 }
270 
271 #[no_mangle]
272 pub unsafe extern "C" fn pte_osThreadSetPriority(
273     threadHandle: pte_osThreadHandle,
274     newPriority: c_int,
275 ) -> pte_osResult {
276     PTE_OS_OK
277 }
278 
279 #[no_mangle]
280 pub unsafe extern "C" fn pte_osThreadGetMinPriority() -> c_int {
281     1
282 }
283 
284 #[no_mangle]
285 pub unsafe extern "C" fn pte_osThreadGetMaxPriority() -> c_int {
286     1
287 }
288 
289 #[no_mangle]
290 pub unsafe extern "C" fn pte_osThreadGetDefaultPriority() -> c_int {
291     1
292 }
293 
294 #[no_mangle]
295 pub unsafe extern "C" fn pte_osMutexCreate(pHandle: *mut pte_osMutexHandle) -> pte_osResult {
296     *pHandle = Box::into_raw(Box::new(Mutex::new(())));
297     PTE_OS_OK
298 }
299 
300 #[no_mangle]
301 pub unsafe extern "C" fn pte_osMutexDelete(handle: pte_osMutexHandle) -> pte_osResult {
302     Box::from_raw(handle);
303     PTE_OS_OK
304 }
305 
306 #[no_mangle]
307 pub unsafe extern "C" fn pte_osMutexLock(handle: pte_osMutexHandle) -> pte_osResult {
308     (*handle).manual_lock();
309     PTE_OS_OK
310 }
311 
312 #[no_mangle]
313 pub unsafe extern "C" fn pte_osMutexUnlock(handle: pte_osMutexHandle) -> pte_osResult {
314     (*handle).manual_unlock();
315     PTE_OS_OK
316 }
317 
318 #[no_mangle]
319 pub unsafe extern "C" fn pte_osSemaphoreCreate(
320     initialValue: c_int,
321     pHandle: *mut pte_osSemaphoreHandle,
322 ) -> pte_osResult {
323     *pHandle = Box::into_raw(Box::new(Semaphore {
324         lock: Mutex::new(()),
325         count: initialValue,
326     }));
327     PTE_OS_OK
328 }
329 
330 #[no_mangle]
331 pub unsafe extern "C" fn pte_osSemaphoreDelete(handle: pte_osSemaphoreHandle) -> pte_osResult {
332     Box::from_raw(handle);
333     PTE_OS_OK
334 }
335 
336 #[no_mangle]
337 pub unsafe extern "C" fn pte_osSemaphorePost(
338     handle: pte_osSemaphoreHandle,
339     count: c_int,
340 ) -> pte_osResult {
341     let semaphore = &mut *handle;
342     let _guard = semaphore.lock.lock();
343     intrinsics::atomic_xadd(&mut semaphore.count, 1);
344     PTE_OS_OK
345 }
346 
347 #[no_mangle]
348 pub unsafe extern "C" fn pte_osSemaphorePend(
349     handle: pte_osSemaphoreHandle,
350     pTimeout: *mut c_uint,
351 ) -> pte_osResult {
352     //TODO: pTimeout
353     let semaphore = &mut *handle;
354     loop {
355         {
356             let _guard = semaphore.lock.lock();
357             if intrinsics::atomic_load(&semaphore.count) > 0 {
358                 intrinsics::atomic_xsub(&mut semaphore.count, 1);
359                 break;
360             }
361         }
362         Sys::sched_yield();
363     }
364     PTE_OS_OK
365 }
366 
367 #[no_mangle]
368 pub unsafe extern "C" fn pte_osSemaphoreCancellablePend(
369     handle: pte_osSemaphoreHandle,
370     pTimeout: *mut c_uint,
371 ) -> pte_osResult {
372     //TODO
373     pte_osSemaphorePend(handle, pTimeout)
374 }
375 
376 #[no_mangle]
377 pub unsafe extern "C" fn pte_osAtomicExchange(ptarg: *mut c_int, val: c_int) -> c_int {
378     intrinsics::atomic_xchg(ptarg, val)
379 }
380 
381 #[no_mangle]
382 pub unsafe extern "C" fn pte_osAtomicCompareExchange(
383     pdest: *mut c_int,
384     exchange: c_int,
385     comp: c_int,
386 ) -> c_int {
387     intrinsics::atomic_cxchg(pdest, comp, exchange).0
388 }
389 
390 #[no_mangle]
391 pub unsafe extern "C" fn pte_osAtomicExchangeAdd(pAppend: *mut c_int, value: c_int) -> c_int {
392     intrinsics::atomic_xadd(pAppend, value)
393 }
394 
395 #[no_mangle]
396 pub unsafe extern "C" fn pte_osAtomicDecrement(pdest: *mut c_int) -> c_int {
397     intrinsics::atomic_xadd(pdest, -1) - 1
398 }
399 
400 #[no_mangle]
401 pub unsafe extern "C" fn pte_osAtomicIncrement(pdest: *mut c_int) -> c_int {
402     intrinsics::atomic_xadd(pdest, 1) + 1
403 }
404 
405 #[no_mangle]
406 pub unsafe extern "C" fn pte_osTlsSetValue(index: c_uint, value: *mut c_void) -> pte_osResult {
407     locals().insert(index, value);
408     PTE_OS_OK
409 }
410 
411 #[no_mangle]
412 pub unsafe extern "C" fn pte_osTlsGetValue(index: c_uint) -> *mut c_void {
413     locals().get_mut(&index).copied().unwrap_or(ptr::null_mut())
414 }
415 
416 #[no_mangle]
417 pub unsafe extern "C" fn pte_osTlsAlloc(pKey: *mut c_uint) -> pte_osResult {
418     *pKey = NEXT_KEY.fetch_add(1, Ordering::SeqCst);
419     PTE_OS_OK
420 }
421 
422 #[no_mangle]
423 pub unsafe extern "C" fn pte_osTlsFree(index: c_uint) -> pte_osResult {
424     // XXX free keys
425     PTE_OS_OK
426 }
427