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