relibc/header/pthread/barrier.rs
1use crate::header::errno::EINVAL;
2
3use core::num::NonZeroU32;
4
5use crate::sync::barrier::{Barrier, WaitResult};
6
7use super::{
8 PTHREAD_BARRIER_SERIAL_THREAD, PTHREAD_PROCESS_PRIVATE, c_int, c_uint, pthread_barrier_t,
9 pthread_barrierattr_t,
10};
11
12pub(crate) type RlctBarrier = Barrier;
13
14#[derive(Clone, Copy)]
15pub(crate) struct RlctBarrierAttr {
16 pshared: c_int,
17}
18impl Default for RlctBarrierAttr {
19 fn default() -> Self {
20 // pshared = PTHREAD_PROCESS_PRIVATE is default according to POSIX.
21 Self {
22 pshared: PTHREAD_PROCESS_PRIVATE,
23 }
24 }
25}
26
27/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_barrier_destroy.html>.
28///
29/// Destroys the barrier referenced by `barrier` and releases any resources
30/// used by the barrier.
31///
32/// Upon success, returns `0`. Upon error, returns an error number.
33///
34/// # Implementation
35/// Not async-signal-safe.
36///
37/// # Safety
38/// The following will result in undefined behaviour:
39/// - Use of `barrier` after this function unless reinitialized by
40/// `pthread_barrier_init()`.
41/// - This function is called with an uninitialized `barrier`.
42/// - This function is called when any thread is blocked on `barrier`.
43#[unsafe(no_mangle)]
44pub unsafe extern "C" fn pthread_barrier_destroy(barrier: *mut pthread_barrier_t) -> c_int {
45 // No-op, currently.
46 unsafe { core::ptr::drop_in_place(barrier.cast::<RlctBarrier>()) };
47
48 0
49}
50
51/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_barrier_init.html>.
52///
53/// Allocates any resources required to use the barrier referenced by `barrier`
54/// and shall initialize the barrier with attributes referenced by `attr`.
55///
56/// Upon success, returns `0`. Upon error, returns an error number.
57///
58/// # Implementation
59/// Not async-signal-safe.
60///
61/// # Safety
62/// The following will result in undefined behaviour:
63/// - Use of `barrier` before this function is called.
64/// - This function is called with an already initialized `barrier`.
65/// - This function is called when any thread is blocked on `barrier`.
66#[unsafe(no_mangle)]
67pub unsafe extern "C" fn pthread_barrier_init(
68 barrier: *mut pthread_barrier_t,
69 attr: *const pthread_barrierattr_t,
70 count: c_uint,
71) -> c_int {
72 let attr = unsafe { attr.cast::<RlctBarrierAttr>().as_ref() }
73 .copied()
74 .unwrap_or_default();
75
76 let Some(count) = NonZeroU32::new(count) else {
77 return EINVAL;
78 };
79
80 unsafe { barrier.cast::<RlctBarrier>().write(RlctBarrier::new(count)) };
81 0
82}
83
84fn unlikely(condition: bool) -> bool {
85 condition
86}
87
88/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_barrier_wait.html>.
89///
90/// Synchronizes participating threads at the barrier referenced by `barrier`.
91///
92/// Upon success, returns `PTHREAD_BARRIER_SERIAL_THREAD` for a single
93/// (arbitrary) thread synchronized at the barrier and `0` for each of the
94/// other threads. Upon failure, returns an error number.
95///
96/// # Implementation
97/// Not async-signal-safe.
98///
99/// # Safety
100/// Undefined behaviour will occur if `barrier` is uninitialized.
101#[unsafe(no_mangle)]
102pub unsafe extern "C" fn pthread_barrier_wait(barrier: *mut pthread_barrier_t) -> c_int {
103 let barrier = unsafe { &*barrier.cast::<RlctBarrier>() };
104
105 match barrier.wait() {
106 WaitResult::NotifiedAll => PTHREAD_BARRIER_SERIAL_THREAD,
107 WaitResult::Waited => 0,
108 }
109}
110
111/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_barrierattr_init.html>.
112///
113/// Initializes a barrier attributes object `attr` with the default value of
114/// all of the attributes defined by the implementation.
115///
116/// Upon success, returns `0`. Upon error, returns an error number.
117///
118/// # Implementation
119/// Not async-signal-safe.
120///
121/// # Safety
122/// Undefined behaviour will occur if `attr` is already initialized.
123#[unsafe(no_mangle)]
124pub unsafe extern "C" fn pthread_barrierattr_init(attr: *mut pthread_barrierattr_t) -> c_int {
125 unsafe { core::ptr::write(attr.cast::<RlctBarrierAttr>(), RlctBarrierAttr::default()) };
126
127 0
128}
129
130/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_barrierattr_setpshared.html>.
131///
132/// Sets the process-shared attribute in an initialized attributes object
133/// referenced by `attr`.
134///
135/// Upon success, returns `0`. Upon error, returns an error number.
136///
137/// # Implementation
138/// Not async-signal-safe.
139///
140/// # Safety
141/// Undefined behaviour will occur if `attr` is uninitialized.
142#[unsafe(no_mangle)]
143pub unsafe extern "C" fn pthread_barrierattr_setpshared(
144 attr: *mut pthread_barrierattr_t,
145 pshared: c_int,
146) -> c_int {
147 unsafe {
148 (*attr.cast::<RlctBarrierAttr>()).pshared = pshared;
149 }
150 0
151}
152
153/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_barrierattr_getpshared.html>.
154///
155/// Obtains the value of the process-shared attribute from the attributes
156/// object referenced by `attr`.
157///
158/// Upon success, returns `0` and stores the value of the process-shared
159/// attribute of `attr` into the object referenced by `pshared`. Upon error,
160/// returns an error number.
161///
162/// # Implementation
163/// Not async-signal-safe.
164///
165/// # Safety
166/// Undefined behaviour will occur if `attr` is uninitialized.
167#[unsafe(no_mangle)]
168pub unsafe extern "C" fn pthread_barrierattr_getpshared(
169 attr: *const pthread_barrierattr_t,
170 pshared: *mut c_int,
171) -> c_int {
172 unsafe { core::ptr::write(pshared, (*attr.cast::<RlctBarrierAttr>()).pshared) };
173 0
174}
175
176/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_barrierattr_destroy.html>.
177///
178/// Destroys a barrier attributes object.
179///
180/// Upon success, returns `0`. Upon error, returns an error number.
181///
182/// # Implementation
183/// Not async-signal-safe.
184///
185/// # Safety
186/// Undefined behaviour will occur if `attr` is uninitialized or if `attr` is
187/// used after calling this function.
188#[unsafe(no_mangle)]
189pub unsafe extern "C" fn pthread_barrierattr_destroy(attr: *mut pthread_barrierattr_t) -> c_int {
190 unsafe { core::ptr::drop_in_place(attr) };
191 0
192}