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 mike 1.6 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
|