blob: 64c165b64666c5143eea8f48d5fa14f02080ec48 [file] [log] [blame]
/***************************************************************************
condition.cpp - class Condition
-------------------
begin : 2003/09/29
copyright : (C) 2003 by Michael CATANZARITI
email : mcatan@free.fr
***************************************************************************/
/***************************************************************************
* Copyright (C) The Apache Software Foundation. All rights reserved. *
* *
* This software is published under the terms of the Apache Software *
* License version 1.1, a copy of which has been included with this *
* distribution in the LICENSE.txt file. *
***************************************************************************/
#include <log4cxx/config.h>
#ifdef HAVE_MS_THREAD
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0400 // SignalObjectAndWait
#endif
#include <windows.h>
#endif
#include <log4cxx/helpers/condition.h>
using namespace log4cxx::helpers;
using namespace log4cxx;
Condition::Condition()
{
#ifdef HAVE_PTHREAD
::pthread_cond_init(&condition, 0);
#elif defined(HAVE_MS_THREAD)
waiters = 0;
wasBroadCast = false;
waitersDone = ::CreateEvent(0, FALSE, FALSE, NULL);
#endif
}
Condition::~Condition()
{
#ifdef HAVE_PTHREAD
::pthread_cond_destroy(&condition);
#elif defined(HAVE_MS_THREAD)
::CloseHandle(waitersDone);
#endif
}
void Condition::broadcast()
{
#ifdef HAVE_PTHREAD
::pthread_cond_broadcast(&condition);
#elif defined(HAVE_MS_THREAD)
#endif
}
void Condition::signal()
{
#ifdef HAVE_PTHREAD
::pthread_cond_signal(&condition);
#elif defined(HAVE_MS_THREAD)
// If there aren't any waiters, then this is a no-op. Note that
// this function *must* be called with the <external_mutex> held
// since other wise there is a race condition that can lead to the
// lost wakeup bug... This is needed to ensure that the <waiters>
// value is not in an inconsistent internal state while being
// updated by another thread.
// if (waiters != 0) (atomic comparison)
# if _MSC_VER == 1200 // MSDEV 6
if ((long)InterlockedCompareExchange((void**)&waiters, 0, 0) != 0)
# else
if ((long)InterlockedCompareExchange(&waiters, 0, 0) != 0)
# endif
{
sema.post();
}
#endif
}
void Condition::wait(Mutex& mutex)
{
#ifdef HAVE_PTHREAD
::pthread_cond_wait(&condition, &mutex.mutex);
#elif defined(HAVE_MS_THREAD)
#if _MSC_VER == 1200 // MSDEV 6
::InterlockedIncrement((long *)&waiters);
#else
::InterlockedIncrement(&waiters);
#endif
if (SignalObjectAndWait(mutex.mutex, sema.semaphore, INFINITE, FALSE)
== WAIT_ABANDONED)
{
throw ConditionException();
}
#if _MSC_VER == 1200 // MSDEV 6
long oldWaiters = ::InterlockedDecrement((long*)&waiters);
#else
long oldWaiters = ::InterlockedDecrement(&waiters);
#endif
bool lastWaiter = wasBroadCast && (oldWaiters == 0);
if (lastWaiter)
{
// This call atomically signals the <waiters_done_> event and
// waits until it can acquire the mutex. This is important to
// prevent unfairness.
if (SignalObjectAndWait(waitersDone, mutex.mutex, INFINITE, FALSE)
== WAIT_ABANDONED)
{
throw ConditionException();
}
}
mutex.lock();
#endif
}
void Condition::wait(Mutex& mutex, long timeOut)
{
}