

#include "palConditionVariable.h"
#include "palMutex.h"
#include "palSysMemory.h"
#include "util/lnx/lnxTimeout.h"
#include <errno.h>

namespace Util
{

// =====================================================================================================================
// Atomically releases the given mutex object and goes to sleep on the condition variable.  Once we awake from this
// sleep, reacquire the critical section.  Returns false if the specified number of milliseconds elapse before it is
// awoken.
bool ConditionVariable::Wait(
    Mutex* pMutex,
    uint32 milliseconds)  // Can be set to 0xFFFFFFFF to wait forever.
{
    bool result = false;

    if (pMutex != nullptr)
    {
        Mutex::MutexData*const pOsMutex  = pMutex->GetMutexData();
        pthread_cond_t*const   pOsCndVar = &m_osCondVariable;

        constexpr uint32 Infinite = 0xFFFFFFFF;
        if (milliseconds == Infinite)
        {
            // Wait on the condition variable indefinitely.
            const int32 ret = pthread_cond_wait(pOsCndVar, pOsMutex);
            PAL_ASSERT(ret == 0);

            result = true;
        }
        else
        {
            timespec timeout = {};
            ComputeTimeoutExpiration(&timeout, milliseconds * 1000 * 1000);

            // Wait on the condition variable until a timeout occurs.
            const int32 ret = pthread_cond_timedwait(pOsCndVar, pOsMutex, &timeout);
            PAL_ASSERT((ret == 0) || (ret == ETIMEDOUT));

            result = (ret == 0);
        }
    }

    return result;
}

// =====================================================================================================================
// Wakes up one thread that is waiting on this condition variable.
void ConditionVariable::WakeOne()
{
    const int32 ret = pthread_cond_signal(&m_osCondVariable);
    PAL_ASSERT(ret == 0);
}

// =====================================================================================================================
// Wakes up all threads that are waiting on this condition variable.
void ConditionVariable::WakeAll()
{
    const int32 ret = pthread_cond_broadcast(&m_osCondVariable);
    PAL_ASSERT(ret == 0);
}

} // Util
