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

  1 mike  1.1.2.1 //%2006////////////////////////////////////////////////////////////////////////
  2               //
  3               // Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development
  4               // Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems.
  5               // Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L.P.;
  6               // IBM Corp.; EMC Corporation, The Open Group.
  7               // Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.;
  8               // IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group.
  9               // Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.;
 10               // EMC Corporation; VERITAS Software Corporation; The Open Group.
 11               // Copyright (c) 2006 Hewlett-Packard Development Company, L.P.; IBM Corp.;
 12               // EMC Corporation; Symantec Corporation; The Open Group.
 13               //
 14               // Permission is hereby granted, free of charge, to any person obtaining a copy
 15               // of this software and associated documentation files (the "Software"), to
 16               // deal in the Software without restriction, including without limitation the
 17               // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 18               // sell copies of the Software, and to permit persons to whom the Software is
 19               // furnished to do so, subject to the following conditions:
 20               // 
 21               // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
 22 mike  1.1.2.1 // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED
 23               // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
 24               // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
 25               // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 26               // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 27               // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 28               // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 29               //
 30               //==============================================================================
 31               //
 32               // Author: Mike Day (mdday@us.ibm.com)
 33               //
 34               // Reworked By: Mike Brasher (m.brasher@inovadevelopment.com)
 35               //
 36               //%/////////////////////////////////////////////////////////////////////////////
 37               
 38               #include "ReadWriteSem.h"
 39               #include "Time.h"
 40               #include "PegasusAssert.h"
 41               
 42               PEGASUS_NAMESPACE_BEGIN
 43 mike  1.1.2.1 //==============================================================================
 44               //
 45               // PEGASUS_USE_POSIX_RWLOCK
 46               //
 47               //==============================================================================
 48               #ifdef PEGASUS_USE_POSIX_RWLOCK
 49 mike  1.1.2.2 ReadWriteSem::ReadWriteSem():_readers(0), _writers(0)
 50 mike  1.1.2.1 {
 51                   pthread_rwlock_init(&_rwlock.rwlock, NULL);
 52 mike  1.1.2.4     _rwlock.owner.clear();
 53 mike  1.1.2.1 }
 54               
 55               ReadWriteSem::~ReadWriteSem()
 56               {
 57               
 58                   while (EBUSY == pthread_rwlock_destroy(&_rwlock.rwlock))
 59                   {
 60                       Threads::yield();
 61                   }
 62               }
 63               
 64               void ReadWriteSem::wait(Uint32 mode, ThreadType caller)
 65               {
 66                   int errorcode;
 67                   if (mode == PEG_SEM_READ)
 68                   {
 69                       if (0 == (errorcode = pthread_rwlock_rdlock(&_rwlock.rwlock)))
 70                       {
 71                           _readers++;
 72                           return;
 73                       }
 74 mike  1.1.2.1     }
 75                   else if (mode == PEG_SEM_WRITE)
 76                   {
 77                       if (0 == (errorcode = pthread_rwlock_wrlock(&_rwlock.rwlock)))
 78                       {
 79                           _rwlock.owner = caller;
 80                           _writers++;
 81                           return;
 82                       }
 83                   }
 84                   else
 85                       throw(Permission(Threads::self()));
 86               
 87                   if (errorcode == EDEADLK)
 88                       throw(Deadlock(_rwlock.owner));
 89                   else
 90                       throw(WaitFailed(Threads::self()));
 91               }
 92               
 93               void ReadWriteSem::try_wait(Uint32 mode, ThreadType caller)
 94               {
 95 mike  1.1.2.1     int errorcode = 0;
 96                   if (mode == PEG_SEM_READ)
 97                   {
 98                       if (0 == (errorcode = pthread_rwlock_tryrdlock(&_rwlock.rwlock)))
 99                       {
100                           _readers++;
101                           return;
102                       }
103                   }
104                   else if (mode == PEG_SEM_WRITE)
105                   {
106                       if (0 == (errorcode = pthread_rwlock_trywrlock(&_rwlock.rwlock)))
107                       {
108                           _writers++;
109                           _rwlock.owner = caller;
110                           return;
111                       }
112                   }
113                   else
114                       throw(Permission(Threads::self()));
115               
116 mike  1.1.2.1     if (errorcode == EBUSY)
117                       throw(AlreadyLocked(_rwlock.owner));
118                   else if (errorcode == EDEADLK)
119                       throw(Deadlock(_rwlock.owner));
120                   else
121                       throw(WaitFailed(Threads::self()));
122               }
123               
124               
125               // timedrdlock and timedwrlock are not supported on HPUX
126               // mdday Sun Aug  5 14:21:00 2001
127 mike  1.1.2.2 void ReadWriteSem::timed_wait(Uint32 mode,
128                                             ThreadType caller, int milliseconds)
129 mike  1.1.2.1 {
130                   int errorcode = 0, timeout;
131                   struct timeval now, finish, remaining;
132                   Uint32 usec;
133               
134                   gettimeofday(&finish, NULL);
135                   finish.tv_sec += (milliseconds / 1000);
136                   milliseconds %= 1000;
137                   usec = finish.tv_usec + (milliseconds * 1000);
138                   finish.tv_sec += (usec / 1000000);
139                   finish.tv_usec = usec % 1000000;
140               
141                   if (mode == PEG_SEM_READ)
142                   {
143                       do
144                       {
145                           errorcode = pthread_rwlock_tryrdlock(&_rwlock.rwlock);
146                           gettimeofday(&now, NULL);
147                       }
148                       while (errorcode == EBUSY &&
149 mike  1.1.2.2                (0 == (timeout = Time::subtract(&remaining, &finish, &now))));
150 mike  1.1.2.1         if (0 == errorcode)
151                       {
152                           _readers++;
153                           return;
154                       }
155                   }
156                   else if (mode == PEG_SEM_WRITE)
157                   {
158                       do
159                       {
160                           errorcode = pthread_rwlock_trywrlock(&_rwlock.rwlock);
161                           gettimeofday(&now, NULL);
162                       }
163                       while (errorcode == EBUSY &&
164 mike  1.1.2.2                (0 == (timeout = Time::subtract(&remaining, &finish, &now))));
165 mike  1.1.2.1 
166                       if (0 == errorcode)
167                       {
168                           _writers++;
169                           _rwlock.owner = caller;
170                           return;
171                       }
172                   }
173                   else
174                       throw(Permission(Threads::self()));
175                   if (timeout != 0)
176                       throw(TimeOut(_rwlock.owner));
177                   else if (errorcode == EDEADLK)
178                       throw(Deadlock(_rwlock.owner));
179                   else
180                       throw(WaitFailed(Threads::self()));
181               }
182               
183               void ReadWriteSem::unlock(Uint32 mode, ThreadType caller)
184               {
185                   ThreadType owner;
186 mike  1.1.2.1 
187                   if (mode == PEG_SEM_WRITE)
188                   {
189                       owner = _rwlock.owner;
190 mike  1.1.2.4         _rwlock.owner.clear();
191 mike  1.1.2.1     }
192                   if (0 != pthread_rwlock_unlock(&_rwlock.rwlock))
193                   {
194                       _rwlock.owner = owner;
195                       throw(Permission(Threads::self()));
196                   }
197                   if (mode == PEG_SEM_READ && _readers.get() != 0)
198                       _readers--;
199                   else if (_writers.get() != 0)
200                       _writers--;
201               }
202               
203 mike  1.1.2.3 int ReadWriteSem::read_count() const
204 mike  1.1.2.1 {
205               #if defined(PEGASUS_PLATFORM_LINUX_GENERIC_GNU)
206                   PEGASUS_ASSERT(_readers.get() == _rwlock.rwlock.__rw_readers);
207               #endif
208                   return (_readers.get());
209               }
210               
211 mike  1.1.2.3 int ReadWriteSem::write_count() const
212 mike  1.1.2.1 {
213               #if defined(PEGASUS_PLATFORM_LINUX_GENERIC_GNU)
214                   if (_rwlock.rwlock.__rw_writer != NULL)
215                   {
216                       PEGASUS_ASSERT(_writers.get() == 1);
217                   }
218               #endif
219                   return (_writers.get());
220               }
221               
222               #endif /* PEGASUS_USE_POSIX_RWLOCK */
223               
224               //==============================================================================
225               //
226               // PEGASUS_USE_SEMAPHORE_RWLOCK
227               //
228               //==============================================================================
229               
230               #if defined(PEGASUS_USE_SEMAPHORE_RWLOCK)
231               
232               // // If i get cancelled, I MUST ensure:
233 mike  1.1.2.1 // 1) I do not hold the internal mutex
234               // 2) I do not hold the write lock
235               // 3) I am not using a reader slot
236               
237               void extricate_read_write(void *parm)
238               {
239 mike  1.1.2.2     ReadWriteSem *rws = (ReadWriteSem *) parm;
240                   ThreadType myself = Threads::self();
241 mike  1.1.2.1 
242 mike  1.1.2.2     if (Threads::equal(rws->_rwlock._wlock.get_owner(), myself))
243                       rws->_rwlock._wlock.unlock();
244                   else if (rws->_readers.get() > 0)
245                       rws->_rwlock._rlock.signal();
246               
247                   if (Threads::equal(rws->_rwlock._internal_lock.get_owner(), myself))
248                       rws->_rwlock._internal_lock.unlock();
249 mike  1.1.2.1 }
250               
251               
252 mike  1.1.2.2 ReadWriteSem::ReadWriteSem():_readers(0), _writers(0), _rwlock()
253               {
254 mike  1.1.2.1 }
255               
256               ReadWriteSem::~ReadWriteSem()
257               {
258 mike  1.1.2.2     // lock everyone out of this object
259                   try
260                   {
261                       _rwlock._internal_lock.lock(Threads::self());
262                   }
263                   catch(Deadlock & d)
264                   {
265                       d = d;                  // no problem - we own the lock, which is
266                                               // what we want
267                   }
268                   catch(IPCException &)
269                   {
270                       PEGASUS_ASSERT(0);
271                   }
272                   while (_readers.get() > 0 || _writers.get() > 0)
273                   {
274                       Threads::yield();
275                   }
276                   _rwlock._internal_lock.unlock();
277 mike  1.1.2.1 }
278               
279               
280               
281               
282               
283               
284               //-----------------------------------------------------------------
285               // if milliseconds == -1, wait indefinately
286               // if milliseconds == 0, fast wait
287               //-----------------------------------------------------------------
288 mike  1.1.2.2 void ReadWriteSem::timed_wait(Uint32 mode, ThreadType caller,
289                                             int milliseconds)
290 mike  1.1.2.1 {
291               
292               //-----------------------------------------------------------------
293               // Lock this object to maintain integrity while we decide
294               // exactly what to do next.
295               //-----------------------------------------------------------------
296 mike  1.1.2.2     // AutoPtr<IPCException> caught;
297                   // IPCException caught((ThreadType)0);
298                   // WaitFailed caughtWaitFailed((ThreadType)0);
299                   // TimeOut caughtTimeOut((ThreadType)0);
300                   // TooManyReaders caughtTooManyReaders((ThreadType)0);
301 mike  1.1.2.1 
302                   ThreadType zero;
303                   IPCException caught(zero);
304                   WaitFailed caughtWaitFailed(zero);
305                   TimeOut caughtTimeOut(zero);
306                   TooManyReaders caughtTooManyReaders(zero);
307               
308 mike  1.1.2.2     {                           // cleanup stack frame
309 mike  1.1.2.1 
310 mike  1.1.2.2         Threads::cleanup_push(extricate_read_write, this);
311 mike  1.1.2.1 
312 mike  1.1.2.2         try
313                       {
314                           if (milliseconds == 0)
315                               _rwlock._internal_lock.try_lock(Threads::self());
316                           else if (milliseconds == -1)
317                               _rwlock._internal_lock.lock(Threads::self());
318                           else
319                               _rwlock._internal_lock.timed_lock(milliseconds,
320                                                                 Threads::self());
321                       }
322                       catch(const IPCException & e)
323                       {
324                           caught = e;
325                           goto throw_from_here;
326                       }
327               
328                       if (mode == PEG_SEM_WRITE)
329                       {
330 mike  1.1.2.1 //-----------------------------------------------------------------
331               // Write Lock Step 1: lock the object and allow all the readers to exit
332               //-----------------------------------------------------------------
333               
334               
335 mike  1.1.2.2             if (milliseconds == 0)      // fast wait
336                           {
337                               if (_readers.get() > 0)
338                               {
339                                   _rwlock._internal_lock.unlock();
340                                   // caught.reset(new WaitFailed(Threads::self()));
341                                   caughtWaitFailed = WaitFailed(Threads::self());
342                                   goto throw_from_here;
343                               }
344                           }
345                           else if (milliseconds == -1)        // infinite wait
346                           {
347                               while (_readers.get() > 0)
348                                   Threads::yield();
349                           }
350                           else                // timed wait
351                           {
352                               struct timeval start, now;
353                               gettimeofday(&start, NULL);
354                               start.tv_usec += (1000 * milliseconds);
355                               while (_readers.get() > 0)
356 mike  1.1.2.2                 {
357                                   gettimeofday(&now, NULL);
358                                   if ((now.tv_usec > start.tv_usec) ||
359                                       now.tv_sec > start.tv_sec)
360                                   {
361                                       _rwlock._internal_lock.unlock();
362                                       // caught.reset(new TimeOut(Threads::self()));
363                                       caughtTimeOut = TimeOut(Threads::self());
364                                       goto throw_from_here;
365                                   }
366                                   Threads::yield();
367                               }
368                           }
369 mike  1.1.2.1 //-----------------------------------------------------------------
370               // Write Lock Step 2: Obtain the Write Mutex
371               //  Although there are no readers, there may be a writer
372               //-----------------------------------------------------------------
373 mike  1.1.2.2             if (milliseconds == 0)      // fast wait
374                           {
375                               try
376                               {
377                                   _rwlock._wlock.try_lock(Threads::self());
378                               }
379                               catch(IPCException & e)
380                               {
381                                   _rwlock._internal_lock.unlock();
382                                   caught = e;
383                                   goto throw_from_here;
384                               }
385                           }
386                           else if (milliseconds == -1)        // infinite wait
387                           {
388                               try
389                               {
390                                   _rwlock._wlock.lock(Threads::self());
391                               }
392                               catch(const IPCException & e)
393                               {
394 mike  1.1.2.2                     _rwlock._internal_lock.unlock();
395                                   caught = e;
396                                   goto throw_from_here;
397                               }
398                           }
399                           else                // timed wait
400                           {
401                               try
402                               {
403                                   _rwlock._wlock.timed_lock(milliseconds, Threads::self());
404                               }
405                               catch(const IPCException & e)
406                               {
407                                   _rwlock._internal_lock.unlock();
408                                   caught = e;
409                                   goto throw_from_here;
410                               }
411                           }
412 mike  1.1.2.1 
413               //-----------------------------------------------------------------
414               // Write Lock Step 3: set the writer count to one, unlock the object
415               //   There are no readers and we are the only writer !
416               //-----------------------------------------------------------------
417 mike  1.1.2.2             _writers = 1;
418                           // set the owner
419                           _rwlock._owner = Threads::self();
420                           // unlock the object
421                           _rwlock._internal_lock.unlock();
422                       }                       // PEG_SEM_WRITE
423                       else
424                       {
425 mike  1.1.2.1 //-----------------------------------------------------------------
426               // Read Lock Step 1: Wait for the existing writer (if any) to clear
427               //-----------------------------------------------------------------
428 mike  1.1.2.2             if (milliseconds == 0)      // fast wait
429                           {
430                               if (_writers.get() > 0)
431                               {
432                                   _rwlock._internal_lock.unlock();
433                                   // caught.reset(new WaitFailed(Threads::self()));
434                                   caughtWaitFailed = WaitFailed(Threads::self());
435                                   goto throw_from_here;
436                               }
437                           }
438                           else if (milliseconds == -1)        // infinite wait
439                           {
440                               while (_writers.get() > 0)
441                                   Threads::yield();
442                           }
443                           else                // timed wait
444                           {
445                               struct timeval start, now;
446                               Time::gettimeofday(&start);
447                               start.tv_usec += (milliseconds * 1000);
448               
449 mike  1.1.2.2                 while (_writers.get() > 0)
450                               {
451                                   Time::gettimeofday(&now);
452                                   if ((now.tv_usec > start.tv_usec) ||
453                                       (now.tv_sec > start.tv_sec))
454                                   {
455                                       _rwlock._internal_lock.unlock();
456                                       // caught.reset(new TimeOut(Threads::self()));
457                                       caughtTimeOut = TimeOut(Threads::self());
458                                       goto throw_from_here;
459                                   }
460                                   Threads::yield();
461                                   Time::gettimeofday(&now);
462                               }
463                           }
464 mike  1.1.2.1 
465               //-----------------------------------------------------------------
466               // Read Lock Step 2: wait for a reader slot to open up, then return
467               //  At this point there are no writers, but there may be too many
468               //  readers.
469               //-----------------------------------------------------------------
470 mike  1.1.2.2             if (milliseconds == 0)      // fast wait
471                           {
472                               try
473                               {
474                                   _rwlock._rlock.try_wait();
475                               }
476                               catch(const IPCException &)
477                               {
478                                   // the wait failed, there must be too many readers
479                                   // already.
480                                   // unlock the object
481                                   caughtTooManyReaders = TooManyReaders(Threads::self());
482                                   _rwlock._internal_lock.unlock();
483                                   // caught.reset(new TooManyReaders(Threads::self()));
484                               }
485                           }
486                           else if (milliseconds == -1)        // infinite wait
487                           {
488                               try
489                               {
490                                   _rwlock._rlock.wait();
491 mike  1.1.2.2                 }
492                               catch(const IPCException & e)
493                               {
494                                   _rwlock._internal_lock.unlock();
495                                   caught = e;
496                                   goto throw_from_here;
497                               }
498                           }
499                           else                // timed wait
500                           {
501                               try
502                               {
503                                   _rwlock._rlock.time_wait(milliseconds);
504                               }
505                               catch(const IPCException & e)
506                               {
507                                   _rwlock._internal_lock.unlock();
508                                   caught = e;
509                                   goto throw_from_here;
510                               }
511                           }
512 mike  1.1.2.1 
513               //-----------------------------------------------------------------
514               // Read Lock Step 3: increment the number of readers, unlock the object,
515               // return
516               //-----------------------------------------------------------------
517 mike  1.1.2.2             _readers++;
518                           _rwlock._internal_lock.unlock();
519                       }
520 mike  1.1.2.1       throw_from_here:
521               // ATTN:
522 mike  1.1.2.2         Threads::cleanup_pop(0);
523                   }                           // cleanup stack frame
524 mike  1.1.2.1 
525 mike  1.1.2.2     if (caught.get_owner().id() != 0)
526                       throw caught;
527                   if (caughtWaitFailed.get_owner().id() != 0)
528                       throw caughtWaitFailed;
529                   if (caughtTimeOut.get_owner().id() != 0)
530                       throw caughtTimeOut;
531                   if (caughtTooManyReaders.get_owner().id() != 0)
532                       throw caughtTooManyReaders;
533                   return;
534 mike  1.1.2.1 }
535               
536               //---------------------------------------------------------------------
537               void ReadWriteSem::wait(Uint32 mode, ThreadType caller)
538               {
539 mike  1.1.2.2     timed_wait(mode, caller, -1);
540 mike  1.1.2.1 }
541               
542               void ReadWriteSem::try_wait(Uint32 mode, ThreadType caller)
543               {
544 mike  1.1.2.2     timed_wait(mode, caller, 0);
545 mike  1.1.2.1 }
546               
547               
548               void ReadWriteSem::unlock(Uint32 mode, ThreadType caller)
549               {
550 mike  1.1.2.2     if (mode == PEG_SEM_WRITE && _writers.get() != 0)
551                   {
552                       _writers = 0;
553                       _rwlock._wlock.unlock();
554                   }
555                   else if (_readers.get() != 0)
556                   {
557                       _readers--;
558                       _rwlock._rlock.signal();
559                   }
560 mike  1.1.2.1 }
561               
562               int ReadWriteSem::read_count() const
563               {
564 mike  1.1.2.2     return (_readers.get());
565 mike  1.1.2.1 }
566               
567               int ReadWriteSem::write_count() const
568               {
569 mike  1.1.2.2     return (_writers.get());
570 mike  1.1.2.1 }
571               
572               #endif /* !PEGASUS_USE_SEMAPHORE_RWLOCK */
573               
574               PEGASUS_NAMESPACE_END

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2