OW_Condition.cpp

Go to the documentation of this file.
00001 /*******************************************************************************
00002 * Copyright (C) 2001-2004 Vintela, Inc. All rights reserved.
00003 *
00004 * Redistribution and use in source and binary forms, with or without
00005 * modification, are permitted provided that the following conditions are met:
00006 *
00007 *  - Redistributions of source code must retain the above copyright notice,
00008 *    this list of conditions and the following disclaimer.
00009 *
00010 *  - Redistributions in binary form must reproduce the above copyright notice,
00011 *    this list of conditions and the following disclaimer in the documentation
00012 *    and/or other materials provided with the distribution.
00013 *
00014 *  - Neither the name of Vintela, Inc. nor the names of its
00015 *    contributors may be used to endorse or promote products derived from this
00016 *    software without specific prior written permission.
00017 *
00018 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
00019 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00020 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00021 * ARE DISCLAIMED. IN NO EVENT SHALL Vintela, Inc. OR THE CONTRIBUTORS
00022 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00023 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00024 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00025 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00026 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00027 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00028 * POSSIBILITY OF SUCH DAMAGE.
00029 *******************************************************************************/
00030 
00034 #include "OW_config.h"
00035 #include "OW_Condition.hpp"
00036 #include "OW_NonRecursiveMutexLock.hpp"
00037 #include "OW_ExceptionIds.hpp"
00038 
00039 #include <cassert>
00040 #include <cerrno>
00041 #ifdef OW_HAVE_SYS_TIME_H
00042 #include <sys/time.h>
00043 #endif
00044 
00045 namespace OW_NAMESPACE
00046 {
00047 
00048 OW_DEFINE_EXCEPTION_WITH_ID(ConditionLock);
00049 OW_DEFINE_EXCEPTION_WITH_ID(ConditionResource);
00050 #if defined(OW_USE_PTHREAD)
00051 
00052 Condition::Condition()
00053 {
00054    int res = pthread_cond_init(&m_condition, 0);
00055    if (res != 0)
00056    {
00057       OW_THROW(ConditionResourceException, "Failed initializing condition variable");
00058    }
00059 }
00061 Condition::~Condition()
00062 {
00063    int res = pthread_cond_destroy(&m_condition);
00064    assert(res == 0);
00065 }
00067 void
00068 Condition::notifyOne()
00069 {
00070    int res = pthread_cond_signal(&m_condition);
00071    assert(res == 0);
00072 }
00074 void
00075 Condition::notifyAll()
00076 {
00077    int res = pthread_cond_broadcast(&m_condition);
00078    assert(res == 0);
00079 }
00081 void
00082 Condition::doWait(NonRecursiveMutex& mutex)
00083 {
00084    int res;
00085    NonRecursiveMutexLockState state;
00086    mutex.conditionPreWait(state);
00087    res = pthread_cond_wait(&m_condition, state.pmutex);
00088    mutex.conditionPostWait(state);
00089    assert(res == 0);
00090 }
00092 bool
00093 Condition::doTimedWait(NonRecursiveMutex& mutex, UInt32 sTimeout, UInt32 usTimeout)
00094 {
00095    int res;
00096    NonRecursiveMutexLockState state;
00097    mutex.conditionPreWait(state);
00098    bool ret = false;
00099    timespec ts;
00100    struct timeval now;
00101    ::gettimeofday(&now, NULL);
00102    
00103    ts.tv_sec = now.tv_sec + sTimeout;
00104 
00105    const int NANOSECONDS_PER_MICROSECOND = 1000;
00106    const int NANOSECONDS_PER_SECOND = 1000000000;
00107    int nsec = (now.tv_usec + usTimeout) * NANOSECONDS_PER_MICROSECOND;
00108    ts.tv_sec += nsec / NANOSECONDS_PER_SECOND;
00109    ts.tv_nsec = nsec % NANOSECONDS_PER_SECOND;
00110 
00111    res = pthread_cond_timedwait(&m_condition, state.pmutex, &ts);
00112    mutex.conditionPostWait(state);
00113    assert(res == 0 || res == ETIMEDOUT);
00114    ret = res != ETIMEDOUT;
00115    return ret;
00116 }
00117 #elif defined (OW_WIN32)
00118 
00119 Condition::Condition()
00120    : m_condition(new ConditionInfo_t)
00121 {
00122    m_condition->waitersCount = 0;
00123    m_condition->wasBroadcast = false;
00124    m_condition->queue = ::CreateSemaphore(
00125       NULL,    // No security
00126       0,       // initially 0
00127       0x7fffffff, // max count
00128       NULL);      // Unnamed
00129    ::InitializeCriticalSection(&m_condition->waitersCountLock);
00130    m_condition->waitersDone = ::CreateEvent(
00131       NULL,    // No security
00132       false,      // auto-reset
00133       false,      // non-signaled initially
00134       NULL);      // Unnamed
00135 }
00137 Condition::~Condition()
00138 {
00139    ::CloseHandle(m_condition->queue);
00140    ::DeleteCriticalSection(&m_condition->waitersCountLock);
00141    ::CloseHandle(m_condition->waitersDone);
00142    delete m_condition;
00143 }
00145 void
00146 Condition::notifyOne()
00147 {
00148    ::EnterCriticalSection(&m_condition->waitersCountLock);
00149    bool haveWaiters = m_condition->waitersCount > 0;
00150    ::LeaveCriticalSection(&m_condition->waitersCountLock);
00151 
00152    // If no threads waiting, then this is a no-op
00153    if (haveWaiters)
00154    {
00155       ::ReleaseSemaphore(m_condition->queue, 1, 0);
00156    }
00157 }
00159 void
00160 Condition::notifyAll()
00161 {
00162    ::EnterCriticalSection(&m_condition->waitersCountLock);
00163    bool haveWaiters = false;
00164    if (m_condition->waitersCount > 0)
00165    {
00166       // It's gonna be a broadcast, even if there's only one waiting thread.
00167       haveWaiters = m_condition->wasBroadcast = true;
00168    }
00169 
00170    if (haveWaiters)
00171    {
00172       // Wake up all the waiting threads atomically
00173       ::ReleaseSemaphore(m_condition->queue, m_condition->waitersCount, 0);
00174       ::LeaveCriticalSection(&m_condition->waitersCountLock);
00175 
00176       // Wait for all the threads to acquire the counting semaphore
00177       ::WaitForSingleObject(m_condition->waitersDone, INFINITE);
00178       m_condition->wasBroadcast = false;
00179    }
00180    else
00181    {
00182       ::LeaveCriticalSection(&m_condition->waitersCountLock);
00183    }
00184 }
00186 void
00187 Condition::doWait(NonRecursiveMutex& mutex)
00188 {
00189    doTimedWait(mutex, INFINITE, 0);
00190 }
00192 bool
00193 Condition::doTimedWait(NonRecursiveMutex& mutex, UInt32 sTimeout, UInt32 usTimeout)
00194 {
00195    bool cc = true;
00196    NonRecursiveMutexLockState state;
00197    mutex.conditionPreWait(state);
00198 
00199    ::EnterCriticalSection(&m_condition->waitersCountLock);
00200    m_condition->waitersCount++;
00201    ::LeaveCriticalSection(&m_condition->waitersCountLock);
00202 
00203    // Calc timeout if specified
00204    if (sTimeout != INFINITE)
00205    {
00206       sTimeout *= 1000;    // Convert to ms
00207       sTimeout += usTimeout / 1000;    // Convert micro seconds to ms and add
00208    }
00209 
00210    // Atomically release the mutex and wait on the
00211    // queue until signal/broadcast.
00212    if (::SignalObjectAndWait(mutex.m_mutex, m_condition->queue, sTimeout,
00213       false) == WAIT_TIMEOUT)
00214    {
00215       cc = false;
00216    }
00217 
00218    ::EnterCriticalSection(&m_condition->waitersCountLock);
00219    m_condition->waitersCount--;
00220 
00221    // Check to see if we're the last waiter after the broadcast
00222    bool isLastWaiter = (m_condition->wasBroadcast && m_condition->waitersCount == 0
00223       && cc == true);
00224 
00225    ::LeaveCriticalSection(&m_condition->waitersCountLock);
00226 
00227    // If this is the last thread waiting for this broadcast, then let all the
00228    // other threads proceed.
00229    if (isLastWaiter)
00230    {
00231       // Atomically signal the waitersDone event and wait to acquire
00232       // the external mutex. Enusres fairness
00233       ::SignalObjectAndWait(m_condition->waitersDone, mutex.m_mutex,
00234          INFINITE, false);
00235    }
00236    else
00237    {
00238       // Re-gain ownership of the external mutex
00239       ::WaitForSingleObject(mutex.m_mutex, INFINITE);
00240    }
00241    mutex.conditionPostWait(state);
00242    return cc;
00243 }
00244 #else
00245 #error "port me!"
00246 #endif
00247 
00248 void
00249 Condition::wait(NonRecursiveMutexLock& lock)
00250 {
00251    if (!lock.isLocked())
00252    {
00253       OW_THROW(ConditionLockException, "Lock must be locked");
00254    }
00255    doWait(*(lock.m_mutex));
00256 }
00258 bool
00259 Condition::timedWait(NonRecursiveMutexLock& lock, UInt32 sTimeout, UInt32 usTimeout)
00260 {
00261    if (!lock.isLocked())
00262    {
00263       OW_THROW(ConditionLockException, "Lock must be locked");
00264    }
00265    return doTimedWait(*(lock.m_mutex), sTimeout, usTimeout);
00266 }
00267 
00268 } // end namespace OW_NAMESPACE
00269 

Generated on Thu Feb 9 08:47:56 2006 for openwbem by  doxygen 1.4.6