Meziu
3 years ago
commit
74acb03a72
3 changed files with 429 additions and 0 deletions
@ -0,0 +1,14 @@ |
|||||||
|
[package] |
||||||
|
name = "pthread-3ds" |
||||||
|
authors = [ "Andrea Ciliberti <meziu210@icloud.com>" ] |
||||||
|
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" |
@ -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<dyn FnOnce()>)(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
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<Key, Option<Dtor>> = ptr::null_mut(); |
||||||
|
|
||||||
|
#[thread_local] |
||||||
|
static mut LOCALS: *mut BTreeMap<Key, *mut u8> = ptr::null_mut(); |
||||||
|
|
||||||
|
unsafe fn keys() -> &'static mut BTreeMap<Key, Option<Dtor>> { |
||||||
|
if KEYS == ptr::null_mut() { |
||||||
|
KEYS = Box::into_raw(Box::new(BTreeMap::new())); |
||||||
|
} |
||||||
|
&mut *KEYS |
||||||
|
} |
||||||
|
|
||||||
|
unsafe fn locals() -> &'static mut BTreeMap<Key, *mut u8> { |
||||||
|
if LOCALS == ptr::null_mut() { |
||||||
|
LOCALS = Box::into_raw(Box::new(BTreeMap::new())); |
||||||
|
} |
||||||
|
&mut *LOCALS |
||||||
|
} |
||||||
|
|
||||||
|
#[inline] |
||||||
|
pub unsafe fn create(dtor: Option<unsafe extern "C" fn(*mut u8)>) -> 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<unsafe extern "C" fn(*mut libc::c_void)>, |
||||||
|
) -> 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 |
||||||
|
} |
Loading…
Reference in new issue