(file) Return to ReadWriteSem.cpp CVS log (file) (dir) Up to [Pegasus] / pegasus / src / Pegasus / Common

Diff for /pegasus/src/Pegasus/Common/ReadWriteSem.cpp between version 1.1.2.11 and 1.15.8.1

version 1.1.2.11, 2006/07/29 01:18:27 version 1.15.8.1, 2013/06/03 22:35:13
Line 1 
Line 1 
 //%2006////////////////////////////////////////////////////////////////////////  //%LICENSE////////////////////////////////////////////////////////////////
 // //
 // Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development  // Licensed to The Open Group (TOG) under one or more contributor license
 // Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems.  // agreements.  Refer to the OpenPegasusNOTICE.txt file distributed with
 // Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L.P.;  // this work for additional information regarding copyright ownership.
 // IBM Corp.; EMC Corporation, The Open Group.  // Each contributor licenses this file to you under the OpenPegasus Open
 // Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.;  // Source License; you may not use this file except in compliance with the
 // IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group.  // License.
 // Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.;  //
 // EMC Corporation; VERITAS Software Corporation; The Open Group.  // Permission is hereby granted, free of charge, to any person obtaining a
 // Copyright (c) 2006 Hewlett-Packard Development Company, L.P.; IBM Corp.;  // copy of this software and associated documentation files (the "Software"),
 // EMC Corporation; Symantec Corporation; The Open Group.  // to deal in the Software without restriction, including without limitation
   // the rights to use, copy, modify, merge, publish, distribute, sublicense,
   // and/or sell copies of the Software, and to permit persons to whom the
   // Software is furnished to do so, subject to the following conditions:
   //
   // The above copyright notice and this permission notice shall be included
   // in all copies or substantial portions of the Software.
   //
   // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
   // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
   // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
   // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
   // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
   // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 // //
 // Permission is hereby granted, free of charge, to any person obtaining a copy  //////////////////////////////////////////////////////////////////////////
 // of this software and associated documentation files (the "Software"), to  
 // deal in the Software without restriction, including without limitation the  
 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or  
 // sell copies of the Software, and to permit persons to whom the Software is  
 // furnished to do so, subject to the following conditions:  
 //  
 // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN  
 // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED  
 // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT  
 // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR  
 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT  
 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN  
 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION  
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  
 //  
 //==============================================================================  
 //  
 // Author: Mike Day (mdday@us.ibm.com)  
 //  
 // Reworked By: Mike Brasher (m.brasher@inovadevelopment.com)  
 // //
 //%///////////////////////////////////////////////////////////////////////////// //%/////////////////////////////////////////////////////////////////////////////
  
Line 39 
Line 33 
 #include "Time.h" #include "Time.h"
 #include "PegasusAssert.h" #include "PegasusAssert.h"
 #include "Threads.h" #include "Threads.h"
   #include "Exception.h"
   #include "System.h"
  
 PEGASUS_NAMESPACE_BEGIN PEGASUS_NAMESPACE_BEGIN
  
