Exemple #1
0
bool cond_variable::imp_wait(u32 _old, u64 _timeout) noexcept
{
	verify(HERE), _old != -1; // Very unlikely: it requires 2^32 distinct threads to wait simultaneously

#ifdef _WIN32
	LARGE_INTEGER timeout;
	timeout.QuadPart = _timeout * -10;

	if (HRESULT rc = NtWaitForKeyedEvent(nullptr, &m_value, false, _timeout == -1 ? nullptr : &timeout))
	{
		verify(HERE), rc == WAIT_TIMEOUT;

		// Retire
		if (!m_value.fetch_op([](u32& value) { if (value) value--; }))
		{
			NtWaitForKeyedEvent(nullptr, &m_value, false, nullptr);
			return true;
		}

		return false;
	}

	return true;
#elif __linux__
	timespec timeout;
	timeout.tv_sec  = _timeout / 1000000;
	timeout.tv_nsec = (_timeout % 1000000) * 1000;

	for (u32 value = _old + 1;; value = m_value)
	{
		const int err = futex((int*)&m_value.raw(), FUTEX_WAIT_PRIVATE, value, _timeout == -1 ? nullptr : &timeout, nullptr, 0) == 0
			? 0
			: errno;

		// Normal or timeout wakeup
		if (!err || (_timeout != -1 && err == ETIMEDOUT))
		{
			// Cleanup (remove waiter)
			verify(HERE), m_value--;
			return !err;
		}

		// Not a wakeup
		verify(HERE), err == EAGAIN;
	}
#else
	// TODO
	std::this_thread::sleep_for(std::chrono::microseconds(50));
	verify(HERE), m_value--;
	return true;
#endif
}
Exemple #2
0
void shared_mutex::imp_wait()
{
#ifdef _WIN32
	NtWaitForKeyedEvent(nullptr, &m_value, false, nullptr);
#else
	while (true)
	{
		// Load new value, try to acquire c_sig
		auto [value, ok] = m_value.fetch_op([](u32& value)
		{
			if (value >= c_sig)
			{
				value -= c_sig;
				return true;
			}

			return false;
		});

		if (ok)
		{
			return;
		}

		futex(reinterpret_cast<int*>(&m_value.raw()), FUTEX_WAIT_BITSET_PRIVATE, value, nullptr, nullptr, c_sig);
	}
#endif
}
/**
 * Waits for a wait block to be unblocked.
 *
 * \param WaitBlock A wait block.
 * \param Spin TRUE to spin, FALSE to block immediately.
 * \param Timeout A timeout value.
 */
__mayRaise FORCEINLINE NTSTATUS PhpBlockOnQueuedWaitBlock(
    __inout PPH_QUEUED_WAIT_BLOCK WaitBlock,
    __in BOOLEAN Spin,
    __in_opt PLARGE_INTEGER Timeout
    )
{
    NTSTATUS status;
    ULONG i;

    if (Spin)
    {
        PHLIB_INC_STATISTIC(QlBlockSpins);

        for (i = PhQueuedLockSpinCount; i != 0; i--)
        {
            if (!(*(volatile ULONG *)&WaitBlock->Flags & PH_QUEUED_WAITER_SPINNING))
                return STATUS_SUCCESS;

            YieldProcessor();
        }
    }

    if (_interlockedbittestandreset((PLONG)&WaitBlock->Flags, PH_QUEUED_WAITER_SPINNING_SHIFT))
    {
        PHLIB_INC_STATISTIC(QlBlockWaits);

        status = NtWaitForKeyedEvent(
            PhQueuedLockKeyedEventHandle,
            WaitBlock,
            FALSE,
            Timeout
            );

        // If an error occurred (timeout is not an error), raise an exception
        // as it is nearly impossible to recover from this situation.
        if (!NT_SUCCESS(status))
            PhRaiseStatus(status);
    }
    else
    {
        status = STATUS_SUCCESS;
    }

    return status;
}