From 74acb03a720eeb9d320459d6bb53d3f41621a732 Mon Sep 17 00:00:00 2001 From: Meziu Date: Fri, 29 Oct 2021 17:17:29 +0200 Subject: [PATCH] Working state --- .gitignore | 3 + Cargo.toml | 14 ++ src/lib.rs | 412 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 429 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 src/lib.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c34b8d3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +target +Cargo.lock +.cargo diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..e7c3008 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "pthread-3ds" +authors = [ "Andrea Ciliberti " ] +version = "0.1.0" +license = "MIT/Apache 2.0" +edition = "2018" + +[lib] +name = "pthread_3ds" +path = "src/lib.rs" +crate-type = ["staticlib"] + +[dependencies.libc] +path = "../libc" diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..dec3059 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,412 @@ +#![feature(thread_local)] + +// LIBCTRU THREADS + +pub type _LOCK_T = i32; +pub type _LOCK_RECURSIVE_T = __lock_t; + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct __lock_t { + pub lock: _LOCK_T, + pub thread_tag: u32, + pub counter: u32, +} + +pub type LightLock = _LOCK_T; +pub type RecursiveLock = _LOCK_RECURSIVE_T; +pub type CondVar = i32; +pub type Thread = *mut libc::c_void; +pub type ThreadFunc = extern "C" fn(arg1: *mut libc::c_void); + +type ResultCode = u32; + +extern "C" { + pub fn svcSleepThread(ns: i64); + pub fn svcGetThreadPriority(out: *mut i32, handle: u32) -> ResultCode; + + pub fn threadCreate( + entrypoint: ThreadFunc, + arg: *mut libc::c_void, + stack_size: libc::size_t, + prio: libc::c_int, + core_id: libc::c_int, + detached: bool, + ) -> Thread; + pub fn threadJoin(thread: Thread, timeout_ns: u64) -> ResultCode; + pub fn threadFree(thread: Thread); + pub fn threadDetach(thread: Thread); + + pub fn LightLock_Init(lock: *mut LightLock); + pub fn LightLock_Lock(lock: *mut LightLock); + pub fn LightLock_TryLock(lock: *mut LightLock) -> libc::c_int; + pub fn LightLock_Unlock(lock: *mut LightLock); + + pub fn RecursiveLock_Init(lock: *mut RecursiveLock); + pub fn RecursiveLock_Lock(lock: *mut RecursiveLock); + pub fn RecursiveLock_TryLock(lock: *mut RecursiveLock) -> libc::c_int; + pub fn RecursiveLock_Unlock(lock: *mut RecursiveLock); + + pub fn CondVar_Init(cv: *mut CondVar); + pub fn CondVar_Wait(cv: *mut CondVar, lock: *mut LightLock); + pub fn CondVar_WaitTimeout( + cv: *mut CondVar, + lock: *mut LightLock, + timeout_ns: i64, + ) -> libc::c_int; + pub fn CondVar_WakeUp(cv: *mut CondVar, num_threads: i32); +} + +// PTHREAD LAYER TO CALL LIBCTRU + +use libc; + +#[no_mangle] +pub unsafe extern "C" fn pthread_create( + native: *mut libc::pthread_t, + attr: *const libc::pthread_attr_t, + f: extern "C" fn(_: *mut libc::c_void) -> *mut libc::c_void, + value: *mut libc::c_void, +) -> libc::c_int { + let mut priority = 0; + svcGetThreadPriority(&mut priority, 0xFFFF8000); + + extern "C" fn thread_start(main: *mut libc::c_void) { + unsafe { + Box::from_raw(main as *mut Box)(); + } + } + + let handle = threadCreate( + thread_start, + value, + *(attr as *mut libc::size_t), + priority, + -2, + false, + ); + + *native = handle as _; + + 0 +} + +#[no_mangle] +pub unsafe extern "C" fn pthread_join( + native: libc::pthread_t, + value: *mut *mut libc::c_void, +) -> libc::c_int { + threadJoin(native as *mut libc::c_void, u64::max_value()); + threadFree(native as *mut libc::c_void); + + 0 +} + +#[no_mangle] +pub unsafe extern "C" fn pthread_detach(thread: libc::pthread_t) -> libc::c_int { + threadDetach(thread as _); + + 0 +} + +#[no_mangle] +pub unsafe extern "C" fn pthread_attr_init(attr: *mut libc::pthread_attr_t) -> libc::c_int { + 0 +} + +#[no_mangle] +pub unsafe extern "C" fn pthread_attr_destroy(attr: *mut libc::pthread_attr_t) -> libc::c_int { + 0 +} + +#[no_mangle] +pub unsafe extern "C" fn pthread_attr_setstacksize( + attr: *mut libc::pthread_attr_t, + stack_size: libc::size_t, +) -> libc::c_int { + let pointer = attr as *mut libc::size_t; + *pointer = stack_size; + + 0 +} + +#[no_mangle] +pub unsafe extern "C" fn sched_yield() -> libc::c_int { + svcSleepThread(0); + + 0 +} + +#[no_mangle] +pub unsafe extern "C" fn pthread_cond_init( + cond: *mut libc::pthread_cond_t, + attr: *const libc::pthread_condattr_t, +) -> libc::c_int { + CondVar_Init(cond as _); + + 0 +} + +#[no_mangle] +pub unsafe extern "C" fn pthread_cond_signal(cond: *mut libc::pthread_cond_t) -> libc::c_int { + CondVar_WakeUp(cond as _, 1); + + 0 +} + +#[no_mangle] +pub unsafe extern "C" fn pthread_cond_broadcast(cond: *mut libc::pthread_cond_t) -> libc::c_int { + CondVar_WakeUp(cond as _, -1); + + 0 +} + +#[no_mangle] +pub unsafe extern "C" fn pthread_cond_wait( + cond: *mut libc::pthread_cond_t, + lock: *mut libc::pthread_mutex_t, +) -> libc::c_int { + CondVar_Wait(cond as _, lock as _); + + 0 +} + +#[no_mangle] +pub unsafe extern "C" fn pthread_cond_timedwait( + cond: *mut libc::pthread_cond_t, + lock: *mut libc::pthread_mutex_t, + abstime: *const libc::timespec, +) -> libc::c_int { + let nsec: i64 = ((*abstime).tv_sec as i64 * 1_000_000_000) + (*abstime).tv_nsec as i64; + + CondVar_WaitTimeout(cond as _, lock as _, nsec) +} + +#[no_mangle] +pub unsafe extern "C" fn pthread_cond_destroy(cond: *mut libc::pthread_cond_t) -> libc::c_int { + 0 +} + +#[no_mangle] +pub unsafe extern "C" fn pthread_mutexattr_init( + attr: *mut libc::pthread_mutexattr_t, +) -> libc::c_int { + 0 +} + +#[no_mangle] +pub unsafe extern "C" fn pthread_mutexattr_settype( + attr: *mut libc::pthread_mutexattr_t, + _type: libc::c_int, +) -> libc::c_int { + let attr: *mut libc::c_int = attr as _; + + *attr = _type as _; + + 0 +} + +#[no_mangle] +pub unsafe extern "C" fn pthread_mutex_init( + lock: *mut libc::pthread_mutex_t, + attr: *const libc::pthread_mutexattr_t, +) -> libc::c_int { + let lock = lock as *mut u8; + + let attr: libc::c_int = *(attr as *const libc::c_int); + + if attr == libc::PTHREAD_MUTEX_NORMAL { + LightLock_Init(lock as _); + } else if attr == libc::PTHREAD_MUTEX_RECURSIVE { + RecursiveLock_Init(lock as _) + } + + *(lock.offset(39)) = attr as u8; + + 0 +} + +#[no_mangle] +pub unsafe extern "C" fn pthread_mutex_destroy(lock: *mut libc::pthread_mutex_t) -> libc::c_int { + 0 +} + +#[no_mangle] +pub unsafe extern "C" fn pthread_mutex_lock(lock: *mut libc::pthread_mutex_t) -> libc::c_int { + let lock = lock as *const u8; + + if *(lock.offset(39)) as u8 == libc::PTHREAD_MUTEX_NORMAL as u8 { + LightLock_Lock(lock as _); + } else if *(lock.offset(39)) as u8 == libc::PTHREAD_MUTEX_RECURSIVE as u8 { + RecursiveLock_Lock(lock as _); + } + + 0 +} + +#[no_mangle] +pub unsafe extern "C" fn pthread_mutex_trylock(lock: *mut libc::pthread_mutex_t) -> libc::c_int { + let lock = lock as *const u8; + + if *(lock.offset(39)) as u8 == libc::PTHREAD_MUTEX_NORMAL as u8 { + return LightLock_TryLock(lock as _); + } else if *(lock.offset(39)) as u8 == libc::PTHREAD_MUTEX_RECURSIVE as u8 { + return RecursiveLock_TryLock(lock as _); + } + + 0 +} + +#[no_mangle] +pub unsafe extern "C" fn pthread_mutex_unlock(lock: *mut libc::pthread_mutex_t) -> libc::c_int { + let lock = lock as *const u8; + + if *(lock.offset(39)) as u8 == libc::PTHREAD_MUTEX_NORMAL as u8 { + LightLock_Unlock(lock as _); + } else if *(lock.offset(39)) as u8 == libc::PTHREAD_MUTEX_RECURSIVE as u8 { + RecursiveLock_Unlock(lock as _); + } + + 0 +} + +#[no_mangle] +pub unsafe extern "C" fn pthread_mutexattr_destroy( + attr: *mut libc::pthread_mutexattr_t, +) -> libc::c_int { + 0 +} + +#[no_mangle] +pub unsafe extern "C" fn pthread_rwlock_init( + lock: *mut libc::pthread_rwlock_t, + attr: *const libc::pthread_rwlockattr_t, +) -> libc::c_int { + 1 +} + +#[no_mangle] +pub unsafe extern "C" fn pthread_rwlock_destroy(lock: *mut libc::pthread_rwlock_t) -> libc::c_int { + 1 +} + +#[no_mangle] +pub unsafe extern "C" fn pthread_rwlock_rdlock(lock: *mut libc::pthread_rwlock_t) -> libc::c_int { + 1 +} + +#[no_mangle] +pub unsafe extern "C" fn pthread_rwlock_tryrdlock( + lock: *mut libc::pthread_rwlock_t, +) -> libc::c_int { + 1 +} + +#[no_mangle] +pub unsafe extern "C" fn pthread_rwlock_wrlock(lock: *mut libc::pthread_rwlock_t) -> libc::c_int { + 1 +} + +#[no_mangle] +pub unsafe extern "C" fn pthread_rwlock_trywrlock( + lock: *mut libc::pthread_rwlock_t, +) -> libc::c_int { + 1 +} + +#[no_mangle] +pub unsafe extern "C" fn pthread_rwlock_unlock(lock: *mut libc::pthread_rwlock_t) -> libc::c_int { + 1 +} + +#[no_mangle] +pub unsafe extern "C" fn pthread_rwlockattr_init( + attr: *mut libc::pthread_rwlockattr_t, +) -> libc::c_int { + 1 +} + +#[no_mangle] +pub unsafe extern "C" fn pthread_rwlockattr_destroy( + attr: *mut libc::pthread_rwlockattr_t, +) -> libc::c_int { + 1 +} + + +// THREAD KEYS IMPLEMENTATION FOR RUST STD + +use std::collections::BTreeMap; +use std::ptr; +use std::sync::atomic::{AtomicUsize, Ordering}; + +pub type Key = usize; + +type Dtor = unsafe extern fn(*mut u8); + +static NEXT_KEY: AtomicUsize = AtomicUsize::new(1); + +static mut KEYS: *mut BTreeMap> = ptr::null_mut(); + +#[thread_local] +static mut LOCALS: *mut BTreeMap = ptr::null_mut(); + +unsafe fn keys() -> &'static mut BTreeMap> { + if KEYS == ptr::null_mut() { + KEYS = Box::into_raw(Box::new(BTreeMap::new())); + } + &mut *KEYS +} + +unsafe fn locals() -> &'static mut BTreeMap { + if LOCALS == ptr::null_mut() { + LOCALS = Box::into_raw(Box::new(BTreeMap::new())); + } + &mut *LOCALS +} + +#[inline] +pub unsafe fn create(dtor: Option) -> Key { + let key = NEXT_KEY.fetch_add(1, Ordering::SeqCst); + keys().insert(key, dtor); + key +} + + +#[no_mangle] +pub unsafe extern "C" fn pthread_key_create( + key: *mut libc::pthread_key_t, + dtor: Option, +) -> libc::c_int { + let new_key = NEXT_KEY.fetch_add(1, Ordering::SeqCst); + keys().insert(new_key, std::mem::transmute(dtor)); + + *key = new_key as u32; + + 0 +} + +#[no_mangle] +pub unsafe extern "C" fn pthread_key_delete(key: libc::pthread_key_t) -> libc::c_int { + keys().remove(&(key as usize)); + + 0 +} + +#[no_mangle] +pub unsafe extern "C" fn pthread_getspecific(key: libc::pthread_key_t) -> *mut libc::c_void { + if let Some(&entry) = locals().get(&(key as usize)) { + entry as _ + } else { + ptr::null_mut() + } +} + +#[no_mangle] +pub unsafe extern "C" fn pthread_setspecific( + key: libc::pthread_key_t, + value: *const libc::c_void, +) -> libc::c_int { + locals().insert(key as usize, std::mem::transmute(value)); + 0 +}