Misc improvements, move barrier to safe module.

This commit is contained in:
4lDO2
2023-04-12 12:27:01 +02:00
parent 316203102a
commit b455e2e374
6 changed files with 348 additions and 96 deletions
+40 -44
View File
@@ -1,83 +1,79 @@
use crate::header::errno::*;
use core::sync::atomic::{AtomicU32 as AtomicUint, AtomicI32 as AtomicInt, Ordering};
use core::num::NonZeroU32;
use crate::sync::barrier::*;
use super::*;
pub(crate) struct RlctBarrier {
pub count: AtomicUint,
pub original_count: c_uint,
pub epoch: AtomicInt,
}
pub(crate) type RlctBarrier = Barrier;
#[derive(Clone, Copy)]
pub(crate) struct RlctBarrierAttr {
pub pshared: c_int,
pshared: c_int,
}
impl Default for RlctBarrierAttr {
fn default() -> Self {
// pshared = PTHREAD_PROCESS_PRIVATE is default according to POSIX.
Self { pshared: PTHREAD_PROCESS_PRIVATE }
}
}
// Not async-signal-safe.
#[no_mangle]
pub unsafe extern "C" fn pthread_barrier_destroy(barrier: *mut pthread_barrier_t) -> c_int {
// Behavior is undefined if any thread is currently waiting.
// Behavior is undefined if any thread is currently waiting when this is called.
// No-op, currently.
core::ptr::drop_in_place(barrier.cast::<RlctBarrier>());
0
}
// Not async-signal-safe.
#[no_mangle]
pub unsafe extern "C" fn pthread_barrier_init(barrier: *mut pthread_barrier_t, attr: *const pthread_barrierattr_t, count: c_uint) -> c_int {
let attr = attr.cast::<RlctBarrierAttr>().as_ref();
let attr = attr.cast::<RlctBarrierAttr>().as_ref().copied().unwrap_or_default();
if count == 0 {
let Some(count) = NonZeroU32::new(count) else {
return EINVAL;
}
};
barrier.cast::<RlctBarrier>().write(RlctBarrier {
count: AtomicUint::new(0),
original_count: count,
epoch: AtomicInt::new(0),
});
barrier.cast::<RlctBarrier>().write(RlctBarrier::new(count));
0
}
fn unlikely(condition: bool) -> bool { condition }
// Not async-signal-safe.
#[no_mangle]
pub unsafe extern "C" fn pthread_barrier_wait(barrier: *mut pthread_barrier_t) -> c_int {
let barrier = &*barrier.cast::<RlctBarrier>();
// TODO: Orderings
let mut cached = barrier.count.load(Ordering::SeqCst);
loop {
let new = if cached == barrier.original_count - 1 { 0 } else { cached + 1 };
match barrier.count.compare_exchange_weak(cached, new, Ordering::SeqCst, Ordering::SeqCst) {
Ok(_) => if new == 0 {
// We reached COUNT waits, and will thus be the thread notifying every other
// waiter.
todo!();
return PTHREAD_BARRIER_SERIAL_THREAD;
} else {
// We increased the wait count, but this was not sufficient. We will thus have to
// wait for the epoch to tick up.
todo!();
return 0;
}
Err(value) => {
cached = value;
core::hint::spin_loop();
}
}
match barrier.wait() {
WaitResult::NotifiedAll => PTHREAD_BARRIER_SERIAL_THREAD,
WaitResult::Waited => 0,
}
}
// Not async-signal-safe.
#[no_mangle]
pub unsafe extern "C" fn pthread_barrierattr_init(attr: *mut pthread_barrierattr_t) -> c_int {
// PTHREAD_PROCESS_PRIVATE is default according to POSIX.
core::ptr::write(attr.cast::<RlctBarrierAttr>(), RlctBarrierAttr { pshared: PTHREAD_PROCESS_PRIVATE });
core::ptr::write(attr.cast::<RlctBarrierAttr>(), RlctBarrierAttr::default());
0
}
// Not async-signal-safe.
#[no_mangle]
pub unsafe extern "C" fn pthread_barrierattr_setpshared(attr: *mut pthread_barrierattr_t, pshared: c_int) -> c_int {
(*attr.cast::<RlctBarrierAttr>()).pshared = pshared;
0
}
// Not async-signal-safe.
#[no_mangle]
pub unsafe extern "C" fn pthread_barrierattr_getpshared(attr: *const pthread_barrierattr_t, pshared: *mut c_int) -> c_int {
core::ptr::write(pshared, (*attr.cast::<RlctBarrierAttr>()).pshared);
0
}
+59 -19
View File
@@ -7,6 +7,13 @@ use crate::platform::{self, Pal, Sys, types::*};
use crate::header::{sched::*, time::timespec};
use crate::pthread;
fn e(result: Result<(), pthread::Errno>) -> i32 {
match result {
Ok(()) => 0,
Err(pthread::Errno(error)) => error,
}
}
#[derive(Clone, Copy)]
pub(crate) struct RlctAttr {
pub detachstate: c_uchar,
@@ -25,7 +32,7 @@ pub const PTHREAD_CANCEL_ASYNCHRONOUS: c_int = 0;
pub const PTHREAD_CANCEL_ENABLE: c_int = 1;
pub const PTHREAD_CANCEL_DEFERRED: c_int = 2;
pub const PTHREAD_CANCEL_DISABLE: c_int = 3;
pub const PTHREAD_CANCELED: *mut c_void = core::ptr::null_mut();
pub const PTHREAD_CANCELED: *mut c_void = (!0_usize) as *mut c_void;
pub const PTHREAD_CREATE_DETACHED: c_int = 0;
pub const PTHREAD_CREATE_JOINABLE: c_int = 1;
@@ -101,19 +108,34 @@ pub unsafe extern "C" fn pthread_exit(retval: *mut c_void) -> ! {
pthread::exit_current_thread(pthread::Retval(retval))
}
// #[no_mangle]
pub extern "C" fn pthread_getconcurrency() -> c_int {
todo!()
#[no_mangle]
pub unsafe extern "C" fn pthread_getconcurrency() -> c_int {
// Redox and Linux threads are 1:1, not M:N.
1
}
// #[no_mangle]
pub extern "C" fn pthread_getcpuclockid(thread: pthread_t, clock: *mut clockid_t) -> c_int {
todo!()
#[no_mangle]
pub unsafe extern "C" fn pthread_getcpuclockid(thread: pthread_t, clock_out: *mut clockid_t) -> c_int {
match pthread::get_cpu_clkid(&*thread.cast()) {
Ok(clock) => {
clock_out.write(clock);
0
}
Err(pthread::Errno(error)) => error,
}
}
// #[no_mangle]
pub extern "C" fn pthread_getschedparam(thread: pthread_t, policy: *mut clockid_t, param: *mut sched_param) -> c_int {
todo!()
#[no_mangle]
pub unsafe extern "C" fn pthread_getschedparam(thread: pthread_t, policy_out: *mut c_int, param_out: *mut sched_param) -> c_int {
match pthread::get_sched_param(&*thread.cast()) {
Ok((policy, param)) => {
policy_out.write(policy);
param_out.write(param);
0
}
Err(pthread::Errno(error)) => error,
}
}
pub mod tls;
@@ -143,22 +165,40 @@ pub use self::rwlock::*;
pub unsafe extern "C" fn pthread_self() -> pthread_t {
pthread::current_thread().unwrap_unchecked() as *const _ as *mut _
}
pub extern "C" fn pthread_setcancelstate(state: c_int, oldstate: *mut c_int) -> c_int {
todo!();
#[no_mangle]
pub unsafe extern "C" fn pthread_setcancelstate(state: c_int, oldstate: *mut c_int) -> c_int {
match pthread::set_cancel_state(state) {
Ok(old) => {
oldstate.write(old);
0
}
Err(pthread::Errno(error)) => error,
}
}
pub extern "C" fn pthread_setcanceltype(ty: c_int, oldty: *mut c_int) -> c_int {
todo!();
#[no_mangle]
pub unsafe extern "C" fn pthread_setcanceltype(ty: c_int, oldty: *mut c_int) -> c_int {
match pthread::set_cancel_type(ty) {
Ok(old) => {
oldty.write(old);
0
}
Err(pthread::Errno(error)) => error,
}
}
#[no_mangle]
pub extern "C" fn pthread_setconcurrency(concurrency: c_int) -> c_int {
todo!();
// Redox and Linux threads are 1:1, not M:N.
0
}
pub extern "C" fn pthread_setschedparam(thread: pthread_t, policy: c_int, param: *const sched_param) -> c_int {
todo!();
#[no_mangle]
pub unsafe extern "C" fn pthread_setschedparam(thread: pthread_t, policy: c_int, param: *const sched_param) -> c_int {
e(pthread::set_sched_param(&*thread.cast(), policy, &*param))
}
pub extern "C" fn pthread_setschedprio(thread: pthread_t, prio: c_int) -> c_int {
todo!();
#[no_mangle]
pub unsafe extern "C" fn pthread_setschedprio(thread: pthread_t, prio: c_int) -> c_int {
e(pthread::set_sched_priority(&*thread.cast(), prio))
}
pub mod spin;
+55 -17
View File
@@ -1,18 +1,27 @@
use super::*;
use crate::header::errno::EBUSY;
use crate::header::errno::*;
use core::sync::atomic::AtomicI32 as AtomicInt;
// PTHREAD_MUTEX_INITIALIZER
// PTHREAD_MUTEX_INITIALIZER is defined in bits_pthread/cbindgen.toml
#[repr(u8)]
enum State {
Unlocked,
Locked,
Waiting,
}
// #[no_mangle]
pub extern "C" fn pthread_mutex_consistent(mutex: *mut pthread_mutex_t) -> c_int {
todo!();
pub unsafe extern "C" fn pthread_mutex_consistent(mutex: *mut pthread_mutex_t) -> c_int {
let mutex = &*mutex.cast::<RlctMutex>();
todo!()
}
#[no_mangle]
pub unsafe extern "C" fn pthread_mutex_destroy(mutex: *mut pthread_mutex_t) -> c_int {
let _mutex: &pthread_mutex_t = &*mutex;
let _mutex = &mut *mutex.cast::<RlctMutex>();
0
}
@@ -23,11 +32,20 @@ pub extern "C" fn pthread_mutex_getprioceiling(mutex: *const pthread_mutex_t, pr
#[no_mangle]
pub unsafe extern "C" fn pthread_mutex_init(mutex: *mut pthread_mutex_t, attr: *const pthread_mutexattr_t) -> c_int {
let attr = attr.cast::<RlctMutexAttr>().as_ref();
let attr = attr.cast::<RlctMutexAttr>().as_ref().copied().unwrap_or_default();
// TODO: attr
mutex.cast::<RlctMutex>().write(RlctMutex {
inner: crate::sync::mutex::UNLOCKED.into(),
/*robust: attr.robust != 0,
ty: match attr.ty {
PTHREAD_MUTEX_DEFAULT => Ty::Def,
PTHREAD_MUTEX_ERRORCHECK => Ty::Errck,
PTHREAD_MUTEX_RECURSIVE => Ty::Recursive,
PTHREAD_MUTEX_NORMAL => Ty::Normal,
_ => return EINVAL,
}*/
});
0
}
@@ -68,7 +86,10 @@ pub unsafe extern "C" fn pthread_mutex_unlock(mutex: *mut pthread_mutex_t) -> c_
}
#[no_mangle]
pub extern "C" fn pthread_mutexattr_destroy(_attr: *mut pthread_mutexattr_t) -> c_int {
pub unsafe extern "C" fn pthread_mutexattr_destroy(attr: *mut pthread_mutexattr_t) -> c_int {
// No-op
core::ptr::drop_in_place(attr);
0
}
@@ -102,14 +123,7 @@ pub unsafe extern "C" fn pthread_mutexattr_gettype(attr: *const pthread_mutexatt
}
#[no_mangle]
pub unsafe extern "C" fn pthread_mutexattr_init(attr: *mut pthread_mutexattr_t) -> c_int {
attr.cast::<RlctMutexAttr>().write(RlctMutexAttr {
robust: PTHREAD_MUTEX_STALLED,
pshared: PTHREAD_PROCESS_PRIVATE,
protocol: PTHREAD_PRIO_NONE,
// TODO
prioceiling: 0,
ty: PTHREAD_MUTEX_DEFAULT,
});
attr.cast::<RlctMutexAttr>().write(RlctMutexAttr::default());
0
}
@@ -144,10 +158,23 @@ pub unsafe extern "C" fn pthread_mutexattr_settype(attr: *mut pthread_mutexattr_
#[repr(C)]
pub(crate) struct RlctMutex {
pub inner: AtomicInt,
// Actual locking word. Allows the states UNLOCKED, LOCKED, and WAITING, a substate of LOCKED.
inner: AtomicInt,
/*robust: bool,
ty: Ty,*/
// TODO: Robust mutexes
}
enum Ty {
Normal,
Def,
Errck,
Recursive,
}
#[repr(C)]
#[derive(Clone, Copy)]
pub(crate) struct RlctMutexAttr {
pub prioceiling: c_int,
pub protocol: c_int,
@@ -155,4 +182,15 @@ pub(crate) struct RlctMutexAttr {
pub robust: c_int,
pub ty: c_int,
}
impl Default for RlctMutexAttr {
fn default() -> Self {
Self {
robust: PTHREAD_MUTEX_STALLED,
pshared: PTHREAD_PROCESS_PRIVATE,
protocol: PTHREAD_PRIO_NONE,
// TODO
prioceiling: 0,
ty: PTHREAD_MUTEX_DEFAULT,
}
}
}