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

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2