diff --git a/Libraries/LibSync/ConditionVariable.h b/Libraries/LibSync/ConditionVariable.h index 33ae7b6362..94ad90f48b 100644 --- a/Libraries/LibSync/ConditionVariable.h +++ b/Libraries/LibSync/ConditionVariable.h @@ -8,6 +8,7 @@ #pragma once #include +#include #include #include #include @@ -24,7 +25,6 @@ namespace Sync { // A signaling condition variable that wraps over the platform APIs. // On posix it is a wrapper of pthread_cond_*. // On Windows it wraps ConditionVariable -// TODO: Implement timed_wait() template requires Detail::IsIntraprocess && Detail::IsNonRecursive class SYNC_API ConditionVariableBase { @@ -38,6 +38,7 @@ public: // As with pthread APIs, the mutex must be locked or undefined behavior ensues. // Condition variables are allowed spurious wakeups. As such waiting on a condition in a loop is preferred. void wait(); + bool wait_for(AK::Duration const&); ALWAYS_INLINE void wait_while(Function condition) { diff --git a/Libraries/LibSync/ConditionVariablePOSIX.cpp b/Libraries/LibSync/ConditionVariablePOSIX.cpp index bc8c0b4eaa..eecf137ad6 100644 --- a/Libraries/LibSync/ConditionVariablePOSIX.cpp +++ b/Libraries/LibSync/ConditionVariablePOSIX.cpp @@ -5,9 +5,11 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include #include #include #include +#include #include namespace Sync { @@ -47,6 +49,21 @@ void ConditionVariableBase::wait() VERIFY(result == 0); } +template +requires Detail::IsIntraprocess && Detail::IsNonRecursive +bool ConditionVariableBase::wait_for(AK::Duration const& timeout) +{ + if (timeout <= AK::Duration::zero()) + return false; + + auto absolute_timeout = (AK::UnixDateTime::now() + timeout).to_timespec(); + int result = pthread_cond_timedwait(to_impl(m_storage), reinterpret_cast(m_to_wait_on.m_storage), &absolute_timeout); + if (result == ETIMEDOUT) + return false; + VERIFY(result == 0); + return true; +} + template requires Detail::IsIntraprocess && Detail::IsNonRecursive void ConditionVariableBase::signal() diff --git a/Libraries/LibSync/ConditionVariableWindows.cpp b/Libraries/LibSync/ConditionVariableWindows.cpp index ef7d4fc480..29cfa64fba 100644 --- a/Libraries/LibSync/ConditionVariableWindows.cpp +++ b/Libraries/LibSync/ConditionVariableWindows.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -44,6 +45,24 @@ void ConditionVariableBase::wait() } } +template<> +bool ConditionVariableBase::wait_for(AK::Duration const& timeout) +{ + if (timeout <= AK::Duration::zero()) + return false; + + auto timeout_ms = timeout.to_milliseconds(); + VERIFY(timeout_ms >= 0); + auto result = SleepConditionVariableSRW(to_impl(m_storage), reinterpret_cast(m_to_wait_on.m_storage), static_cast(min(timeout_ms, INFINITE - 1)), 0); + if (result) + return true; + auto error = GetLastError(); + if (error == ERROR_TIMEOUT) + return false; + warnln("SleepConditionVariableSRW failed with: {}", Error::from_windows_error(error)); + VERIFY_NOT_REACHED(); +} + template requires Detail::IsIntraprocess && Detail::IsNonRecursive void ConditionVariableBase::signal()