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
|