(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 mike  1.1.2.10     int errorcode = 0, timeout = 0;
135 mike  1.1.2.1      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 mike  1.1.2.11 #if 0
233 mike  1.1.2.1  void extricate_read_write(void *parm)
234                {
235 mike  1.1.2.2      ReadWriteSem *rws = (ReadWriteSem *) parm;
236                    ThreadType myself = Threads::self();
237 mike  1.1.2.1  
238 mike  1.1.2.2      if (Threads::equal(rws->_rwlock._wlock.get_owner(), myself))
239                        rws->_rwlock._wlock.unlock();
240                    else if (rws->_readers.get() > 0)
241                        rws->_rwlock._rlock.signal();
242                
243                    if (Threads::equal(rws->_rwlock._internal_lock.get_owner(), myself))
244                        rws->_rwlock._internal_lock.unlock();
245 mike  1.1.2.1  }
246 mike  1.1.2.11 #endif
247 mike  1.1.2.1  
248                
249 mike  1.1.2.2  ReadWriteSem::ReadWriteSem():_readers(0), _writers(0), _rwlock()
250                {
251 mike  1.1.2.1  }
252                
253                ReadWriteSem::~ReadWriteSem()
254                {
255 mike  1.1.2.2      // lock everyone out of this object
256                    try
257                    {
258 mike  1.1.2.11         _rwlock._internal_lock.lock();
259 mike  1.1.2.2      }
260 kumpf 1.1.2.12     catch(Deadlock &)
261 mike  1.1.2.2      {
262 kumpf 1.1.2.12         // no problem - we own the lock, which is what we want
263 mike  1.1.2.2      }
264                    catch(IPCException &)
265                    {
266                        PEGASUS_ASSERT(0);
267                    }
268                    while (_readers.get() > 0 || _writers.get() > 0)
269                    {
270                        Threads::yield();
271                    }
272                    _rwlock._internal_lock.unlock();
273 mike  1.1.2.1  }
274                
275                
276                
277                
278                
279                
280                //-----------------------------------------------------------------
281                // if milliseconds == -1, wait indefinately
282                // if milliseconds == 0, fast wait
283                //-----------------------------------------------------------------
284 mike  1.1.2.2  void ReadWriteSem::timed_wait(Uint32 mode, ThreadType caller,
285                                              int milliseconds)
286 mike  1.1.2.1  {
287                //-----------------------------------------------------------------
288                // Lock this object to maintain integrity while we decide
289                // exactly what to do next.
290                //-----------------------------------------------------------------
291 mike  1.1.2.2      // AutoPtr<IPCException> caught;
292                    // IPCException caught((ThreadType)0);
293                    // WaitFailed caughtWaitFailed((ThreadType)0);
294                    // TimeOut caughtTimeOut((ThreadType)0);
295                    // TooManyReaders caughtTooManyReaders((ThreadType)0);
296 mike  1.1.2.1  
297                    ThreadType zero;
298                    IPCException caught(zero);
299                    WaitFailed caughtWaitFailed(zero);
300                    TimeOut caughtTimeOut(zero);
301                    TooManyReaders caughtTooManyReaders(zero);
302                
303 mike  1.1.2.5      // cleanup stack frame
304                    {
305 mike  1.1.2.11         // 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 mike  1.1.2.11                 _rwlock._internal_lock.try_lock();
311 mike  1.1.2.2              else if (milliseconds == -1)
312 mike  1.1.2.11                 _rwlock._internal_lock.lock();
313 mike  1.1.2.2              else
314 mike  1.1.2.11                 _rwlock._internal_lock.timed_lock(milliseconds);
315 mike  1.1.2.2          }
316                        catch(const IPCException & e)
317                        {
318                            caught = e;
319                            goto throw_from_here;
320                        }
321                
322                        if (mode == PEG_SEM_WRITE)
323                        {
324 mike  1.1.2.1  //-----------------------------------------------------------------
325                // Write Lock Step 1: lock the object and allow all the readers to exit
326                //-----------------------------------------------------------------
327                
328                
329 mike  1.1.2.2              if (milliseconds == 0)      // fast wait
330                            {
331                                if (_readers.get() > 0)
332                                {
333                                    _rwlock._internal_lock.unlock();
334                                    // caught.reset(new WaitFailed(Threads::self()));
335                                    caughtWaitFailed = WaitFailed(Threads::self());
336                                    goto throw_from_here;
337                                }
338                            }
339                            else if (milliseconds == -1)        // infinite wait
340                            {
341                                while (_readers.get() > 0)
342                                    Threads::yield();
343                            }
344                            else                // timed wait
345                            {
346                                struct timeval start, now;
347 mike  1.1.2.5                  Time::gettimeofday(&start);
348 mike  1.1.2.2                  start.tv_usec += (1000 * milliseconds);
349                                while (_readers.get() > 0)
350                                {
351 mike  1.1.2.5                      Time::gettimeofday(&now);
352 mike  1.1.2.2                      if ((now.tv_usec > start.tv_usec) ||
353                                        now.tv_sec > start.tv_sec)
354                                    {
355                                        _rwlock._internal_lock.unlock();
356                                        // caught.reset(new TimeOut(Threads::self()));
357                                        caughtTimeOut = TimeOut(Threads::self());
358                                        goto throw_from_here;
359                                    }
360                                    Threads::yield();
361                                }
362                            }
363 mike  1.1.2.1  //-----------------------------------------------------------------
364                // Write Lock Step 2: Obtain the Write Mutex
365                //  Although there are no readers, there may be a writer
366                //-----------------------------------------------------------------
367 mike  1.1.2.2              if (milliseconds == 0)      // fast wait
368                            {
369                                try
370                                {
371 mike  1.1.2.11                     _rwlock._wlock.try_lock();
372 mike  1.1.2.2                  }
373                                catch(IPCException & e)
374                                {
375                                    _rwlock._internal_lock.unlock();
376                                    caught = e;
377                                    goto throw_from_here;
378                                }
379                            }
380                            else if (milliseconds == -1)        // infinite wait
381                            {
382                                try
383                                {
384 mike  1.1.2.11                     _rwlock._wlock.lock();
385 mike  1.1.2.2                  }
386                                catch(const IPCException & e)
387                                {
388                                    _rwlock._internal_lock.unlock();
389                                    caught = e;
390                                    goto throw_from_here;
391                                }
392                            }
393                            else                // timed wait
394                            {
395                                try
396                                {
397 mike  1.1.2.11                     _rwlock._wlock.timed_lock(milliseconds);
398 mike  1.1.2.2                  }
399                                catch(const IPCException & e)
400                                {
401                                    _rwlock._internal_lock.unlock();
402                                    caught = e;
403                                    goto throw_from_here;
404                                }
405                            }
406 mike  1.1.2.1  
407                //-----------------------------------------------------------------
408                // Write Lock Step 3: set the writer count to one, unlock the object
409                //   There are no readers and we are the only writer !
410                //-----------------------------------------------------------------
411 mike  1.1.2.2              _writers = 1;
412                            // set the owner
413                            _rwlock._owner = Threads::self();
414                            // unlock the object
415                            _rwlock._internal_lock.unlock();
416                        }                       // PEG_SEM_WRITE
417                        else
418                        {
419 mike  1.1.2.1  //-----------------------------------------------------------------
420                // Read Lock Step 1: Wait for the existing writer (if any) to clear
421                //-----------------------------------------------------------------
422 mike  1.1.2.2              if (milliseconds == 0)      // fast wait
423                            {
424                                if (_writers.get() > 0)
425                                {
426                                    _rwlock._internal_lock.unlock();
427                                    // caught.reset(new WaitFailed(Threads::self()));
428                                    caughtWaitFailed = WaitFailed(Threads::self());
429                                    goto throw_from_here;
430                                }
431                            }
432                            else if (milliseconds == -1)        // infinite wait
433                            {
434                                while (_writers.get() > 0)
435                                    Threads::yield();
436                            }
437                            else                // timed wait
438                            {
439                                struct timeval start, now;
440                                Time::gettimeofday(&start);
441                                start.tv_usec += (milliseconds * 1000);
442                
443 mike  1.1.2.2                  while (_writers.get() > 0)
444                                {
445                                    Time::gettimeofday(&now);
446                                    if ((now.tv_usec > start.tv_usec) ||
447                                        (now.tv_sec > start.tv_sec))
448                                    {
449                                        _rwlock._internal_lock.unlock();
450                                        // caught.reset(new TimeOut(Threads::self()));
451                                        caughtTimeOut = TimeOut(Threads::self());
452                                        goto throw_from_here;
453                                    }
454                                    Threads::yield();
455                                    Time::gettimeofday(&now);
456                                }
457                            }
458 mike  1.1.2.1  
459                //-----------------------------------------------------------------
460                // Read Lock Step 2: wait for a reader slot to open up, then return
461                //  At this point there are no writers, but there may be too many
462                //  readers.
463                //-----------------------------------------------------------------
464 mike  1.1.2.2              if (milliseconds == 0)      // fast wait
465                            {
466                                try
467                                {
468                                    _rwlock._rlock.try_wait();
469                                }
470                                catch(const IPCException &)
471                                {
472                                    // the wait failed, there must be too many readers
473                                    // already.
474                                    // unlock the object
475                                    caughtTooManyReaders = TooManyReaders(Threads::self());
476                                    _rwlock._internal_lock.unlock();
477                                    // caught.reset(new TooManyReaders(Threads::self()));
478                                }
479                            }
480                            else if (milliseconds == -1)        // infinite wait
481                            {
482                                try
483                                {
484                                    _rwlock._rlock.wait();
485 mike  1.1.2.2                  }
486                                catch(const IPCException & e)
487                                {
488                                    _rwlock._internal_lock.unlock();
489                                    caught = e;
490                                    goto throw_from_here;
491                                }
492                            }
493                            else                // timed wait
494                            {
495                                try
496                                {
497                                    _rwlock._rlock.time_wait(milliseconds);
498                                }
499                                catch(const IPCException & e)
500                                {
501                                    _rwlock._internal_lock.unlock();
502                                    caught = e;
503                                    goto throw_from_here;
504                                }
505                            }
506 mike  1.1.2.1  
507                //-----------------------------------------------------------------
508                // Read Lock Step 3: increment the number of readers, unlock the object,
509                // return
510                //-----------------------------------------------------------------
511 mike  1.1.2.2              _readers++;
512                            _rwlock._internal_lock.unlock();
513                        }
514 mike  1.1.2.1        throw_from_here:
515 mike  1.1.2.5  	// ATTN:
516 mike  1.1.2.2          Threads::cleanup_pop(0);
517 mike  1.1.2.5      }
518 mike  1.1.2.1  
519 mike  1.1.2.5      if (Threads::id(caught.get_owner()) != 0)
520 mike  1.1.2.2          throw caught;
521 mike  1.1.2.5      if (Threads::id(caughtWaitFailed.get_owner()) != 0)
522 mike  1.1.2.2          throw caughtWaitFailed;
523 mike  1.1.2.5      if (Threads::id(caughtTimeOut.get_owner()) != 0)
524 mike  1.1.2.2          throw caughtTimeOut;
525 mike  1.1.2.5      if (Threads::id(caughtTooManyReaders.get_owner()) != 0)
526 mike  1.1.2.2          throw caughtTooManyReaders;
527                    return;
528 mike  1.1.2.1  }
529                
530                //---------------------------------------------------------------------
531                void ReadWriteSem::wait(Uint32 mode, ThreadType caller)
532                {
533 mike  1.1.2.2      timed_wait(mode, caller, -1);
534 mike  1.1.2.1  }
535                
536                void ReadWriteSem::try_wait(Uint32 mode, ThreadType caller)
537                {
538 mike  1.1.2.2      timed_wait(mode, caller, 0);
539 mike  1.1.2.1  }
540                
541                
542                void ReadWriteSem::unlock(Uint32 mode, ThreadType caller)
543                {
544 mike  1.1.2.2      if (mode == PEG_SEM_WRITE && _writers.get() != 0)
545                    {
546                        _writers = 0;
547                        _rwlock._wlock.unlock();
548                    }
549                    else if (_readers.get() != 0)
550                    {
551                        _readers--;
552                        _rwlock._rlock.signal();
553                    }
554 mike  1.1.2.1  }
555                
556                int ReadWriteSem::read_count() const
557                {
558 mike  1.1.2.2      return (_readers.get());
559 mike  1.1.2.1  }
560                
561                int ReadWriteSem::write_count() const
562                {
563 mike  1.1.2.2      return (_writers.get());
564 mike  1.1.2.1  }
565                
566                #endif /* !PEGASUS_USE_SEMAPHORE_RWLOCK */
567                
568                PEGASUS_NAMESPACE_END

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2