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 marek 1.3 int r=0;
58 while (r=pthread_rwlock_destroy(&_rwlock.rwlock) == EBUSY || (r == -1 && errno == EBUSY))
|
59 mike 1.2 {
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 }
75 else if (mode == PEG_SEM_WRITE)
76 {
77 if (0 == (errorcode = pthread_rwlock_wrlock(&_rwlock.rwlock)))
78 {
79 _rwlock.owner = caller;
80 mike 1.2 _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 int errorcode = 0;
96 if (mode == PEG_SEM_READ)
97 {
98 if (0 == (errorcode = pthread_rwlock_tryrdlock(&_rwlock.rwlock)))
99 {
100 _readers++;
101 mike 1.2 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 marek 1.3 if (errorcode == -1)
116 errorcode = errno;
|
117 mike 1.2 if (errorcode == EBUSY)
118 throw(AlreadyLocked(_rwlock.owner));
119 else if (errorcode == EDEADLK)
120 throw(Deadlock(_rwlock.owner));
121 else
122 throw(WaitFailed(Threads::self()));
123 }
124
125
126 // timedrdlock and timedwrlock are not supported on HPUX
127 // mdday Sun Aug 5 14:21:00 2001
128 void ReadWriteSem::timed_wait(Uint32 mode,
129 ThreadType caller, int milliseconds)
130 {
131 int errorcode = 0, timeout = 0;
132 struct timeval now, finish, remaining;
133 Uint32 usec;
134
135 gettimeofday(&finish, NULL);
136 finish.tv_sec += (milliseconds / 1000);
137 milliseconds %= 1000;
138 mike 1.2 usec = finish.tv_usec + (milliseconds * 1000);
139 finish.tv_sec += (usec / 1000000);
140 finish.tv_usec = usec % 1000000;
141
142 if (mode == PEG_SEM_READ)
143 {
144 do
145 {
146 errorcode = pthread_rwlock_tryrdlock(&_rwlock.rwlock);
|
147 marek 1.3 if (errorcode == -1)
148 errorcode = errno;
|
149 mike 1.2 gettimeofday(&now, NULL);
150 }
151 while (errorcode == EBUSY &&
152 (0 == (timeout = Time::subtract(&remaining, &finish, &now))));
153 if (0 == errorcode)
154 {
155 _readers++;
156 return;
157 }
158 }
159 else if (mode == PEG_SEM_WRITE)
160 {
161 do
162 {
163 errorcode = pthread_rwlock_trywrlock(&_rwlock.rwlock);
|
164 marek 1.3 if (errorcode == -1)
165 errorcode = errno;
|
166 mike 1.2 gettimeofday(&now, NULL);
167 }
168 while (errorcode == EBUSY &&
169 (0 == (timeout = Time::subtract(&remaining, &finish, &now))));
170
171 if (0 == errorcode)
172 {
173 _writers++;
174 _rwlock.owner = caller;
175 return;
176 }
177 }
178 else
179 throw(Permission(Threads::self()));
180 if (timeout != 0)
181 throw(TimeOut(_rwlock.owner));
182 else if (errorcode == EDEADLK)
183 throw(Deadlock(_rwlock.owner));
184 else
185 throw(WaitFailed(Threads::self()));
186 }
187 mike 1.2
188 void ReadWriteSem::unlock(Uint32 mode, ThreadType caller)
189 {
190 ThreadType owner;
191
192 if (mode == PEG_SEM_WRITE)
193 {
194 owner = _rwlock.owner;
195 Threads::clear(_rwlock.owner);
196 }
197 if (0 != pthread_rwlock_unlock(&_rwlock.rwlock))
198 {
199 _rwlock.owner = owner;
200 throw(Permission(Threads::self()));
201 }
202 if (mode == PEG_SEM_READ && _readers.get() != 0)
203 _readers--;
204 else if (_writers.get() != 0)
205 _writers--;
206 }
207
208 mike 1.2 int ReadWriteSem::read_count() const
209 {
210 return (_readers.get());
211 }
212
213 int ReadWriteSem::write_count() const
214 {
215 return (_writers.get());
216 }
217
218 #endif /* PEGASUS_USE_POSIX_RWLOCK */
219
220 //==============================================================================
221 //
222 // PEGASUS_USE_SEMAPHORE_RWLOCK
223 //
224 //==============================================================================
225
226 #if defined(PEGASUS_USE_SEMAPHORE_RWLOCK)
227
228 // // If i get cancelled, I MUST ensure:
229 mike 1.2 // 1) I do not hold the internal mutex
230 // 2) I do not hold the write lock
231 // 3) I am not using a reader slot
232
233 #if 0
234 void extricate_read_write(void *parm)
235 {
236 ReadWriteSem *rws = (ReadWriteSem *) parm;
237 ThreadType myself = Threads::self();
238
239 if (Threads::equal(rws->_rwlock._wlock.get_owner(), myself))
240 rws->_rwlock._wlock.unlock();
241 else if (rws->_readers.get() > 0)
242 rws->_rwlock._rlock.signal();
243
244 if (Threads::equal(rws->_rwlock._internal_lock.get_owner(), myself))
245 rws->_rwlock._internal_lock.unlock();
246 }
247 #endif
248
249
250 mike 1.2 ReadWriteSem::ReadWriteSem():_readers(0), _writers(0), _rwlock()
251 {
252 }
253
254 ReadWriteSem::~ReadWriteSem()
255 {
256 // lock everyone out of this object
257 try
258 {
259 _rwlock._internal_lock.lock();
260 }
261 catch(Deadlock &)
262 {
263 // no problem - we own the lock, which is what we want
264 }
265 catch(IPCException &)
266 {
267 PEGASUS_ASSERT(0);
268 }
269 while (_readers.get() > 0 || _writers.get() > 0)
270 {
271 mike 1.2 Threads::yield();
272 }
273 _rwlock._internal_lock.unlock();
274 }
275
276
277
278
279
280
281 //-----------------------------------------------------------------
282 // if milliseconds == -1, wait indefinately
283 // if milliseconds == 0, fast wait
284 //-----------------------------------------------------------------
285 void ReadWriteSem::timed_wait(Uint32 mode, ThreadType caller,
286 int milliseconds)
287 {
288 //-----------------------------------------------------------------
289 // Lock this object to maintain integrity while we decide
290 // exactly what to do next.
291 //-----------------------------------------------------------------
292 mike 1.2 // AutoPtr<IPCException> caught;
293 // IPCException caught((ThreadType)0);
294 // WaitFailed caughtWaitFailed((ThreadType)0);
295 // TimeOut caughtTimeOut((ThreadType)0);
296 // TooManyReaders caughtTooManyReaders((ThreadType)0);
297
298 ThreadType zero;
299 IPCException caught(zero);
300 WaitFailed caughtWaitFailed(zero);
301 TimeOut caughtTimeOut(zero);
302 TooManyReaders caughtTooManyReaders(zero);
303
304 // cleanup stack frame
305 {
306 // Threads::cleanup_push(extricate_read_write, this);
307
308 try
309 {
310 if (milliseconds == 0)
311 _rwlock._internal_lock.try_lock();
312 else if (milliseconds == -1)
313 mike 1.2 _rwlock._internal_lock.lock();
314 else
315 _rwlock._internal_lock.timed_lock(milliseconds);
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 //-----------------------------------------------------------------
326 // Write Lock Step 1: lock the object and allow all the readers to exit
327 //-----------------------------------------------------------------
328
329
330 if (milliseconds == 0) // fast wait
331 {
332 if (_readers.get() > 0)
333 {
334 mike 1.2 _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 Time::gettimeofday(&start);
349 start.tv_usec += (1000 * milliseconds);
350 while (_readers.get() > 0)
351 {
352 Time::gettimeofday(&now);
353 if ((now.tv_usec > start.tv_usec) ||
354 now.tv_sec > start.tv_sec)
355 mike 1.2 {
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 //-----------------------------------------------------------------
365 // Write Lock Step 2: Obtain the Write Mutex
366 // Although there are no readers, there may be a writer
367 //-----------------------------------------------------------------
368 if (milliseconds == 0) // fast wait
369 {
370 try
371 {
372 _rwlock._wlock.try_lock();
373 }
374 catch(IPCException & e)
375 {
376 mike 1.2 _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();
386 }
387 catch(const IPCException & e)
388 {
389 _rwlock._internal_lock.unlock();
390 caught = e;
391 goto throw_from_here;
392 }
393 }
394 else // timed wait
395 {
396 try
397 mike 1.2 {
398 _rwlock._wlock.timed_lock(milliseconds);
399 }
400 catch(const IPCException & e)
401 {
402 _rwlock._internal_lock.unlock();
403 caught = e;
404 goto throw_from_here;
405 }
406 }
407
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 _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 mike 1.2 else
419 {
420 //-----------------------------------------------------------------
421 // Read Lock Step 1: Wait for the existing writer (if any) to clear
422 //-----------------------------------------------------------------
423 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 mike 1.2 {
440 struct timeval start, now;
441 Time::gettimeofday(&start);
442 start.tv_usec += (milliseconds * 1000);
443
444 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
460 mike 1.2 //-----------------------------------------------------------------
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 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 mike 1.2 else if (milliseconds == -1) // infinite wait
482 {
483 try
484 {
485 _rwlock._rlock.wait();
486 }
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 mike 1.2 _rwlock._internal_lock.unlock();
503 caught = e;
504 goto throw_from_here;
505 }
506 }
507
508 //-----------------------------------------------------------------
509 // Read Lock Step 3: increment the number of readers, unlock the object,
510 // return
511 //-----------------------------------------------------------------
512 _readers++;
513 _rwlock._internal_lock.unlock();
514 }
515 throw_from_here:
516 // ATTN:
517 Threads::cleanup_pop(0);
518 }
519
|
520 mike 1.4 if (!Threads::null(caught.get_owner()))
|
521 mike 1.2 throw caught;
|
522 mike 1.4 if (!Threads::null(caughtWaitFailed.get_owner()))
|
523 mike 1.2 throw caughtWaitFailed;
|
524 mike 1.4 if (!Threads::null(caughtTimeOut.get_owner()))
|
525 mike 1.2 throw caughtTimeOut;
|
526 mike 1.4 if (!Threads::null(caughtTooManyReaders.get_owner()))
527
|
528 mike 1.2 throw caughtTooManyReaders;
529 return;
530 }
531
532 //---------------------------------------------------------------------
533 void ReadWriteSem::wait(Uint32 mode, ThreadType caller)
534 {
535 timed_wait(mode, caller, -1);
536 }
537
538 void ReadWriteSem::try_wait(Uint32 mode, ThreadType caller)
539 {
540 timed_wait(mode, caller, 0);
541 }
542
543
544 void ReadWriteSem::unlock(Uint32 mode, ThreadType caller)
545 {
546 if (mode == PEG_SEM_WRITE && _writers.get() != 0)
547 {
548 _writers = 0;
549 mike 1.2 _rwlock._wlock.unlock();
550 }
551 else if (_readers.get() != 0)
552 {
553 _readers--;
554 _rwlock._rlock.signal();
555 }
556 }
557
558 int ReadWriteSem::read_count() const
559 {
560 return (_readers.get());
561 }
562
563 int ReadWriteSem::write_count() const
564 {
565 return (_writers.get());
566 }
567
568 #endif /* !PEGASUS_USE_SEMAPHORE_RWLOCK */
569
570 mike 1.2 PEGASUS_NAMESPACE_END
|