Line 50 
Line 46 
  
 #ifdef PEGASUS_USE_POSIX_RWLOCK #ifdef PEGASUS_USE_POSIX_RWLOCK
  
 ReadWriteSem::ReadWriteSem():_readers(0), _writers(0)  ReadWriteSem::ReadWriteSem()
 { {
     pthread_rwlock_init(&_rwlock.rwlock, NULL);     pthread_rwlock_init(&_rwlock.rwlock, NULL);
     Threads::clear(_rwlock.owner);  
 } }
  
 ReadWriteSem::~ReadWriteSem() ReadWriteSem::~ReadWriteSem()
 { {
       int r = 0;
     while (EBUSY == pthread_rwlock_destroy(&_rwlock.rwlock))      while ((r = pthread_rwlock_destroy(&_rwlock.rwlock)) == EBUSY ||
              (r == -1 && errno == EBUSY))
     {     {
         Threads::yield();         Threads::yield();
     }     }
 } }
  
 void ReadWriteSem::wait(Uint32 mode, ThreadType caller)  void ReadWriteSem::waitRead()
 {  
     int errorcode;  
     if (mode == PEG_SEM_READ)  
     {  
         if (0 == (errorcode = pthread_rwlock_rdlock(&_rwlock.rwlock)))  
         {  
             _readers++;  
             return;  
         }  
     }  
     else if (mode == PEG_SEM_WRITE)  
     {     {
         if (0 == (errorcode = pthread_rwlock_wrlock(&_rwlock.rwlock)))      int r = pthread_rwlock_rdlock(&_rwlock.rwlock);
         {  
             _rwlock.owner = caller;  
             _writers++;  
             return;  
         }  
     }  
     else  
         throw(Permission(Threads::self()));  
   
     if (errorcode == EDEADLK)  
         throw(Deadlock(_rwlock.owner));  
     else  
         throw(WaitFailed(Threads::self()));  
 }  
  
 void ReadWriteSem::try_wait(Uint32 mode, ThreadType caller)      if (r != 0)
 {  
     int errorcode = 0;  
     if (mode == PEG_SEM_READ)  
     {  
         if (0 == (errorcode = pthread_rwlock_tryrdlock(&_rwlock.rwlock)))  
         {  
             _readers++;  
             return;  
         }  
     }  
     else if (mode == PEG_SEM_WRITE)  
     {     {
         if (0 == (errorcode = pthread_rwlock_trywrlock(&_rwlock.rwlock)))          if (r != -1)
         {         {
             _writers++;              // Special behavior for Single UNIX Specification, Version 3
             _rwlock.owner = caller;              errno = r;
             return;  
         }         }
     }  
     else  
         throw(Permission(Threads::self()));  
   
     if (errorcode == EBUSY)  
         throw(AlreadyLocked(_rwlock.owner));  
     else if (errorcode == EDEADLK)  
         throw(Deadlock(_rwlock.owner));  
     else  
         throw(WaitFailed(Threads::self()));  
 }  
   
   
 // timedrdlock and timedwrlock are not supported on HPUX  
 // mdday Sun Aug  5 14:21:00 2001  
 void ReadWriteSem::timed_wait(Uint32 mode,  
                               ThreadType caller, int milliseconds)  
 {  
     int errorcode = 0, timeout = 0;  
     struct timeval now, finish, remaining;  
     Uint32 usec;  
   
     gettimeofday(&finish, NULL);  
     finish.tv_sec += (milliseconds / 1000);  
     milliseconds %= 1000;  
     usec = finish.tv_usec + (milliseconds * 1000);  
     finish.tv_sec += (usec / 1000000);  
     finish.tv_usec = usec % 1000000;  
  
     if (mode == PEG_SEM_READ)          throw Exception(MessageLoaderParms(
     {              "Common.InternalException.READ_LOCK_FAILED",
         do              "Failed to acquire read lock: $0",
         {              PEGASUS_SYSTEM_ERRORMSG_NLS));
             errorcode = pthread_rwlock_tryrdlock(&_rwlock.rwlock);  
             gettimeofday(&now, NULL);  
         }  
         while (errorcode == EBUSY &&  
                (0 == (timeout = Time::subtract(&remaining, &finish, &now))));  
         if (0 == errorcode)  
         {  
             _readers++;  
             return;  
         }         }
     }     }
     else if (mode == PEG_SEM_WRITE)  
     {  
         do  
         {  
             errorcode = pthread_rwlock_trywrlock(&_rwlock.rwlock);  
             gettimeofday(&now, NULL);  
         }  
         while (errorcode == EBUSY &&  
                (0 == (timeout = Time::subtract(&remaining, &finish, &now))));  
  
         if (0 == errorcode)  void ReadWriteSem::waitWrite()
         {         {
             _writers++;      int r = pthread_rwlock_wrlock(&_rwlock.rwlock);
             _rwlock.owner = caller;  
             return;  
         }  
     }  
     else  
         throw(Permission(Threads::self()));  
     if (timeout != 0)  
         throw(TimeOut(_rwlock.owner));  
     else if (errorcode == EDEADLK)  
         throw(Deadlock(_rwlock.owner));  
     else  
         throw(WaitFailed(Threads::self()));  
 }  
  
 void ReadWriteSem::unlock(Uint32 mode, ThreadType caller)      if (r != 0)
 { {
     ThreadType owner;          if (r != -1)
   
     if (mode == PEG_SEM_WRITE)  
     {     {
         owner = _rwlock.owner;              // Special behavior for Single UNIX Specification, Version 3
         Threads::clear(_rwlock.owner);              errno = r;
     }     }
     if (0 != pthread_rwlock_unlock(&_rwlock.rwlock))  
     {          throw Exception(MessageLoaderParms(
         _rwlock.owner = owner;              "Common.InternalException.WRITE_LOCK_FAILED",
         throw(Permission(Threads::self()));              "Failed to acquire write lock: $0",
               PEGASUS_SYSTEM_ERRORMSG_NLS));
     }     }
     if (mode == PEG_SEM_READ && _readers.get() != 0)  
         _readers--;  
     else if (_writers.get() != 0)  
         _writers--;  
 } }
  
 int ReadWriteSem::read_count() const  void ReadWriteSem::unlockRead()
 { {
     return (_readers.get());      // All documented error codes represent coding errors.
       PEGASUS_FCT_EXECUTE_AND_ASSERT(0, pthread_rwlock_unlock(&_rwlock.rwlock));
 } }
  
 int ReadWriteSem::write_count() const  void ReadWriteSem::unlockWrite()
 { {
     return (_writers.get());      // All documented error codes represent coding errors.
       PEGASUS_FCT_EXECUTE_AND_ASSERT(0, pthread_rwlock_unlock(&_rwlock.rwlock));
 } }
  
 #endif /* PEGASUS_USE_POSIX_RWLOCK */ #endif /* PEGASUS_USE_POSIX_RWLOCK */
