barrier.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454
  1. /*++
  2. Copyright (c) 2016 Minoca Corp.
  3. This file is licensed under the terms of the GNU General Public License
  4. version 3. Alternative licensing terms are available. Contact
  5. info@minocacorp.com for details. See the LICENSE file at the root of this
  6. project for complete licensing information.
  7. Module Name:
  8. barrier.c
  9. Abstract:
  10. This module implements barrier support functions for the POSIX thread
  11. library.
  12. Author:
  13. Chris Stevens 1-Jul-2016
  14. Environment:
  15. User Mode C Library
  16. --*/
  17. //
  18. // ------------------------------------------------------------------- Includes
  19. //
  20. #include "pthreadp.h"
  21. //
  22. // ---------------------------------------------------------------- Definitions
  23. //
  24. #define PTHREAD_BARRIER_SHARED 0x00000001
  25. #define PTHREAD_BARRIER_FLAGS 0x00000001
  26. #define PTHREAD_BARRIER_COUNTER_SHIFT 1
  27. #define PTHREAD_BARRIER_COUNTER_MASK (~PTHREAD_BARRIER_FLAGS)
  28. //
  29. // ------------------------------------------------------ Data Type Definitions
  30. //
  31. //
  32. // ----------------------------------------------- Internal Function Prototypes
  33. //
  34. //
  35. // -------------------------------------------------------------------- Globals
  36. //
  37. //
  38. // ------------------------------------------------------------------ Functions
  39. //
  40. PTHREAD_API
  41. int
  42. pthread_barrier_init (
  43. pthread_barrier_t *Barrier,
  44. const pthread_barrierattr_t *Attribute,
  45. unsigned Count
  46. )
  47. /*++
  48. Routine Description:
  49. This routine initializes the given POSIX thread barrier with the given
  50. attributes and thread count.
  51. Arguments:
  52. Barrier - Supplies a pointer to the POSIX thread barrier to be initialized.
  53. Attribute - Supplies an optional pointer to the attribute to use for
  54. initializing the barrier.
  55. Count - Supplies the number of threads that must wait on the barrier for it
  56. to be satisfied.
  57. Return Value:
  58. 0 on success.
  59. Returns an error number on failure.
  60. --*/
  61. {
  62. PPTHREAD_BARRIER_ATTRIBUTE AttributeInternal;
  63. PPTHREAD_BARRIER BarrierInternal;
  64. pthread_mutexattr_t MutexAttribute;
  65. pthread_mutexattr_t *MutexAttributePointer;
  66. INT Result;
  67. ASSERT(sizeof(pthread_barrier_t) >= sizeof(PTHREAD_BARRIER));
  68. if (Count == 0) {
  69. return EINVAL;
  70. }
  71. BarrierInternal = (PPTHREAD_BARRIER)Barrier;
  72. MutexAttributePointer = NULL;
  73. if (Attribute == NULL) {
  74. BarrierInternal->State = 0;
  75. } else {
  76. AttributeInternal = (PPTHREAD_BARRIER_ATTRIBUTE)Attribute;
  77. BarrierInternal->State = AttributeInternal->Flags &
  78. PTHREAD_BARRIER_FLAGS;
  79. if ((BarrierInternal->State & PTHREAD_BARRIER_SHARED) != 0) {
  80. MutexAttributePointer = &MutexAttribute;
  81. pthread_mutexattr_init(MutexAttributePointer);
  82. pthread_mutexattr_setpshared(MutexAttributePointer,
  83. PTHREAD_PROCESS_SHARED);
  84. }
  85. }
  86. Result = pthread_mutex_init(&(BarrierInternal->Mutex),
  87. MutexAttributePointer);
  88. if (Result != 0) {
  89. return Result;
  90. }
  91. BarrierInternal->WaitingThreadCount = 0;
  92. BarrierInternal->ThreadCount = Count;
  93. return 0;
  94. }
  95. PTHREAD_API
  96. int
  97. pthread_barrier_destroy (
  98. pthread_barrier_t *Barrier
  99. )
  100. /*++
  101. Routine Description:
  102. This routine destroys the given POSIX thread barrier.
  103. Arguments:
  104. Barrier - Supplies a pointer to the POSIX thread barrier to destroy.
  105. Return Value:
  106. 0 on success.
  107. Returns an error number on failure.
  108. --*/
  109. {
  110. PPTHREAD_BARRIER BarrierInternal;
  111. BarrierInternal = (PPTHREAD_BARRIER)Barrier;
  112. BarrierInternal->State = MAX_ULONG;
  113. BarrierInternal->ThreadCount = 0;
  114. BarrierInternal->WaitingThreadCount = 0;
  115. pthread_mutex_destroy(&(BarrierInternal->Mutex));
  116. return 0;
  117. }
  118. PTHREAD_API
  119. int
  120. pthread_barrier_wait (
  121. pthread_barrier_t *Barrier
  122. )
  123. /*++
  124. Routine Description:
  125. This routine blocks untils the required number of threads have waited on
  126. the barrier. Upon success, an arbitrary thread will receive
  127. PTHREAD_BARRIER_SERIAL_THREAD as a return value; the rest will receive 0.
  128. This routine does not get interrupted by signals and will continue to block
  129. after a signal is handled.
  130. Arguments:
  131. Barrier - Supplies a pointer to the POSIX thread barrier.
  132. Return Value:
  133. 0 or PTHREAD_BARRIER_SERIAL_THREAD on success.
  134. Returns an error number on failure.
  135. --*/
  136. {
  137. PPTHREAD_BARRIER BarrierInternal;
  138. KSTATUS KernelStatus;
  139. ULONG OldState;
  140. ULONG Operation;
  141. INT Status;
  142. ULONG ThreadCount;
  143. BarrierInternal = (PPTHREAD_BARRIER)Barrier;
  144. //
  145. // Acquire the mutex and increment the waiting thread count. If this
  146. // thread's wait satisfies the barrier, then attempt to wake all of the
  147. // other waiting threads.
  148. //
  149. pthread_mutex_lock(&(BarrierInternal->Mutex));
  150. BarrierInternal->WaitingThreadCount += 1;
  151. if (BarrierInternal->WaitingThreadCount >= BarrierInternal->ThreadCount) {
  152. Operation = UserLockWake;
  153. if ((BarrierInternal->State & PTHREAD_BARRIER_SHARED) == 0) {
  154. Operation |= USER_LOCK_PRIVATE;
  155. }
  156. ThreadCount = MAX_ULONG;
  157. KernelStatus = OsUserLock(&(BarrierInternal->State),
  158. Operation,
  159. &ThreadCount,
  160. 0);
  161. //
  162. // On success, this thread gets the unique serialization return value.
  163. // Also, reset the barrier to the initialization state and increment
  164. // the state, so that any threads about to wait on this now satisfied
  165. // barrier will fail in the kernel.
  166. //
  167. if (KSUCCESS(KernelStatus)) {
  168. Status = PTHREAD_BARRIER_SERIAL_THREAD;
  169. BarrierInternal->WaitingThreadCount = 0;
  170. RtlAtomicAdd32(&(BarrierInternal->State),
  171. 1 << PTHREAD_BARRIER_COUNTER_SHIFT);
  172. } else {
  173. Status = ClConvertKstatusToErrorNumber(KernelStatus);
  174. }
  175. pthread_mutex_unlock(&(BarrierInternal->Mutex));
  176. //
  177. // Otherwise, wait on the current state until the required number of
  178. // threads arrive.
  179. //
  180. } else {
  181. OldState = BarrierInternal->State;
  182. pthread_mutex_unlock(&(BarrierInternal->Mutex));
  183. Operation = UserLockWait;
  184. if ((OldState & PTHREAD_BARRIER_SHARED) == 0) {
  185. Operation |= USER_LOCK_PRIVATE;
  186. }
  187. //
  188. // If a signal interrupts the wait, the barrier should continue waiting
  189. // after the signal is handled.
  190. //
  191. do {
  192. KernelStatus = OsUserLock(&(BarrierInternal->State),
  193. Operation,
  194. &OldState,
  195. SYS_WAIT_TIME_INDEFINITE);
  196. } while (KernelStatus == STATUS_INTERRUPTED);
  197. //
  198. // The wait may have failed immediately if the barrier was satisfied
  199. // between this thread releasing the lock and executing the wait.
  200. // Convert this failure into success.
  201. //
  202. if (KSUCCESS(KernelStatus) ||
  203. (KernelStatus == STATUS_OPERATION_WOULD_BLOCK)) {
  204. Status = 0;
  205. } else {
  206. Status = ClConvertKstatusToErrorNumber(KernelStatus);
  207. }
  208. }
  209. return Status;
  210. }
  211. PTHREAD_API
  212. int
  213. pthread_barrierattr_init (
  214. pthread_barrierattr_t *Attribute
  215. )
  216. /*++
  217. Routine Description:
  218. This routine initializes a barrier attribute structure.
  219. Arguments:
  220. Attribute - Supplies a pointer to the barrier attribute structure to
  221. initialize.
  222. Return Value:
  223. 0 on success.
  224. Returns an error number on failure.
  225. --*/
  226. {
  227. PPTHREAD_BARRIER_ATTRIBUTE AttributeInternal;
  228. AttributeInternal = (PPTHREAD_BARRIER_ATTRIBUTE)Attribute;
  229. AttributeInternal->Flags = 0;
  230. return 0;
  231. }
  232. PTHREAD_API
  233. int
  234. pthread_barrierattr_destroy (
  235. pthread_barrierattr_t *Attribute
  236. )
  237. /*++
  238. Routine Description:
  239. This routine destroys the given barrier attribute structure.
  240. Arguments:
  241. Attribute - Supplies a pointer to the barrier attribute to destroy.
  242. Return Value:
  243. 0 on success.
  244. Returns an error number on failure.
  245. --*/
  246. {
  247. PPTHREAD_BARRIER_ATTRIBUTE AttributeInternal;
  248. AttributeInternal = (PPTHREAD_BARRIER_ATTRIBUTE)Attribute;
  249. AttributeInternal->Flags = MAX_ULONG;
  250. return 0;
  251. }
  252. PTHREAD_API
  253. int
  254. pthread_barrierattr_getpshared (
  255. const pthread_barrierattr_t *Attribute,
  256. int *Shared
  257. )
  258. /*++
  259. Routine Description:
  260. This routine determines the shared state in a barrier attribute.
  261. Arguments:
  262. Attribute - Supplies a pointer to the barrier attribute structure.
  263. Shared - Supplies a pointer where the shared attribute will be returned,
  264. indicating whether the condition variable is visible across processes.
  265. See PTHREAD_PROCESS_* definitions.
  266. Return Value:
  267. 0 on success.
  268. Returns an error number on failure.
  269. --*/
  270. {
  271. PPTHREAD_BARRIER_ATTRIBUTE AttributeInternal;
  272. AttributeInternal = (PPTHREAD_BARRIER_ATTRIBUTE)Attribute;
  273. *Shared = PTHREAD_PROCESS_PRIVATE;
  274. if ((AttributeInternal->Flags & PTHREAD_BARRIER_SHARED) != 0) {
  275. *Shared = PTHREAD_PROCESS_SHARED;
  276. }
  277. return 0;
  278. }
  279. PTHREAD_API
  280. int
  281. pthread_barrierattr_setpshared (
  282. const pthread_barrierattr_t *Attribute,
  283. int Shared
  284. )
  285. /*++
  286. Routine Description:
  287. This routine sets the shared state in a barrier attribute.
  288. Arguments:
  289. Attribute - Supplies a pointer to the barrier attribute structure.
  290. Shared - Supplies the value indicating whether this barrier should be
  291. visible across processes. See PTHREAD_PROCESS_* definitions.
  292. Return Value:
  293. 0 on success.
  294. Returns an error number on failure.
  295. --*/
  296. {
  297. PPTHREAD_BARRIER_ATTRIBUTE AttributeInternal;
  298. AttributeInternal = (PPTHREAD_BARRIER_ATTRIBUTE)Attribute;
  299. if (Shared == PTHREAD_PROCESS_PRIVATE) {
  300. AttributeInternal->Flags &= ~PTHREAD_BARRIER_SHARED;
  301. } else if (Shared == PTHREAD_PROCESS_SHARED) {
  302. AttributeInternal->Flags |= PTHREAD_BARRIER_SHARED;
  303. } else {
  304. return EINVAL;
  305. }
  306. return 0;
  307. }
  308. //
  309. // --------------------------------------------------------- Internal Functions
  310. //