Compare commits

..

3 Commits

Author SHA1 Message Date
xenua 6e02c67a9f
fork: update refs 8 months ago
Meziu c885d8cda6
Merge pull request #25 from rust3ds/fix/licensing 2 years ago
Meziu 3c10dfb6f3
Merge pull request #22 from rust3ds/refresh 2 years ago
  1. 7
      Cargo.toml
  2. 117
      src/condvar.rs
  3. 4
      src/lib.rs
  4. 26
      src/misc.rs
  5. 91
      src/mutex.rs
  6. 169
      src/rwlock.rs
  7. 53
      src/thread.rs
  8. 87
      src/thread/attr.rs
  9. 8
      src/thread_keys.rs

7
Cargo.toml

@ -7,6 +7,9 @@ edition = "2021"
[dependencies] [dependencies]
libc = "0.2.116" libc = "0.2.116"
ctru-sys = { git = "https://github.com/rust3ds/ctru-rs.git" } ctru-sys = { git = "https://git.xenua.me/rust3ds/ctru-rs.git" }
spin = { version = "0.9", default-features = false, features = ["rwlock", "std"] } spin = { version = "0.9", default-features = false, features = [
"rwlock",
"std",
] }
static_assertions = "1.0" static_assertions = "1.0"

117
src/condvar.rs

@ -0,0 +1,117 @@
//! 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
}
}

4
src/lib.rs

@ -2,5 +2,9 @@
#![allow(non_camel_case_types)] #![allow(non_camel_case_types)]
#![allow(clippy::missing_safety_doc)] #![allow(clippy::missing_safety_doc)]
mod condvar;
mod misc;
mod mutex;
mod rwlock;
mod thread; mod thread;
mod thread_keys; mod thread_keys;

26
src/misc.rs

@ -0,0 +1,26 @@
//! Miscellaneous pthread functions
#[no_mangle]
pub unsafe extern "C" fn sched_yield() -> libc::c_int {
ctru_sys::svcSleepThread(0);
0
}
#[no_mangle]
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
}

91
src/mutex.rs

@ -0,0 +1,91 @@
//! 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
}

169
src/rwlock.rs

@ -0,0 +1,169 @@
//! 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
}

53
src/thread/mod.rs → src/thread.rs

