|  | #include <errno.h> | 
|  | #include <locks.h> | 
|  |  | 
|  | namespace | 
|  | { | 
|  | constexpr uint32_t WaitersBit = 1 << 31; | 
|  | } // namespace | 
|  |  | 
|  | int semaphore_get(Timeout *timeout, CountingSemaphoreState *semaphore) | 
|  | { | 
|  | do | 
|  | { | 
|  | uint32_t value      = semaphore->count.load(); | 
|  | uint32_t count      = value & ~WaitersBit; | 
|  | bool     hasWaiters = value & WaitersBit; | 
|  | // If the count is greater than zero, we should be able to just acquire | 
|  | // a semaphore. | 
|  | if (count > 0) | 
|  | { | 
|  | if (semaphore->count.compare_exchange_strong(value, value - 1)) | 
|  | { | 
|  | return 0; | 
|  | } | 
|  | continue; | 
|  | } | 
|  | // If there are no waiters, mark this as adding one. | 
|  | if (!hasWaiters) | 
|  | { | 
|  | // If we lost a race, retry. | 
|  | if (!semaphore->count.compare_exchange_strong(value, | 
|  | value | WaitersBit)) | 
|  | { | 
|  | continue; | 
|  | } | 
|  | } | 
|  | // If we fail in the futex wait, return the error. | 
|  | if (int ret = semaphore->count.wait(timeout, value | WaitersBit); | 
|  | ret != 0) | 
|  | { | 
|  | return ret; | 
|  | } | 
|  | } while (true); | 
|  | } | 
|  |  | 
|  | int semaphore_put(CountingSemaphoreState *semaphore) | 
|  | { | 
|  | do | 
|  | { | 
|  | uint32_t value      = semaphore->count.load(); | 
|  | uint32_t count      = value & ~WaitersBit; | 
|  | bool     hasWaiters = value & WaitersBit; | 
|  | if (count == semaphore->maxCount) | 
|  | { | 
|  | return -EINVAL; | 
|  | } | 
|  | if (semaphore->count.compare_exchange_strong(value, count + 1)) | 
|  | { | 
|  | // If there were waiters, wake them. | 
|  | if (hasWaiters) | 
|  | { | 
|  | semaphore->count.notify_all(); | 
|  | } | 
|  | return 0; | 
|  | } | 
|  | } while (true); | 
|  | } |