// bslmt_fastpostsemaphoreimpl.h -*-C++-*- #ifndef INCLUDED_BSLMT_FASTPOSTSEMAPHOREIMPL #define INCLUDED_BSLMT_FASTPOSTSEMAPHOREIMPL #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide a testable semaphore class optimizing 'post'. // //@CLASSES: // bslmt::FastPostSemaphoreImpl: testable semaphore class optimizing 'post' // //@SEE_ALSO: bslmt_fastpostsemaphore, bslmt_semaphore // //@DESCRIPTION: This component defines a testable semaphore, // 'bslmt::FastPostSemaphoreImpl', with the 'post' operation being optimized at // the potential expense of other operations. In particular, // 'bslmt::FastPostSemaphoreImpl' is an efficient synchronization primitive // that enables sharing of a counted number of resources. // 'bslmt::FastPostSemaphoreImpl' supports the methods 'timedWait', 'enable', // and 'disable' in addition to the standard semaphore methods. // // Commonly, during periods of time when the protected resource is scarce (the // semaphore count is frequently zero) and threads are frequently blocked on // wait methods, pessimizing the performance of the threads that block will // have little effect on overall performance. In this case, optimizing 'post' // *may* be a performance improvement. Note that when the resource is // plentiful, there are no blocked threads and we expect the differences // between semaphore implementations to be trivial. // ///Supported Clock-Types ///--------------------- // 'bsls::SystemClockType' supplies the enumeration indicating the system clock // on which timeouts supplied to other methods should be based. If the clock // type indicated at construction is 'bsls::SystemClockType::e_REALTIME', the // 'absTime' argument passed to the 'timedWait' method should be expressed as // an *absolute* offset since 00:00:00 UTC, January 1, 1970 (which matches the // epoch used in 'bsls::SystemTime::now(bsls::SystemClockType::e_REALTIME)'. // If the clock type indicated at construction is // 'bsls::SystemClockType::e_MONOTONIC', the 'absTime' argument passed to the // 'timedWait' method should be expressed as an *absolute* offset since the // epoch of this clock (which matches the epoch used in // 'bsls::SystemTime::now(bsls::SystemClockType::e_MONOTONIC)'. // ///Usage ///----- // There is no usage example for this component since it is not meant for // direct client use. #include <bslscm_version.h> #include <bslmt_lockguard.h> #include <bsls_systemclocktype.h> #include <bsls_timeinterval.h> #include <bsls_types.h> #include <bsl_climits.h> namespace BloombergLP { namespace bslmt { // =========================== // class FastPostSemaphoreImpl // =========================== template <class ATOMIC_OP, class MUTEX, class CONDITION, class THREADUTIL> class FastPostSemaphoreImpl { // This class implements a semaphore type, optimized for 'post', for thread // synchronization. // PRIVATE TYPES typedef typename ATOMIC_OP::AtomicTypes::Int64 AtomicInt64; typedef bsls::Types::Int64 Int64; // DATA AtomicInt64 d_state; // bit pattern representing the state of the // semaphore (see *Implementation* *Note*) MUTEX d_waitMutex; // mutex used with 'd_waitCondition', does // not protect any values CONDITION d_waitCondition; // condition variable for blocking/signalling // threads in the wait methods // PRIVATE CLASS METHODS static bsls::Types::Int64 disabledGeneration(Int64 state); // Return a value suitable for detecting a rapid short sequence of // 'disable' and 'enable' invocations, by comparing the value returned // by 'disabledGeneration' before and after the sequence, for the // specified 'state'. static bsls::Types::Int64 getValueRaw(Int64 state); // Return the semaphore value, without enforcing a zero minimum value, // implied by the specified 'state'. static bool hasAvailable(Int64 state); // Return 'true' if the specified 'state' implies the associated // semaphore has available count. static bool hasBlockedThread(Int64 state); // Return 'true' if the specified 'state' implies the associated // semaphore has one or more threads blocked in a wait operation. static bool isDisabled(Int64 state); // Return 'true' if the specified 'state' implies the associated // semaphore is "wait disabled". static bool willHaveBlockedThread(Int64 state); // Return 'true' if the specified 'state' implies the associated // semaphore does not have sufficient resources to meet the demand upon // the resources, implying there will be one or more threads blocked in // wait operations (without further 'post' invocations). // PRIVATE MANIPULATORS int timedWaitSlowPath(const bsls::TimeInterval& absTime, const bsls::Types::Int64 initialState); // If this semaphore becomes disabled as detected from the disabled // generation encoded in the specified 'initialState' (see // *Implementation* *Note*), return 'e_DISABLED' with no effect on the // count. Otherwise, block until the count of this semaphore is a // positive value or the specified 'absTime' timeout expires. If the // count of this timed semaphore is a positive value, return 0 and // atomically decrement the count. If the 'absTime' timeout expires, // return 'e_TIMED_OUT' with no effect on the count. 'absTime' is an // absolute time represented as an interval from some epoch, which is // determined by the clock indicated at construction (see {Supported // Clock-Types} in the component-level documentation). This method is // invoked from 'timedWait' when the invoking thread may have to be // blocked. int waitSlowPath(const bsls::Types::Int64 initialState); // If this semaphore becomes disabled as detected from the disabled // generation encoded in the specified 'initialState' (see // *Implementation* *Note*), return 'e_DISABLED' with no effect on the // count. Otherwise, block until the count of this semaphore is a // positive value, return 0 and atomically decrement the count. This // method is invoked from 'wait' when the invoking thread may have to // be blocked. // NOT IMPLEMENTED FastPostSemaphoreImpl(const FastPostSemaphoreImpl&); FastPostSemaphoreImpl& operator=(const FastPostSemaphoreImpl&); public: // PUBLIC CONSTANTS enum ReturnValue { e_SUCCESS = 0, // indicates success e_DISABLED = -1, // indicates semaphore is disabled e_TIMED_OUT = -2, // indicates operation timed out e_WOULD_BLOCK = -3, // indicates operation would block ('tryWait') e_FAILED = -4 // indicates failure reported from condition }; // The following constants are used to maintain the semaphore's 'd_state' // attribute values for: //: o number of threads blocked, //: o generation count for tracking enabled/disabled, //: o and available count. // // The 'k_*_MASK' constants define the layout of the attributes, the // 'k_*_INC' constants are used to modify the 'd_state' attributes, and the // 'k_*_SHIFT' constants allow recovery of the stored value. // // See *Implementation* *Note* for further details. These are 'public' to // ease testing. static const Int64 k_BLOCKED_INC = 0x0000000000000001LL; static const Int64 k_BLOCKED_MASK = 0x0000000000ffffffLL; static const Int64 k_DISABLED_GEN_INC = 0x0000000001000000LL; static const Int64 k_DISABLED_GEN_MASK = 0x000000000f000000LL; static const int k_DISABLED_GEN_SHIFT = 24; static const Int64 k_AVAILABLE_INC = 0x0000000010000000LL; static const Int64 k_AVAILABLE_MASK = 0xfffffffff0000000LL; static const int k_AVAILABLE_SHIFT = 28; // CREATORS explicit FastPostSemaphoreImpl( bsls::SystemClockType::Enum clockType = bsls::SystemClockType::e_REALTIME); // Create a 'FastPostSemaphoreImpl' object initially having a count of // 0. Optionally specify a 'clockType' indicating the type of the // system clock against which the 'bsls::TimeInterval' 'absTime' // timeouts passed to the 'timedWait' method are to be interpreted (see // {Supported Clock-Types} in the component-level documentation). If // 'clockType' is not specified then the realtime system clock is used. explicit FastPostSemaphoreImpl( int count, bsls::SystemClockType::Enum clockType = bsls::SystemClockType::e_REALTIME); // Create a 'FastPostSemaphoreImpl' object initially having the // specified 'count'. Optionally specify a 'clockType' indicating the // type of the system clock against which the 'bsls::TimeInterval' // 'absTime' timeouts passed to the 'timedWait' method are to be // interpreted (see {Supported Clock-Types} in the component // documentation). If 'clockType' is not specified then the realtime // system clock is used. // ~FastPostSemaphoreImpl() = default; // Destroy this object. // MANIPULATORS void disable(); // Disable waiting on this semaphore. All subsequent invocations of // 'wait', 'tryWait', and 'timedWait' will fail immediately. All // blocked invocations of 'wait' and 'timedWait' will fail immediately. // If the semaphore is initially disabled, this call has no effect. void enable(); // Enable waiting on this semaphore. If the semaphore is initially // enabled, this call has no effect. void post(); // Atomically increment the count of this semaphore. void post(int value); // Atomically increase the count of this semaphore by the specified // 'value'. The behavior is undefined unless 'value > 0'. int take(int maximumToTake); // If the count of this semaphore is positive, reduce the count by the // lesser of the count and the specified 'maximumToTake' and return the // magnitude of the change to the count. Otherwise, do nothing and // return 0. int takeAll(); // If the count of this semaphore is positive, reduce the count to 0 // and return the original value of the count. Otherwise, do nothing // and return 0. int timedWait(const bsls::TimeInterval& absTime); // If this semaphore is initially disabled, or becomes disabled while // blocking, return 'e_DISABLED' with no effect on the count. // Otherwise, block until the count of this semaphore is a positive // value or the specified 'absTime' timeout expires. If the count of // this semaphore is a positive value, return 0 and atomically // decrement the count. If the 'absTime' timeout expires, return // 'e_TIMED_OUT' with no effect on the count. Return 'e_FAILED' if an // error occurs. 'absTime' is an *absolute* time represented as an // interval from some epoch, which is determined by the clock indicated // at construction (see {Supported Clock-Types} in the component // documentation). int tryWait(); // If this semaphore is initially disabled, return 'e_DISABLED' with no // effect on the count. Otherwise, if the count of this semaphore is a // positive value, return 0 and atomically decrement the count. If // this semaphore is not disabled and the count of this semaphore is // not a positive value, return 'e_WOULD_BLOCK' with no effect on the // count. int wait(); // If this semaphore is initially disabled, or becomes disabled while // blocking, return 'e_DISABLED' with no effect on the count. // Otherwise, block until the count of this semaphore is a positive // value, return 0 and atomically decrement the count. Return // 'e_FAILED' if an error occurs. // ACCESSORS bsls::SystemClockType::Enum clockType() const; // Return the clock type used for timeouts. int getDisabledState() const; // Return an odd value if this semaphore is wait disabled, and an even // value otherwise. The returned value can be used to detect a rapid // short sequence of 'disable' and 'enable' invocations by comparing // the value returned by 'getDisabledState' before and after the // sequence. For example, for any initial state of a semphore instance // 'obj': //.. // int state = obj.getDisabledState(); // obj.disable(); // obj.enable(); // ASSERT(state != obj.getDisabledState()); //.. // This functionality is useful in higher-level components to determine // if this semaphore was disabled during an operation. int getValue() const; // Return the current value ('count > 0 ? count : 0') of this // semaphore. bool isDisabled() const; // Return 'true' if this semaphore is wait disabled, and 'false' // otherwise. Note that the semaphore is created in the "wait enabled" // state. }; // ============================================================================ // INLINE DEFINITIONS // ============================================================================ // --------------------------- // class FastPostSemaphoreImpl // --------------------------- // PRIVATE CLASS METHODS template <class ATOMIC_OP, class MUTEX, class CONDITION, class THREADUTIL> inline bsls::Types::Int64 FastPostSemaphoreImpl<ATOMIC_OP, MUTEX, CONDITION, THREADUTIL> ::disabledGeneration(Int64 state) { return state & k_DISABLED_GEN_MASK; } template <class ATOMIC_OP, class MUTEX, class CONDITION, class THREADUTIL> inline bsls::Types::Int64 FastPostSemaphoreImpl<ATOMIC_OP, MUTEX, CONDITION, THREADUTIL> ::getValueRaw(Int64 state) { return (state >> k_AVAILABLE_SHIFT) - (state & k_BLOCKED_MASK); } template <class ATOMIC_OP, class MUTEX, class CONDITION, class THREADUTIL> inline bool FastPostSemaphoreImpl<ATOMIC_OP, MUTEX, CONDITION, THREADUTIL> ::hasAvailable(Int64 state) { return k_AVAILABLE_INC <= state; } template <class ATOMIC_OP, class MUTEX, class CONDITION, class THREADUTIL> inline bool FastPostSemaphoreImpl<ATOMIC_OP, MUTEX, CONDITION, THREADUTIL> ::hasBlockedThread(Int64 state) { return 0 != (state & k_BLOCKED_MASK); } template <class ATOMIC_OP, class MUTEX, class CONDITION, class THREADUTIL> inline bool FastPostSemaphoreImpl<ATOMIC_OP, MUTEX, CONDITION, THREADUTIL> ::isDisabled(Int64 state) { return 0 != (state & k_DISABLED_GEN_INC); } template <class ATOMIC_OP, class MUTEX, class CONDITION, class THREADUTIL> inline bool FastPostSemaphoreImpl<ATOMIC_OP, MUTEX, CONDITION, THREADUTIL> ::willHaveBlockedThread(Int64 state) { return (state >> k_AVAILABLE_SHIFT) < (state & k_BLOCKED_MASK); } // PRIVATE MANIPULATORS template <class ATOMIC_OP, class MUTEX, class CONDITION, class THREADUTIL> int FastPostSemaphoreImpl<ATOMIC_OP, MUTEX, CONDITION, THREADUTIL> ::timedWaitSlowPath(const bsls::TimeInterval& absTime, const bsls::Types::Int64 initialState) { int rv = e_SUCCESS; const Int64 disabledGen = disabledGeneration(initialState); // 'state' currently indicates the thread should block, yield and retest // instead THREADUTIL::yield(); Int64 state = ATOMIC_OP::getInt64Acquire(&d_state); if (willHaveBlockedThread(state)) { { LockGuard<MUTEX> guard(&d_waitMutex); // note that the following operation indicates the thread is // blocked (see *Implementation* *Notes*) and does not affect the // decision for other threads to block state = ATOMIC_OP::addInt64NvAcqRel( &d_state, k_AVAILABLE_INC + k_BLOCKED_INC); // wait until there is an available resource or this semaphore is // disabled while ( !hasAvailable(state) && disabledGen == disabledGeneration(state)) { int rv = d_waitCondition.timedWait(&d_waitMutex, absTime); if (rv) { ATOMIC_OP::addInt64AcqRel(&d_state, -k_BLOCKED_INC); if (-1 == rv) { return e_TIMED_OUT; // RETURN } return e_FAILED; // RETURN } state = ATOMIC_OP::getInt64Acquire(&d_state); } if (hasAvailable(state)) { state = ATOMIC_OP::addInt64NvAcqRel( &d_state, -(k_AVAILABLE_INC + k_BLOCKED_INC)); } else { ATOMIC_OP::addInt64AcqRel(&d_state, -k_BLOCKED_INC); rv = e_DISABLED; } } // signal when 'state' indicates there is an available resource, the // semaphore is not disabled, and there are blocked threads if ( hasAvailable(state) && !isDisabled(state) && hasBlockedThread(state)) { d_waitCondition.signal(); } } else { // signal when 'state' indicates there is an available resource, the // semaphore is not disabled, and there are blocked threads if ( hasAvailable(state) && !isDisabled(state) && hasBlockedThread(state)) { { LockGuard<MUTEX> guard(&d_waitMutex); } d_waitCondition.signal(); } } return rv; } template <class ATOMIC_OP, class MUTEX, class CONDITION, class THREADUTIL> int FastPostSemaphoreImpl<ATOMIC_OP, MUTEX, CONDITION, THREADUTIL> ::waitSlowPath(const bsls::Types::Int64 initialState) { int rv = e_SUCCESS; const Int64 disabledGen = disabledGeneration(initialState); // 'state' currently indicates the thread should block, yield and retest // instead THREADUTIL::yield(); Int64 state = ATOMIC_OP::getInt64Acquire(&d_state); if (willHaveBlockedThread(state)) { { LockGuard<MUTEX> guard(&d_waitMutex); // note that the following operation indicates the thread is // blocked (see *Implementation* *Notes*) and does not affect the // decision for other threads to block state = ATOMIC_OP::addInt64NvAcqRel( &d_state, k_AVAILABLE_INC + k_BLOCKED_INC); // wait until there is an available resource or this semaphore is // disabled while ( !hasAvailable(state) && disabledGen == disabledGeneration(state)) { int rv = d_waitCondition.wait(&d_waitMutex); if (rv) { ATOMIC_OP::addInt64AcqRel(&d_state, -k_BLOCKED_INC); return e_FAILED; // RETURN } state = ATOMIC_OP::getInt64Acquire(&d_state); } if (hasAvailable(state)) { state = ATOMIC_OP::addInt64NvAcqRel( &d_state, -(k_AVAILABLE_INC + k_BLOCKED_INC)); } else { ATOMIC_OP::addInt64AcqRel(&d_state, -k_BLOCKED_INC); rv = e_DISABLED; } } // signal when 'state' indicates there is an available resource, the // semaphore is not disabled, and there are blocked threads if ( hasAvailable(state) && !isDisabled(state) && hasBlockedThread(state)) { d_waitCondition.signal(); } } else { // signal when 'state' indicates there is an available resource, the // semaphore is not disabled, and there are blocked threads if ( hasAvailable(state) && !isDisabled(state) && hasBlockedThread(state)) { { LockGuard<MUTEX> guard(&d_waitMutex); } d_waitCondition.signal(); } } return rv; } // CREATORS template <class ATOMIC_OP, class MUTEX, class CONDITION, class THREADUTIL> inline FastPostSemaphoreImpl<ATOMIC_OP, MUTEX, CONDITION, THREADUTIL> ::FastPostSemaphoreImpl(bsls::SystemClockType::Enum clockType) : d_waitMutex() , d_waitCondition(clockType) { ATOMIC_OP::initInt64(&d_state, 0); } template <class ATOMIC_OP, class MUTEX, class CONDITION, class THREADUTIL> inline FastPostSemaphoreImpl<ATOMIC_OP, MUTEX, CONDITION, THREADUTIL> ::FastPostSemaphoreImpl(int count, bsls::SystemClockType::Enum clockType) : d_waitMutex() , d_waitCondition(clockType) { ATOMIC_OP::initInt64(&d_state, k_AVAILABLE_INC * count); } // MANIPULATORS template <class ATOMIC_OP, class MUTEX, class CONDITION, class THREADUTIL> void FastPostSemaphoreImpl<ATOMIC_OP, MUTEX, CONDITION, THREADUTIL>::disable() { Int64 state = ATOMIC_OP::getInt64Acquire(&d_state); while (false == isDisabled(state)) { const Int64 expState = state; // increment, without overflowing, the disabled attribute Int64 newState = (state & ~k_DISABLED_GEN_MASK) | ((state + k_DISABLED_GEN_INC) & k_DISABLED_GEN_MASK); state = ATOMIC_OP::testAndSwapInt64AcqRel(&d_state, state, newState); if (expState == state) { state = newState; // note that 'd_waitMutex' must be acquired to ensure a thread in a // wait operation either "sees" the change in state before // determining whether to block using 'd_waitCondition', or has // blocked and will receive a signal sent to 'd_waitCondition' { LockGuard<MUTEX> guard(&d_waitMutex); } d_waitCondition.broadcast(); } } // When threads blocked on 'd_waitCondition' are signalled, they must // prefer consuming available resources and returning success over // returning 'e_DISABLED'. This ensures the signalled thread obtains the // resource when another thread issues a post followed by a disablement // (see DRQS 153332608). Similarly, to ensure a disablement followed by a // post method does not provide a resource to the signalled thread, // 'disable' must wait until no threads will block before returning. Note // that the semaphore may be re-enabled (and re-disabled) during this wait. while (isDisabled(state) && willHaveBlockedThread(state)) { THREADUTIL::yield(); state = ATOMIC_OP::getInt64Acquire(&d_state); } } template <class ATOMIC_OP, class MUTEX, class CONDITION, class THREADUTIL> void FastPostSemaphoreImpl<ATOMIC_OP, MUTEX, CONDITION, THREADUTIL>::enable() { Int64 state = ATOMIC_OP::getInt64Acquire(&d_state); while (isDisabled(state)) { // When this semaphore is disabled, an 'enable' followed by a post // method must not provide a resource to a signalled thread that should // return 'e_DISABLED' (see note in 'disable'). Hence, wait until no // threads will block before performing the enablement. if (willHaveBlockedThread(state)) { THREADUTIL::yield(); state = ATOMIC_OP::getInt64Acquire(&d_state); } else { const Int64 expState = state; // increment, without overflowing, the disabled attribute Int64 newState = (state & ~k_DISABLED_GEN_MASK) | ((state + k_DISABLED_GEN_INC) & k_DISABLED_GEN_MASK); state = ATOMIC_OP::testAndSwapInt64AcqRel(&d_state, state, newState); if (expState == state) { state = newState; } } } } template <class ATOMIC_OP, class MUTEX, class CONDITION, class THREADUTIL> inline void FastPostSemaphoreImpl<ATOMIC_OP, MUTEX, CONDITION, THREADUTIL>::post() { Int64 state = ATOMIC_OP::addInt64NvAcqRel(&d_state, k_AVAILABLE_INC); // signal only when 'state' indicates there are no other threads that can // unblock blocked threads if ( k_AVAILABLE_INC == (state & k_AVAILABLE_MASK) && !isDisabled(state) && hasBlockedThread(state)) { // note that 'd_waitMutex' must be acquired to ensure a thread in a // wait operation either "sees" the change in state before determining // whether to block using 'd_waitCondition', or has blocked and will // receive a signal sent to 'd_waitCondition' { LockGuard<MUTEX> guard(&d_waitMutex); } d_waitCondition.signal(); } } template <class ATOMIC_OP, class MUTEX, class CONDITION, class THREADUTIL> inline void FastPostSemaphoreImpl<ATOMIC_OP, MUTEX, CONDITION, THREADUTIL> ::post(int value) { Int64 v = k_AVAILABLE_INC * value; Int64 state = ATOMIC_OP::addInt64NvAcqRel(&d_state, v); // signal only when 'state' indicates there are no other threads that can // unblock blocked threads if ( v == (state & k_AVAILABLE_MASK) && !isDisabled(state) && hasBlockedThread(state)) { // note that 'd_waitMutex' must be acquired to ensure a thread in a // wait operation either "sees" the change in state before determining // whether to block using 'd_waitCondition', or has blocked and will // receive a signal sent to 'd_waitCondition' { LockGuard<MUTEX> guard(&d_waitMutex); } d_waitCondition.signal(); } } template <class ATOMIC_OP, class MUTEX, class CONDITION, class THREADUTIL> inline int FastPostSemaphoreImpl<ATOMIC_OP, MUTEX, CONDITION, THREADUTIL> ::take(int maximumToTake) { Int64 state = ATOMIC_OP::getInt64Acquire(&d_state); Int64 expState; Int64 count; do { // remove all available up to 'maximumToTake' expState = state; count = getValueRaw(state); if (0 >= count) { return 0; // RETURN } if (maximumToTake < count) { count = maximumToTake; } state = ATOMIC_OP::testAndSwapInt64AcqRel( &d_state, state, state - k_AVAILABLE_INC * count); } while (state != expState); return static_cast<int>(count); } template <class ATOMIC_OP, class MUTEX, class CONDITION, class THREADUTIL> inline int FastPostSemaphoreImpl<ATOMIC_OP, MUTEX, CONDITION, THREADUTIL>::takeAll() { return take(INT_MAX); } template <class ATOMIC_OP, class MUTEX, class CONDITION, class THREADUTIL> inline int FastPostSemaphoreImpl<ATOMIC_OP, MUTEX, CONDITION, THREADUTIL> ::timedWait(const bsls::TimeInterval& absTime) { Int64 state = ATOMIC_OP::addInt64NvAcqRel(&d_state, -k_AVAILABLE_INC); if (isDisabled(state)) { post(); return e_DISABLED; // RETURN } if (willHaveBlockedThread(state)) { return timedWaitSlowPath(absTime, state); // RETURN } return 0; } template <class ATOMIC_OP, class MUTEX, class CONDITION, class THREADUTIL> inline int FastPostSemaphoreImpl<ATOMIC_OP, MUTEX, CONDITION, THREADUTIL>::tryWait() { Int64 state = ATOMIC_OP::addInt64NvAcqRel(&d_state, -k_AVAILABLE_INC); if (isDisabled(state)) { post(); return e_DISABLED; // RETURN } if (willHaveBlockedThread(state)) { post(); return e_WOULD_BLOCK; // RETURN } return 0; } template <class ATOMIC_OP, class MUTEX, class CONDITION, class THREADUTIL> inline int FastPostSemaphoreImpl<ATOMIC_OP, MUTEX, CONDITION, THREADUTIL>::wait() { Int64 state = ATOMIC_OP::addInt64NvAcqRel(&d_state, -k_AVAILABLE_INC); if (isDisabled(state)) { post(); return e_DISABLED; // RETURN } if (willHaveBlockedThread(state)) { return waitSlowPath(state); // RETURN } return 0; } // ACCESSORS template <class ATOMIC_OP, class MUTEX, class CONDITION, class THREADUTIL> inline bsls::SystemClockType::Enum FastPostSemaphoreImpl<ATOMIC_OP, MUTEX, CONDITION, THREADUTIL> ::clockType() const { return d_waitCondition.clockType(); } template <class ATOMIC_OP, class MUTEX, class CONDITION, class THREADUTIL> inline int FastPostSemaphoreImpl<ATOMIC_OP, MUTEX, CONDITION, THREADUTIL> ::getDisabledState() const { Int64 state = ATOMIC_OP::getInt64Acquire(&d_state); return static_cast<int>((state & k_DISABLED_GEN_MASK) >> k_DISABLED_GEN_SHIFT); } template <class ATOMIC_OP, class MUTEX, class CONDITION, class THREADUTIL> inline int FastPostSemaphoreImpl<ATOMIC_OP, MUTEX, CONDITION, THREADUTIL> ::getValue() const { Int64 count = getValueRaw(ATOMIC_OP::getInt64Acquire(&d_state)); return static_cast<int>(count > 0 ? count : 0); } template <class ATOMIC_OP, class MUTEX, class CONDITION, class THREADUTIL> inline bool FastPostSemaphoreImpl<ATOMIC_OP, MUTEX, CONDITION, THREADUTIL> ::isDisabled() const { Int64 state = ATOMIC_OP::getInt64Acquire(&d_state); return isDisabled(state); } } // close package namespace } // close enterprise namespace #endif // ---------------------------------------------------------------------------- // Copyright 2020 Bloomberg Finance L.P. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ----------------------------- END-OF-FILE ----------------------------------