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