2 * Copyright 2016, Dmytro Shynkevych, dm.shynk@gmail.com
3 * Distributed under the terms of the MIT license.
8 #include "pthread_private.h"
14 #include <syscall_utils.h>
16 #include <user_mutex_defs.h>
19 #define BARRIER_FLAG_SHARED 0x80000000
22 static const pthread_barrierattr pthread_barrierattr_default
= {
23 /* .process_shared = */ false
28 pthread_barrier_init(pthread_barrier_t
* barrier
,
29 const pthread_barrierattr_t
* _attr
, unsigned count
)
31 const pthread_barrierattr
* attr
= _attr
!= NULL
32 ? *_attr
: &pthread_barrierattr_default
;
34 if (barrier
== NULL
|| attr
== NULL
|| count
< 1)
37 barrier
->flags
= attr
->process_shared
? BARRIER_FLAG_SHARED
: 0;
40 barrier
->waiter_count
= 0;
41 barrier
->waiter_max
= count
;
48 pthread_barrier_wait(pthread_barrier_t
* barrier
)
53 // Enter critical region: lock the mutex
54 int32 status
= atomic_or((int32
*)&barrier
->mutex
, B_USER_MUTEX_LOCKED
);
56 // If already locked, call the kernel
57 if (status
& (B_USER_MUTEX_LOCKED
| B_USER_MUTEX_WAITING
)) {
59 status
= _kern_mutex_lock((int32
*)&barrier
->mutex
, NULL
, 0, 0);
60 } while (status
== B_INTERRUPTED
);
66 barrier
->waiter_count
++;
68 // If this thread is the last to arrive
69 if (barrier
->waiter_count
== barrier
->waiter_max
) {
70 // Let other threads exit the do...while loop
71 barrier
->waiter_count
= 0;
73 // Wake up everyone trying to acquire the barrier lock
74 _kern_mutex_unlock((int32
*)&barrier
->lock
, B_USER_MUTEX_UNBLOCK_ALL
);
76 // Exit critical region: unlock the mutex
77 int32 status
= atomic_and((int32
*)&barrier
->mutex
,
78 ~(int32
)B_USER_MUTEX_LOCKED
);
80 if (status
& B_USER_MUTEX_WAITING
)
81 _kern_mutex_unlock((int32
*)&barrier
->mutex
, 0);
83 // Inform the calling thread that it arrived last
84 return PTHREAD_BARRIER_SERIAL_THREAD
;
88 // Wait indefinitely trying to acquire the barrier lock.
89 // Other threads may now enter (mutex is unlocked).
90 _kern_mutex_switch_lock((int32
*)&barrier
->mutex
,
91 (int32
*)&barrier
->lock
, "barrier wait", 0, 0);
92 } while (barrier
->waiter_count
!= 0);
94 // This thread did not arrive last
100 pthread_barrier_destroy(pthread_barrier_t
* barrier
)
102 // No dynamic resources to free
108 pthread_barrierattr_init(pthread_barrierattr_t
* _attr
)
110 pthread_barrierattr
* attr
= (pthread_barrierattr
*)malloc(
111 sizeof(pthread_barrierattr
));
116 *attr
= pthread_barrierattr_default
;
124 pthread_barrierattr_destroy(pthread_barrierattr_t
* _attr
)
126 pthread_barrierattr
* attr
= _attr
!= NULL
? *_attr
: NULL
;
138 pthread_barrierattr_getpshared(const pthread_barrierattr_t
* _attr
, int* shared
)
140 pthread_barrierattr
* attr
;
142 if (_attr
== NULL
|| (attr
= *_attr
) == NULL
|| shared
== NULL
)
145 *shared
= attr
->process_shared
146 ? PTHREAD_PROCESS_SHARED
: PTHREAD_PROCESS_PRIVATE
;
153 pthread_barrierattr_setpshared(pthread_barrierattr_t
* _attr
, int shared
)
155 pthread_barrierattr
* attr
;
157 if (_attr
== NULL
|| (attr
= *_attr
) == NULL
158 || shared
< PTHREAD_PROCESS_PRIVATE
159 || shared
> PTHREAD_PROCESS_SHARED
) {
163 attr
->process_shared
= shared
== PTHREAD_PROCESS_SHARED
;