void shared_mutex::imp_signal() { #ifdef _WIN32 NtReleaseKeyedEvent(nullptr, &m_value, false, nullptr); #else m_value += c_sig; futex(reinterpret_cast<int*>(&m_value.raw()), FUTEX_WAKE_BITSET_PRIVATE, 1, nullptr, nullptr, c_sig); //futex(reinterpret_cast<int*>(&m_value.raw()), FUTEX_WAKE_BITSET_PRIVATE, c_one, nullptr, nullptr, c_sig - 1); #endif }
void cond_variable::imp_wake(u32 _count) noexcept { #ifdef _WIN32 // Try to subtract required amount of waiters const u32 count = m_value.atomic_op([=](u32& value) { if (value > _count) { value -= _count; return _count; } return std::exchange(value, 0); }); for (u32 i = count; i > 0; i--) { NtReleaseKeyedEvent(nullptr, &m_value, false, nullptr); } #elif __linux__ for (u32 i = _count; i > 0; sched_yield()) { const u32 value = m_value; // Constrain remaining amount with imaginary waiter count if (i > value) { i = value; } if (!value || i == 0) { // Nothing to do return; } if (const int res = futex((int*)&m_value.raw(), FUTEX_WAKE_PRIVATE, i > INT_MAX ? INT_MAX : i, nullptr, nullptr, 0)) { verify(HERE), res >= 0 && res <= i; i -= res; } if (!m_value || i == 0) { // Escape return; } } #endif }
/** * Unblocks a wait block. * * \param WaitBlock A wait block. * * \remarks The wait block is in an undefined state after it is * unblocked. Do not attempt to read any values from it. All relevant * information should be saved before unblocking the wait block. */ __mayRaise FORCEINLINE VOID PhpUnblockQueuedWaitBlock( __inout PPH_QUEUED_WAIT_BLOCK WaitBlock ) { NTSTATUS status; if (!_interlockedbittestandreset((PLONG)&WaitBlock->Flags, PH_QUEUED_WAITER_SPINNING_SHIFT)) { if (!NT_SUCCESS(status = NtReleaseKeyedEvent( PhQueuedLockKeyedEventHandle, WaitBlock, FALSE, NULL ))) PhRaiseStatus(status); } }