headers/bsd: Add sys/queue.h.
[haiku.git] / src / system / libroot / posix / pthread / pthread_barrier.cpp
blob1637b8e0a12b33938cde4e05aca6c39185b11358
1 /*
2 * Copyright 2016, Dmytro Shynkevych, dm.shynk@gmail.com
3 * Distributed under the terms of the MIT license.
4 */
7 #include <pthread.h>
8 #include "pthread_private.h"
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
14 #include <syscall_utils.h>
15 #include <syscalls.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
27 int
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)
35 return B_BAD_VALUE;
37 barrier->flags = attr->process_shared ? BARRIER_FLAG_SHARED : 0;
38 barrier->lock = 0;
39 barrier->mutex = 0;
40 barrier->waiter_count = 0;
41 barrier->waiter_max = count;
43 return B_OK;
47 int
48 pthread_barrier_wait(pthread_barrier_t* barrier)
50 if (barrier == NULL)
51 return B_BAD_VALUE;
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)) {
58 do {
59 status = _kern_mutex_lock((int32*)&barrier->mutex, NULL, 0, 0);
60 } while (status == B_INTERRUPTED);
62 if (status != B_OK)
63 return status;
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;
87 do {
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
95 return 0;
99 int
100 pthread_barrier_destroy(pthread_barrier_t* barrier)
102 // No dynamic resources to free
103 return B_OK;
108 pthread_barrierattr_init(pthread_barrierattr_t* _attr)
110 pthread_barrierattr* attr = (pthread_barrierattr*)malloc(
111 sizeof(pthread_barrierattr));
113 if (attr == NULL)
114 return B_NO_MEMORY;
116 *attr = pthread_barrierattr_default;
117 *_attr = attr;
119 return B_OK;
124 pthread_barrierattr_destroy(pthread_barrierattr_t* _attr)
126 pthread_barrierattr* attr = _attr != NULL ? *_attr : NULL;
128 if (attr == NULL)
129 return B_BAD_VALUE;
131 free(attr);
133 return B_OK;
138 pthread_barrierattr_getpshared(const pthread_barrierattr_t* _attr, int* shared)
140 pthread_barrierattr* attr;
142 if (_attr == NULL || (attr = *_attr) == NULL || shared == NULL)
143 return B_BAD_VALUE;
145 *shared = attr->process_shared
146 ? PTHREAD_PROCESS_SHARED : PTHREAD_PROCESS_PRIVATE;
148 return B_OK;
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) {
160 return B_BAD_VALUE;
163 attr->process_shared = shared == PTHREAD_PROCESS_SHARED;
165 return 0;