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 sys_mman::munmap(stack_base, stack_size); 229 } 230 } 231 pte_osMutexUnlock(&mut pid_stacks_lock); 232 233 PTE_OS_OK 234 } 235 236 #[no_mangle] 237 pub unsafe extern "C" fn pte_osThreadWaitForEnd(handle: pte_osThreadHandle) -> pte_osResult { 238 let mut status = 0; 239 Sys::waitpid(handle, &mut status, 0); 240 PTE_OS_OK 241 } 242 243 #[no_mangle] 244 pub unsafe extern "C" fn pte_osThreadCancel(handle: pte_osThreadHandle) -> pte_osResult { 245 //TODO: allow cancel of thread 246 PTE_OS_OK 247 } 248 249 #[no_mangle] 250 pub unsafe extern "C" fn pte_osThreadCheckCancel(handle: pte_osThreadHandle) -> pte_osResult { 251 PTE_OS_OK 252 } 253 254 #[no_mangle] 255 pub unsafe extern "C" fn pte_osThreadSleep(msecs: c_uint) { 256 let tm = timespec { 257 tv_sec: msecs as i64 / 1000, 258 tv_nsec: (msecs % 1000) as i64 * 1000000, 259 }; 260 Sys::nanosleep(&tm, ptr::null_mut()); 261 } 262 263 #[no_mangle] 264 pub unsafe extern "C" fn pte_osThreadGetHandle() -> pte_osThreadHandle { 265 Sys::gettid() 266 } 267 268 #[no_mangle] 269 pub unsafe extern "C" fn pte_osThreadGetPriority(threadHandle: pte_osThreadHandle) -> c_int { 270 // XXX Shouldn't Redox support priorities? 271 1 272 } 273 274 #[no_mangle] 275 pub unsafe extern "C" fn pte_osThreadSetPriority( 276 threadHandle: pte_osThreadHandle, 277 newPriority: c_int, 278 ) -> pte_osResult { 279 PTE_OS_OK 280 } 281 282 #[no_mangle] 283 pub unsafe extern "C" fn pte_osThreadGetMinPriority() -> c_int { 284 1 285 } 286 287 #[no_mangle] 288 pub unsafe extern "C" fn pte_osThreadGetMaxPriority() -> c_int { 289 1 290 } 291 292 #[no_mangle] 293 pub unsafe extern "C" fn pte_osThreadGetDefaultPriority() -> c_int { 294 1 295 } 296 297 #[no_mangle] 298 pub unsafe extern "C" fn pte_osMutexCreate(pHandle: *mut pte_osMutexHandle) -> pte_osResult { 299 *pHandle = Box::into_raw(Box::new(Mutex::new(()))); 300 PTE_OS_OK 301 } 302 303 #[no_mangle] 304 pub unsafe extern "C" fn pte_osMutexDelete(handle: pte_osMutexHandle) -> pte_osResult { 305 Box::from_raw(handle); 306 PTE_OS_OK 307 } 308 309 #[no_mangle] 310 pub unsafe extern "C" fn pte_osMutexLock(handle: pte_osMutexHandle) -> pte_osResult { 311 (*handle).manual_lock(); 312 PTE_OS_OK 313 } 314 315 #[no_mangle] 316 pub unsafe extern "C" fn pte_osMutexUnlock(handle: pte_osMutexHandle) -> pte_osResult { 317 (*handle).manual_unlock(); 318 PTE_OS_OK 319 } 320 321 #[no_mangle] 322 pub unsafe extern "C" fn pte_osSemaphoreCreate( 323 initialValue: c_int, 324 pHandle: *mut pte_osSemaphoreHandle, 325 ) -> pte_osResult { 326 *pHandle = Box::into_raw(Box::new(Semaphore { 327 lock: Mutex::new(()), 328 count: initialValue, 329 })); 330 PTE_OS_OK 331 } 332 333 #[no_mangle] 334 pub unsafe extern "C" fn pte_osSemaphoreDelete(handle: pte_osSemaphoreHandle) -> pte_osResult { 335 Box::from_raw(handle); 336 PTE_OS_OK 337 } 338 339 #[no_mangle] 340 pub unsafe extern "C" fn pte_osSemaphorePost( 341 handle: pte_osSemaphoreHandle, 342 count: c_int, 343 ) -> pte_osResult { 344 let semaphore = &mut *handle; 345 let _guard = semaphore.lock.lock(); 346 intrinsics::atomic_xadd(&mut semaphore.count, 1); 347 PTE_OS_OK 348 } 349 350 #[no_mangle] 351 pub unsafe extern "C" fn pte_osSemaphorePend( 352 handle: pte_osSemaphoreHandle, 353 pTimeout: *mut c_uint, 354 ) -> pte_osResult { 355 //TODO: pTimeout 356 let semaphore = &mut *handle; 357 loop { 358 { 359 let _guard = semaphore.lock.lock(); 360 if intrinsics::atomic_load(&semaphore.count) > 0 { 361 intrinsics::atomic_xsub(&mut semaphore.count, 1); 362 break; 363 } 364 } 365 Sys::sched_yield(); 366 } 367 PTE_OS_OK 368 } 369 370 #[no_mangle] 371 pub unsafe extern "C" fn pte_osSemaphoreCancellablePend( 372 handle: pte_osSemaphoreHandle, 373 pTimeout: *mut c_uint, 374 ) -> pte_osResult { 375 //TODO 376 pte_osSemaphorePend(handle, pTimeout) 377 } 378 379 #[no_mangle] 380 pub unsafe extern "C" fn pte_osAtomicExchange(ptarg: *mut c_int, val: c_int) -> c_int { 381 intrinsics::atomic_xchg(ptarg, val) 382 } 383 384 #[no_mangle] 385 pub unsafe extern "C" fn pte_osAtomicCompareExchange( 386 pdest: *mut c_int, 387 exchange: c_int, 388 comp: c_int, 389 ) -> c_int { 390 intrinsics::atomic_cxchg(pdest, comp, exchange).0 391 } 392 393 #[no_mangle] 394 pub unsafe extern "C" fn pte_osAtomicExchangeAdd(pAppend: *mut c_int, value: c_int) -> c_int { 395 intrinsics::atomic_xadd(pAppend, value) 396 } 397 398 #[no_mangle] 399 pub unsafe extern "C" fn pte_osAtomicDecrement(pdest: *mut c_int) -> c_int { 400 intrinsics::atomic_xadd(pdest, -1) - 1 401 } 402 403 #[no_mangle] 404 pub unsafe extern "C" fn pte_osAtomicIncrement(pdest: *mut c_int) -> c_int { 405 intrinsics::atomic_xadd(pdest, 1) + 1 406 } 407 408 #[no_mangle] 409 pub unsafe extern "C" fn pte_osTlsSetValue(index: c_uint, value: *mut c_void) -> pte_osResult { 410 locals().insert(index, value); 411 PTE_OS_OK 412 } 413 414 #[no_mangle] 415 pub unsafe extern "C" fn pte_osTlsGetValue(index: c_uint) -> *mut c_void { 416 locals().get_mut(&index).copied().unwrap_or(ptr::null_mut()) 417 } 418 419 #[no_mangle] 420 pub unsafe extern "C" fn pte_osTlsAlloc(pKey: *mut c_uint) -> pte_osResult { 421 *pKey = NEXT_KEY.fetch_add(1, Ordering::SeqCst); 422 PTE_OS_OK 423 } 424 425 #[no_mangle] 426 pub unsafe extern "C" fn pte_osTlsFree(index: c_uint) -> pte_osResult { 427 // XXX free keys 428 PTE_OS_OK 429 } 430