Line 229 
Line 126 
 // 2) I do not hold the write lock // 2) I do not hold the write lock
 // 3) I am not using a reader slot // 3) I am not using a reader slot
  
 #if 0  ReadWriteSem::ReadWriteSem() : _rwlock()
 void extricate_read_write(void *parm)  
 {  
     ReadWriteSem *rws = (ReadWriteSem *) parm;  
     ThreadType myself = Threads::self();  
   
     if (Threads::equal(rws->_rwlock._wlock.get_owner(), myself))  
         rws->_rwlock._wlock.unlock();  
     else if (rws->_readers.get() > 0)  
         rws->_rwlock._rlock.signal();  
   
     if (Threads::equal(rws->_rwlock._internal_lock.get_owner(), myself))  
         rws->_rwlock._internal_lock.unlock();  
 }  
 #endif  
   
   
 ReadWriteSem::ReadWriteSem():_readers(0), _writers(0), _rwlock()  
 { {
 } }
  
Line 257 
Line 137 
     {     {
         _rwlock._internal_lock.lock();         _rwlock._internal_lock.lock();
     }     }
     catch(Deadlock & d)      catch (...)
     {  
         d = d;                  // no problem - we own the lock, which is  
                                 // what we want  
     }  
     catch(IPCException &)  
     {     {
         PEGASUS_ASSERT(0);         PEGASUS_ASSERT(0);
     }     }
     while (_readers.get() > 0 || _writers.get() > 0)      while (_rwlock._readers.get() > 0 || _rwlock._writers.get() > 0)
     {  
         Threads::yield();  
     }  
     _rwlock._internal_lock.unlock();  
 }  
   
   
   
   
   
   
 //-----------------------------------------------------------------  
 // if milliseconds == -1, wait indefinately  
 // if milliseconds == 0, fast wait  
 //-----------------------------------------------------------------  
 void ReadWriteSem::timed_wait(Uint32 mode, ThreadType caller,  
                               int milliseconds)  
 {  
 //-----------------------------------------------------------------  
 // Lock this object to maintain integrity while we decide  
 // exactly what to do next.  
 //-----------------------------------------------------------------  
     // AutoPtr<IPCException> caught;  
     // IPCException caught((ThreadType)0);  
     // WaitFailed caughtWaitFailed((ThreadType)0);  
     // TimeOut caughtTimeOut((ThreadType)0);  
     // TooManyReaders caughtTooManyReaders((ThreadType)0);  
   
     ThreadType zero;  
     IPCException caught(zero);  
     WaitFailed caughtWaitFailed(zero);  
     TimeOut caughtTimeOut(zero);  
     TooManyReaders caughtTooManyReaders(zero);  
   
     // cleanup stack frame  
     {  
         // Threads::cleanup_push(extricate_read_write, this);  
   
         try  
         {  
             if (milliseconds == 0)  
                 _rwlock._internal_lock.try_lock();  
             else if (milliseconds == -1)  
                 _rwlock._internal_lock.lock();  
             else  
                 _rwlock._internal_lock.timed_lock(milliseconds);  
         }  
         catch(const IPCException & e)  
         {  
             caught = e;  
             goto throw_from_here;  
         }  
   
         if (mode == PEG_SEM_WRITE)  
         {  
 //-----------------------------------------------------------------  
 // Write Lock Step 1: lock the object and allow all the readers to exit  
 //-----------------------------------------------------------------  
   
   
             if (milliseconds == 0)      // fast wait  
             {  
                 if (_readers.get() > 0)  
                 {  
                     _rwlock._internal_lock.unlock();  
                     // caught.reset(new WaitFailed(Threads::self()));  
                     caughtWaitFailed = WaitFailed(Threads::self());  
                     goto throw_from_here;  
                 }  
             }  
             else if (milliseconds == -1)        // infinite wait  
             {  
                 while (_readers.get() > 0)  
                     Threads::yield();  
             }  
             else                // timed wait  
             {             {
                 struct timeval start, now;  
                 Time::gettimeofday(&start);  
                 start.tv_usec += (1000 * milliseconds);  
                 while (_readers.get() > 0)  
                 {  
                     Time::gettimeofday(&now);  
                     if ((now.tv_usec > start.tv_usec) ||  
                         now.tv_sec > start.tv_sec)  
                     {  
                         _rwlock._internal_lock.unlock();  
                         // caught.reset(new TimeOut(Threads::self()));  
                         caughtTimeOut = TimeOut(Threads::self());  
                         goto throw_from_here;  
                     }  
                     Threads::yield();                     Threads::yield();
                 }                 }
             }  
 //-----------------------------------------------------------------  
 // Write Lock Step 2: Obtain the Write Mutex  
 //  Although there are no readers, there may be a writer  
 //-----------------------------------------------------------------  
             if (milliseconds == 0)      // fast wait  
             {  
                 try  
                 {  
                     _rwlock._wlock.try_lock();  
                 }  
                 catch(IPCException & e)  
                 {  
                     _rwlock._internal_lock.unlock();                     _rwlock._internal_lock.unlock();
                     caught = e;  
                     goto throw_from_here;  
                 }  
             }  
             else if (milliseconds == -1)        // infinite wait  
             {  
                 try  
                 {  
                     _rwlock._wlock.lock();  
                 }  
                 catch(const IPCException & e)  
                 {  
                     _rwlock._internal_lock.unlock();  
                     caught = e;  
                     goto throw_from_here;  
                 }  
             }  
             else                // timed wait  
             {  
                 try  
                 {  
                     _rwlock._wlock.timed_lock(milliseconds);  
                 }  
                 catch(const IPCException & e)  
                 {  
                     _rwlock._internal_lock.unlock();  
                     caught = e;  
                     goto throw_from_here;  
                 }  
             }             }
  
 //-----------------------------------------------------------------  void ReadWriteSem::waitRead()
 // Write Lock Step 3: set the writer count to one, unlock the object  
 //   There are no readers and we are the only writer !  
 //-----------------------------------------------------------------  
             _writers = 1;  
             // set the owner  
             _rwlock._owner = Threads::self();  
             // unlock the object  
             _rwlock._internal_lock.unlock();  
         }                       // PEG_SEM_WRITE  
         else  
         {  
 //-----------------------------------------------------------------  
 // Read Lock Step 1: Wait for the existing writer (if any) to clear  
 //-----------------------------------------------------------------  
             if (milliseconds == 0)      // fast wait  
             {  
                 if (_writers.get() > 0)  
                 {  
                     _rwlock._internal_lock.unlock();  
                     // caught.reset(new WaitFailed(Threads::self()));  
                     caughtWaitFailed = WaitFailed(Threads::self());  
                     goto throw_from_here;  
                 }  
             }  
             else if (milliseconds == -1)        // infinite wait  
             {  
                 while (_writers.get() > 0)  
                     Threads::yield();  
             }  
             else                // timed wait  
             {             {
                 struct timeval start, now;      // Lock the internal mutex to ensure only one waiter is processed at a time.
                 Time::gettimeofday(&start);      AutoMutex lock(_rwlock._internal_lock);
                 start.tv_usec += (milliseconds * 1000);  
  
                 while (_writers.get() > 0)      // Wait for the existing writer (if any) to clear.
                 {      while (_rwlock._writers.get() > 0)
                     Time::gettimeofday(&now);  
                     if ((now.tv_usec > start.tv_usec) ||  
                         (now.tv_sec > start.tv_sec))  
                     {                     {
                         _rwlock._internal_lock.unlock();  
                         // caught.reset(new TimeOut(Threads::self()));  
                         caughtTimeOut = TimeOut(Threads::self());  
                         goto throw_from_here;  
                     }  
                     Threads::yield();                     Threads::yield();
                     Time::gettimeofday(&now);  
                 }  
             }             }
  
 //-----------------------------------------------------------------      // Wait for a reader slot to open up.
 // Read Lock Step 2: wait for a reader slot to open up, then return  
 //  At this point there are no writers, but there may be too many  
 //  readers.  
 //-----------------------------------------------------------------  
             if (milliseconds == 0)      // fast wait  
             {  
                 try  
                 {  
                     _rwlock._rlock.try_wait();  
                 }  
                 catch(const IPCException &)  
                 {  
                     // the wait failed, there must be too many readers  
                     // already.  
                     // unlock the object  
                     caughtTooManyReaders = TooManyReaders(Threads::self());  
                     _rwlock._internal_lock.unlock();  
                     // caught.reset(new TooManyReaders(Threads::self()));  
                 }  
             }  
             else if (milliseconds == -1)        // infinite wait  
             {  
                 try  
                 {  
                     _rwlock._rlock.wait();                     _rwlock._rlock.wait();
                 }  
                 catch(const IPCException & e)  
                 {  
                     _rwlock._internal_lock.unlock();  
                     caught = e;  
                     goto throw_from_here;  
                 }  
             }  
             else                // timed wait  
             {  
                 try  
                 {  
                     _rwlock._rlock.time_wait(milliseconds);  
                 }  
                 catch(const IPCException & e)  
                 {  
                     _rwlock._internal_lock.unlock();  
                     caught = e;  
                     goto throw_from_here;  
                 }  
             }  
   
 //-----------------------------------------------------------------  
 // Read Lock Step 3: increment the number of readers, unlock the object,  
 // return  
 //-----------------------------------------------------------------  
             _readers++;  
             _rwlock._internal_lock.unlock();  
         }  
       throw_from_here:  
         // ATTN:  
         Threads::cleanup_pop(0);  
     }  
  
     if (Threads::id(caught.get_owner()) != 0)      // Increment the number of readers.
         throw caught;      _rwlock._readers++;
     if (Threads::id(caughtWaitFailed.get_owner()) != 0)  
         throw caughtWaitFailed;  
     if (Threads::id(caughtTimeOut.get_owner()) != 0)  
         throw caughtTimeOut;  
     if (Threads::id(caughtTooManyReaders.get_owner()) != 0)  
         throw caughtTooManyReaders;  
     return;  
 } }
  
 //---------------------------------------------------------------------  void ReadWriteSem::waitWrite()
 void ReadWriteSem::wait(Uint32 mode, ThreadType caller)  
 { {
     timed_wait(mode, caller, -1);      // Lock the internal mutex to ensure only one waiter is processed at a time.
 }      AutoMutex lock(_rwlock._internal_lock);
  
 void ReadWriteSem::try_wait(Uint32 mode, ThreadType caller)      // Allow all the readers to exit.
       while (_rwlock._readers.get() > 0)
 { {
     timed_wait(mode, caller, 0);          Threads::yield();
 } }
  
       // Obtain the write mutex.
       _rwlock._wlock.lock();
  
 void ReadWriteSem::unlock(Uint32 mode, ThreadType caller)      // Set the writer count to one.
 {      _rwlock._writers = 1;
     if (mode == PEG_SEM_WRITE && _writers.get() != 0)  
     {  
         _writers = 0;  
         _rwlock._wlock.unlock();  
     }  
     else if (_readers.get() != 0)  
     {  
         _readers--;  
         _rwlock._rlock.signal();  
     }  
 } }
  
 int ReadWriteSem::read_count() const  void ReadWriteSem::unlockRead()
 { {
     return (_readers.get());      PEGASUS_ASSERT(_rwlock._readers.get() > 0);
       _rwlock._readers--;
       _rwlock._rlock.signal();
 } }
  
 int ReadWriteSem::write_count() const  void ReadWriteSem::unlockWrite()
 { {
     return (_writers.get());      PEGASUS_ASSERT(_rwlock._writers.get() == 1);
       _rwlock._writers = 0;
       _rwlock._wlock.unlock();
 } }
  
 #endif /* !PEGASUS_USE_SEMAPHORE_RWLOCK */ #endif /* !PEGASUS_USE_SEMAPHORE_RWLOCK */


Legend:
Removed from v.1.1.2.11  
changed lines
  Added in v.1.15.8.1

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2