1 /* 2 * Copyright 2016, Dmytro Shynkevych, dm.shynk@gmail.com 3 * Distributed under the terms of the MIT license. 4 */ 5 6 7 #include <pthread.h> 8 #include "pthread_private.h" 9 10 #include <stdio.h> 11 #include <stdlib.h> 12 #include <string.h> 13 14 #include <syscall_utils.h> 15 #include <syscalls.h> 16 #include <user_mutex_defs.h> 17 18 19 #define BARRIER_FLAG_SHARED 0x80000000 20 21 22 static const pthread_barrierattr pthread_barrierattr_default = { 23 /* .process_shared = */ false 24 }; 25 26 27 int 28 pthread_barrier_init(pthread_barrier_t* barrier, 29 const pthread_barrierattr_t* _attr, unsigned count) 30 { 31 const pthread_barrierattr* attr = _attr != NULL 32 ? *_attr : &pthread_barrierattr_default; 33 34 if (barrier == NULL || attr == NULL || count < 1) 35 return B_BAD_VALUE; 36 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; 42 43 return B_OK; 44 } 45 46 47 int 48 pthread_barrier_wait(pthread_barrier_t* barrier) 49 { 50 if (barrier == NULL) 51 return B_BAD_VALUE; 52 53 // Enter critical region: lock the mutex 54 int32 status = atomic_or((int32*)&barrier->mutex, B_USER_MUTEX_LOCKED); 55 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); 61 62 if (status != B_OK) 63 return status; 64 } 65 66 barrier->waiter_count++; 67 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; 72 73 // Wake up everyone trying to acquire the barrier lock 74 _kern_mutex_unlock((int32*)&barrier->lock, B_USER_MUTEX_UNBLOCK_ALL); 75 76 // Exit critical region: unlock the mutex 77 int32 status = atomic_and((int32*)&barrier->mutex, 78 ~(int32)B_USER_MUTEX_LOCKED); 79 80 if (status & B_USER_MUTEX_WAITING) 81 _kern_mutex_unlock((int32*)&barrier->mutex, 0); 82 83 // Inform the calling thread that it arrived last 84 return PTHREAD_BARRIER_SERIAL_THREAD; 85 } 86 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); 93 94 // This thread did not arrive last 95 return 0; 96 } 97 98 99 int 100 pthread_barrier_destroy(pthread_barrier_t* barrier) 101 { 102 // No dynamic resources to free 103 return B_OK; 104 } 105 106 107 int 108 pthread_barrierattr_init(pthread_barrierattr_t* _attr) 109 { 110 pthread_barrierattr* attr = (pthread_barrierattr*)malloc( 111 sizeof(pthread_barrierattr)); 112 113 if (attr == NULL) 114 return B_NO_MEMORY; 115 116 *attr = pthread_barrierattr_default; 117 *_attr = attr; 118 119 return B_OK; 120 } 121 122 123 int 124 pthread_barrierattr_destroy(pthread_barrierattr_t* _attr) 125 { 126 pthread_barrierattr* attr = _attr != NULL ? *_attr : NULL; 127 128 if (attr == NULL) 129 return B_BAD_VALUE; 130 131 free(attr); 132 133 return B_OK; 134 } 135 136 137 int 138 pthread_barrierattr_getpshared(const pthread_barrierattr_t* _attr, int* shared) 139 { 140 pthread_barrierattr* attr; 141 142 if (_attr == NULL || (attr = *_attr) == NULL || shared == NULL) 143 return B_BAD_VALUE; 144 145 *shared = attr->process_shared 146 ? PTHREAD_PROCESS_SHARED : PTHREAD_PROCESS_PRIVATE; 147 148 return B_OK; 149 } 150 151 152 int 153 pthread_barrierattr_setpshared(pthread_barrierattr_t* _attr, int shared) 154 { 155 pthread_barrierattr* attr; 156 157 if (_attr == NULL || (attr = *_attr) == NULL 158 || shared < PTHREAD_PROCESS_PRIVATE 159 || shared > PTHREAD_PROCESS_SHARED) { 160 return B_BAD_VALUE; 161 } 162 163 attr->process_shared = shared == PTHREAD_PROCESS_SHARED; 164 165 return 0; 166 } 167