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

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

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2