OW_RWLocker.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 
00036 #include "OW_config.h"
00037 #include "OW_RWLocker.hpp"
00038 #include "OW_Assertion.hpp"
00039 #include "OW_ThreadImpl.hpp"
00040 #include "OW_TimeoutException.hpp"
00041 #include "OW_ExceptionIds.hpp"
00042 
00043 namespace OW_NAMESPACE
00044 {
00045 
00046 OW_DEFINE_EXCEPTION_WITH_ID(RWLocker);
00048 RWLocker::RWLocker()
00049    : m_waiting_writers()
00050    , m_waiting_readers()
00051    , m_num_waiting_writers(0)
00052    , m_num_waiting_readers(0)
00053    , m_readers_next(0)
00054    , m_guard()
00055    , m_state(0)
00056 {
00057 }
00059 RWLocker::~RWLocker()
00060 {
00061    // ???
00062    //try
00063    //{
00064    // m_cond.notifyAll();
00065    //}
00066    //catch (...)
00067    //{
00068       // don't let exceptions escape
00069    //}
00070 }
00072 void
00073 RWLocker::getReadLock(UInt32 sTimeout, UInt32 usTimeout)
00074 {
00075    NonRecursiveMutexLock l(m_guard);
00076    
00077    // Wait until no exclusive lock is held.
00078    //
00079    // Note:  Scheduling priorities are enforced in the unlock()
00080    //   call.  unlock will wake the proper thread.
00081    // if we will lock, then make sure we won't deadlock
00082    Thread_t tid = ThreadImpl::currentThread();
00083    if (m_state < 0)
00084    {
00085       // see if we already have the write lock
00086       if (ThreadImpl::sameThreads(m_writer, tid))
00087       {
00088          OW_THROW(DeadlockException, "A thread that has a write lock is trying to acquire a read lock.");
00089       }
00090    }
00091    while (m_state < 0)
00092    {
00093       ++m_num_waiting_readers;
00094       //m_waiting_readers.wait(l);
00095       if (!m_waiting_readers.timedWait(l, sTimeout, usTimeout))
00096       {
00097          --m_num_waiting_readers;
00098          OW_THROW(TimeoutException, "Timeout while waiting for read lock.");
00099       }
00100       --m_num_waiting_readers;
00101    }
00102    
00103    // Increase the reader count
00104    m_state++;
00105    m_readers.push_back(tid);
00106 }
00108 void
00109 RWLocker::getWriteLock(UInt32 sTimeout, UInt32 usTimeout)
00110 {
00111    NonRecursiveMutexLock l(m_guard);
00112    // Wait until no exclusive lock is held.
00113    //
00114    // Note:  Scheduling priorities are enforced in the unlock()
00115    //   call.  unlock will wake the proper thread.
00116    // if we will lock, then make sure we won't deadlock
00117    Thread_t tid = ThreadImpl::currentThread();
00118    if (m_state != 0)
00119    {
00120       // see if we already have a read lock
00121       for (size_t i = 0; i < m_readers.size(); ++i)
00122       {
00123          if (ThreadImpl::sameThreads(m_readers[i], tid))
00124          {
00125             OW_THROW(DeadlockException, "A thread that has a read lock is trying to acquire a write lock.");
00126          }
00127       }
00128    }
00129    while (m_state != 0)
00130    {
00131       ++m_num_waiting_writers;
00132       if (!m_waiting_writers.timedWait(l, sTimeout, usTimeout))
00133       {
00134          --m_num_waiting_writers;
00135          OW_THROW(TimeoutException, "Timeout while waiting for write lock.");
00136       }
00137       --m_num_waiting_writers;
00138    }
00139    m_state = -1;
00140    m_writer = tid;
00141 }
00143 void
00144 RWLocker::releaseReadLock()
00145 {
00146    NonRecursiveMutexLock l(m_guard);
00147    if (m_state > 0)        // Release a reader.
00148       --m_state;
00149    else
00150       OW_THROW(RWLockerException, "A writer is releasing a read lock");
00151    if (m_state == 0)
00152    {
00153       doWakeups();
00154    }
00155    Thread_t tid = ThreadImpl::currentThread();
00156    size_t i = 0;
00157    while (i < m_readers.size())
00158    {
00159       if (ThreadImpl::sameThreads(m_readers[i], tid))
00160       {
00161          m_readers.remove(i);
00162       }
00163       else
00164       {
00165          ++i;
00166       }
00167    }
00168 }
00170 void
00171 RWLocker::releaseWriteLock()
00172 {
00173    NonRecursiveMutexLock l(m_guard);
00174    if (m_state == -1)
00175    {
00176       m_state = 0;
00177    }
00178    else
00179    {
00180       OW_THROW(RWLockerException, "A reader is releasing a write lock");
00181    }
00182    // After a writer is unlocked, we are always back in the unlocked state.
00183    //
00184    doWakeups();
00185 }
00187 void
00188 RWLocker::doWakeups()
00189 {
00190    if ( m_num_waiting_writers > 0 && 
00191       m_num_waiting_readers > 0)
00192    {
00193       if (m_readers_next == 1)
00194       {
00195          m_readers_next = 0;
00196          m_waiting_readers.notifyAll();
00197       }
00198       else
00199       {
00200          m_waiting_writers.notifyOne();
00201          m_readers_next = 1;
00202       }
00203    }
00204    else if (m_num_waiting_writers > 0)
00205    {
00206       // Only writers - scheduling doesn't matter
00207       m_waiting_writers.notifyOne();
00208    }
00209    else if (m_num_waiting_readers > 0)
00210    {
00211       // Only readers - scheduling doesn't matter
00212       m_waiting_readers.notifyAll();
00213    }
00214 }
00215 
00216 } // end namespace OW_NAMESPACE
00217 

Generated on Thu Feb 9 08:48:10 2006 for openwbem by  doxygen 1.4.6