123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454 |
- /*++
- Copyright (c) 2016 Minoca Corp.
- This file is licensed under the terms of the GNU General Public License
- version 3. Alternative licensing terms are available. Contact
- info@minocacorp.com for details. See the LICENSE file at the root of this
- project for complete licensing information.
- Module Name:
- barrier.c
- Abstract:
- This module implements barrier support functions for the POSIX thread
- library.
- Author:
- Chris Stevens 1-Jul-2016
- Environment:
- User Mode C Library
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include "pthreadp.h"
- //
- // ---------------------------------------------------------------- Definitions
- //
- #define PTHREAD_BARRIER_SHARED 0x00000001
- #define PTHREAD_BARRIER_FLAGS 0x00000001
- #define PTHREAD_BARRIER_COUNTER_SHIFT 1
- #define PTHREAD_BARRIER_COUNTER_MASK (~PTHREAD_BARRIER_FLAGS)
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- //
- // -------------------------------------------------------------------- Globals
- //
- //
- // ------------------------------------------------------------------ Functions
- //
- PTHREAD_API
- int
- pthread_barrier_init (
- pthread_barrier_t *Barrier,
- const pthread_barrierattr_t *Attribute,
- unsigned Count
- )
- /*++
- Routine Description:
- This routine initializes the given POSIX thread barrier with the given
- attributes and thread count.
- Arguments:
- Barrier - Supplies a pointer to the POSIX thread barrier to be initialized.
- Attribute - Supplies an optional pointer to the attribute to use for
- initializing the barrier.
- Count - Supplies the number of threads that must wait on the barrier for it
- to be satisfied.
- Return Value:
- 0 on success.
- Returns an error number on failure.
- --*/
- {
- PPTHREAD_BARRIER_ATTRIBUTE AttributeInternal;
- PPTHREAD_BARRIER BarrierInternal;
- pthread_mutexattr_t MutexAttribute;
- pthread_mutexattr_t *MutexAttributePointer;
- INT Result;
- ASSERT(sizeof(pthread_barrier_t) >= sizeof(PTHREAD_BARRIER));
- if (Count == 0) {
- return EINVAL;
- }
- BarrierInternal = (PPTHREAD_BARRIER)Barrier;
- MutexAttributePointer = NULL;
- if (Attribute == NULL) {
- BarrierInternal->State = 0;
- } else {
- AttributeInternal = (PPTHREAD_BARRIER_ATTRIBUTE)Attribute;
- BarrierInternal->State = AttributeInternal->Flags &
- PTHREAD_BARRIER_FLAGS;
- if ((BarrierInternal->State & PTHREAD_BARRIER_SHARED) != 0) {
- MutexAttributePointer = &MutexAttribute;
- pthread_mutexattr_init(MutexAttributePointer);
- pthread_mutexattr_setpshared(MutexAttributePointer,
- PTHREAD_PROCESS_SHARED);
- }
- }
- Result = pthread_mutex_init(&(BarrierInternal->Mutex),
- MutexAttributePointer);
- if (Result != 0) {
- return Result;
- }
- BarrierInternal->WaitingThreadCount = 0;
- BarrierInternal->ThreadCount = Count;
- return 0;
- }
- PTHREAD_API
- int
- pthread_barrier_destroy (
- pthread_barrier_t *Barrier
- )
- /*++
- Routine Description:
- This routine destroys the given POSIX thread barrier.
- Arguments:
- Barrier - Supplies a pointer to the POSIX thread barrier to destroy.
- Return Value:
- 0 on success.
- Returns an error number on failure.
- --*/
- {
- PPTHREAD_BARRIER BarrierInternal;
- BarrierInternal = (PPTHREAD_BARRIER)Barrier;
- BarrierInternal->State = MAX_ULONG;
- BarrierInternal->ThreadCount = 0;
- BarrierInternal->WaitingThreadCount = 0;
- pthread_mutex_destroy(&(BarrierInternal->Mutex));
- return 0;
- }
- PTHREAD_API
- int
- pthread_barrier_wait (
- pthread_barrier_t *Barrier
- )
- /*++
- Routine Description:
- This routine blocks untils the required number of threads have waited on
- the barrier. Upon success, an arbitrary thread will receive
- PTHREAD_BARRIER_SERIAL_THREAD as a return value; the rest will receive 0.
- This routine does not get interrupted by signals and will continue to block
- after a signal is handled.
- Arguments:
- Barrier - Supplies a pointer to the POSIX thread barrier.
- Return Value:
- 0 or PTHREAD_BARRIER_SERIAL_THREAD on success.
- Returns an error number on failure.
- --*/
- {
- PPTHREAD_BARRIER BarrierInternal;
- KSTATUS KernelStatus;
- ULONG OldState;
- ULONG Operation;
- INT Status;
- ULONG ThreadCount;
- BarrierInternal = (PPTHREAD_BARRIER)Barrier;
- //
- // Acquire the mutex and increment the waiting thread count. If this
- // thread's wait satisfies the barrier, then attempt to wake all of the
- // other waiting threads.
- //
- pthread_mutex_lock(&(BarrierInternal->Mutex));
- BarrierInternal->WaitingThreadCount += 1;
- if (BarrierInternal->WaitingThreadCount >= BarrierInternal->ThreadCount) {
- Operation = UserLockWake;
- if ((BarrierInternal->State & PTHREAD_BARRIER_SHARED) == 0) {
- Operation |= USER_LOCK_PRIVATE;
- }
- ThreadCount = MAX_ULONG;
- KernelStatus = OsUserLock(&(BarrierInternal->State),
- Operation,
- &ThreadCount,
- 0);
- //
- // On success, this thread gets the unique serialization return value.
- // Also, reset the barrier to the initialization state and increment
- // the state, so that any threads about to wait on this now satisfied
- // barrier will fail in the kernel.
- //
- if (KSUCCESS(KernelStatus)) {
- Status = PTHREAD_BARRIER_SERIAL_THREAD;
- BarrierInternal->WaitingThreadCount = 0;
- RtlAtomicAdd32(&(BarrierInternal->State),
- 1 << PTHREAD_BARRIER_COUNTER_SHIFT);
- } else {
- Status = ClConvertKstatusToErrorNumber(KernelStatus);
- }
- pthread_mutex_unlock(&(BarrierInternal->Mutex));
- //
- // Otherwise, wait on the current state until the required number of
- // threads arrive.
- //
- } else {
- OldState = BarrierInternal->State;
- pthread_mutex_unlock(&(BarrierInternal->Mutex));
- Operation = UserLockWait;
- if ((OldState & PTHREAD_BARRIER_SHARED) == 0) {
- Operation |= USER_LOCK_PRIVATE;
- }
- //
- // If a signal interrupts the wait, the barrier should continue waiting
- // after the signal is handled.
- //
- do {
- KernelStatus = OsUserLock(&(BarrierInternal->State),
- Operation,
- &OldState,
- SYS_WAIT_TIME_INDEFINITE);
- } while (KernelStatus == STATUS_INTERRUPTED);
- //
- // The wait may have failed immediately if the barrier was satisfied
- // between this thread releasing the lock and executing the wait.
- // Convert this failure into success.
- //
- if (KSUCCESS(KernelStatus) ||
- (KernelStatus == STATUS_OPERATION_WOULD_BLOCK)) {
- Status = 0;
- } else {
- Status = ClConvertKstatusToErrorNumber(KernelStatus);
- }
- }
- return Status;
- }
- PTHREAD_API
- int
- pthread_barrierattr_init (
- pthread_barrierattr_t *Attribute
- )
- /*++
- Routine Description:
- This routine initializes a barrier attribute structure.
- Arguments:
- Attribute - Supplies a pointer to the barrier attribute structure to
- initialize.
- Return Value:
- 0 on success.
- Returns an error number on failure.
- --*/
- {
- PPTHREAD_BARRIER_ATTRIBUTE AttributeInternal;
- AttributeInternal = (PPTHREAD_BARRIER_ATTRIBUTE)Attribute;
- AttributeInternal->Flags = 0;
- return 0;
- }
- PTHREAD_API
- int
- pthread_barrierattr_destroy (
- pthread_barrierattr_t *Attribute
- )
- /*++
- Routine Description:
- This routine destroys the given barrier attribute structure.
- Arguments:
- Attribute - Supplies a pointer to the barrier attribute to destroy.
- Return Value:
- 0 on success.
- Returns an error number on failure.
- --*/
- {
- PPTHREAD_BARRIER_ATTRIBUTE AttributeInternal;
- AttributeInternal = (PPTHREAD_BARRIER_ATTRIBUTE)Attribute;
- AttributeInternal->Flags = MAX_ULONG;
- return 0;
- }
- PTHREAD_API
- int
- pthread_barrierattr_getpshared (
- const pthread_barrierattr_t *Attribute,
- int *Shared
- )
- /*++
- Routine Description:
- This routine determines the shared state in a barrier attribute.
- Arguments:
- Attribute - Supplies a pointer to the barrier attribute structure.
- Shared - Supplies a pointer where the shared attribute will be returned,
- indicating whether the condition variable is visible across processes.
- See PTHREAD_PROCESS_* definitions.
- Return Value:
- 0 on success.
- Returns an error number on failure.
- --*/
- {
- PPTHREAD_BARRIER_ATTRIBUTE AttributeInternal;
- AttributeInternal = (PPTHREAD_BARRIER_ATTRIBUTE)Attribute;
- *Shared = PTHREAD_PROCESS_PRIVATE;
- if ((AttributeInternal->Flags & PTHREAD_BARRIER_SHARED) != 0) {
- *Shared = PTHREAD_PROCESS_SHARED;
- }
- return 0;
- }
- PTHREAD_API
- int
- pthread_barrierattr_setpshared (
- const pthread_barrierattr_t *Attribute,
- int Shared
- )
- /*++
- Routine Description:
- This routine sets the shared state in a barrier attribute.
- Arguments:
- Attribute - Supplies a pointer to the barrier attribute structure.
- Shared - Supplies the value indicating whether this barrier should be
- visible across processes. See PTHREAD_PROCESS_* definitions.
- Return Value:
- 0 on success.
- Returns an error number on failure.
- --*/
- {
- PPTHREAD_BARRIER_ATTRIBUTE AttributeInternal;
- AttributeInternal = (PPTHREAD_BARRIER_ATTRIBUTE)Attribute;
- if (Shared == PTHREAD_PROCESS_PRIVATE) {
- AttributeInternal->Flags &= ~PTHREAD_BARRIER_SHARED;
- } else if (Shared == PTHREAD_PROCESS_SHARED) {
- AttributeInternal->Flags |= PTHREAD_BARRIER_SHARED;
- } else {
- return EINVAL;
- }
- return 0;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
|