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