(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 marek 1.3     int r=0;
 58               while (r=pthread_rwlock_destroy(&_rwlock.rwlock) == EBUSY || (r == -1 && errno == EBUSY))
 59 mike  1.2     {
 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               }
 75               else if (mode == PEG_SEM_WRITE)
 76               {
 77                   if (0 == (errorcode = pthread_rwlock_wrlock(&_rwlock.rwlock)))
 78                   {
 79                       _rwlock.owner = caller;
 80 mike  1.2             _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               int errorcode = 0;
 96               if (mode == PEG_SEM_READ)
 97               {
 98                   if (0 == (errorcode = pthread_rwlock_tryrdlock(&_rwlock.rwlock)))
 99                   {
100                       _readers++;
101 mike  1.2             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 marek 1.3     if (errorcode == -1)
116                   errorcode = errno;
117 mike  1.2     if (errorcode == EBUSY)
118                   throw(AlreadyLocked(_rwlock.owner));
119               else if (errorcode == EDEADLK)
120                   throw(Deadlock(_rwlock.owner));
121               else
122                   throw(WaitFailed(Threads::self()));
123           }
124           
125           
126           // timedrdlock and timedwrlock are not supported on HPUX
127           // mdday Sun Aug  5 14:21:00 2001
128           void ReadWriteSem::timed_wait(Uint32 mode,
129                                         ThreadType caller, int milliseconds)
130           {
131               int errorcode = 0, timeout = 0;
132               struct timeval now, finish, remaining;
133               Uint32 usec;
134           
135               gettimeofday(&finish, NULL);
136               finish.tv_sec += (milliseconds / 1000);
137               milliseconds %= 1000;
138 mike  1.2     usec = finish.tv_usec + (milliseconds * 1000);
139               finish.tv_sec += (usec / 1000000);
140               finish.tv_usec = usec % 1000000;
141           
142               if (mode == PEG_SEM_READ)
143               {
144                   do
145                   {
146                       errorcode = pthread_rwlock_tryrdlock(&_rwlock.rwlock);
147 marek 1.3             if (errorcode == -1)
148                           errorcode = errno;
149 mike  1.2             gettimeofday(&now, NULL);
150                   }
151                   while (errorcode == EBUSY &&
152                          (0 == (timeout = Time::subtract(&remaining, &finish, &now))));
153                   if (0 == errorcode)
154                   {
155                       _readers++;
156                       return;
157                   }
158               }
159               else if (mode == PEG_SEM_WRITE)
160               {
161                   do
162                   {
163                       errorcode = pthread_rwlock_trywrlock(&_rwlock.rwlock);
164 marek 1.3             if (errorcode == -1)
165                           errorcode = errno;
166 mike  1.2             gettimeofday(&now, NULL);
167                   }
168                   while (errorcode == EBUSY &&
169                          (0 == (timeout = Time::subtract(&remaining, &finish, &now))));
170           
171                   if (0 == errorcode)
172                   {
173                       _writers++;
174                       _rwlock.owner = caller;
175                       return;
176                   }
177               }
178               else
179                   throw(Permission(Threads::self()));
180               if (timeout != 0)
181                   throw(TimeOut(_rwlock.owner));
182               else if (errorcode == EDEADLK)
183                   throw(Deadlock(_rwlock.owner));
184               else
185                   throw(WaitFailed(Threads::self()));
186           }
187 mike  1.2 
188           void ReadWriteSem::unlock(Uint32 mode, ThreadType caller)
189           {
190               ThreadType owner;
191           
192               if (mode == PEG_SEM_WRITE)
193               {
194                   owner = _rwlock.owner;
195                   Threads::clear(_rwlock.owner);
196               }
197               if (0 != pthread_rwlock_unlock(&_rwlock.rwlock))
198               {
199                   _rwlock.owner = owner;
200                   throw(Permission(Threads::self()));
201               }
202               if (mode == PEG_SEM_READ && _readers.get() != 0)
203                   _readers--;
204               else if (_writers.get() != 0)
205                   _writers--;
206           }
207           
208 mike  1.2 int ReadWriteSem::read_count() const
209           {
210               return (_readers.get());
211           }
212           
213           int ReadWriteSem::write_count() const
214           {
215               return (_writers.get());
216           }
217           
218           #endif /* PEGASUS_USE_POSIX_RWLOCK */
219           
220           //==============================================================================
221           //
222           // PEGASUS_USE_SEMAPHORE_RWLOCK
223           //
224           //==============================================================================
225           
226           #if defined(PEGASUS_USE_SEMAPHORE_RWLOCK)
227           
228           // // If i get cancelled, I MUST ensure:
229 mike  1.2 // 1) I do not hold the internal mutex
230           // 2) I do not hold the write lock
231           // 3) I am not using a reader slot
232           
233           #if 0
234           void extricate_read_write(void *parm)
235           {
236               ReadWriteSem *rws = (ReadWriteSem *) parm;
237               ThreadType myself = Threads::self();
238           
239               if (Threads::equal(rws->_rwlock._wlock.get_owner(), myself))
240                   rws->_rwlock._wlock.unlock();
241               else if (rws->_readers.get() > 0)
242                   rws->_rwlock._rlock.signal();
243           
244               if (Threads::equal(rws->_rwlock._internal_lock.get_owner(), myself))
245                   rws->_rwlock._internal_lock.unlock();
246           }
247           #endif
248           
249           
250 mike  1.2 ReadWriteSem::ReadWriteSem():_readers(0), _writers(0), _rwlock()
251           {
252           }
253           
254           ReadWriteSem::~ReadWriteSem()
255           {
256               // lock everyone out of this object
257               try
258               {
259                   _rwlock._internal_lock.lock();
260               }
261               catch(Deadlock &)
262               {
263                   // no problem - we own the lock, which is what we want
264               }
265               catch(IPCException &)
266               {
267                   PEGASUS_ASSERT(0);
268               }
269               while (_readers.get() > 0 || _writers.get() > 0)
270               {
271 mike  1.2         Threads::yield();
272               }
273               _rwlock._internal_lock.unlock();
274           }
275           
276           
277           
278           
279           
280           
281           //-----------------------------------------------------------------
282           // if milliseconds == -1, wait indefinately
283           // if milliseconds == 0, fast wait
284           //-----------------------------------------------------------------
285           void ReadWriteSem::timed_wait(Uint32 mode, ThreadType caller,
286                                         int milliseconds)
287           {
288           //-----------------------------------------------------------------
289           // Lock this object to maintain integrity while we decide
290           // exactly what to do next.
291           //-----------------------------------------------------------------
292 mike  1.2     // AutoPtr<IPCException> caught;
293               // IPCException caught((ThreadType)0);
294               // WaitFailed caughtWaitFailed((ThreadType)0);
295               // TimeOut caughtTimeOut((ThreadType)0);
296               // TooManyReaders caughtTooManyReaders((ThreadType)0);
297           
298               ThreadType zero;
299               IPCException caught(zero);
300               WaitFailed caughtWaitFailed(zero);
301               TimeOut caughtTimeOut(zero);
302               TooManyReaders caughtTooManyReaders(zero);
303           
304               // cleanup stack frame
305               {
306                   // Threads::cleanup_push(extricate_read_write, this);
307           
308                   try
309                   {
310                       if (milliseconds == 0)
311                           _rwlock._internal_lock.try_lock();
312                       else if (milliseconds == -1)
313 mike  1.2                 _rwlock._internal_lock.lock();
314                       else
315                           _rwlock._internal_lock.timed_lock(milliseconds);
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           //-----------------------------------------------------------------
326           // Write Lock Step 1: lock the object and allow all the readers to exit
327           //-----------------------------------------------------------------
328           
329           
330                       if (milliseconds == 0)      // fast wait
331                       {
332                           if (_readers.get() > 0)
333                           {
334 mike  1.2                     _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                           Time::gettimeofday(&start);
349                           start.tv_usec += (1000 * milliseconds);
350                           while (_readers.get() > 0)
351                           {
352                               Time::gettimeofday(&now);
353                               if ((now.tv_usec > start.tv_usec) ||
354                                   now.tv_sec > start.tv_sec)
355 mike  1.2                     {
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           //-----------------------------------------------------------------
365           // Write Lock Step 2: Obtain the Write Mutex
366           //  Although there are no readers, there may be a writer
367           //-----------------------------------------------------------------
368                       if (milliseconds == 0)      // fast wait
369                       {
370                           try
371                           {
372                               _rwlock._wlock.try_lock();
373                           }
374                           catch(IPCException & e)
375                           {
376 mike  1.2                     _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();
386                           }
387                           catch(const IPCException & e)
388                           {
389                               _rwlock._internal_lock.unlock();
390                               caught = e;
391                               goto throw_from_here;
392                           }
393                       }
394                       else                // timed wait
395                       {
396                           try
397 mike  1.2                 {
398                               _rwlock._wlock.timed_lock(milliseconds);
399                           }
400                           catch(const IPCException & e)
401                           {
402                               _rwlock._internal_lock.unlock();
403                               caught = e;
404                               goto throw_from_here;
405                           }
406                       }
407           
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                       _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 mike  1.2         else
419                   {
420           //-----------------------------------------------------------------
421           // Read Lock Step 1: Wait for the existing writer (if any) to clear
422           //-----------------------------------------------------------------
423                       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 mike  1.2             {
440                           struct timeval start, now;
441                           Time::gettimeofday(&start);
442                           start.tv_usec += (milliseconds * 1000);
443           
444                           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           
460 mike  1.2 //-----------------------------------------------------------------
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                       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 mike  1.2             else if (milliseconds == -1)        // infinite wait
482                       {
483                           try
484                           {
485                               _rwlock._rlock.wait();
486                           }
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 mike  1.2                     _rwlock._internal_lock.unlock();
503                               caught = e;
504                               goto throw_from_here;
505                           }
506                       }
507           
508           //-----------------------------------------------------------------
509           // Read Lock Step 3: increment the number of readers, unlock the object,
510           // return
511           //-----------------------------------------------------------------
512                       _readers++;
513                       _rwlock._internal_lock.unlock();
514                   }
515                 throw_from_here:
516           	// ATTN:
517                   Threads::cleanup_pop(0);
518               }
519           
520 mike  1.4     if (!Threads::null(caught.get_owner()))
521 mike  1.2         throw caught;
522 mike  1.4     if (!Threads::null(caughtWaitFailed.get_owner()))
523 mike  1.2         throw caughtWaitFailed;
524 mike  1.4     if (!Threads::null(caughtTimeOut.get_owner()))
525 mike  1.2         throw caughtTimeOut;
526 mike  1.4     if (!Threads::null(caughtTooManyReaders.get_owner()))
527           
528 mike  1.2         throw caughtTooManyReaders;
529               return;
530           }
531           
532           //---------------------------------------------------------------------
533           void ReadWriteSem::wait(Uint32 mode, ThreadType caller)
534           {
535               timed_wait(mode, caller, -1);
536           }
537           
538           void ReadWriteSem::try_wait(Uint32 mode, ThreadType caller)
539           {
540               timed_wait(mode, caller, 0);
541           }
542           
543           
544           void ReadWriteSem::unlock(Uint32 mode, ThreadType caller)
545           {
546               if (mode == PEG_SEM_WRITE && _writers.get() != 0)
547               {
548                   _writers = 0;
549 mike  1.2         _rwlock._wlock.unlock();
550               }
551               else if (_readers.get() != 0)
552               {
553                   _readers--;
554                   _rwlock._rlock.signal();
555               }
556           }
557           
558           int ReadWriteSem::read_count() const
559           {
560               return (_readers.get());
561           }
562           
563           int ReadWriteSem::write_count() const
564           {
565               return (_writers.get());
566           }
567           
568           #endif /* !PEGASUS_USE_SEMAPHORE_RWLOCK */
569           
570 mike  1.2 PEGASUS_NAMESPACE_END

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2