Andrea Ciliberti
2 years ago
8 changed files with 38 additions and 507 deletions
@ -1,117 +0,0 @@ |
|||||||
//! PThread condition variables implemented using libctru.
|
|
||||||
|
|
||||||
#[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 { |
|
||||||
ctru_sys::CondVar_Init(cond as _); |
|
||||||
|
|
||||||
0 |
|
||||||
} |
|
||||||
|
|
||||||
#[no_mangle] |
|
||||||
pub unsafe extern "C" fn pthread_cond_signal(cond: *mut libc::pthread_cond_t) -> libc::c_int { |
|
||||||
ctru_sys::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 { |
|
||||||
ctru_sys::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 { |
|
||||||
ctru_sys::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 { |
|
||||||
// libctru expects a duration, but we have an absolute timestamp.
|
|
||||||
// Convert to a duration before calling libctru.
|
|
||||||
|
|
||||||
// Get the current time so we can make a duration
|
|
||||||
let mut now = libc::timeval { |
|
||||||
tv_sec: 0, |
|
||||||
tv_usec: 0, |
|
||||||
}; |
|
||||||
let r = libc::gettimeofday(&mut now, std::ptr::null_mut()); |
|
||||||
if r != 0 { |
|
||||||
return r; |
|
||||||
} |
|
||||||
|
|
||||||
// Calculate the duration
|
|
||||||
let duration_nsec = (*abstime) |
|
||||||
.tv_sec |
|
||||||
// Get the difference in seconds
|
|
||||||
.saturating_sub(now.tv_sec) |
|
||||||
// Convert to nanoseconds
|
|
||||||
.saturating_mul(1_000_000_000) |
|
||||||
// Add the difference in nanoseconds
|
|
||||||
.saturating_add((*abstime).tv_nsec as i64) |
|
||||||
.saturating_sub(now.tv_usec as i64 * 1_000) |
|
||||||
// Don't go negative
|
|
||||||
.max(0); |
|
||||||
|
|
||||||
let r = ctru_sys::CondVar_WaitTimeout(cond as _, lock as _, duration_nsec); |
|
||||||
|
|
||||||
// CondVar_WaitTimeout returns a boolean which is true (nonzero) if it timed out
|
|
||||||
if r == 0 { |
|
||||||
0 |
|
||||||
} else { |
|
||||||
libc::ETIMEDOUT |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
#[no_mangle] |
|
||||||
pub unsafe extern "C" fn pthread_cond_destroy(_cond: *mut libc::pthread_cond_t) -> libc::c_int { |
|
||||||
0 |
|
||||||
} |
|
||||||
|
|
||||||
#[no_mangle] |
|
||||||
pub extern "C" fn pthread_condattr_init(_attr: *const libc::pthread_condattr_t) -> libc::c_int { |
|
||||||
0 |
|
||||||
} |
|
||||||
|
|
||||||
#[no_mangle] |
|
||||||
pub extern "C" fn pthread_condattr_destroy(_attr: *const libc::pthread_condattr_t) -> libc::c_int { |
|
||||||
0 |
|
||||||
} |
|
||||||
|
|
||||||
#[no_mangle] |
|
||||||
pub extern "C" fn pthread_condattr_getclock( |
|
||||||
_attr: *const libc::pthread_condattr_t, |
|
||||||
clock_id: *mut libc::clockid_t, |
|
||||||
) -> libc::c_int { |
|
||||||
unsafe { |
|
||||||
*clock_id = libc::CLOCK_REALTIME; |
|
||||||
} |
|
||||||
|
|
||||||
0 |
|
||||||
} |
|
||||||
|
|
||||||
#[no_mangle] |
|
||||||
pub extern "C" fn pthread_condattr_setclock( |
|
||||||
_attr: *mut libc::pthread_condattr_t, |
|
||||||
clock_id: libc::clockid_t, |
|
||||||
) -> libc::c_int { |
|
||||||
// only one clock is supported, so all other options are considered an error
|
|
||||||
if clock_id == libc::CLOCK_REALTIME { |
|
||||||
0 |
|
||||||
} else { |
|
||||||
libc::EINVAL |
|
||||||
} |
|
||||||
} |
|
@ -1,26 +1,13 @@ |
|||||||
//! Miscellaneous pthread functions
|
//! Miscellaneous pthread functions
|
||||||
|
|
||||||
|
// The implementation within `newlib` stubs this out *entirely*. It's not possible to use a "syscall".
|
||||||
|
/* |
||||||
#[no_mangle] |
#[no_mangle] |
||||||
pub unsafe extern "C" fn sched_yield() -> libc::c_int { |
pub unsafe extern "C" fn sched_yield() -> libc::c_int { |
||||||
ctru_sys::svcSleepThread(0); |
ctru_sys::svcSleepThread(0); |
||||||
|
|
||||||
0 |
0 |
||||||
} |
} |
||||||
|
*/ |
||||||
|
|
||||||
#[no_mangle] |
// `pthread_sigmask` and `pthread_atfork` are stubbed out by `newlib`
|
||||||
pub unsafe extern "C" fn pthread_sigmask( |
|
||||||
_how: ::libc::c_int, |
|
||||||
_set: *const libc::sigset_t, |
|
||||||
_oldset: *mut libc::sigset_t, |
|
||||||
) -> ::libc::c_int { |
|
||||||
-1 |
|
||||||
} |
|
||||||
|
|
||||||
#[no_mangle] |
|
||||||
pub extern "C" fn pthread_atfork( |
|
||||||
_prepare: Option<unsafe extern "C" fn()>, |
|
||||||
_parent: Option<unsafe extern "C" fn()>, |
|
||||||
_child: Option<unsafe extern "C" fn()>, |
|
||||||
) -> libc::c_int { |
|
||||||
0 |
|
||||||
} |
|
@ -1,91 +0,0 @@ |
|||||||
//! PThread mutex implemented using libctru.
|
|
||||||
|
|
||||||
#[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 { |
|
||||||
ctru_sys::LightLock_Init(lock as _); |
|
||||||
} else if attr == libc::PTHREAD_MUTEX_RECURSIVE { |
|
||||||
ctru_sys::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 { |
|
||||||
ctru_sys::LightLock_Lock(lock as _); |
|
||||||
} else if *(lock.offset(39)) as u8 == libc::PTHREAD_MUTEX_RECURSIVE as u8 { |
|
||||||
ctru_sys::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 ctru_sys::LightLock_TryLock(lock as _); |
|
||||||
} else if *(lock.offset(39)) as u8 == libc::PTHREAD_MUTEX_RECURSIVE as u8 { |
|
||||||
return ctru_sys::RecursiveLock_TryLock(lock as _); |
|
||||||
} |
|
||||||
|
|
||||||
-1 |
|
||||||
} |
|
||||||
|
|
||||||
#[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 { |
|
||||||
ctru_sys::LightLock_Unlock(lock as _); |
|
||||||
} else if *(lock.offset(39)) as u8 == libc::PTHREAD_MUTEX_RECURSIVE as u8 { |
|
||||||
ctru_sys::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 |
|
||||||
} |
|
@ -1,169 +0,0 @@ |
|||||||
//! PThread read-write lock implemented using libctru.
|
|
||||||
|
|
||||||
use crate::{condvar, mutex}; |
|
||||||
|
|
||||||
struct rwlock_clear { |
|
||||||
mutex: libc::pthread_mutex_t, |
|
||||||
cvar: i32, |
|
||||||
num_readers: i32, |
|
||||||
writer_active: bool, |
|
||||||
initialized: bool, |
|
||||||
} |
|
||||||
|
|
||||||
/// Initializes the rwlock internal members if they weren't already
|
|
||||||
fn init_rwlock(lock: *mut libc::pthread_rwlock_t) { |
|
||||||
let lock = lock as *mut rwlock_clear; |
|
||||||
|
|
||||||
unsafe { |
|
||||||
if !(*lock).initialized { |
|
||||||
let mut attr = std::mem::MaybeUninit::<libc::pthread_mutexattr_t>::uninit(); |
|
||||||
mutex::pthread_mutexattr_init(attr.as_mut_ptr()); |
|
||||||
let mut attr = attr.assume_init(); |
|
||||||
mutex::pthread_mutexattr_settype(&mut attr, libc::PTHREAD_MUTEX_NORMAL); |
|
||||||
|
|
||||||
mutex::pthread_mutex_init(&mut (*lock).mutex, &attr); |
|
||||||
condvar::pthread_cond_init(&mut (*lock).cvar as *mut i32 as *mut _, core::ptr::null()); |
|
||||||
|
|
||||||
(*lock).num_readers = 0; |
|
||||||
(*lock).writer_active = false; |
|
||||||
|
|
||||||
(*lock).initialized = true; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
#[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 { |
|
||||||
init_rwlock(lock); |
|
||||||
|
|
||||||
0 |
|
||||||
} |
|
||||||
|
|
||||||
#[no_mangle] |
|
||||||
pub unsafe extern "C" fn pthread_rwlock_destroy(_lock: *mut libc::pthread_rwlock_t) -> libc::c_int { |
|
||||||
0 |
|
||||||
} |
|
||||||
|
|
||||||
#[no_mangle] |
|
||||||
pub unsafe extern "C" fn pthread_rwlock_rdlock(lock: *mut libc::pthread_rwlock_t) -> libc::c_int { |
|
||||||
init_rwlock(lock); |
|
||||||
let lock = lock as *mut rwlock_clear; |
|
||||||
|
|
||||||
mutex::pthread_mutex_lock(&mut (*lock).mutex); |
|
||||||
|
|
||||||
while (*lock).writer_active { |
|
||||||
condvar::pthread_cond_wait(&mut (*lock).cvar as *mut i32 as _, &mut (*lock).mutex); |
|
||||||
} |
|
||||||
|
|
||||||
(*lock).num_readers += 1; |
|
||||||
|
|
||||||
mutex::pthread_mutex_unlock(&mut (*lock).mutex); |
|
||||||
|
|
||||||
0 |
|
||||||
} |
|
||||||
|
|
||||||
#[no_mangle] |
|
||||||
pub unsafe extern "C" fn pthread_rwlock_tryrdlock( |
|
||||||
lock: *mut libc::pthread_rwlock_t, |
|
||||||
) -> libc::c_int { |
|
||||||
init_rwlock(lock); |
|
||||||
let lock = lock as *mut rwlock_clear; |
|
||||||
|
|
||||||
if mutex::pthread_mutex_trylock(&mut (*lock).mutex) != 0 { |
|
||||||
return -1; |
|
||||||
} |
|
||||||
|
|
||||||
while (*lock).writer_active { |
|
||||||
condvar::pthread_cond_wait(&mut (*lock).cvar as *mut i32 as _, &mut (*lock).mutex); |
|
||||||
} |
|
||||||
|
|
||||||
(*lock).num_readers += 1; |
|
||||||
|
|
||||||
mutex::pthread_mutex_unlock(&mut (*lock).mutex); |
|
||||||
|
|
||||||
0 |
|
||||||
} |
|
||||||
|
|
||||||
#[no_mangle] |
|
||||||
pub unsafe extern "C" fn pthread_rwlock_wrlock(lock: *mut libc::pthread_rwlock_t) -> libc::c_int { |
|
||||||
init_rwlock(lock); |
|
||||||
let lock = lock as *mut rwlock_clear; |
|
||||||
|
|
||||||
mutex::pthread_mutex_lock(&mut (*lock).mutex); |
|
||||||
|
|
||||||
while (*lock).writer_active || (*lock).num_readers > 0 { |
|
||||||
condvar::pthread_cond_wait(&mut (*lock).cvar as *mut i32 as _, &mut (*lock).mutex); |
|
||||||
} |
|
||||||
|
|
||||||
(*lock).writer_active = true; |
|
||||||
|
|
||||||
mutex::pthread_mutex_unlock(&mut (*lock).mutex); |
|
||||||
|
|
||||||
0 |
|
||||||
} |
|
||||||
|
|
||||||
#[no_mangle] |
|
||||||
pub unsafe extern "C" fn pthread_rwlock_trywrlock( |
|
||||||
lock: *mut libc::pthread_rwlock_t, |
|
||||||
) -> libc::c_int { |
|
||||||
init_rwlock(lock); |
|
||||||
let lock = lock as *mut rwlock_clear; |
|
||||||
|
|
||||||
if mutex::pthread_mutex_trylock(&mut (*lock).mutex) != 0 { |
|
||||||
return -1; |
|
||||||
} |
|
||||||
|
|
||||||
while (*lock).writer_active || (*lock).num_readers > 0 { |
|
||||||
condvar::pthread_cond_wait(&mut (*lock).cvar as *mut i32 as _, &mut (*lock).mutex); |
|
||||||
} |
|
||||||
|
|
||||||
(*lock).writer_active = true; |
|
||||||
|
|
||||||
mutex::pthread_mutex_unlock(&mut (*lock).mutex); |
|
||||||
|
|
||||||
0 |
|
||||||
} |
|
||||||
|
|
||||||
#[no_mangle] |
|
||||||
pub unsafe extern "C" fn pthread_rwlock_unlock(lock: *mut libc::pthread_rwlock_t) -> libc::c_int { |
|
||||||
init_rwlock(lock); |
|
||||||
let lock = lock as *mut rwlock_clear; |
|
||||||
|
|
||||||
mutex::pthread_mutex_lock(&mut (*lock).mutex); |
|
||||||
|
|
||||||
// If there are readers and no writer => Must be a reader
|
|
||||||
if (*lock).num_readers > 0 && !(*lock).writer_active { |
|
||||||
(*lock).num_readers -= 1; |
|
||||||
|
|
||||||
// If there are no more readers, signal to a waiting writer
|
|
||||||
if (*lock).num_readers == 0 { |
|
||||||
condvar::pthread_cond_signal(&mut (*lock).cvar as *mut i32 as _); |
|
||||||
} |
|
||||||
// If there are no readers and a writer => Must be a writer
|
|
||||||
} else if (*lock).num_readers == 0 && (*lock).writer_active { |
|
||||||
(*lock).writer_active = false; |
|
||||||
|
|
||||||
condvar::pthread_cond_broadcast(&mut (*lock).cvar as *mut i32 as _); |
|
||||||
} |
|
||||||
|
|
||||||
mutex::pthread_mutex_unlock(&mut (*lock).mutex); |
|
||||||
|
|
||||||
0 |
|
||||||
} |
|
||||||
|
|
||||||
#[no_mangle] |
|
||||||
pub unsafe extern "C" fn pthread_rwlockattr_init( |
|
||||||
_attr: *mut libc::pthread_rwlockattr_t, |
|
||||||
) -> libc::c_int { |
|
||||||
0 |
|
||||||
} |
|
||||||
|
|
||||||
#[no_mangle] |
|
||||||
pub unsafe extern "C" fn pthread_rwlockattr_destroy( |
|
||||||
_attr: *mut libc::pthread_rwlockattr_t, |
|
||||||
) -> libc::c_int { |
|
||||||
0 |
|
||||||
} |
|
Loading…
Reference in new issue