| #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); | |
| } |