libc: add pthread_mutex_t and pthread_barrier_t
This commit is contained in:
parent
03f6362756
commit
a14206204a
@ -139,7 +139,7 @@ impl<TA: TableAllocator> ProcessAddressSpaceImpl<TA> {
|
||||
|
||||
let page = l3[l3i].as_page()?;
|
||||
|
||||
Some((page, l3[l3i].attributes().into()))
|
||||
Some((page.add(virt & 0xFFF), l3[l3i].attributes().into()))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -120,7 +120,7 @@ impl<TA: TableAllocator> ProcessAddressSpaceImpl<TA> {
|
||||
let l3 = self.l0.get(l0i)?;
|
||||
let page = l3[l3i].as_page()?;
|
||||
|
||||
Some((page, l3[l3i].attributes().into()))
|
||||
Some((page.add(virt & 0xFFF), l3[l3i].attributes().into()))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -144,7 +144,7 @@ impl<TA: TableAllocator> ProcessAddressSpaceImpl<TA> {
|
||||
|
||||
let page = l3[l3i].as_page()?;
|
||||
|
||||
Some((page, l3[l3i].attributes().into()))
|
||||
Some((page.add(virt & 0xFFF), l3[l3i].attributes().into()))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,8 @@ use core::{
|
||||
use bytemuck::{Pod, Zeroable};
|
||||
use kernel_arch_interface::mem::KernelTableManager;
|
||||
|
||||
use crate::table::EntryLevel;
|
||||
|
||||
/// Wrapper type to represent a physical memory address
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Pod, Zeroable)]
|
||||
#[repr(transparent)]
|
||||
|
@ -1,4 +1,5 @@
|
||||
use core::{
|
||||
future::poll_fn,
|
||||
pin::Pin,
|
||||
sync::atomic::{AtomicU32, Ordering},
|
||||
task::{Context, Poll},
|
||||
@ -6,57 +7,59 @@ use core::{
|
||||
|
||||
use alloc::sync::Arc;
|
||||
use futures_util::Future;
|
||||
use libk_mm::{
|
||||
address::{AsPhysicalAddress, PhysicalAddress},
|
||||
pointer::PhysicalRef,
|
||||
process::ProcessAddressSpace,
|
||||
};
|
||||
use libk_util::waker::QueueWaker;
|
||||
use yggdrasil_abi::error::Error;
|
||||
|
||||
use crate::task::thread::Thread;
|
||||
|
||||
/// User-space mutex (like BSD/Linux's futex) data structure
|
||||
pub struct UserspaceMutex {
|
||||
queue: QueueWaker,
|
||||
space: Arc<ProcessAddressSpace>,
|
||||
address: usize,
|
||||
}
|
||||
|
||||
impl UserspaceMutex {
|
||||
/// Creates a new [UserspaceMutex] associated with given `address`
|
||||
pub fn new(address: usize) -> Self {
|
||||
Self {
|
||||
pub fn new(space: &Arc<ProcessAddressSpace>, address: usize) -> Result<Self, Error> {
|
||||
Ok(Self {
|
||||
queue: QueueWaker::new(),
|
||||
space: space.clone(),
|
||||
address,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn load(&self) -> u32 {
|
||||
// TODO: this is slow, but this prevents the kernel from reading from unmapped memory
|
||||
let phys = self.space.translate(self.address).unwrap();
|
||||
unsafe { PhysicalRef::<AtomicU32>::map(phys).load(Ordering::Acquire) }
|
||||
}
|
||||
|
||||
async fn wait_predicate<P: Fn(u32) -> bool>(&self, predicate: P) {
|
||||
poll_fn(|cx| {
|
||||
if predicate(self.load()) {
|
||||
self.queue.remove(cx.waker());
|
||||
Poll::Ready(())
|
||||
} else {
|
||||
self.queue.register(cx.waker());
|
||||
Poll::Pending
|
||||
}
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn wait_until(self: Arc<Self>, compare_value: u32) {
|
||||
self.wait_predicate(|value| value == compare_value).await
|
||||
}
|
||||
|
||||
/// Blocks until the value at the mutex's address becomes different from `compare_value`
|
||||
pub fn wait(self: Arc<Self>, compare_value: u32) -> impl Future<Output = ()> {
|
||||
struct WaitFuture {
|
||||
mutex: Arc<UserspaceMutex>,
|
||||
compare_value: u32,
|
||||
}
|
||||
|
||||
impl WaitFuture {
|
||||
fn load(&self, ordering: Ordering) -> u32 {
|
||||
let value = unsafe { &*(self.mutex.address as *const AtomicU32) };
|
||||
value.load(ordering)
|
||||
}
|
||||
}
|
||||
|
||||
impl Future for WaitFuture {
|
||||
type Output = ();
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
self.mutex.queue.register(cx.waker());
|
||||
|
||||
// Test the mutex
|
||||
if self.load(Ordering::Acquire) != self.compare_value {
|
||||
self.mutex.queue.remove(cx.waker());
|
||||
Poll::Ready(())
|
||||
} else {
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WaitFuture {
|
||||
mutex: self,
|
||||
compare_value,
|
||||
}
|
||||
pub async fn wait(self: Arc<Self>, compare_value: u32) {
|
||||
self.wait_predicate(|value| value != compare_value).await
|
||||
}
|
||||
|
||||
/// Wakes up a single task waiting on the mutex
|
||||
|
@ -5,7 +5,7 @@ use core::{
|
||||
|
||||
use abi_lib::SyscallRegister;
|
||||
use alloc::{
|
||||
collections::BTreeMap,
|
||||
collections::{btree_map, BTreeMap},
|
||||
string::String,
|
||||
sync::{Arc, Weak},
|
||||
vec::Vec,
|
||||
@ -349,13 +349,17 @@ impl Process {
|
||||
|
||||
/// Returns a [UserspaceMutex] associated with the `address`. If one does not exist, will
|
||||
/// create it.
|
||||
pub fn get_or_insert_mutex(&self, address: usize) -> Arc<UserspaceMutex> {
|
||||
pub fn get_or_insert_mutex(&self, address: usize) -> Result<Arc<UserspaceMutex>, Error> {
|
||||
let space = self.space();
|
||||
let mut inner = self.inner.write();
|
||||
inner
|
||||
.mutexes
|
||||
.entry(address)
|
||||
.or_insert_with(|| Arc::new(UserspaceMutex::new(address)))
|
||||
.clone()
|
||||
match inner.mutexes.entry(address) {
|
||||
btree_map::Entry::Vacant(slot) => {
|
||||
let mutex = Arc::new(UserspaceMutex::new(&space, address)?);
|
||||
slot.insert(mutex.clone());
|
||||
Ok(mutex)
|
||||
}
|
||||
btree_map::Entry::Occupied(slot) => Ok(slot.get().clone()),
|
||||
}
|
||||
}
|
||||
|
||||
// Process list
|
||||
|
@ -214,10 +214,11 @@ pub(crate) fn mutex(mutex: &AtomicU32, op: &MutexOperation) -> Result<(), Error>
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
let mutex = process.get_or_insert_mutex((mutex as *const AtomicU32).addr());
|
||||
let mutex = process.get_or_insert_mutex((mutex as *const AtomicU32).addr())?;
|
||||
|
||||
match op {
|
||||
&MutexOperation::Wait(value, _timeout) => block! { mutex.wait(value).await },
|
||||
&MutexOperation::WaitUntil(value, _timeout) => block! { mutex.wait_until(value).await },
|
||||
MutexOperation::Wake => {
|
||||
mutex.wake();
|
||||
Ok(())
|
||||
|
@ -54,6 +54,8 @@ pub enum SpawnOption {
|
||||
pub enum MutexOperation {
|
||||
/// Waits on the mutex object until it is different from "compare value"
|
||||
Wait(u32, Option<Duration>),
|
||||
/// Waits on the mutex object until it becomes equal to the "compare value"
|
||||
WaitUntil(u32, Option<Duration>),
|
||||
/// Wakes a single mutex-waiting thread
|
||||
Wake,
|
||||
/// Wakes all threads waiting on the mutex
|
||||
|
26
test.c
26
test.c
@ -1,27 +1,31 @@
|
||||
#include <pthread.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/yggdrasil.h>
|
||||
|
||||
_Thread_local int x = 123;
|
||||
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
static void *function(void *arg) {
|
||||
printf("This is thread %u\n", pthread_self());
|
||||
printf("argument: %s\n", (const char *) arg);
|
||||
printf("[child] x = %d\n", x);
|
||||
x += 1;
|
||||
printf("[child] x = %d\n", x);
|
||||
pthread_barrier_t *barrier = (pthread_barrier_t *) arg;
|
||||
printf("[child] waiting for parent\n");
|
||||
pthread_barrier_wait(barrier);
|
||||
printf("[child] barrier signalled!!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv) {
|
||||
pthread_t thread;
|
||||
printf("[main] &x = %p\n", &x);
|
||||
printf("[main] x = %d\n", x);
|
||||
x = 321;
|
||||
printf("[main] x = %d\n", x);
|
||||
pthread_barrier_t barrier;
|
||||
|
||||
assert(pthread_create(&thread, NULL, function, (void *) "thread1") == 0);
|
||||
pthread_barrier_init(&barrier, NULL, 2);
|
||||
|
||||
printf("[main] will make the child wait on a barrier\n");
|
||||
assert(pthread_create(&thread, NULL, function, (void *) &barrier) == 0);
|
||||
|
||||
sleep(3);
|
||||
pthread_barrier_wait(&barrier);
|
||||
printf("[main] barrier signalled!!\n");
|
||||
|
||||
pthread_join(thread, NULL);
|
||||
|
||||
|
@ -15,6 +15,7 @@ const RENAMES: &[(&str, &str)] = &[
|
||||
("CFdResult", "int"),
|
||||
("COffsetResult", "off_t"),
|
||||
("CPidResult", "pid_t"),
|
||||
("AtomicU32", "uint32_t"),
|
||||
];
|
||||
|
||||
fn include_dir(d: &DirEntry) -> bool {
|
||||
|
6
userspace/lib/ygglibc/include/bits/pthread.h
Normal file
6
userspace/lib/ygglibc/include/bits/pthread.h
Normal file
@ -0,0 +1,6 @@
|
||||
#ifndef _YGGDRASIL_PTHREAD_H
|
||||
#define _YGGDRASIL_PTHREAD_H 1
|
||||
|
||||
#define PTHREAD_MUTEX_INITIALIZER { 0 }
|
||||
|
||||
#endif
|
@ -1,9 +1,119 @@
|
||||
// PTHREAD_BARRIER_SERIAL_THREAD
|
||||
|
||||
// int pthread_barrier_destroy(pthread_barrier_t *);
|
||||
// int pthread_barrier_init(pthread_barrier_t *restrict, const pthread_barrierattr_t *restrict, unsigned);
|
||||
// int pthread_barrier_wait(pthread_barrier_t *);
|
||||
// int pthread_barrierattr_destroy(pthread_barrierattr_t *);
|
||||
// int pthread_barrierattr_getpshared(const pthread_barrierattr_t *restrict, int *restrict);
|
||||
// int pthread_barrierattr_init(pthread_barrierattr_t *);
|
||||
// int pthread_barrierattr_setpshared(pthread_barrierattr_t *, int);
|
||||
use core::{
|
||||
ffi::{c_int, c_uint},
|
||||
ptr::NonNull,
|
||||
sync::atomic::{self, Ordering},
|
||||
};
|
||||
|
||||
use yggdrasil_rt::process::MutexOperation;
|
||||
|
||||
use crate::{
|
||||
error::{self, CIntZeroResult, CResult},
|
||||
headers::{
|
||||
errno,
|
||||
sys_types::{pthread_barrier_t, pthread_barrierattr_t},
|
||||
},
|
||||
util::PointerExt,
|
||||
};
|
||||
|
||||
use super::PTHREAD_PROCESS_PRIVATE;
|
||||
|
||||
impl pthread_barrier_t {
|
||||
fn wait(&self) {
|
||||
// Fastpath
|
||||
if self.__state.fetch_add(1, Ordering::Release) >= self.__limit {
|
||||
self.signal();
|
||||
return;
|
||||
}
|
||||
|
||||
loop {
|
||||
if self.check() {
|
||||
self.signal();
|
||||
return;
|
||||
}
|
||||
self.block();
|
||||
}
|
||||
}
|
||||
|
||||
fn block(&self) {
|
||||
unsafe {
|
||||
yggdrasil_rt::sys::mutex(
|
||||
&self.__state,
|
||||
&MutexOperation::WaitUntil(self.__limit, None),
|
||||
)
|
||||
.ok()
|
||||
};
|
||||
}
|
||||
|
||||
fn signal(&self) {
|
||||
unsafe { yggdrasil_rt::sys::mutex(&self.__state, &MutexOperation::WakeAll).ok() };
|
||||
}
|
||||
|
||||
fn check(&self) -> bool {
|
||||
self.__state.load(Ordering::Acquire) >= self.__limit
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn pthread_barrier_destroy(_barrier: *mut pthread_barrier_t) -> c_int {
|
||||
yggdrasil_rt::debug_trace!("TODO: pthread_barrier_destroy()");
|
||||
0
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn pthread_barrier_init(
|
||||
barrier: *mut pthread_barrier_t,
|
||||
_attr: *const pthread_barrierattr_t,
|
||||
limit: c_uint,
|
||||
) -> c_int {
|
||||
let barrier = barrier.ensure_mut();
|
||||
barrier.__state.store(0, Ordering::Release);
|
||||
barrier.__limit = limit;
|
||||
atomic::fence(Ordering::Release);
|
||||
0
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn pthread_barrier_wait(barrier: *mut pthread_barrier_t) -> c_int {
|
||||
let barrier = barrier.ensure_mut();
|
||||
barrier.wait();
|
||||
0
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn pthread_barrierattr_destroy(_attr: *mut pthread_barrierattr_t) -> c_int {
|
||||
yggdrasil_rt::debug_trace!("TODO: pthread_barrierattr_destroy()");
|
||||
0
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn pthread_barrierattr_getpshared(
|
||||
_attr: *const pthread_barrierattr_t,
|
||||
shared: *mut c_int,
|
||||
) -> c_int {
|
||||
if let Some(shared) = NonNull::new(shared) {
|
||||
shared.write(PTHREAD_PROCESS_PRIVATE);
|
||||
}
|
||||
0
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn pthread_barrierattr_init(_attr: *mut pthread_barrierattr_t) -> c_int {
|
||||
yggdrasil_rt::debug_trace!("TODO: pthread_barrierattr_init()");
|
||||
0
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn pthread_barrierattr_setpshared(
|
||||
_attr: *mut pthread_barrierattr_t,
|
||||
shared: c_int,
|
||||
) -> CIntZeroResult {
|
||||
if shared == PTHREAD_PROCESS_PRIVATE {
|
||||
CIntZeroResult::SUCCESS
|
||||
} else {
|
||||
yggdrasil_rt::debug_trace!("TODO: pthread_barrierattr_setpshared()");
|
||||
error::errno = errno::EINVAL;
|
||||
CIntZeroResult::ERROR
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,8 @@ style = "Type"
|
||||
sys_includes = [
|
||||
"sys/types.h",
|
||||
"sched.h",
|
||||
"time.h"
|
||||
"time.h",
|
||||
"bits/pthread.h"
|
||||
]
|
||||
no_includes = true
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
use core::{
|
||||
ffi::c_void,
|
||||
ffi::{c_int, c_void},
|
||||
mem::MaybeUninit,
|
||||
ptr::null_mut,
|
||||
sync::atomic::{AtomicPtr, Ordering},
|
||||
@ -47,5 +47,12 @@ mod tls;
|
||||
// PTHREAD_SCOPE_SYSTEM
|
||||
//
|
||||
|
||||
pub const PTHREAD_PRIO_NONE: c_int = 0;
|
||||
pub const PTHREAD_PRIO_INHERIOT: c_int = 1;
|
||||
pub const PTHREAD_PRIO_PROTECT: c_int = 2;
|
||||
|
||||
pub const PTHREAD_PROCESS_PRIVATE: c_int = 0;
|
||||
pub const PTHREAD_PROCESS_SHARED: c_int = 1;
|
||||
|
||||
// int pthread_once(pthread_once_t *, void (*)(void));
|
||||
|
||||
|
@ -1,31 +1,286 @@
|
||||
// PTHREAD_MUTEX_DEFAULT
|
||||
// PTHREAD_MUTEX_ERRORCHECK
|
||||
// PTHREAD_MUTEX_NORMAL
|
||||
// PTHREAD_MUTEX_RECURSIVE
|
||||
// PTHREAD_MUTEX_ROBUST
|
||||
// PTHREAD_MUTEX_STALLED
|
||||
//
|
||||
// PTHREAD_MUTEX_INITIALIZER (macro)
|
||||
use core::{ffi::c_int, ptr::NonNull, sync::atomic::Ordering};
|
||||
|
||||
use yggdrasil_rt::process::MutexOperation;
|
||||
|
||||
// int pthread_mutex_consistent(pthread_mutex_t *);
|
||||
// int pthread_mutex_destroy(pthread_mutex_t *);
|
||||
// int pthread_mutex_getprioceiling(const pthread_mutex_t *restrict, int *restrict);
|
||||
// int pthread_mutex_init(pthread_mutex_t *restrict, const pthread_mutexattr_t *restrict);
|
||||
// int pthread_mutex_lock(pthread_mutex_t *);
|
||||
// int pthread_mutex_setprioceiling(pthread_mutex_t *restrict, int, int *restrict);
|
||||
// int pthread_mutex_timedlock(pthread_mutex_t *restrict, const struct timespec *restrict);
|
||||
// int pthread_mutex_trylock(pthread_mutex_t *);
|
||||
// int pthread_mutex_unlock(pthread_mutex_t *);
|
||||
// int pthread_mutexattr_destroy(pthread_mutexattr_t *);
|
||||
// int pthread_mutexattr_getprioceiling( const pthread_mutexattr_t *restrict, int *restrict);
|
||||
// int pthread_mutexattr_getprotocol(const pthread_mutexattr_t *restrict, int *restrict);
|
||||
// int pthread_mutexattr_getpshared(const pthread_mutexattr_t *restrict, int *restrict);
|
||||
// int pthread_mutexattr_getrobust(const pthread_mutexattr_t *restrict, int *restrict);
|
||||
// int pthread_mutexattr_gettype(const pthread_mutexattr_t *restrict, int *restrict);
|
||||
// int pthread_mutexattr_init(pthread_mutexattr_t *);
|
||||
// int pthread_mutexattr_setprioceiling(pthread_mutexattr_t *, int);
|
||||
// int pthread_mutexattr_setprotocol(pthread_mutexattr_t *, int);
|
||||
// int pthread_mutexattr_setpshared(pthread_mutexattr_t *, int);
|
||||
// int pthread_mutexattr_setrobust(pthread_mutexattr_t *, int);
|
||||
// int pthread_mutexattr_settype(pthread_mutexattr_t *, int);
|
||||
use crate::{
|
||||
error::{self, CIntZeroResult, CResult, EResult},
|
||||
headers::{
|
||||
errno,
|
||||
pthread::PTHREAD_PRIO_NONE,
|
||||
sys_time::__ygg_timespec_t,
|
||||
sys_types::{pthread_mutex_t, pthread_mutexattr_t},
|
||||
},
|
||||
util::PointerExt,
|
||||
};
|
||||
|
||||
use super::PTHREAD_PROCESS_PRIVATE;
|
||||
|
||||
impl pthread_mutex_t {
|
||||
const UNLOCKED: u32 = 0;
|
||||
const LOCKED: u32 = 1;
|
||||
|
||||
fn try_lock(&self) -> bool {
|
||||
self.__state
|
||||
.compare_exchange(
|
||||
Self::UNLOCKED,
|
||||
Self::LOCKED,
|
||||
Ordering::Acquire,
|
||||
Ordering::Relaxed,
|
||||
)
|
||||
.is_ok()
|
||||
}
|
||||
|
||||
fn try_lock_err(&self) -> EResult<()> {
|
||||
if self.try_lock() {
|
||||
EResult::Ok(())
|
||||
} else {
|
||||
EResult::Err(errno::EBUSY)
|
||||
}
|
||||
}
|
||||
|
||||
fn lock(&self) {
|
||||
loop {
|
||||
if self.try_lock() {
|
||||
return;
|
||||
}
|
||||
|
||||
self.wait();
|
||||
}
|
||||
}
|
||||
|
||||
fn wait(&self) {
|
||||
unsafe {
|
||||
yggdrasil_rt::sys::mutex(&self.__state, &MutexOperation::Wait(Self::LOCKED, None)).ok()
|
||||
};
|
||||
}
|
||||
|
||||
unsafe fn release(&self) {
|
||||
if self.__state.swap(Self::UNLOCKED, Ordering::Release) == Self::LOCKED {
|
||||
yggdrasil_rt::sys::mutex(&self.__state, &MutexOperation::Wake).ok();
|
||||
// TODO maybe yield for a fairer mutex?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub const PTHREAD_MUTEX_NORMAL: c_int = 0;
|
||||
pub const PTHREAD_MUTEX_RECURSIVE: c_int = 1;
|
||||
pub const PTHREAD_MUTEX_ERRORCHECK: c_int = 2;
|
||||
|
||||
pub const PTHREAD_MUTEX_DEFAULT: c_int = PTHREAD_MUTEX_NORMAL;
|
||||
|
||||
pub const PTHREAD_MUTEX_STALLED: c_int = 0;
|
||||
pub const PTHREAD_MUTEX_ROBUST: c_int = 1;
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn pthread_mutex_consistent(_mutex: *mut pthread_mutex_t) -> c_int {
|
||||
yggdrasil_rt::debug_trace!("TODO: pthread_mutex_consistent()");
|
||||
0
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn pthread_mutex_destroy(_mutex: *mut pthread_mutex_t) -> c_int {
|
||||
yggdrasil_rt::debug_trace!("TODO: pthread_mutex_destroy()");
|
||||
0
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn pthread_mutex_getprioceiling(
|
||||
_mutex: *const pthread_mutex_t,
|
||||
maxprio: *mut c_int,
|
||||
) -> c_int {
|
||||
yggdrasil_rt::debug_trace!("TODO: pthread_mutex_getprioceiling()");
|
||||
if let Some(maxprio) = NonNull::new(maxprio) {
|
||||
maxprio.write(10);
|
||||
}
|
||||
0
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn pthread_mutex_init(
|
||||
mutex: *mut pthread_mutex_t,
|
||||
_attr: *const pthread_mutexattr_t,
|
||||
) -> c_int {
|
||||
let mutex = mutex.ensure_mut();
|
||||
mutex
|
||||
.__state
|
||||
.store(pthread_mutex_t::UNLOCKED, Ordering::Release);
|
||||
0
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn pthread_mutex_lock(mutex: *mut pthread_mutex_t) -> c_int {
|
||||
let mutex = mutex.ensure_mut();
|
||||
mutex.lock();
|
||||
0
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn pthread_mutex_setprioceiling(
|
||||
_mutex: *mut pthread_mutex_t,
|
||||
new: c_int,
|
||||
old: *mut c_int,
|
||||
) -> c_int {
|
||||
yggdrasil_rt::debug_trace!("TODO: pthread_mutex_setprioceiling()");
|
||||
if let Some(old) = NonNull::new(old) {
|
||||
old.write(new);
|
||||
}
|
||||
0
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn pthread_mutex_timedlock(
|
||||
_mutex: *mut pthread_mutex_t,
|
||||
_timeout: *const __ygg_timespec_t,
|
||||
) -> c_int {
|
||||
todo!("pthread_mutex_timedlock()")
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn pthread_mutex_trylock(mutex: *mut pthread_mutex_t) -> CIntZeroResult {
|
||||
let mutex = mutex.ensure_mut();
|
||||
mutex.try_lock_err()?;
|
||||
CIntZeroResult::SUCCESS
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn pthread_mutex_unlock(mutex: *mut pthread_mutex_t) -> c_int {
|
||||
let mutex = mutex.ensure_mut();
|
||||
mutex.release();
|
||||
0
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn pthread_mutexattr_destroy(_attr: *mut pthread_mutexattr_t) -> c_int {
|
||||
yggdrasil_rt::debug_trace!("TODO: pthread_mutexattr_destroy()");
|
||||
0
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn pthread_mutexattr_getprioceiling(
|
||||
_attr: *const pthread_mutexattr_t,
|
||||
maxprio: *mut c_int,
|
||||
) -> c_int {
|
||||
yggdrasil_rt::debug_trace!("TODO: pthread_mutexattr_getprioceiling()");
|
||||
if let Some(maxprio) = NonNull::new(maxprio) {
|
||||
maxprio.write(10);
|
||||
}
|
||||
0
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn pthread_mutexattr_getprotocol(
|
||||
_attr: *const pthread_mutexattr_t,
|
||||
protocol: *mut c_int,
|
||||
) -> c_int {
|
||||
yggdrasil_rt::debug_trace!("TODO: pthread_mutexattr_getprotocol()");
|
||||
if let Some(protocol) = NonNull::new(protocol) {
|
||||
protocol.write(PTHREAD_PRIO_NONE);
|
||||
}
|
||||
0
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn pthread_mutexattr_getpshared(
|
||||
_attr: *const pthread_mutexattr_t,
|
||||
shared: *mut c_int,
|
||||
) -> c_int {
|
||||
if let Some(shared) = NonNull::new(shared) {
|
||||
shared.write(PTHREAD_PROCESS_PRIVATE);
|
||||
}
|
||||
0
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn pthread_mutexattr_getrobust(
|
||||
_attr: *const pthread_mutexattr_t,
|
||||
robust: *mut c_int,
|
||||
) -> c_int {
|
||||
yggdrasil_rt::debug_trace!("TODO: pthread_mutexattr_getrobust()");
|
||||
if let Some(robust) = NonNull::new(robust) {
|
||||
robust.write(PTHREAD_MUTEX_STALLED);
|
||||
}
|
||||
0
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn pthread_mutexattr_gettype(
|
||||
_attr: *const pthread_mutexattr_t,
|
||||
ty: *mut c_int,
|
||||
) -> c_int {
|
||||
yggdrasil_rt::debug_trace!("TODO: pthread_mutexattr_gettype()");
|
||||
if let Some(ty) = NonNull::new(ty) {
|
||||
ty.write(PTHREAD_MUTEX_NORMAL);
|
||||
}
|
||||
0
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn pthread_mutexattr_init(_attr: *mut pthread_mutexattr_t) -> c_int {
|
||||
yggdrasil_rt::debug_trace!("TODO: pthread_mutexattr_init()");
|
||||
0
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn pthread_mutexattr_setprioceiling(
|
||||
_attr: *mut pthread_mutexattr_t,
|
||||
_maxprio: c_int,
|
||||
) -> c_int {
|
||||
yggdrasil_rt::debug_trace!("TODO: pthread_mutexattr_setprioceiling()");
|
||||
0
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn pthread_mutexattr_setprotocol(
|
||||
_attr: *mut pthread_mutexattr_t,
|
||||
protocol: c_int,
|
||||
) -> CIntZeroResult {
|
||||
if protocol == PTHREAD_PRIO_NONE {
|
||||
CIntZeroResult::SUCCESS
|
||||
} else {
|
||||
yggdrasil_rt::debug_trace!("TODO: pthread_mutexattr_setprotocol()");
|
||||
error::errno = errno::EINVAL;
|
||||
CIntZeroResult::ERROR
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn pthread_mutexattr_setpshared(
|
||||
_attr: *mut pthread_mutexattr_t,
|
||||
shared: c_int,
|
||||
) -> CIntZeroResult {
|
||||
if shared == PTHREAD_PROCESS_PRIVATE {
|
||||
CIntZeroResult::SUCCESS
|
||||
} else {
|
||||
yggdrasil_rt::debug_trace!("TODO: pthread_mutexattr_setpshared()");
|
||||
error::errno = errno::EINVAL;
|
||||
CIntZeroResult::ERROR
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn pthread_mutexattr_setrobust(
|
||||
_attr: *mut pthread_mutexattr_t,
|
||||
robust: c_int,
|
||||
) -> CIntZeroResult {
|
||||
if robust == PTHREAD_MUTEX_STALLED {
|
||||
CIntZeroResult::SUCCESS
|
||||
} else {
|
||||
yggdrasil_rt::debug_trace!("TODO: pthread_mutexattr_setrobust()");
|
||||
error::errno = errno::EINVAL;
|
||||
CIntZeroResult::ERROR
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn pthread_mutexattr_settype(
|
||||
_attr: *mut pthread_mutexattr_t,
|
||||
ty: c_int,
|
||||
) -> CIntZeroResult {
|
||||
if ty == PTHREAD_MUTEX_NORMAL {
|
||||
CIntZeroResult::SUCCESS
|
||||
} else {
|
||||
yggdrasil_rt::debug_trace!("TODO: pthread_mutexattr_settype()");
|
||||
error::errno = errno::EINVAL;
|
||||
CIntZeroResult::ERROR
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
use core::ffi::{c_int, c_ulong, c_void};
|
||||
use core::{ffi::{c_int, c_ulong, c_void}, sync::atomic::AtomicU32};
|
||||
|
||||
#[cfg(any(target_pointer_width = "64", rust_analyzer))]
|
||||
mod bits64;
|
||||
@ -51,7 +51,12 @@ pub struct pthread_attr_t {
|
||||
pub stack_size: usize,
|
||||
}
|
||||
|
||||
pub struct pthread_barrier_t {}
|
||||
#[repr(C)]
|
||||
pub struct pthread_barrier_t {
|
||||
pub(crate) __state: AtomicU32,
|
||||
pub(crate) __limit: u32,
|
||||
}
|
||||
#[repr(C)]
|
||||
pub struct pthread_barrierattr_t {}
|
||||
|
||||
#[repr(C)]
|
||||
@ -64,8 +69,9 @@ pub struct pthread_key_t {}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct pthread_mutex_t {
|
||||
__dummy: c_int
|
||||
pub(crate) __state: AtomicU32
|
||||
}
|
||||
#[repr(C)]
|
||||
pub struct pthread_mutexattr_t {}
|
||||
|
||||
pub struct pthread_once_t {}
|
||||
|
Loading…
x
Reference in New Issue
Block a user