(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 denise.eckstein 1.5.4.1     while ((r=pthread_rwlock_destroy(&_rwlock.rwlock)) == EBUSY ||
 59 kumpf           1.5                (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