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