From 7cac7ff9166bb8fd7827b12c9c1a7d91c19dec18 Mon Sep 17 00:00:00 2001 From: carbotaniuman <41451839+carbotaniuman@users.noreply.github.com> Date: Fri, 17 May 2024 21:16:51 -0500 Subject: [PATCH] Add some functions and modularize `thread` (#129) * Add some functions * Modularize rwlock * Modularize mutex * Reorder and format * Modularize once * Use atomic for spinlock * Write `eaccess` in terms of `euidaccess` --- c-scape/src/fs/access.rs | 12 + c-scape/src/fs/fallocate.rs | 20 +- c-scape/src/fs/rename.rs | 24 +- c-scape/src/io/read.rs | 43 +++ c-scape/src/io/write.rs | 33 ++ c-scape/src/lib.rs | 1 + c-scape/src/system/mod.rs | 28 ++ c-scape/src/thread/mod.rs | 497 +------------------------------ c-scape/src/thread/mutex.rs | 352 ++++++++++++++++++++++ c-scape/src/thread/once.rs | 28 ++ c-scape/src/thread/rwlock.rs | 126 ++++++++ c-scape/src/thread/spinlock.rs | 57 ++++ c-scape/src/todo.rs | 33 -- c-scape/src/todo/pthread_spin.rs | 25 -- 14 files changed, 727 insertions(+), 552 deletions(-) create mode 100644 c-scape/src/system/mod.rs create mode 100644 c-scape/src/thread/mutex.rs create mode 100644 c-scape/src/thread/once.rs create mode 100644 c-scape/src/thread/rwlock.rs create mode 100644 c-scape/src/thread/spinlock.rs delete mode 100644 c-scape/src/todo/pthread_spin.rs diff --git a/c-scape/src/fs/access.rs b/c-scape/src/fs/access.rs index ef731f8..b1e8839 100644 --- a/c-scape/src/fs/access.rs +++ b/c-scape/src/fs/access.rs @@ -32,3 +32,15 @@ unsafe extern "C" fn faccessat( None => -1, } } + +#[no_mangle] +unsafe extern "C" fn euidaccess(pathname: *const c_char, amode: c_int) -> c_int { + libc!(libc::euidaccess(pathname, amode)); + faccessat(libc::AT_FDCWD, pathname, amode, libc::AT_EACCESS) +} + +#[no_mangle] +unsafe extern "C" fn eaccess(pathname: *const c_char, amode: c_int) -> c_int { + libc!(libc::eaccess(pathname, amode)); + euidaccess(pathname, amode) +} diff --git a/c-scape/src/fs/fallocate.rs b/c-scape/src/fs/fallocate.rs index 2c2d47d..8863b39 100644 --- a/c-scape/src/fs/fallocate.rs +++ b/c-scape/src/fs/fallocate.rs @@ -1,11 +1,17 @@ use crate::convert_res; -use libc::{c_int, off_t}; +use libc::{c_int, off64_t, off_t}; use rustix::fd::BorrowedFd; use rustix::fs::FallocateFlags; #[no_mangle] unsafe extern "C" fn fallocate(fd: c_int, mode: c_int, offset: off_t, len: off_t) -> c_int { libc!(libc::fallocate(fd, mode, offset, len)); + fallocate64(fd, mode, offset as _, len as _) +} + +#[no_mangle] +unsafe extern "C" fn fallocate64(fd: c_int, mode: c_int, offset: off64_t, len: off64_t) -> c_int { + libc!(libc::fallocate64(fd, mode, offset, len)); let fd = BorrowedFd::borrow_raw(fd); let mode = FallocateFlags::from_bits_retain(mode as _); @@ -14,3 +20,15 @@ unsafe extern "C" fn fallocate(fd: c_int, mode: c_int, offset: off_t, len: off_t None => -1, } } + +#[no_mangle] +unsafe extern "C" fn posix_fallocate(fd: c_int, offset: off_t, len: off_t) -> c_int { + libc!(libc::posix_fallocate(fd, offset, len)); + fallocate64(fd, 0, offset as _, len as _) +} + +#[no_mangle] +unsafe extern "C" fn posix_fallocate64(fd: c_int, offset: off64_t, len: off64_t) -> c_int { + libc!(libc::posix_fallocate64(fd, offset, len)); + fallocate64(fd, 0, offset, len) +} diff --git a/c-scape/src/fs/rename.rs b/c-scape/src/fs/rename.rs index ed4625a..7a4586f 100644 --- a/c-scape/src/fs/rename.rs +++ b/c-scape/src/fs/rename.rs @@ -1,7 +1,7 @@ use core::ffi::CStr; use rustix::fd::BorrowedFd; -use libc::{c_char, c_int}; +use libc::{c_char, c_int, c_uint}; use crate::convert_res; @@ -31,3 +31,25 @@ unsafe extern "C" fn renameat( None => -1, } } + +#[no_mangle] +unsafe extern "C" fn renameat2( + old_fd: c_int, + old: *const c_char, + new_fd: c_int, + new: *const c_char, + flags: c_uint, +) -> c_int { + libc!(libc::renameat2(old_fd, old, new_fd, new, flags)); + + match convert_res(rustix::fs::renameat_with( + BorrowedFd::borrow_raw(old_fd), + CStr::from_ptr(old.cast()), + BorrowedFd::borrow_raw(new_fd), + CStr::from_ptr(new.cast()), + rustix::fs::RenameFlags::from_bits_retain(flags), + )) { + Some(()) => 0, + None => -1, + } +} diff --git a/c-scape/src/io/read.rs b/c-scape/src/io/read.rs index 5a07002..e9e7f35 100644 --- a/c-scape/src/io/read.rs +++ b/c-scape/src/io/read.rs @@ -85,6 +85,18 @@ unsafe extern "C" fn preadv(fd: c_int, iov: *const iovec, iovcnt: c_int, offset: preadv64(fd, iov, iovcnt, offset as off64_t) } +#[no_mangle] +unsafe extern "C" fn preadv2( + fd: c_int, + iov: *const iovec, + iovcnt: c_int, + offset: off_t, + flags: c_int, +) -> isize { + libc!(libc::preadv2(fd, iov, iovcnt, offset, flags)); + preadv64v2(fd, iov, iovcnt, offset as off64_t, flags) +} + #[no_mangle] unsafe extern "C" fn preadv64( fd: c_int, @@ -114,6 +126,37 @@ unsafe extern "C" fn preadv64( } } +#[no_mangle] +unsafe extern "C" fn preadv64v2( + fd: c_int, + iov: *const iovec, + iovcnt: c_int, + offset: off64_t, + flags: c_int, +) -> isize { + libc!(libc::preadv64v2(fd, iov, iovcnt, offset, flags)); + + if fd == -1 { + set_errno(Errno(libc::EBADF)); + return -1; + } + + let iov: *const IoSliceMut<'_> = checked_cast!(iov); + + // Note that rustix's `readv` takes a `&mut`, however it doesn't + // mutate the `IoSliceMut` instances themselves, so it's safe to + // cast away the `const` here. + match convert_res(rustix::io::preadv2( + BorrowedFd::borrow_raw(fd), + slice::from_raw_parts_mut(iov.cast_mut(), iovcnt as usize), + offset as u64, + rustix::io::ReadWriteFlags::from_bits_retain(flags as _), + )) { + Some(nwritten) => nwritten as isize, + None => -1, + } +} + // `__*_chk` functions that have to live in c-gull because they depend on // C functions not in the libc crate, due to `VaList` being unstable. diff --git a/c-scape/src/io/write.rs b/c-scape/src/io/write.rs index 363be6e..dc22661 100644 --- a/c-scape/src/io/write.rs +++ b/c-scape/src/io/write.rs @@ -68,6 +68,18 @@ unsafe extern "C" fn pwritev(fd: c_int, iov: *const iovec, iovcnt: c_int, offset pwritev64(fd, iov, iovcnt, offset as off64_t) } +#[no_mangle] +unsafe extern "C" fn pwritev2( + fd: c_int, + iov: *const iovec, + iovcnt: c_int, + offset: off_t, + flags: c_int, +) -> isize { + libc!(libc::pwritev2(fd, iov, iovcnt, offset, flags)); + pwritev64v2(fd, iov, iovcnt, offset as off64_t, flags) +} + #[no_mangle] unsafe extern "C" fn pwritev64( fd: c_int, @@ -86,3 +98,24 @@ unsafe extern "C" fn pwritev64( None => -1, } } + +#[no_mangle] +unsafe extern "C" fn pwritev64v2( + fd: c_int, + iov: *const iovec, + iovcnt: c_int, + offset: off64_t, + flags: c_int, +) -> isize { + libc!(libc::pwritev64v2(fd, iov, iovcnt, offset, flags)); + + match convert_res(rustix::io::pwritev2( + BorrowedFd::borrow_raw(fd), + slice::from_raw_parts(checked_cast!(iov), iovcnt as usize), + offset as u64, + rustix::io::ReadWriteFlags::from_bits_retain(flags as _), + )) { + Some(nwritten) => nwritten as isize, + None => -1, + } +} diff --git a/c-scape/src/lib.rs b/c-scape/src/lib.rs index 423bf3d..394bee1 100644 --- a/c-scape/src/lib.rs +++ b/c-scape/src/lib.rs @@ -107,6 +107,7 @@ mod stdio; mod strtod; mod strtol; mod syscall; +mod system; mod time; #[cfg(feature = "deprecated-and-unimplemented")] diff --git a/c-scape/src/system/mod.rs b/c-scape/src/system/mod.rs new file mode 100644 index 0000000..ab44aa7 --- /dev/null +++ b/c-scape/src/system/mod.rs @@ -0,0 +1,28 @@ +use errno::{set_errno, Errno}; +use libc::c_int; + +use crate::convert_res; + +#[no_mangle] +unsafe extern "C" fn reboot(cmd: c_int) -> c_int { + libc!(libc::reboot(cmd)); + + let arg = match cmd { + libc::LINUX_REBOOT_CMD_CAD_OFF => rustix::system::RebootCommand::CadOff, + libc::LINUX_REBOOT_CMD_CAD_ON => rustix::system::RebootCommand::CadOn, + libc::LINUX_REBOOT_CMD_HALT => rustix::system::RebootCommand::Halt, + libc::LINUX_REBOOT_CMD_KEXEC => rustix::system::RebootCommand::Kexec, + libc::LINUX_REBOOT_CMD_POWER_OFF => rustix::system::RebootCommand::PowerOff, + libc::LINUX_REBOOT_CMD_RESTART => rustix::system::RebootCommand::Restart, + libc::LINUX_REBOOT_CMD_SW_SUSPEND => rustix::system::RebootCommand::SwSuspend, + _ => { + set_errno(Errno(libc::EINVAL)); + return -1; + } + }; + + match convert_res(rustix::system::reboot(arg)) { + Some(()) => 0, + None => -1, + } +} diff --git a/c-scape/src/thread/mod.rs b/c-scape/src/thread/mod.rs index f5dfdd5..512d6d5 100644 --- a/c-scape/src/thread/mod.rs +++ b/c-scape/src/thread/mod.rs @@ -1,19 +1,17 @@ mod key; +mod mutex; +mod once; +mod rwlock; +mod spinlock; -use crate::GetThreadId; use alloc::boxed::Box; use alloc::format; use core::ffi::c_void; -use core::mem::{align_of, size_of, transmute, zeroed, ManuallyDrop, MaybeUninit}; +use core::mem::{align_of, size_of, transmute, zeroed, MaybeUninit}; use core::ptr::{self, copy_nonoverlapping, null_mut, NonNull}; use core::slice; -use core::sync::atomic::Ordering::SeqCst; -use core::sync::atomic::{AtomicBool, AtomicU32}; -use core::time::Duration; use origin::thread::{self, Thread}; use rustix::fs::{Mode, OFlags}; -use rustix_futex_sync::lock_api::{RawMutex as _, RawReentrantMutex, RawRwLock as _}; -use rustix_futex_sync::{Once, RawCondvar, RawMutex, RawRwLock}; use libc::{c_char, c_int, size_t}; @@ -71,55 +69,6 @@ impl Default for PthreadAttrT { } } -#[allow(non_camel_case_types)] -#[repr(C)] -union pthread_mutex_u { - normal: ManuallyDrop, - reentrant: ManuallyDrop>, -} - -#[allow(non_camel_case_types)] -#[repr(C)] -struct PthreadMutexT { - kind: AtomicU32, - u: pthread_mutex_u, - pad0: usize, - #[cfg(any(target_arch = "aarch64", target_arch = "x86"))] - pad1: usize, -} -libc_type!(PthreadMutexT, pthread_mutex_t); - -#[allow(non_camel_case_types)] -#[repr(C)] -struct PthreadRwlockT { - lock: RawRwLock, - exclusive: AtomicBool, - pad0: usize, - pad1: usize, - pad2: usize, - pad3: usize, - pad4: usize, -} -libc_type!(PthreadRwlockT, pthread_rwlock_t); - -#[allow(non_camel_case_types)] -#[repr(C)] -struct PthreadMutexattrT { - kind: AtomicU32, - #[cfg(target_arch = "aarch64")] - pad0: u32, -} -libc_type!(PthreadMutexattrT, pthread_mutexattr_t); - -#[allow(non_camel_case_types)] -#[cfg_attr(target_pointer_width = "32", repr(C, align(4)))] -#[cfg_attr(target_pointer_width = "64", repr(C, align(8)))] -struct PthreadRwlockattrT { - kind: AtomicU32, - pad0: u32, -} -libc_type!(PthreadRwlockattrT, pthread_rwlockattr_t); - #[no_mangle] unsafe extern "C" fn pthread_self() -> PthreadT { libc!(ptr::with_exposed_provenance_mut(libc::pthread_self() as _)); @@ -232,198 +181,6 @@ unsafe extern "C" fn pthread_attr_getdetachstate( 0 } -#[no_mangle] -unsafe extern "C" fn pthread_mutexattr_destroy(attr: *mut PthreadMutexattrT) -> c_int { - libc!(libc::pthread_mutexattr_destroy(checked_cast!(attr))); - ptr::drop_in_place(attr); - 0 -} - -#[no_mangle] -unsafe extern "C" fn pthread_mutexattr_init(attr: *mut PthreadMutexattrT) -> c_int { - libc!(libc::pthread_mutexattr_init(checked_cast!(attr))); - ptr::write( - attr, - PthreadMutexattrT { - kind: AtomicU32::new(libc::PTHREAD_MUTEX_DEFAULT as u32), - #[cfg(target_arch = "aarch64")] - pad0: 0, - }, - ); - 0 -} - -#[no_mangle] -unsafe extern "C" fn pthread_mutexattr_settype(attr: *mut PthreadMutexattrT, kind: c_int) -> c_int { - libc!(libc::pthread_mutexattr_settype(checked_cast!(attr), kind)); - - match kind { - libc::PTHREAD_MUTEX_NORMAL - | libc::PTHREAD_MUTEX_ERRORCHECK - | libc::PTHREAD_MUTEX_RECURSIVE => {} - _ => return libc::EINVAL, - } - - (*attr).kind.store(kind as u32, SeqCst); - 0 -} - -#[no_mangle] -unsafe extern "C" fn pthread_mutexattr_gettype( - attr: *mut PthreadMutexattrT, - kind: *mut c_int, -) -> c_int { - //libc!(libc::pthread_mutexattr_gettype(checked_cast!(attr), kind)); - - *kind = (*attr).kind.load(SeqCst) as c_int; - 0 -} - -#[no_mangle] -unsafe extern "C" fn pthread_mutex_destroy(mutex: *mut PthreadMutexT) -> c_int { - libc!(libc::pthread_mutex_destroy(checked_cast!(mutex))); - match (*mutex).kind.load(SeqCst) as i32 { - libc::PTHREAD_MUTEX_NORMAL => ManuallyDrop::drop(&mut (*mutex).u.normal), - libc::PTHREAD_MUTEX_RECURSIVE => ManuallyDrop::drop(&mut (*mutex).u.reentrant), - libc::PTHREAD_MUTEX_ERRORCHECK => todo!("PTHREAD_MUTEX_ERRORCHECK"), - other => unimplemented!("unsupported pthread mutex kind {}", other), - } - (*mutex).kind.store(!0, SeqCst); - 0 -} - -#[no_mangle] -unsafe extern "C" fn pthread_mutex_init( - mutex: *mut PthreadMutexT, - mutexattr: *const PthreadMutexattrT, -) -> c_int { - libc!(libc::pthread_mutex_init( - checked_cast!(mutex), - checked_cast!(mutexattr) - )); - let kind = if mutexattr.is_null() { - libc::PTHREAD_MUTEX_DEFAULT as u32 - } else { - (*mutexattr).kind.load(SeqCst) - }; - - match kind as i32 { - libc::PTHREAD_MUTEX_NORMAL => { - ptr::write(&mut (*mutex).u.normal, ManuallyDrop::new(RawMutex::INIT)) - } - libc::PTHREAD_MUTEX_RECURSIVE => ptr::write( - &mut (*mutex).u.reentrant, - ManuallyDrop::new(RawReentrantMutex::INIT), - ), - libc::PTHREAD_MUTEX_ERRORCHECK => todo!("PTHREAD_MUTEX_ERRORCHECK"), - other => unimplemented!("unsupported pthread mutex kind {}", other), - } - (*mutex).kind.store(kind, SeqCst); - 0 -} - -#[no_mangle] -unsafe extern "C" fn pthread_mutex_lock(mutex: *mut PthreadMutexT) -> c_int { - libc!(libc::pthread_mutex_lock(checked_cast!(mutex))); - match (*mutex).kind.load(SeqCst) as i32 { - libc::PTHREAD_MUTEX_NORMAL => (*mutex).u.normal.lock(), - libc::PTHREAD_MUTEX_RECURSIVE => (*mutex).u.reentrant.lock(), - libc::PTHREAD_MUTEX_ERRORCHECK => todo!("PTHREAD_MUTEX_ERRORCHECK"), - other => unimplemented!("unsupported pthread mutex kind {}", other), - } - 0 -} - -#[no_mangle] -unsafe extern "C" fn pthread_mutex_trylock(mutex: *mut PthreadMutexT) -> c_int { - libc!(libc::pthread_mutex_trylock(checked_cast!(mutex))); - if match (*mutex).kind.load(SeqCst) as i32 { - libc::PTHREAD_MUTEX_NORMAL => (*mutex).u.normal.try_lock(), - libc::PTHREAD_MUTEX_RECURSIVE => (*mutex).u.reentrant.try_lock(), - libc::PTHREAD_MUTEX_ERRORCHECK => todo!("PTHREAD_MUTEX_ERRORCHECK"), - other => unimplemented!("unsupported pthread mutex kind {}", other), - } { - 0 - } else { - libc::EBUSY - } -} - -#[no_mangle] -unsafe extern "C" fn pthread_mutex_unlock(mutex: *mut PthreadMutexT) -> c_int { - libc!(libc::pthread_mutex_unlock(checked_cast!(mutex))); - - let mutex = &*mutex; - match mutex.kind.load(SeqCst) as i32 { - libc::PTHREAD_MUTEX_NORMAL => { - if !mutex.u.normal.is_locked() { - return libc::EPERM; - } - mutex.u.normal.unlock() - } - libc::PTHREAD_MUTEX_RECURSIVE => { - if !mutex.u.reentrant.is_locked() { - return libc::EPERM; - } - mutex.u.reentrant.unlock() - } - libc::PTHREAD_MUTEX_ERRORCHECK => todo!("PTHREAD_MUTEX_ERRORCHECK"), - other => unimplemented!("unsupported pthread mutex kind {}", other), - } - 0 -} - -#[no_mangle] -unsafe extern "C" fn pthread_rwlock_tryrdlock(rwlock: *mut PthreadRwlockT) -> c_int { - libc!(libc::pthread_rwlock_tryrdlock(checked_cast!(rwlock))); - let result = (*rwlock).lock.try_lock_shared(); - if result { - (*rwlock).exclusive.store(false, SeqCst); - 0 - } else { - libc::EBUSY - } -} - -#[no_mangle] -unsafe extern "C" fn pthread_rwlock_trywrlock(rwlock: *mut PthreadRwlockT) -> c_int { - libc!(libc::pthread_rwlock_trywrlock(checked_cast!(rwlock))); - let result = (*rwlock).lock.try_lock_exclusive(); - if result { - (*rwlock).exclusive.store(true, SeqCst); - 0 - } else { - libc::EBUSY - } -} - -#[no_mangle] -unsafe extern "C" fn pthread_rwlock_rdlock(rwlock: *mut PthreadRwlockT) -> c_int { - libc!(libc::pthread_rwlock_rdlock(checked_cast!(rwlock))); - (*rwlock).lock.lock_shared(); - (*rwlock).exclusive.store(false, SeqCst); - 0 -} - -#[no_mangle] -unsafe extern "C" fn pthread_rwlock_unlock(rwlock: *mut PthreadRwlockT) -> c_int { - libc!(libc::pthread_rwlock_unlock(checked_cast!(rwlock))); - - let rwlock = &*rwlock; - if rwlock.exclusive.load(SeqCst) { - if !rwlock.lock.is_locked_exclusive() { - return libc::EPERM; - } - rwlock.lock.unlock_exclusive(); - } else { - if !rwlock.lock.is_locked() { - return libc::EPERM; - } - rwlock.lock.unlock_shared(); - } - 0 -} - #[no_mangle] unsafe extern "C" fn pthread_attr_getguardsize( attr: *const PthreadAttrT, @@ -444,227 +201,6 @@ unsafe extern "C" fn pthread_attr_setguardsize(attr: *mut PthreadAttrT, guardsiz 0 } -const SIZEOF_PTHREAD_COND_T: usize = 48; - -#[cfg_attr(target_arch = "x86", repr(C, align(4)))] -#[cfg_attr(not(target_arch = "x86"), repr(C, align(8)))] -struct PthreadCondT { - inner: RawCondvar, - attr: PthreadCondattrT, - pad: [u8; SIZEOF_PTHREAD_COND_T - size_of::() - size_of::()], -} - -libc_type!(PthreadCondT, pthread_cond_t); - -#[cfg(any( - target_arch = "x86", - target_arch = "x86_64", - target_arch = "arm", - all(target_arch = "aarch64", target_pointer_width = "32"), - target_arch = "riscv64", -))] -const SIZEOF_PTHREAD_CONDATTR_T: usize = 4; - -#[cfg(all(target_arch = "aarch64", target_pointer_width = "64"))] -const SIZEOF_PTHREAD_CONDATTR_T: usize = 8; - -#[repr(C, align(4))] -struct PthreadCondattrT { - pad: [u8; SIZEOF_PTHREAD_CONDATTR_T], -} - -impl Default for PthreadCondattrT { - fn default() -> Self { - Self { - pad: [0_u8; SIZEOF_PTHREAD_CONDATTR_T], - } - } -} - -libc_type!(PthreadCondattrT, pthread_condattr_t); - -#[no_mangle] -unsafe extern "C" fn pthread_condattr_destroy(attr: *mut PthreadCondattrT) -> c_int { - libc!(libc::pthread_condattr_destroy(checked_cast!(attr))); - ptr::drop_in_place(attr); - 0 -} - -#[no_mangle] -unsafe extern "C" fn pthread_condattr_init(attr: *mut PthreadCondattrT) -> c_int { - libc!(libc::pthread_condattr_init(checked_cast!(attr))); - ptr::write(attr, PthreadCondattrT::default()); - 0 -} - -#[no_mangle] -unsafe extern "C" fn pthread_condattr_setclock( - attr: *mut PthreadCondattrT, - clock_id: c_int, -) -> c_int { - libc!(libc::pthread_condattr_setclock( - checked_cast!(attr), - clock_id - )); - let _ = attr; - - if clock_id == libc::CLOCK_PROCESS_CPUTIME_ID || clock_id == libc::CLOCK_THREAD_CPUTIME_ID { - return libc::EINVAL; - } - - rustix::io::write( - rustix::stdio::stderr(), - b"unimplemented: pthread_condattr_setclock\n", - ) - .ok(); - 0 -} - -#[no_mangle] -unsafe extern "C" fn pthread_cond_broadcast(cond: *mut PthreadCondT) -> c_int { - libc!(libc::pthread_cond_broadcast(checked_cast!(cond))); - (*cond).inner.notify_all(); - 0 -} - -#[no_mangle] -unsafe extern "C" fn pthread_cond_destroy(cond: *mut PthreadCondT) -> c_int { - libc!(libc::pthread_cond_destroy(checked_cast!(cond))); - ptr::drop_in_place(cond); - 0 -} - -#[no_mangle] -unsafe extern "C" fn pthread_cond_init( - cond: *mut PthreadCondT, - attr: *const PthreadCondattrT, -) -> c_int { - libc!(libc::pthread_cond_init( - checked_cast!(cond), - checked_cast!(attr) - )); - let attr = if attr.is_null() { - PthreadCondattrT::default() - } else { - ptr::read(attr) - }; - ptr::write( - cond, - PthreadCondT { - inner: RawCondvar::new(), - attr, - pad: [0_u8; - SIZEOF_PTHREAD_COND_T - size_of::() - size_of::()], - }, - ); - 0 -} - -#[no_mangle] -unsafe extern "C" fn pthread_cond_signal(cond: *mut PthreadCondT) -> c_int { - libc!(libc::pthread_cond_signal(checked_cast!(cond))); - (*cond).inner.notify_one(); - 0 -} - -#[no_mangle] -unsafe extern "C" fn pthread_cond_wait(cond: *mut PthreadCondT, lock: *mut PthreadMutexT) -> c_int { - libc!(libc::pthread_cond_wait( - checked_cast!(cond), - checked_cast!(lock) - )); - match (*lock).kind.load(SeqCst) as i32 { - libc::PTHREAD_MUTEX_NORMAL => (*cond).inner.wait(&(*lock).u.normal), - libc::PTHREAD_MUTEX_RECURSIVE => todo!("PTHREAD_MUTEX_RECURSIVE"), - libc::PTHREAD_MUTEX_ERRORCHECK => todo!("PTHREAD_MUTEX_ERRORCHECK"), - other => unimplemented!("unsupported pthread mutex kind {}", other), - } - 0 -} - -#[no_mangle] -unsafe extern "C" fn pthread_cond_timedwait( - cond: *mut PthreadCondT, - lock: *mut PthreadMutexT, - abstime: *const libc::timespec, -) -> c_int { - libc!(libc::pthread_cond_timedwait( - checked_cast!(cond), - checked_cast!(lock), - abstime, - )); - let abstime = ptr::read(abstime); - let abstime = Duration::new( - abstime.tv_sec.try_into().unwrap(), - abstime.tv_nsec.try_into().unwrap(), - ); - let now = rustix::time::clock_gettime(rustix::time::ClockId::Realtime); - let now = Duration::new( - now.tv_sec.try_into().unwrap(), - now.tv_nsec.try_into().unwrap(), - ); - let reltime = abstime.saturating_sub(now); - match (*lock).kind.load(SeqCst) as i32 { - libc::PTHREAD_MUTEX_NORMAL => { - if (*cond).inner.wait_timeout(&(*lock).u.normal, reltime) { - 0 - } else { - libc::ETIMEDOUT - } - } - libc::PTHREAD_MUTEX_RECURSIVE => todo!("PTHREAD_MUTEX_RECURSIVE"), - libc::PTHREAD_MUTEX_ERRORCHECK => todo!("PTHREAD_MUTEX_ERRORCHECK"), - other => unimplemented!("unsupported pthread mutex kind {}", other), - } -} - -#[no_mangle] -unsafe extern "C" fn pthread_rwlock_init( - rwlock: *mut PthreadRwlockT, - rwlockattr: *const PthreadRwlockattrT, -) -> c_int { - libc!(libc::pthread_rwlock_init( - checked_cast!(rwlock), - checked_cast!(rwlockattr) - )); - ptr::write(&mut (*rwlock).lock, RawRwLock::INIT); - (*rwlock).exclusive.store(false, SeqCst); - - 0 -} - -#[no_mangle] -unsafe extern "C" fn pthread_rwlock_destroy(rwlock: *mut PthreadRwlockT) -> c_int { - libc!(libc::pthread_rwlock_destroy(checked_cast!(rwlock))); - ptr::drop_in_place(rwlock); - 0 -} - -#[no_mangle] -unsafe extern "C" fn pthread_rwlock_wrlock(rwlock: *mut PthreadRwlockT) -> c_int { - libc!(libc::pthread_rwlock_wrlock(checked_cast!(rwlock))); - (*rwlock).lock.lock_exclusive(); - (*rwlock).exclusive.store(true, SeqCst); - 0 -} - -#[no_mangle] -unsafe extern "C" fn pthread_rwlockattr_init(attr: *mut PthreadRwlockattrT) -> c_int { - libc!(libc::pthread_rwlockattr_init(checked_cast!(attr))); - - attr.write(PthreadRwlockattrT { - kind: AtomicU32::new(0), - pad0: 0, - }); - 0 -} - -#[no_mangle] -unsafe extern "C" fn pthread_rwlockattr_destroy(_attr: *mut PthreadRwlockattrT) -> c_int { - libc!(libc::pthread_rwlockattr_destroy(checked_cast!(_attr))); - 0 -} - #[no_mangle] unsafe extern "C" fn pthread_create( pthread: *mut PthreadT, @@ -983,26 +519,3 @@ unsafe extern "C" fn ___tls_get_addr() { //libc!(libc::___tls_get_addr()); todo!("___tls_get_addr") } - -#[no_mangle] -unsafe extern "C" fn pthread_once( - once_control: *mut libc::pthread_once_t, - init_routine: extern "C" fn(), -) -> c_int { - libc!(libc::pthread_once(once_control, init_routine)); - - // Assert that `PTHREAD_ONCE_INIT` is zero, just like - // `rustix_futex_sync::Once::new()` is documented to be. - debug_assert_eq!(libc::PTHREAD_ONCE_INIT, transmute(Once::new())); - debug_assert_eq!(size_of::(), size_of::()); - debug_assert_eq!(align_of::(), align_of::()); - - // Cast the `*mut pthread_once_t` to `*mut Once`, which we can do since - // `rustix_futex_sync` is documented to be a `repr(transparent)` wrapper - // around `AtomicU32`. - (*once_control.cast::()).call_once(move || { - init_routine(); - }); - - 0 -} diff --git a/c-scape/src/thread/mutex.rs b/c-scape/src/thread/mutex.rs new file mode 100644 index 0000000..42d75ef --- /dev/null +++ b/c-scape/src/thread/mutex.rs @@ -0,0 +1,352 @@ +use rustix_futex_sync::lock_api::{RawMutex as _, RawReentrantMutex}; +use rustix_futex_sync::{RawCondvar, RawMutex}; + +use core::mem::{size_of, ManuallyDrop}; +use core::ptr; +use core::sync::atomic::{AtomicU32, Ordering}; +use core::time::Duration; +use libc::c_int; + +use crate::GetThreadId; + +#[allow(non_camel_case_types)] +#[repr(C)] +union pthread_mutex_u { + normal: ManuallyDrop, + reentrant: ManuallyDrop>, +} + +#[allow(non_camel_case_types)] +#[repr(C)] +struct PthreadMutexT { + kind: AtomicU32, + u: pthread_mutex_u, + pad0: usize, + #[cfg(any(target_arch = "aarch64", target_arch = "x86"))] + pad1: usize, +} +libc_type!(PthreadMutexT, pthread_mutex_t); + +#[allow(non_camel_case_types)] +#[repr(C)] +struct PthreadMutexattrT { + kind: AtomicU32, + #[cfg(target_arch = "aarch64")] + pad0: u32, +} +libc_type!(PthreadMutexattrT, pthread_mutexattr_t); + +#[no_mangle] +unsafe extern "C" fn pthread_mutexattr_destroy(attr: *mut PthreadMutexattrT) -> c_int { + libc!(libc::pthread_mutexattr_destroy(checked_cast!(attr))); + ptr::drop_in_place(attr); + 0 +} + +#[no_mangle] +unsafe extern "C" fn pthread_mutexattr_init(attr: *mut PthreadMutexattrT) -> c_int { + libc!(libc::pthread_mutexattr_init(checked_cast!(attr))); + ptr::write( + attr, + PthreadMutexattrT { + kind: AtomicU32::new(libc::PTHREAD_MUTEX_DEFAULT as u32), + #[cfg(target_arch = "aarch64")] + pad0: 0, + }, + ); + 0 +} + +#[no_mangle] +unsafe extern "C" fn pthread_mutexattr_settype(attr: *mut PthreadMutexattrT, kind: c_int) -> c_int { + libc!(libc::pthread_mutexattr_settype(checked_cast!(attr), kind)); + + match kind { + libc::PTHREAD_MUTEX_NORMAL + | libc::PTHREAD_MUTEX_ERRORCHECK + | libc::PTHREAD_MUTEX_RECURSIVE => {} + _ => return libc::EINVAL, + } + + (*attr).kind.store(kind as u32, Ordering::SeqCst); + 0 +} + +#[no_mangle] +unsafe extern "C" fn pthread_mutexattr_gettype( + attr: *mut PthreadMutexattrT, + kind: *mut c_int, +) -> c_int { + //libc!(libc::pthread_mutexattr_gettype(checked_cast!(attr), kind)); + + *kind = (*attr).kind.load(Ordering::SeqCst) as c_int; + 0 +} + +#[no_mangle] +unsafe extern "C" fn pthread_mutex_destroy(mutex: *mut PthreadMutexT) -> c_int { + libc!(libc::pthread_mutex_destroy(checked_cast!(mutex))); + match (*mutex).kind.load(Ordering::SeqCst) as i32 { + libc::PTHREAD_MUTEX_NORMAL => ManuallyDrop::drop(&mut (*mutex).u.normal), + libc::PTHREAD_MUTEX_RECURSIVE => ManuallyDrop::drop(&mut (*mutex).u.reentrant), + libc::PTHREAD_MUTEX_ERRORCHECK => todo!("PTHREAD_MUTEX_ERRORCHECK"), + other => unimplemented!("unsupported pthread mutex kind {}", other), + } + (*mutex).kind.store(!0, Ordering::SeqCst); + 0 +} + +#[no_mangle] +unsafe extern "C" fn pthread_mutex_init( + mutex: *mut PthreadMutexT, + mutexattr: *const PthreadMutexattrT, +) -> c_int { + libc!(libc::pthread_mutex_init( + checked_cast!(mutex), + checked_cast!(mutexattr) + )); + let kind = if mutexattr.is_null() { + libc::PTHREAD_MUTEX_DEFAULT as u32 + } else { + (*mutexattr).kind.load(Ordering::SeqCst) + }; + + match kind as i32 { + libc::PTHREAD_MUTEX_NORMAL => { + ptr::write(&mut (*mutex).u.normal, ManuallyDrop::new(RawMutex::INIT)) + } + libc::PTHREAD_MUTEX_RECURSIVE => ptr::write( + &mut (*mutex).u.reentrant, + ManuallyDrop::new(RawReentrantMutex::INIT), + ), + libc::PTHREAD_MUTEX_ERRORCHECK => todo!("PTHREAD_MUTEX_ERRORCHECK"), + other => unimplemented!("unsupported pthread mutex kind {}", other), + } + (*mutex).kind.store(kind, Ordering::SeqCst); + 0 +} + +#[no_mangle] +unsafe extern "C" fn pthread_mutex_lock(mutex: *mut PthreadMutexT) -> c_int { + libc!(libc::pthread_mutex_lock(checked_cast!(mutex))); + match (*mutex).kind.load(Ordering::SeqCst) as i32 { + libc::PTHREAD_MUTEX_NORMAL => (*mutex).u.normal.lock(), + libc::PTHREAD_MUTEX_RECURSIVE => (*mutex).u.reentrant.lock(), + libc::PTHREAD_MUTEX_ERRORCHECK => todo!("PTHREAD_MUTEX_ERRORCHECK"), + other => unimplemented!("unsupported pthread mutex kind {}", other), + } + 0 +} + +#[no_mangle] +unsafe extern "C" fn pthread_mutex_trylock(mutex: *mut PthreadMutexT) -> c_int { + libc!(libc::pthread_mutex_trylock(checked_cast!(mutex))); + if match (*mutex).kind.load(Ordering::SeqCst) as i32 { + libc::PTHREAD_MUTEX_NORMAL => (*mutex).u.normal.try_lock(), + libc::PTHREAD_MUTEX_RECURSIVE => (*mutex).u.reentrant.try_lock(), + libc::PTHREAD_MUTEX_ERRORCHECK => todo!("PTHREAD_MUTEX_ERRORCHECK"), + other => unimplemented!("unsupported pthread mutex kind {}", other), + } { + 0 + } else { + libc::EBUSY + } +} + +#[no_mangle] +unsafe extern "C" fn pthread_mutex_unlock(mutex: *mut PthreadMutexT) -> c_int { + libc!(libc::pthread_mutex_unlock(checked_cast!(mutex))); + + let mutex = &*mutex; + match mutex.kind.load(Ordering::SeqCst) as i32 { + libc::PTHREAD_MUTEX_NORMAL => { + if !mutex.u.normal.is_locked() { + return libc::EPERM; + } + mutex.u.normal.unlock() + } + libc::PTHREAD_MUTEX_RECURSIVE => { + if !mutex.u.reentrant.is_locked() { + return libc::EPERM; + } + mutex.u.reentrant.unlock() + } + libc::PTHREAD_MUTEX_ERRORCHECK => todo!("PTHREAD_MUTEX_ERRORCHECK"), + other => unimplemented!("unsupported pthread mutex kind {}", other), + } + 0 +} + +const SIZEOF_PTHREAD_COND_T: usize = 48; + +#[cfg_attr(target_arch = "x86", repr(C, align(4)))] +#[cfg_attr(not(target_arch = "x86"), repr(C, align(8)))] +struct PthreadCondT { + inner: RawCondvar, + attr: PthreadCondattrT, + pad: [u8; SIZEOF_PTHREAD_COND_T - size_of::() - size_of::()], +} + +libc_type!(PthreadCondT, pthread_cond_t); + +#[cfg(any( + target_arch = "x86", + target_arch = "x86_64", + target_arch = "arm", + all(target_arch = "aarch64", target_pointer_width = "32"), + target_arch = "riscv64", +))] +const SIZEOF_PTHREAD_CONDATTR_T: usize = 4; + +#[cfg(all(target_arch = "aarch64", target_pointer_width = "64"))] +const SIZEOF_PTHREAD_CONDATTR_T: usize = 8; + +#[repr(C, align(4))] +struct PthreadCondattrT { + pad: [u8; SIZEOF_PTHREAD_CONDATTR_T], +} + +impl Default for PthreadCondattrT { + fn default() -> Self { + Self { + pad: [0_u8; SIZEOF_PTHREAD_CONDATTR_T], + } + } +} + +libc_type!(PthreadCondattrT, pthread_condattr_t); + +#[no_mangle] +unsafe extern "C" fn pthread_condattr_destroy(attr: *mut PthreadCondattrT) -> c_int { + libc!(libc::pthread_condattr_destroy(checked_cast!(attr))); + ptr::drop_in_place(attr); + 0 +} + +#[no_mangle] +unsafe extern "C" fn pthread_condattr_init(attr: *mut PthreadCondattrT) -> c_int { + libc!(libc::pthread_condattr_init(checked_cast!(attr))); + ptr::write(attr, PthreadCondattrT::default()); + 0 +} + +#[no_mangle] +unsafe extern "C" fn pthread_condattr_setclock( + attr: *mut PthreadCondattrT, + clock_id: c_int, +) -> c_int { + libc!(libc::pthread_condattr_setclock( + checked_cast!(attr), + clock_id + )); + let _ = attr; + + if clock_id == libc::CLOCK_PROCESS_CPUTIME_ID || clock_id == libc::CLOCK_THREAD_CPUTIME_ID { + return libc::EINVAL; + } + + rustix::io::write( + rustix::stdio::stderr(), + b"unimplemented: pthread_condattr_setclock\n", + ) + .ok(); + 0 +} + +#[no_mangle] +unsafe extern "C" fn pthread_cond_broadcast(cond: *mut PthreadCondT) -> c_int { + libc!(libc::pthread_cond_broadcast(checked_cast!(cond))); + (*cond).inner.notify_all(); + 0 +} + +#[no_mangle] +unsafe extern "C" fn pthread_cond_destroy(cond: *mut PthreadCondT) -> c_int { + libc!(libc::pthread_cond_destroy(checked_cast!(cond))); + ptr::drop_in_place(cond); + 0 +} + +#[no_mangle] +unsafe extern "C" fn pthread_cond_init( + cond: *mut PthreadCondT, + attr: *const PthreadCondattrT, +) -> c_int { + libc!(libc::pthread_cond_init( + checked_cast!(cond), + checked_cast!(attr) + )); + let attr = if attr.is_null() { + PthreadCondattrT::default() + } else { + ptr::read(attr) + }; + ptr::write( + cond, + PthreadCondT { + inner: RawCondvar::new(), + attr, + pad: [0_u8; + SIZEOF_PTHREAD_COND_T - size_of::() - size_of::()], + }, + ); + 0 +} + +#[no_mangle] +unsafe extern "C" fn pthread_cond_signal(cond: *mut PthreadCondT) -> c_int { + libc!(libc::pthread_cond_signal(checked_cast!(cond))); + (*cond).inner.notify_one(); + 0 +} + +#[no_mangle] +unsafe extern "C" fn pthread_cond_wait(cond: *mut PthreadCondT, lock: *mut PthreadMutexT) -> c_int { + libc!(libc::pthread_cond_wait( + checked_cast!(cond), + checked_cast!(lock) + )); + match (*lock).kind.load(Ordering::SeqCst) as i32 { + libc::PTHREAD_MUTEX_NORMAL => (*cond).inner.wait(&(*lock).u.normal), + libc::PTHREAD_MUTEX_RECURSIVE => todo!("PTHREAD_MUTEX_RECURSIVE"), + libc::PTHREAD_MUTEX_ERRORCHECK => todo!("PTHREAD_MUTEX_ERRORCHECK"), + other => unimplemented!("unsupported pthread mutex kind {}", other), + } + 0 +} + +#[no_mangle] +unsafe extern "C" fn pthread_cond_timedwait( + cond: *mut PthreadCondT, + lock: *mut PthreadMutexT, + abstime: *const libc::timespec, +) -> c_int { + libc!(libc::pthread_cond_timedwait( + checked_cast!(cond), + checked_cast!(lock), + abstime, + )); + let abstime = ptr::read(abstime); + let abstime = Duration::new( + abstime.tv_sec.try_into().unwrap(), + abstime.tv_nsec.try_into().unwrap(), + ); + let now = rustix::time::clock_gettime(rustix::time::ClockId::Realtime); + let now = Duration::new( + now.tv_sec.try_into().unwrap(), + now.tv_nsec.try_into().unwrap(), + ); + let reltime = abstime.saturating_sub(now); + match (*lock).kind.load(Ordering::SeqCst) as i32 { + libc::PTHREAD_MUTEX_NORMAL => { + if (*cond).inner.wait_timeout(&(*lock).u.normal, reltime) { + 0 + } else { + libc::ETIMEDOUT + } + } + libc::PTHREAD_MUTEX_RECURSIVE => todo!("PTHREAD_MUTEX_RECURSIVE"), + libc::PTHREAD_MUTEX_ERRORCHECK => todo!("PTHREAD_MUTEX_ERRORCHECK"), + other => unimplemented!("unsupported pthread mutex kind {}", other), + } +} diff --git a/c-scape/src/thread/once.rs b/c-scape/src/thread/once.rs new file mode 100644 index 0000000..a8faed0 --- /dev/null +++ b/c-scape/src/thread/once.rs @@ -0,0 +1,28 @@ +use rustix_futex_sync::Once; + +use libc::c_int; + +libc_type!(Once, pthread_once_t); +// Assert that `PTHREAD_ONCE_INIT` is zero, just like +// `rustix_futex_sync::Once::new()` is documented to be. +#[cfg(test)] +static_assertions::const_assert_eq!(libc::PTHREAD_ONCE_INIT, unsafe { + core::mem::transmute(Once::new()) +}); + +#[no_mangle] +unsafe extern "C" fn pthread_once( + once_control: *mut libc::pthread_once_t, + init_routine: extern "C" fn(), +) -> c_int { + libc!(libc::pthread_once(once_control, init_routine)); + + // Cast the `*mut pthread_once_t` to `*mut Once`, which we can do since + // `rustix_futex_sync` is documented to be a `repr(transparent)` wrapper + // around `AtomicU32`. + (*once_control.cast::()).call_once(move || { + init_routine(); + }); + + 0 +} diff --git a/c-scape/src/thread/rwlock.rs b/c-scape/src/thread/rwlock.rs new file mode 100644 index 0000000..50d6f64 --- /dev/null +++ b/c-scape/src/thread/rwlock.rs @@ -0,0 +1,126 @@ +use rustix_futex_sync::lock_api::RawRwLock as _; +use rustix_futex_sync::RawRwLock; + +use core::ptr; +use core::sync::atomic::{AtomicBool, AtomicU32, Ordering}; +use libc::c_int; + +#[allow(non_camel_case_types)] +#[repr(C)] +struct PthreadRwlockT { + lock: RawRwLock, + exclusive: AtomicBool, + pad0: usize, + pad1: usize, + pad2: usize, + pad3: usize, + pad4: usize, +} +libc_type!(PthreadRwlockT, pthread_rwlock_t); + +#[allow(non_camel_case_types)] +#[cfg_attr(target_pointer_width = "32", repr(C, align(4)))] +#[cfg_attr(target_pointer_width = "64", repr(C, align(8)))] +struct PthreadRwlockattrT { + kind: AtomicU32, + pad0: u32, +} +libc_type!(PthreadRwlockattrT, pthread_rwlockattr_t); + +#[no_mangle] +unsafe extern "C" fn pthread_rwlock_init( + rwlock: *mut PthreadRwlockT, + rwlockattr: *const PthreadRwlockattrT, +) -> c_int { + libc!(libc::pthread_rwlock_init( + checked_cast!(rwlock), + checked_cast!(rwlockattr) + )); + ptr::write(&mut (*rwlock).lock, RawRwLock::INIT); + (*rwlock).exclusive.store(false, Ordering::SeqCst); + + 0 +} + +#[no_mangle] +unsafe extern "C" fn pthread_rwlock_destroy(rwlock: *mut PthreadRwlockT) -> c_int { + libc!(libc::pthread_rwlock_destroy(checked_cast!(rwlock))); + ptr::drop_in_place(rwlock); + 0 +} + +#[no_mangle] +unsafe extern "C" fn pthread_rwlock_wrlock(rwlock: *mut PthreadRwlockT) -> c_int { + libc!(libc::pthread_rwlock_wrlock(checked_cast!(rwlock))); + (*rwlock).lock.lock_exclusive(); + (*rwlock).exclusive.store(true, Ordering::SeqCst); + 0 +} + +#[no_mangle] +unsafe extern "C" fn pthread_rwlockattr_init(attr: *mut PthreadRwlockattrT) -> c_int { + libc!(libc::pthread_rwlockattr_init(checked_cast!(attr))); + + attr.write(PthreadRwlockattrT { + kind: AtomicU32::new(0), + pad0: 0, + }); + 0 +} + +#[no_mangle] +unsafe extern "C" fn pthread_rwlockattr_destroy(_attr: *mut PthreadRwlockattrT) -> c_int { + libc!(libc::pthread_rwlockattr_destroy(checked_cast!(_attr))); + 0 +} + +#[no_mangle] +unsafe extern "C" fn pthread_rwlock_tryrdlock(rwlock: *mut PthreadRwlockT) -> c_int { + libc!(libc::pthread_rwlock_tryrdlock(checked_cast!(rwlock))); + let result = (*rwlock).lock.try_lock_shared(); + if result { + (*rwlock).exclusive.store(false, Ordering::SeqCst); + 0 + } else { + libc::EBUSY + } +} + +#[no_mangle] +unsafe extern "C" fn pthread_rwlock_trywrlock(rwlock: *mut PthreadRwlockT) -> c_int { + libc!(libc::pthread_rwlock_trywrlock(checked_cast!(rwlock))); + let result = (*rwlock).lock.try_lock_exclusive(); + if result { + (*rwlock).exclusive.store(true, Ordering::SeqCst); + 0 + } else { + libc::EBUSY + } +} + +#[no_mangle] +unsafe extern "C" fn pthread_rwlock_rdlock(rwlock: *mut PthreadRwlockT) -> c_int { + libc!(libc::pthread_rwlock_rdlock(checked_cast!(rwlock))); + (*rwlock).lock.lock_shared(); + (*rwlock).exclusive.store(false, Ordering::SeqCst); + 0 +} + +#[no_mangle] +unsafe extern "C" fn pthread_rwlock_unlock(rwlock: *mut PthreadRwlockT) -> c_int { + libc!(libc::pthread_rwlock_unlock(checked_cast!(rwlock))); + + let rwlock = &*rwlock; + if rwlock.exclusive.load(Ordering::SeqCst) { + if !rwlock.lock.is_locked_exclusive() { + return libc::EPERM; + } + rwlock.lock.unlock_exclusive(); + } else { + if !rwlock.lock.is_locked() { + return libc::EPERM; + } + rwlock.lock.unlock_shared(); + } + 0 +} diff --git a/c-scape/src/thread/spinlock.rs b/c-scape/src/thread/spinlock.rs new file mode 100644 index 0000000..d640d76 --- /dev/null +++ b/c-scape/src/thread/spinlock.rs @@ -0,0 +1,57 @@ +use core::sync::atomic::{AtomicU32, Ordering}; + +use libc::c_int; + +type PthreadSpinlockT = AtomicU32; +libc_type!(PthreadSpinlockT, pthread_spinlock_t); + +#[no_mangle] +unsafe extern "C" fn pthread_spin_destroy(lock: *mut PthreadSpinlockT) -> c_int { + libc!(libc::pthread_spin_destroy(checked_cast!(lock))); + 0 +} + +#[no_mangle] +unsafe extern "C" fn pthread_spin_init(lock: *mut PthreadSpinlockT, pshared: c_int) -> c_int { + libc!(libc::pthread_spin_init(checked_cast!(lock), pshared)); + + let lock = &*lock; + + lock.store(0, Ordering::Release); + 0 +} + +#[no_mangle] +unsafe extern "C" fn pthread_spin_lock(lock: *mut PthreadSpinlockT) -> c_int { + libc!(libc::pthread_spin_lock(checked_cast!(lock))); + + let lock = &*lock; + + while lock.swap(1, Ordering::Acquire) == 1 { + core::hint::spin_loop(); + } + + 0 +} +#[no_mangle] +unsafe extern "C" fn pthread_spin_trylock(lock: *mut PthreadSpinlockT) -> c_int { + libc!(libc::pthread_spin_trylock(checked_cast!(lock))); + + let lock = &*lock; + + if lock.swap(1, Ordering::Acquire) == 1 { + libc::EBUSY + } else { + 0 + } +} + +#[no_mangle] +unsafe extern "C" fn pthread_spin_unlock(lock: *mut PthreadSpinlockT) -> c_int { + libc!(libc::pthread_spin_unlock(checked_cast!(lock))); + + let lock = &*lock; + + lock.store(0, Ordering::Release); + 0 +} diff --git a/c-scape/src/todo.rs b/c-scape/src/todo.rs index 06a8bb6..2f1af33 100644 --- a/c-scape/src/todo.rs +++ b/c-scape/src/todo.rs @@ -10,7 +10,6 @@ mod locale; mod long_double; mod long_double_complex; mod pthread_cancel; -mod pthread_spin; mod set_id; mod sysv; mod wchar; @@ -27,10 +26,6 @@ unsafe extern "C" fn signalfd() { todo!("signalfd") } #[no_mangle] -unsafe extern "C" fn posix_fallocate() { - todo!("posix_fallocate") -} -#[no_mangle] unsafe extern "C" fn mount() { todo!("mount") } @@ -47,33 +42,9 @@ unsafe extern "C" fn unshare() { todo!("unshare") } #[no_mangle] -unsafe extern "C" fn eaccess() { - todo!("eaccess") -} -#[no_mangle] unsafe extern "C" fn timerfd_gettime() { todo!("timerfd_gettime") } -#[no_mangle] -unsafe extern "C" fn preadv2() { - todo!("preadv2") -} -#[no_mangle] -unsafe extern "C" fn pwritev2() { - todo!("pwritev2") -} -#[no_mangle] -unsafe extern "C" fn preadv64v2() { - todo!("preadv64v2") -} -#[no_mangle] -unsafe extern "C" fn pwritev64v2() { - todo!("pwritev64v2") -} -#[no_mangle] -unsafe extern "C" fn reboot() { - todo!("reboot") -} // `_chk` versions of functions we have implemented, so we just need to add // wrappers with extra checks. @@ -390,10 +361,6 @@ unsafe extern "C" fn sendmmsg() { todo!("sendmmsg") } #[no_mangle] -unsafe extern "C" fn renameat2() { - todo!("renameat2") -} -#[no_mangle] unsafe extern "C" fn timer_create() { todo!("timer_create") } diff --git a/c-scape/src/todo/pthread_spin.rs b/c-scape/src/todo/pthread_spin.rs deleted file mode 100644 index ed9a7a4..0000000 --- a/c-scape/src/todo/pthread_spin.rs +++ /dev/null @@ -1,25 +0,0 @@ -//! Unimplemented pthread spin-lock functions. -//! -//! Spin locks are not widely used and are difficult to use effectively. Most -//! programs should use regular locks. - -#[no_mangle] -unsafe extern "C" fn pthread_spin_destroy() { - todo!("pthread_spin_destroy") -} -#[no_mangle] -unsafe extern "C" fn pthread_spin_init() { - todo!("pthread_spin_init") -} -#[no_mangle] -unsafe extern "C" fn pthread_spin_lock() { - todo!("pthread_spin_lock") -} -#[no_mangle] -unsafe extern "C" fn pthread_spin_trylock() { - todo!("pthread_spin_trylock") -} -#[no_mangle] -unsafe extern "C" fn pthread_spin_unlock() { - todo!("pthread_spin_unlock") -}