123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221 |
- /*++
- Copyright (c) 2015 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:
- mutex.c
- Abstract:
- This module implements mutex support functions for the POSIX thread library.
- Author:
- Evan Green 27-Apr-2015
- Environment:
- User Mode C Library
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include "pthreadp.h"
- //
- // ---------------------------------------------------------------- Definitions
- //
- #define PTHREAD_MUTEX_STATE_UNLOCKED 0
- #define PTHREAD_MUTEX_STATE_LOCKED 1
- #define PTHREAD_MUTEX_STATE_LOCKED_WITH_WAITERS 2
- #define PTHREAD_MUTEX_STATE_MASK 0x00000007
- #define PTHREAD_MUTEX_STATE_COUNTER_SHIFT 4
- #define PTHREAD_MUTEX_STATE_COUNTER_MASK 0x0000FFFF
- #define PTHREAD_MUTEX_STATE_COUNTER_MAX 0x0000FFFF
- #define PTHREAD_MUTEX_STATE_SHARED 0x20000000
- #define PTHREAD_MUTEX_STATE_RECURSIVE 0x40000000
- #define PTHREAD_MUTEX_STATE_ERRORCHECK 0x80000000
- #define PTHREAD_MUTEX_STATE_TYPE_MASK 0xC0000000
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- int
- ClpAcquireMutexWithTimeout (
- PPTHREAD_MUTEX Mutex,
- const struct timespec *AbsoluteTimeout,
- clockid_t Clock
- );
- int
- ClpAcquireNormalMutex (
- PPTHREAD_MUTEX Mutex,
- ULONG Shared,
- const struct timespec *AbsoluteTimeout,
- INT Clock
- );
- int
- ClpTryToAcquireNormalMutex (
- PPTHREAD_MUTEX Mutex,
- ULONG Shared
- );
- VOID
- ClpReleaseNormalMutex (
- PPTHREAD_MUTEX Mutex,
- ULONG Shared
- );
- int
- ClpMutexIncrementAcquireCount (
- PPTHREAD_MUTEX Mutex
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- //
- // ------------------------------------------------------------------ Functions
- //
- PTHREAD_API
- int
- pthread_mutex_init (
- pthread_mutex_t *Mutex,
- const pthread_mutexattr_t *Attribute
- )
- /*++
- Routine Description:
- This routine initializes a mutex.
- Arguments:
- Mutex - Supplies a pointer to the mutex to initialize.
- Attribute - Supplies an optional pointer to the initialized attributes to
- set in the mutex.
- Return Value:
- 0 on success.
- Returns an error number on failure.
- --*/
- {
- PPTHREAD_MUTEX_ATTRIBUTE AttributeInternal;
- ULONG Flags;
- PPTHREAD_MUTEX MutexInternal;
- ULONG State;
- MutexInternal = (PPTHREAD_MUTEX)Mutex;
- ASSERT(sizeof(pthread_mutex_t) >= sizeof(PTHREAD_MUTEX));
- memset(MutexInternal, 0, sizeof(PTHREAD_MUTEX));
- if (Attribute == NULL) {
- return 0;
- }
- AttributeInternal = (PPTHREAD_MUTEX_ATTRIBUTE)Attribute;
- Flags = AttributeInternal->Flags;
- State = 0;
- if ((Flags & PTHREAD_MUTEX_SHARED) != 0) {
- State |= PTHREAD_MUTEX_STATE_SHARED;
- }
- switch (Flags & PTHREAD_MUTEX_TYPE_MASK) {
- case PTHREAD_MUTEX_NORMAL:
- break;
- case PTHREAD_MUTEX_RECURSIVE:
- State |= PTHREAD_MUTEX_STATE_RECURSIVE;
- break;
- case PTHREAD_MUTEX_ERRORCHECK:
- State |= PTHREAD_MUTEX_STATE_ERRORCHECK;
- break;
- default:
- return EINVAL;
- }
- MutexInternal->State = State;
- return 0;
- }
- PTHREAD_API
- int
- pthread_mutex_destroy (
- pthread_mutex_t *Mutex
- )
- /*++
- Routine Description:
- This routine destroys a mutex.
- Arguments:
- Mutex - Supplies a pointer to the mutex to destroy.
- Return Value:
- 0 on success.
- Returns an error number on failure.
- --*/
- {
- PPTHREAD_MUTEX MutexInternal;
- int Status;
- //
- // Try to acquire the lock to ensure it's not invalid and not already
- // locked.
- //
- Status = pthread_mutex_trylock(Mutex);
- if (Status != 0) {
- return Status;
- }
- MutexInternal = (PPTHREAD_MUTEX)Mutex;
- MutexInternal->State = -1;
- return Status;
- }
- PTHREAD_API
- int
- pthread_mutex_lock (
- pthread_mutex_t *Mutex
- )
- /*++
- Routine Description:
- This routine acquires a mutex.
- Arguments:
- Mutex - Supplies a pointer to the mutex to acquire.
- Return Value:
- 0 on success.
- Returns an error number on failure.
- --*/
- {
- PPTHREAD_MUTEX MutexInternal;
- ULONG MutexType;
- ULONG Shared;
- MutexInternal = (PPTHREAD_MUTEX)Mutex;
- MutexType = MutexInternal->State & PTHREAD_MUTEX_STATE_TYPE_MASK;
- Shared = MutexInternal->State & PTHREAD_MUTEX_STATE_SHARED;
- if (MutexType == 0) {
- if (ClpTryToAcquireNormalMutex(MutexInternal, Shared) == 0) {
- return 0;
- }
- }
- return ClpAcquireMutexWithTimeout(MutexInternal, NULL, 0);
- }
- PTHREAD_API
- int
- pthread_mutex_unlock (
- pthread_mutex_t *Mutex
- )
- /*++
- Routine Description:
- This routine releases a mutex.
- Arguments:
- Mutex - Supplies a pointer to the mutex to release.
- Return Value:
- 0 on success.
- EPERM if this thread is not the thread that originally acquire the mutex.
- --*/
- {
- ULONG Count;
- ULONG Counter;
- PPTHREAD_MUTEX MutexInternal;
- ULONG MutexType;
- ULONG OldState;
- ULONG Operation;
- ULONG ReleasedState;
- ULONG Shared;
- UINTN ThreadId;
- MutexInternal = (PPTHREAD_MUTEX)Mutex;
- MutexType = MutexInternal->State & PTHREAD_MUTEX_STATE_TYPE_MASK;
- Shared = MutexInternal->State & PTHREAD_MUTEX_STATE_SHARED;
- //
- // Do a fast release for normal locks.
- //
- if (MutexType == 0) {
- ClpReleaseNormalMutex(MutexInternal, Shared);
- return 0;
- }
- //
- // Check the ownership of the mutex.
- //
- ThreadId = OsGetThreadId();
- if (ThreadId != MutexInternal->Owner) {
- return EPERM;
- }
- //
- // If the counter is non-zero, just decrement it.
- //
- Counter = (MutexInternal->State >> PTHREAD_MUTEX_STATE_COUNTER_SHIFT) &
- PTHREAD_MUTEX_STATE_COUNTER_MASK;
- if (Counter != 0) {
- RtlAtomicAdd32(&(MutexInternal->State),
- 0 - (1 << PTHREAD_MUTEX_STATE_COUNTER_SHIFT));
- return 0;
- }
- //
- // Set the state to free, and release any waiters if contended.
- //
- MutexInternal->Owner = 0;
- ReleasedState = MutexType | Shared | PTHREAD_MUTEX_STATE_UNLOCKED;
- OldState = RtlAtomicExchange32(&(MutexInternal->State), ReleasedState);
- if ((OldState & PTHREAD_MUTEX_STATE_MASK) ==
- PTHREAD_MUTEX_STATE_LOCKED_WITH_WAITERS) {
- Operation = UserLockWake;
- if (Shared == 0) {
- Operation |= USER_LOCK_PRIVATE;
- }
- Count = 1;
- OsUserLock(&(MutexInternal->State), Operation, &Count, 0);
- }
- return 0;
- }
- PTHREAD_API
- int
- pthread_mutex_trylock (
- pthread_mutex_t *Mutex
- )
- /*++
- Routine Description:
- This routine attempts to acquire the given mutex once.
- Arguments:
- Mutex - Supplies a pointer to the mutex to attempt to acquire.
- Return Value:
- 0 on success.
- EBUSY if the mutex is already held by another thread and this is an error
- checking mutex.
- --*/
- {
- ULONG Locked;
- PPTHREAD_MUTEX MutexInternal;
- ULONG MutexType;
- ULONG OldState;
- ULONG Shared;
- UINTN ThreadId;
- ULONG Unlocked;
- MutexInternal = (PPTHREAD_MUTEX)Mutex;
- MutexType = MutexInternal->State & PTHREAD_MUTEX_STATE_TYPE_MASK;
- Shared = MutexInternal->State & PTHREAD_MUTEX_STATE_SHARED;
- //
- // Handle the normal fast path.
- //
- if (MutexType == 0) {
- return ClpTryToAcquireNormalMutex(MutexInternal, Shared);
- }
- //
- // Determine if the thread already owns the mutex.
- //
- ThreadId = OsGetThreadId();
- if (MutexInternal->Owner == ThreadId) {
- if (MutexType == PTHREAD_MUTEX_STATE_ERRORCHECK) {
- return EBUSY;
- }
- return ClpMutexIncrementAcquireCount(MutexInternal);
- }
- Unlocked = MutexType | Shared | PTHREAD_MUTEX_STATE_UNLOCKED;
- Locked = MutexType | Shared | PTHREAD_MUTEX_STATE_LOCKED;
- //
- // Try to go from unlocked to locked, which is the only case under which
- // this attempt could succeed.
- //
- OldState = RtlAtomicCompareExchange32(&(MutexInternal->State),
- Locked,
- Unlocked);
- //
- // If acquired, set the owner and return happily.
- //
- if (OldState == Unlocked) {
- MutexInternal->Owner = ThreadId;
- return 0;
- }
- return EBUSY;
- }
- PTHREAD_API
- int
- pthread_mutex_timedlock (
- pthread_mutex_t *Mutex,
- const struct timespec *AbsoluteTimeout
- )
- /*++
- Routine Description:
- This routine attempts to acquire a mutex, giving up after a specified
- deadline.
- Arguments:
- Mutex - Supplies a pointer to the mutex to acquire.
- AbsoluteTimeout - Supplies the absolute timeout after which the attempt
- shall fail and time out.
- Return Value:
- 0 on success.
- Returns an error number on failure.
- --*/
- {
- int Status;
- Status = ClpAcquireMutexWithTimeout((PPTHREAD_MUTEX)Mutex,
- AbsoluteTimeout,
- CLOCK_REALTIME);
- return Status;
- }
- PTHREAD_API
- int
- pthread_mutexattr_init (
- pthread_mutexattr_t *Attribute
- )
- /*++
- Routine Description:
- This routine initializes a mutex attribute object.
- Arguments:
- Attribute - Supplies a pointer to the attribute to initialize.
- Return Value:
- 0 on success.
- Returns an error number on failure.
- --*/
- {
- PPTHREAD_MUTEX_ATTRIBUTE MutexAttribute;
- MutexAttribute = (PPTHREAD_MUTEX_ATTRIBUTE)Attribute;
- MutexAttribute->Flags = 0;
- return 0;
- }
- PTHREAD_API
- int
- pthread_mutexattr_destroy (
- pthread_mutexattr_t *Attribute
- )
- /*++
- Routine Description:
- This routine destroys a mutex attribute object.
- Arguments:
- Attribute - Supplies a pointer to the attribute to destroy.
- Return Value:
- 0 on success.
- Returns an error number on failure.
- --*/
- {
- PPTHREAD_MUTEX_ATTRIBUTE MutexAttribute;
- MutexAttribute = (PPTHREAD_MUTEX_ATTRIBUTE)Attribute;
- MutexAttribute->Flags = -1;
- return 0;
- }
- PTHREAD_API
- int
- pthread_mutexattr_gettype (
- const pthread_mutexattr_t *Attribute,
- int *Type
- )
- /*++
- Routine Description:
- This routine returns the mutex type given an attribute that was previously
- set.
- Arguments:
- Attribute - Supplies a pointer to the attribute to get the type from.
- Type - Supplies a pointer where the mutex type will be returned on success.
- Return Value:
- 0 on success.
- Returns an error number on failure.
- --*/
- {
- PPTHREAD_MUTEX_ATTRIBUTE MutexAttribute;
- INT MutexType;
- MutexAttribute = (PPTHREAD_MUTEX_ATTRIBUTE)Attribute;
- MutexType = MutexAttribute->Flags & PTHREAD_MUTEX_TYPE_MASK;
- if ((MutexType < PTHREAD_MUTEX_NORMAL) ||
- (MutexType > PTHREAD_MUTEX_RECURSIVE)) {
- return EINVAL;
- }
- *Type = MutexType;
- return 0;
- }
- PTHREAD_API
- int
- pthread_mutexattr_settype (
- pthread_mutexattr_t *Attribute,
- int Type
- )
- /*++
- Routine Description:
- This routine sets a mutex type in the given mutex attributes object.
- Arguments:
- Attribute - Supplies a pointer to the attribute to set the type in.
- Type - Supplies the mutex type to set. See PTHREAD_MUTEX_* definitions.
- Return Value:
- 0 on success.
- Returns an error number on failure.
- --*/
- {
- PPTHREAD_MUTEX_ATTRIBUTE MutexAttribute;
- MutexAttribute = (PPTHREAD_MUTEX_ATTRIBUTE)Attribute;
- if ((Type < PTHREAD_MUTEX_NORMAL) || (Type > PTHREAD_MUTEX_RECURSIVE)) {
- return EINVAL;
- }
- MutexAttribute->Flags &= ~PTHREAD_MUTEX_TYPE_MASK;
- MutexAttribute->Flags |= Type;
- return 0;
- }
- PTHREAD_API
- int
- pthread_mutexattr_getpshared (
- const pthread_mutexattr_t *Attribute,
- int *Shared
- )
- /*++
- Routine Description:
- This routine returns the mutex sharing type given an attribute that was
- previously set.
- Arguments:
- Attribute - Supplies a pointer to the attribute to get the sharing
- information from.
- Shared - Supplies a pointer where the sharing type will be returned on
- success. See PTHREAD_PROCESS_* definitions.
- Return Value:
- 0 on success.
- Returns an error number on failure.
- --*/
- {
- PPTHREAD_MUTEX_ATTRIBUTE MutexAttribute;
- MutexAttribute = (PPTHREAD_MUTEX_ATTRIBUTE)Attribute;
- *Shared = PTHREAD_PROCESS_PRIVATE;
- if ((MutexAttribute->Flags & PTHREAD_MUTEX_SHARED) != 0) {
- *Shared = PTHREAD_PROCESS_SHARED;
- }
- return 0;
- }
- PTHREAD_API
- int
- pthread_mutexattr_setpshared (
- pthread_mutexattr_t *Attribute,
- int Shared
- )
- /*++
- Routine Description:
- This routine sets a mutex sharing type in the given mutex attributes object.
- Arguments:
- Attribute - Supplies a pointer to the attribute to set the type in.
- Shared - Supplies the mutex type to set. See PTHREAD_PROCESS_* definitions.
- Return Value:
- 0 on success.
- Returns an error number on failure.
- --*/
- {
- PPTHREAD_MUTEX_ATTRIBUTE MutexAttribute;
- int Status;
- MutexAttribute = (PPTHREAD_MUTEX_ATTRIBUTE)Attribute;
- Status = 0;
- switch (Shared) {
- case PTHREAD_PROCESS_SHARED:
- MutexAttribute->Flags |= PTHREAD_MUTEX_SHARED;
- break;
- case PTHREAD_PROCESS_PRIVATE:
- MutexAttribute->Flags &= ~PTHREAD_MUTEX_SHARED;
- break;
- default:
- Status = EINVAL;
- break;
- }
- return Status;
- }
- ULONG
- ClpConvertAbsoluteTimespecToRelativeMilliseconds (
- const struct timespec *AbsoluteTime,
- int Clock
- )
- /*++
- Routine Description:
- This routine converts an absolute timespec structure into a number of
- milliseconds from now.
- Arguments:
- AbsoluteTime - Supplies a pointer to the absolute timespec to convert.
- Clock - Supplies the clock to query from.
- Return Value:
- Returns the number of milliseconds from now the timespec expires in.
- 0 if the absolute time is in the past.
- --*/
- {
- struct timespec Delta;
- ULONG Result;
- time_t Seconds;
- int Status;
- Status = clock_gettime(Clock, &Delta);
- if (Status != 0) {
- return 0;
- }
- Delta.tv_sec = AbsoluteTime->tv_sec - Delta.tv_sec;
- Delta.tv_nsec = AbsoluteTime->tv_nsec - Delta.tv_nsec;
- if (Delta.tv_nsec < 0) {
- Delta.tv_sec -= 1;
- Delta.tv_nsec += NANOSECONDS_PER_SECOND;
- }
- if ((Delta.tv_nsec < 0) || (Delta.tv_sec < 0)) {
- return 0;
- }
- if (Delta.tv_nsec >= NANOSECONDS_PER_SECOND) {
- Seconds = Delta.tv_nsec / NANOSECONDS_PER_SECOND;
- Delta.tv_sec += Seconds;
- Delta.tv_nsec -= (Seconds * NANOSECONDS_PER_SECOND);
- }
- Status = ClpConvertSpecificTimeoutToSystemTimeout(&Delta, &Result);
- if (Status != 0) {
- return 0;
- }
- return Result;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- int
- ClpAcquireMutexWithTimeout (
- PPTHREAD_MUTEX Mutex,
- const struct timespec *AbsoluteTimeout,
- clockid_t Clock
- )
- /*++
- Routine Description:
- This routine attempts to acquire a mutex with a timeout.
- Arguments:
- Mutex - Supplies a pointer to the mutex to acquire.
- AbsoluteTimeout - Supplies an optional pointer to the deadline in absolute
- time after which the operation should time out and fail.
- Clock - Supplies the clock to measure the timeout against.
- Return Value:
- 0 on success.
- Returns an error number on failure.
- --*/
- {
- KSTATUS KernelStatus;
- ULONG Locked;
- ULONG LockedWithWaiters;
- ULONG MutexType;
- ULONG NewState;
- ULONG OldState;
- ULONG Operation;
- ULONG Shared;
- UINTN ThreadId;
- ULONG TimeoutInMilliseconds;
- ULONG Unlocked;
- OldState = Mutex->State;
- MutexType = Mutex->State & PTHREAD_MUTEX_STATE_TYPE_MASK;
- Shared = Mutex->State & PTHREAD_MUTEX_STATE_SHARED;
- //
- // Handle the fast-ish path for normal types.
- //
- if (MutexType == 0) {
- return ClpAcquireNormalMutex(Mutex, Shared, AbsoluteTimeout, Clock);
- }
- //
- // Determine if the thread already owns the mutex.
- //
- ThreadId = OsGetThreadId();
- if (ThreadId == Mutex->Owner) {
- if (MutexType == PTHREAD_MUTEX_STATE_ERRORCHECK) {
- return EDEADLK;
- }
- return ClpMutexIncrementAcquireCount(Mutex);
- }
- Unlocked = MutexType | Shared | PTHREAD_MUTEX_STATE_UNLOCKED;
- Locked = MutexType | Shared | PTHREAD_MUTEX_STATE_LOCKED;
- LockedWithWaiters = MutexType | Shared |
- PTHREAD_MUTEX_STATE_LOCKED_WITH_WAITERS;
- //
- // Take an optimistic stab at acquiring the lock assuming it's uncontended.
- // If this works, then it gets left as locked (without waiters), which
- // makes the release operation lightweight.
- //
- if (OldState == Unlocked) {
- OldState = RtlAtomicCompareExchange32(&(Mutex->State),
- Locked,
- Unlocked);
- if (OldState == Unlocked) {
- Mutex->Owner = ThreadId;
- return 0;
- }
- }
- //
- // Contend for the mutex.
- //
- while (TRUE) {
- if (OldState == Unlocked) {
- //
- // Attempt to go from unlocked to locked with waiters. Being inside
- // this loop means there are definitely other threads bouncing
- // around here, so going directly to locked with waiters saves them
- // the trouble of having to go from locked to locked with waiters.
- //
- OldState = RtlAtomicCompareExchange32(&(Mutex->State),
- LockedWithWaiters,
- OldState);
- if (OldState == Unlocked) {
- Mutex->Owner = ThreadId;
- return 0;
- }
- continue;
- //
- // If the mutex is locked (without waiters), set it to locked with
- // with waiters to tell whoever does have it that they need to wake
- // this thread up. The comparison cannot simply be against the locked
- // local variable because a recursive lock may have added to the
- // counter.
- //
- } else if ((OldState & PTHREAD_MUTEX_STATE_MASK) ==
- PTHREAD_MUTEX_STATE_LOCKED) {
- NewState = (OldState & ~PTHREAD_MUTEX_STATE_MASK) |
- PTHREAD_MUTEX_STATE_LOCKED_WITH_WAITERS;
- OldState = RtlAtomicCompareExchange32(&(Mutex->State),
- NewState,
- OldState);
- continue;
- }
- ASSERT((OldState & PTHREAD_MUTEX_STATE_MASK) ==
- PTHREAD_MUTEX_STATE_LOCKED_WITH_WAITERS);
- if (AbsoluteTimeout != NULL) {
- TimeoutInMilliseconds =
- ClpConvertAbsoluteTimespecToRelativeMilliseconds(
- AbsoluteTimeout,
- Clock);
- if (TimeoutInMilliseconds == 0) {
- return ETIMEDOUT;
- }
- } else {
- TimeoutInMilliseconds = SYS_WAIT_TIME_INDEFINITE;
- }
- //
- // Call the kernel to go down for a wait.
- //
- Operation = UserLockWait;
- if (Shared == 0) {
- Operation |= USER_LOCK_PRIVATE;
- }
- KernelStatus = OsUserLock(&(Mutex->State),
- Operation,
- &OldState,
- TimeoutInMilliseconds);
- if (KernelStatus == STATUS_TIMEOUT) {
- return ETIMEDOUT;
- }
- OldState = Mutex->State;
- }
- //
- // This code is never reached.
- //
- ASSERT(FALSE);
- return EINVAL;
- }
- int
- ClpAcquireNormalMutex (
- PPTHREAD_MUTEX Mutex,
- ULONG Shared,
- const struct timespec *AbsoluteTimeout,
- INT Clock
- )
- /*++
- Routine Description:
- This routine acquires a normal mutex. That is one without any recursive or
- error checking attributes.
- Arguments:
- Mutex - Supplies a pointer to the mutex to acquire.
- Shared - Supplies the shared flag for the mutex.
- AbsoluteTimeout - Supplies an optional pointer to the absolute timeout for
- the operation.
- Clock - Supplies the clock source.
- Return Value:
- 0 if the lock was acquired.
- Returns an error code on failure or timeout.
- --*/
- {
- KSTATUS KernelStatus;
- ULONG LockedWithWaiters;
- ULONG OldState;
- ULONG Operation;
- ULONG TimeoutInMilliseconds;
- ULONG Unlocked;
- //
- // Give it a quick fast attempt first.
- //
- if (ClpTryToAcquireNormalMutex(Mutex, Shared) == 0) {
- return 0;
- }
- LockedWithWaiters = Shared | PTHREAD_MUTEX_STATE_LOCKED_WITH_WAITERS;
- Unlocked = Shared | PTHREAD_MUTEX_STATE_UNLOCKED;
- //
- // Set the lock to acquired with waiters (since the quick attempt above
- // failed).
- //
- while (TRUE) {
- OldState = RtlAtomicExchange32(&(Mutex->State), LockedWithWaiters);
- //
- // If the lock was acquired, break out for success.
- //
- if (OldState == Unlocked) {
- break;
- }
- if (AbsoluteTimeout != NULL) {
- TimeoutInMilliseconds =
- ClpConvertAbsoluteTimespecToRelativeMilliseconds(
- AbsoluteTimeout,
- Clock);
- if (TimeoutInMilliseconds == 0) {
- return ETIMEDOUT;
- }
- } else {
- TimeoutInMilliseconds = SYS_WAIT_TIME_INDEFINITE;
- }
- //
- // Call the kernel to go down for a wait.
- //
- Operation = UserLockWait;
- if (Shared == 0) {
- Operation |= USER_LOCK_PRIVATE;
- }
- OldState = LockedWithWaiters;
- KernelStatus = OsUserLock(&(Mutex->State),
- Operation,
- &OldState,
- TimeoutInMilliseconds);
- if (KernelStatus == STATUS_TIMEOUT) {
- return ETIMEDOUT;
- }
- }
- return 0;
- }
- int
- ClpTryToAcquireNormalMutex (
- PPTHREAD_MUTEX Mutex,
- ULONG Shared
- )
- /*++
- Routine Description:
- This routine performs a single non-blocking attempt at acquiring a mutex
- without any fancy attributes like error checking or recursion.
- Arguments:
- Mutex - Supplies a pointer to the mutex to attempt to acquire.
- Shared - Supplies the shared flag for the mutex.
- Return Value:
- 0 if the mutex was acquired.
- EBUSY if the mutex was not successfully acquired.
- --*/
- {
- ULONG Locked;
- ULONG OldState;
- ULONG Unlocked;
- Locked = Shared | PTHREAD_MUTEX_STATE_LOCKED;
- Unlocked = Shared | PTHREAD_MUTEX_STATE_UNLOCKED;
- OldState = RtlAtomicCompareExchange32(&(Mutex->State), Locked, Unlocked);
- if (OldState == Unlocked) {
- return 0;
- }
- return EBUSY;
- }
- VOID
- ClpReleaseNormalMutex (
- PPTHREAD_MUTEX Mutex,
- ULONG Shared
- )
- /*++
- Routine Description:
- This routine releases a mutex without any recursive or error checking
- attributes.
- Arguments:
- Mutex - Supplies a pointer to the mutex to release.
- Shared - Supplies the shared flag for the mutex.
- Return Value:
- None.
- --*/
- {
- ULONG Count;
- ULONG LockedWithWaiters;
- ULONG OldState;
- ULONG Operation;
- ULONG Unlocked;
- Unlocked = Shared | PTHREAD_MUTEX_STATE_UNLOCKED;
- LockedWithWaiters = Shared | PTHREAD_MUTEX_STATE_LOCKED_WITH_WAITERS;
- //
- // Exchange out the state to unlocked. If it had waiters, wake them up.
- //
- OldState = RtlAtomicExchange32(&(Mutex->State), Unlocked);
- if (OldState == LockedWithWaiters) {
- Operation = UserLockWake;
- if (Shared == 0) {
- Operation |= USER_LOCK_PRIVATE;
- }
- Count = 1;
- OsUserLock(&(Mutex->State), Operation, &Count, 0);
- }
- return;
- }
- int
- ClpMutexIncrementAcquireCount (
- PPTHREAD_MUTEX Mutex
- )
- /*++
- Routine Description:
- This routine increments the acquire count on a mutex that's already held
- by the current thread.
- Arguments:
- Mutex - Supplies a pointer to the mutex to increment.
- Return Value:
- 0 on success.
- EAGAIN if the maximum number of recursive acquires was reached (the
- internal counter would overflow).
- --*/
- {
- ULONG Count;
- Count = (Mutex->State >> PTHREAD_MUTEX_STATE_COUNTER_SHIFT) &
- PTHREAD_MUTEX_STATE_COUNTER_MASK;
- if (Count == PTHREAD_MUTEX_STATE_COUNTER_MAX) {
- return EAGAIN;
- }
- //
- // Since other threads might be atomically changing the lower bits, the
- // atomic add is necessary.
- //
- RtlAtomicAdd32(&(Mutex->State), 1 << PTHREAD_MUTEX_STATE_COUNTER_SHIFT);
- return 0;
- }
|