@ -1,5 +1,6 @@
//! PThread threads implemented using libctru. //! PThread threads implemented using libctru.
use attr::PThreadAttr;
use spin::rwlock::RwLock; use spin::rwlock::RwLock;
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::ptr; use std::ptr;
@ -46,18 +47,16 @@ impl<T> Clone for ShareablePtr<T> {
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn __syscall_thread_create( pub unsafe extern "C" fn pthread_create(
native: *mut libc::pthread_t, native: *mut libc::pthread_t,
attr: *const libc::pthread_attr_t,
entrypoint: extern "C" fn(_: *mut libc::c_void) -> *mut libc::c_void, entrypoint: extern "C" fn(_: *mut libc::c_void) -> *mut libc::c_void,
arg: *mut libc::c_void, value: *mut libc::c_void,
_stackaddr: *const libc::c_void,
stacksize: libc::size_t,
) -> libc::c_int { ) -> libc::c_int {
let stack_size = stacksize; let attr = attr as *const PThreadAttr;
// let priority = (*attr).schedparam.sched_priority; let stack_size = (*attr).stack_size;
let mut priority = 0; let priority = (*attr).priority;
let _ = ctru_sys::svcGetThreadPriority(&mut priority, ctru_sys::CUR_THREAD_HANDLE); let processor_id = (*attr).processor_id;
// let processor_id = (*attr).processor_id;
let thread_id = NEXT_ID.fetch_add(1, Ordering::SeqCst) as libc::pthread_t; let thread_id = NEXT_ID.fetch_add(1, Ordering::SeqCst) as libc::pthread_t;
@ -75,7 +74,7 @@ pub unsafe extern "C" fn __syscall_thread_create(
let main: *mut Box<dyn FnOnce()> = Box::into_raw(Box::new(Box::new(move || { let main: *mut Box<dyn FnOnce()> = Box::into_raw(Box::new(Box::new(move || {
THREAD_ID = thread_id; THREAD_ID = thread_id;
let result = entrypoint(arg); let result = entrypoint(value);
// Update the threads map with the result, and remove this thread if // Update the threads map with the result, and remove this thread if
// it's detached. // it's detached.
@ -100,7 +99,7 @@ pub unsafe extern "C" fn __syscall_thread_create(
main as *mut libc::c_void, main as *mut libc::c_void,
stack_size, stack_size,
priority, priority,
0, // Normal CPU processor_id,
false, false,
); );
@ -139,17 +138,19 @@ pub unsafe extern "C" fn __syscall_thread_create(
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn __syscall_thread_join(thread_id: libc::pthread_t) -> *const libc::c_void { pub unsafe extern "C" fn pthread_join(
// The return value is returned as a pointer thread_id: libc::pthread_t,
return_value: *mut *mut libc::c_void,
) -> libc::c_int {
if thread_id == MAIN_THREAD_ID { if thread_id == MAIN_THREAD_ID {
// This is not a valid thread to join on // This is not a valid thread to join on
return std::ptr::null(); return libc::EINVAL;
} }
let thread_map = THREADS.read(); let thread_map = THREADS.read();
let Some(&pthread) = thread_map.get(&thread_id) else { let Some(&pthread) = thread_map.get(&thread_id) else {
// This is not a valid thread ID // This is not a valid thread ID
return std::ptr::null(); return libc::ESRCH
}; };
// We need to drop our read guard so it doesn't stay locked while joining // We need to drop our read guard so it doesn't stay locked while joining
// the thread. // the thread.
@ -157,12 +158,13 @@ pub unsafe extern "C" fn __syscall_thread_join(thread_id: libc::pthread_t) -> *c
if pthread.is_detached { if pthread.is_detached {
// Cannot join on a detached thread // Cannot join on a detached thread
return std::ptr::null(); return libc::EINVAL;
} }
let result = ctru_sys::threadJoin(pthread.thread.0, u64::MAX); let result = ctru_sys::threadJoin(pthread.thread.0, u64::MAX);
if ctru_sys::R_FAILED(result) { if ctru_sys::R_FAILED(result) {
return std::ptr::null(); // TODO: improve the error code by checking the result further?
return libc::EINVAL;
} }
ctru_sys::threadFree(pthread.thread.0); ctru_sys::threadFree(pthread.thread.0);
@ -170,14 +172,16 @@ pub unsafe extern "C" fn __syscall_thread_join(thread_id: libc::pthread_t) -> *c
// This should always be Some, but we use an if let just in case. // This should always be Some, but we use an if let just in case.
if let Some(thread_data) = thread_data { if let Some(thread_data) = thread_data {
return thread_data.result.0; if !return_value.is_null() {
*return_value = thread_data.result.0;
}
} }
std::ptr::null() 0
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn __syscall_thread_detach(thread_id: libc::pthread_t) -> libc::c_int { pub unsafe extern "C" fn pthread_detach(thread_id: libc::pthread_t) -> libc::c_int {
if thread_id == MAIN_THREAD_ID { if thread_id == MAIN_THREAD_ID {
// This is not a valid thread to detach // This is not a valid thread to detach
return libc::EINVAL; return libc::EINVAL;
@ -206,7 +210,7 @@ pub unsafe extern "C" fn __syscall_thread_detach(thread_id: libc::pthread_t) ->
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn __syscall_thread_self() -> libc::pthread_t { pub unsafe extern "C" fn pthread_self() -> libc::pthread_t {
let thread_id = THREAD_ID; let thread_id = THREAD_ID;
if thread_id == MAIN_THREAD_ID { if thread_id == MAIN_THREAD_ID {
@ -236,13 +240,6 @@ pub unsafe extern "C" fn __syscall_thread_self() -> libc::pthread_t {
thread_id thread_id
} }
#[no_mangle]
pub unsafe extern "C" fn sched_yield() -> libc::c_int {
ctru_sys::svcSleepThread(0);
0
}
/// Closes a kernel handle on drop. /// Closes a kernel handle on drop.
struct Handle(ctru_sys::Handle); struct Handle(ctru_sys::Handle);

87
src/thread/attr.rs

@ -1,16 +1,92 @@
use static_assertions::const_assert; use static_assertions::const_assert;
use std::mem; use std::mem;
const_assert!(mem::size_of::<ctru_sys::pthread_attr_t>() <= mem::size_of::<libc::pthread_attr_t>()); /// Internal struct for storing pthread attribute data
/// Must be less than or equal to the size of `libc::pthread_attr_t`. We assert
/// this below via static_assertions.
pub struct PThreadAttr {
pub(crate) stack_size: libc::size_t,
pub(crate) priority: libc::c_int,
pub(crate) processor_id: libc::c_int,
}
const_assert!(mem::size_of::<PThreadAttr>() <= mem::size_of::<libc::pthread_attr_t>());
impl Default for PThreadAttr {
fn default() -> Self {
// Note: we are ignoring the result here, but errors shouldn't occur
// since we're using a valid handle.
let mut priority = 0;
unsafe { ctru_sys::svcGetThreadPriority(&mut priority, ctru_sys::CUR_THREAD_HANDLE) };
PThreadAttr {
stack_size: libc::PTHREAD_STACK_MIN,
// If no priority value is specified, spawn with the same priority
// as the current thread
priority,
// If no processor is specified, spawn on the default core.
// (determined by the application's Exheader)
processor_id: -2,
}
}
}
#[no_mangle]
pub unsafe extern "C" fn pthread_attr_init(attr: *mut libc::pthread_attr_t) -> libc::c_int {
let attr = attr as *mut PThreadAttr;
*attr = PThreadAttr::default();
0
}
#[no_mangle]
pub unsafe extern "C" fn pthread_attr_destroy(attr: *mut libc::pthread_attr_t) -> libc::c_int {
std::ptr::drop_in_place(attr as *mut PThreadAttr);
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 attr = attr as *mut PThreadAttr;
(*attr).stack_size = stack_size;
0
}
#[no_mangle]
pub unsafe extern "C" fn pthread_attr_getschedparam(
attr: *const libc::pthread_attr_t,
param: *mut libc::sched_param,
) -> libc::c_int {
let attr = attr as *const PThreadAttr;
(*param).sched_priority = (*attr).priority;
0
}
#[no_mangle]
pub unsafe extern "C" fn pthread_attr_setschedparam(
attr: *mut libc::pthread_attr_t,
param: *const libc::sched_param,
) -> libc::c_int {
let attr = attr as *mut PThreadAttr;
(*attr).priority = (*param).sched_priority;
// TODO: we could validate the priority here if we wanted?
0
}
// No way to currently use any of these functions, since the thread creation syscall doesn't support them.
/*
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn pthread_attr_getprocessorid_np( pub unsafe extern "C" fn pthread_attr_getprocessorid_np(
attr: *const libc::pthread_attr_t, attr: *const libc::pthread_attr_t,
processor_id: *mut libc::c_int, processor_id: *mut libc::c_int,
) -> libc::c_int { ) -> libc::c_int {
let attr = attr as *mut pthread_attr_t; let attr = attr as *mut PThreadAttr;
(*processor_id) = (*attr).processor_id; (*processor_id) = (*attr).processor_id;
0 0
@ -21,11 +97,10 @@ pub unsafe extern "C" fn pthread_attr_setprocessorid_np(
attr: *mut libc::pthread_attr_t, attr: *mut libc::pthread_attr_t,
processor_id: libc::c_int, processor_id: libc::c_int,
) -> libc::c_int { ) -> libc::c_int {
let attr = attr as *mut pthread_attr_t; let attr = attr as *mut PThreadAttr;
(*attr).processor_id = processor_id; (*attr).processor_id = processor_id;
// TODO: we could validate the processor ID here if we wanted? // TODO: we could validate the processor ID here if we wanted?
0 0
} }
*/

8
src/thread_keys.rs

@ -20,7 +20,7 @@ fn is_valid_key(key: Key) -> bool {
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn __syscall_tls_create( pub unsafe extern "C" fn pthread_key_create(
key: *mut libc::pthread_key_t, key: *mut libc::pthread_key_t,
destructor: Option<Destructor>, destructor: Option<Destructor>,
) -> libc::c_int { ) -> libc::c_int {
@ -33,7 +33,7 @@ pub unsafe extern "C" fn __syscall_tls_create(
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn __syscall_tls_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.write().remove(&(key as Key)) { match KEYS.write().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,
@ -46,7 +46,7 @@ pub unsafe extern "C" fn __syscall_tls_delete(key: libc::pthread_key_t) -> libc:
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn __syscall_tls_get(key: libc::pthread_key_t) -> *mut libc::c_void { pub unsafe extern "C" fn pthread_getspecific(key: libc::pthread_key_t) -> *mut libc::c_void {
if let Some(&value) = LOCALS.get(&(key as Key)) { if let Some(&value) = LOCALS.get(&(key as Key)) {
value as _ value as _
} else { } else {
@ -56,7 +56,7 @@ pub unsafe extern "C" fn __syscall_tls_get(key: libc::pthread_key_t) -> *mut lib
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn __syscall_tls_set( pub unsafe extern "C" fn pthread_setspecific(
key: libc::pthread_key_t, key: libc::pthread_key_t,
value: *const libc::c_void, value: *const libc::c_void,
) -> libc::c_int { ) -> libc::c_int {

Loading…
Cancel
Save