|
|
@ -131,9 +131,40 @@ pub unsafe extern "C" fn pthread_cond_timedwait( |
|
|
|
lock: *mut libc::pthread_mutex_t, |
|
|
|
lock: *mut libc::pthread_mutex_t, |
|
|
|
abstime: *const libc::timespec, |
|
|
|
abstime: *const libc::timespec, |
|
|
|
) -> libc::c_int { |
|
|
|
) -> libc::c_int { |
|
|
|
let nsec: i64 = ((*abstime).tv_sec as i64 * 1_000_000_000) + (*abstime).tv_nsec as i64; |
|
|
|
// libctru expects a duration, but we have an absolute timestamp.
|
|
|
|
|
|
|
|
// Convert to a duration before calling libctru.
|
|
|
|
CondVar_WaitTimeout(cond as _, lock as _, nsec) |
|
|
|
|
|
|
|
|
|
|
|
// 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, 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 = 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] |
|
|
|
#[no_mangle] |
|
|
@ -399,26 +430,24 @@ pub unsafe extern "C" fn pthread_rwlockattr_destroy( |
|
|
|
|
|
|
|
|
|
|
|
// THREAD KEYS IMPLEMENTATION FOR RUST STD
|
|
|
|
// THREAD KEYS IMPLEMENTATION FOR RUST STD
|
|
|
|
|
|
|
|
|
|
|
|
use once_cell::sync::Lazy; |
|
|
|
use spin::rwlock::RwLock; |
|
|
|
use std::collections::BTreeMap; |
|
|
|
use std::collections::BTreeMap; |
|
|
|
use std::ptr; |
|
|
|
use std::ptr; |
|
|
|
use std::sync::atomic::{AtomicUsize, Ordering}; |
|
|
|
use std::sync::atomic::{AtomicUsize, Ordering}; |
|
|
|
use std::sync::{PoisonError, RwLock}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
type Key = usize; |
|
|
|
type Key = usize; |
|
|
|
type Destructor = unsafe extern "C" fn(*mut libc::c_void); |
|
|
|
type Destructor = unsafe extern "C" fn(*mut libc::c_void); |
|
|
|
|
|
|
|
|
|
|
|
static NEXT_KEY: AtomicUsize = AtomicUsize::new(1); |
|
|
|
static NEXT_KEY: AtomicUsize = AtomicUsize::new(1); |
|
|
|
|
|
|
|
|
|
|
|
static KEYS: Lazy<RwLock<BTreeMap<Key, Option<Destructor>>>> = Lazy::new(RwLock::default); |
|
|
|
// This is a spin-lock RwLock which yields the thread every loop
|
|
|
|
|
|
|
|
static KEYS: RwLock<BTreeMap<Key, Option<Destructor>>, spin::Yield> = RwLock::new(BTreeMap::new()); |
|
|
|
|
|
|
|
|
|
|
|
#[thread_local] |
|
|
|
#[thread_local] |
|
|
|
static mut LOCALS: BTreeMap<Key, *mut libc::c_void> = BTreeMap::new(); |
|
|
|
static mut LOCALS: BTreeMap<Key, *mut libc::c_void> = BTreeMap::new(); |
|
|
|
|
|
|
|
|
|
|
|
fn is_valid_key(key: Key) -> bool { |
|
|
|
fn is_valid_key(key: Key) -> bool { |
|
|
|
KEYS.read() |
|
|
|
KEYS.read().contains_key(&(key as Key)) |
|
|
|
.unwrap_or_else(PoisonError::into_inner) |
|
|
|
|
|
|
|
.contains_key(&(key as Key)) |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#[no_mangle] |
|
|
|
#[no_mangle] |
|
|
@ -427,9 +456,7 @@ pub unsafe extern "C" fn pthread_key_create( |
|
|
|
destructor: Option<Destructor>, |
|
|
|
destructor: Option<Destructor>, |
|
|
|
) -> libc::c_int { |
|
|
|
) -> libc::c_int { |
|
|
|
let new_key = NEXT_KEY.fetch_add(1, Ordering::SeqCst); |
|
|
|
let new_key = NEXT_KEY.fetch_add(1, Ordering::SeqCst); |
|
|
|
KEYS.write() |
|
|
|
KEYS.write().insert(new_key, destructor); |
|
|
|
.unwrap_or_else(PoisonError::into_inner) |
|
|
|
|
|
|
|
.insert(new_key, destructor); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*key = new_key as libc::pthread_key_t; |
|
|
|
*key = new_key as libc::pthread_key_t; |
|
|
|
|
|
|
|
|
|
|
@ -438,11 +465,7 @@ pub unsafe extern "C" fn pthread_key_create( |
|
|
|
|
|
|
|
|
|
|
|
#[no_mangle] |
|
|
|
#[no_mangle] |
|
|
|
pub unsafe extern "C" fn pthread_key_delete(key: libc::pthread_key_t) -> libc::c_int { |
|
|
|
pub unsafe extern "C" fn pthread_key_delete(key: libc::pthread_key_t) -> libc::c_int { |
|
|
|
match KEYS |
|
|
|
match KEYS.write().remove(&(key as Key)) { |
|
|
|
.write() |
|
|
|
|
|
|
|
.unwrap_or_else(PoisonError::into_inner) |
|
|
|
|
|
|
|
.remove(&(key as Key)) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
// We had a entry, so it was a valid key.
|
|
|
|
// We had a entry, so it was a valid key.
|
|
|
|
// It's officially undefined behavior if they use the key after this,
|
|
|
|
// It's officially undefined behavior if they use the key after this,
|
|
|
|
// so don't worry about cleaning up LOCALS, especially since we can't
|
|
|
|
// so don't worry about cleaning up LOCALS, especially since we can't
|
|
|
|