VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/posix/semrw-posix.cpp@ 25570

Last change on this file since 25570 was 25570, checked in by vboxsync, 15 years ago

lockvalidator,semrw-posix.cpp: link the read and write records.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 17.7 KB
Line 
1/* $Id: semrw-posix.cpp 25570 2009-12-22 15:11:13Z vboxsync $ */
2/** @file
3 * IPRT - Read-Write Semaphore, POSIX.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.215389.xyz. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 *
26 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
27 * Clara, CA 95054 USA or visit http://www.sun.com if you need
28 * additional information or have any questions.
29 */
30
31/*******************************************************************************
32* Header Files *
33*******************************************************************************/
34#include <iprt/semaphore.h>
35#include "internal/iprt.h"
36
37#include <iprt/asm.h>
38#include <iprt/assert.h>
39#include <iprt/err.h>
40#include <iprt/lockvalidator.h>
41#include <iprt/mem.h>
42#include <iprt/thread.h>
43
44#include <errno.h>
45#include <pthread.h>
46#include <unistd.h>
47#include <sys/time.h>
48
49#include "internal/magics.h"
50#include "internal/strict.h"
51
52
53/*******************************************************************************
54* Defined Constants And Macros *
55*******************************************************************************/
56/** @todo move this to r3/posix/something.h. */
57#ifdef RT_OS_SOLARIS
58# define ATOMIC_GET_PTHREAD_T(pvVar, pThread) ASMAtomicReadSize(pvVar, pThread)
59# define ATOMIC_SET_PTHREAD_T(pvVar, pThread) ASMAtomicWriteSize(pvVar, pThread)
60#else
61AssertCompileSize(pthread_t, sizeof(void *));
62# define ATOMIC_GET_PTHREAD_T(pvVar, pThread) do { *(pThread) = (pthread_t)ASMAtomicReadPtr((void *volatile *)pvVar); } while (0)
63# define ATOMIC_SET_PTHREAD_T(pvVar, pThread) ASMAtomicWritePtr((void *volatile *)pvVar, (void *)pThread)
64#endif
65
66
67/*******************************************************************************
68* Structures and Typedefs *
69*******************************************************************************/
70/** Posix internal representation of a read-write semaphore. */
71struct RTSEMRWINTERNAL
72{
73 /** The usual magic. (RTSEMRW_MAGIC) */
74 uint32_t u32Magic;
75 /** The number of readers.
76 * (For preventing screwing up the lock on linux). */
77 uint32_t volatile cReaders;
78 /** Number of write recursions. */
79 uint32_t cWrites;
80 /** Number of read recursions by the writer. */
81 uint32_t cWriterReads;
82 /** The write owner of the lock. */
83 volatile pthread_t Writer;
84 /** pthread rwlock. */
85 pthread_rwlock_t RWLock;
86#ifdef RTSEMRW_STRICT
87 /** The validator record for the writer. */
88 RTLOCKVALIDATORREC ValidatorWrite;
89 /** The validator record for the readers. */
90 RTLOCKVALIDATORSHARED ValidatorRead;
91#endif
92};
93
94
95RTDECL(int) RTSemRWCreate(PRTSEMRW pRWSem)
96{
97 int rc;
98
99 /*
100 * Allocate handle.
101 */
102 struct RTSEMRWINTERNAL *pThis = (struct RTSEMRWINTERNAL *)RTMemAlloc(sizeof(struct RTSEMRWINTERNAL));
103 if (pThis)
104 {
105 /*
106 * Create the rwlock.
107 */
108 pthread_rwlockattr_t Attr;
109 rc = pthread_rwlockattr_init(&Attr);
110 if (!rc)
111 {
112 rc = pthread_rwlock_init(&pThis->RWLock, &Attr);
113 if (!rc)
114 {
115 pThis->u32Magic = RTSEMRW_MAGIC;
116 pThis->cReaders = 0;
117 pThis->cWrites = 0;
118 pThis->cWriterReads = 0;
119 pThis->Writer = (pthread_t)-1;
120#ifdef RTSEMRW_STRICT
121 RTLockValidatorRecInit(&pThis->ValidatorWrite, NIL_RTLOCKVALIDATORCLASS, RTLOCKVALIDATOR_SUB_CLASS_NONE, NULL, pThis);
122 RTLockValidatorSharedRecInit(&pThis->ValidatorRead, NIL_RTLOCKVALIDATORCLASS, RTLOCKVALIDATOR_SUB_CLASS_NONE, NULL, pThis);
123 RTLockValidatorMakeSiblings(&pThis->ValidatorWrite, &pThis->ValidatorRead);
124#endif
125 *pRWSem = pThis;
126 return VINF_SUCCESS;
127 }
128 }
129
130 rc = RTErrConvertFromErrno(rc);
131 RTMemFree(pThis);
132 }
133 else
134 rc = VERR_NO_MEMORY;
135
136 return rc;
137}
138
139
140RTDECL(int) RTSemRWDestroy(RTSEMRW RWSem)
141{
142 /*
143 * Validate input, nil handle is fine.
144 */
145 struct RTSEMRWINTERNAL *pThis = RWSem;
146 if (pThis == NIL_RTSEMRW)
147 return VINF_SUCCESS;
148 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
149 AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC,
150 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
151 VERR_INVALID_HANDLE);
152 Assert(pThis->Writer == (pthread_t)-1);
153 Assert(!pThis->cReaders);
154 Assert(!pThis->cWrites);
155 Assert(!pThis->cWriterReads);
156
157 /*
158 * Try destroy it.
159 */
160 AssertReturn(ASMAtomicCmpXchgU32(&pThis->u32Magic, ~RTSEMRW_MAGIC, RTSEMRW_MAGIC), VERR_INVALID_HANDLE);
161 int rc = pthread_rwlock_destroy(&pThis->RWLock);
162 if (!rc)
163 {
164#ifdef RTSEMRW_STRICT
165 RTLockValidatorSharedRecDelete(&pThis->ValidatorRead);
166 RTLockValidatorRecDelete(&pThis->ValidatorWrite);
167#endif
168 RTMemFree(pThis);
169 rc = VINF_SUCCESS;
170 }
171 else
172 {
173 ASMAtomicWriteU32(&pThis->u32Magic, RTSEMRW_MAGIC);
174 AssertMsgFailed(("Failed to destroy read-write sem %p, rc=%d.\n", RWSem, rc));
175 rc = RTErrConvertFromErrno(rc);
176 }
177
178 return rc;
179}
180
181
182RTDECL(int) RTSemRWRequestRead(RTSEMRW RWSem, unsigned cMillies)
183{
184 PRTLOCKVALIDATORSRCPOS pSrcPos = NULL;
185
186 /*
187 * Validate input.
188 */
189 struct RTSEMRWINTERNAL *pThis = RWSem;
190 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
191 AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC,
192 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
193 VERR_INVALID_HANDLE);
194
195 /*
196 * Check if it's the writer (implement write+read recursion).
197 */
198 pthread_t Self = pthread_self();
199 pthread_t Writer;
200 ATOMIC_GET_PTHREAD_T(&pThis->Writer, &Writer);
201 if (Writer == Self)
202 {
203#ifdef RTSEMRW_STRICT
204 int rc9 = RTLockValidatorRecordReadWriteRecursion(&pThis->ValidatorWrite, &pThis->ValidatorRead, pSrcPos);
205 if (RT_FAILURE(rc9))
206 return rc9;
207#endif
208 Assert(pThis->cWriterReads < INT32_MAX);
209 pThis->cWriterReads++;
210 return VINF_SUCCESS;
211 }
212
213 /*
214 * Try lock it.
215 */
216#ifdef RTSEMRW_STRICT
217 RTTHREAD hThreadSelf = RTThreadSelfAutoAdopt();
218#else
219 RTTHREAD hThreadSelf = RTThreadSelf();
220#endif
221 if (cMillies > 0)
222 {
223#ifdef RTSEMRW_STRICT
224 int rc9 = RTLockValidatorCheckReadOrderBlocking(&pThis->ValidatorRead, &pThis->ValidatorWrite,
225 hThreadSelf, RTTHREADSTATE_RW_READ, false, pSrcPos);
226 if (RT_FAILURE(rc9))
227 return rc9;
228#endif
229 RTThreadBlocking(hThreadSelf, RTTHREADSTATE_RW_READ);
230 }
231
232 if (cMillies == RT_INDEFINITE_WAIT)
233 {
234 /* take rwlock */
235 int rc = pthread_rwlock_rdlock(&pThis->RWLock);
236 RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_RW_READ);
237 if (rc)
238 {
239 AssertMsgFailed(("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));
240 return RTErrConvertFromErrno(rc);
241 }
242 }
243 else
244 {
245#ifdef RT_OS_DARWIN
246 AssertMsgFailed(("Not implemented on Darwin yet because of incomplete pthreads API."));
247 return VERR_NOT_IMPLEMENTED;
248
249#else /* !RT_OS_DARWIN */
250 /*
251 * Get current time and calc end of wait time.
252 */
253 struct timespec ts = {0,0};
254 clock_gettime(CLOCK_REALTIME, &ts);
255 if (cMillies != 0)
256 {
257 ts.tv_nsec += (cMillies % 1000) * 1000000;
258 ts.tv_sec += cMillies / 1000;
259 if (ts.tv_nsec >= 1000000000)
260 {
261 ts.tv_nsec -= 1000000000;
262 ts.tv_sec++;
263 }
264 }
265
266 /* take rwlock */
267 int rc = pthread_rwlock_timedrdlock(&pThis->RWLock, &ts);
268 RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_RW_READ);
269 if (rc)
270 {
271 AssertMsg(rc == ETIMEDOUT, ("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));
272 return RTErrConvertFromErrno(rc);
273 }
274#endif /* !RT_OS_DARWIN */
275 }
276
277 ASMAtomicIncU32(&pThis->cReaders);
278#ifdef RTSEMRW_STRICT
279 RTLockValidatorAddReadOwner(&pThis->ValidatorRead, hThreadSelf, pSrcPos);
280#endif
281 return VINF_SUCCESS;
282}
283
284
285RTDECL(int) RTSemRWRequestReadNoResume(RTSEMRW RWSem, unsigned cMillies)
286{
287 /* EINTR isn't returned by the wait functions we're using. */
288 return RTSemRWRequestRead(RWSem, cMillies);
289}
290
291
292RTDECL(int) RTSemRWReleaseRead(RTSEMRW RWSem)
293{
294 /*
295 * Validate input.
296 */
297 struct RTSEMRWINTERNAL *pThis = RWSem;
298 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
299 AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC,
300 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
301 VERR_INVALID_HANDLE);
302
303 /*
304 * Check if it's the writer.
305 */
306 pthread_t Self = pthread_self();
307 pthread_t Writer;
308 ATOMIC_GET_PTHREAD_T(&pThis->Writer, &Writer);
309 if (Writer == Self)
310 {
311 AssertMsgReturn(pThis->cWriterReads > 0, ("pThis=%p\n", pThis), VERR_NOT_OWNER);
312#ifdef RTSEMRW_STRICT
313 int rc9 = RTLockValidatorUnwindReadWriteRecursion(&pThis->ValidatorWrite, &pThis->ValidatorRead);
314 if (RT_FAILURE(rc9))
315 return rc9;
316#endif
317 pThis->cWriterReads--;
318 return VINF_SUCCESS;
319 }
320
321 /*
322 * Try unlock it.
323 */
324#ifdef RTSEMRW_STRICT
325 int rc9 = RTLockValidatorCheckAndReleaseReadOwner(&pThis->ValidatorRead, RTThreadSelf());
326 if (RT_FAILURE(rc9))
327 return rc9;
328#endif
329#ifdef RT_OS_LINUX /* glibc (at least 2.8) may screw up when unlocking a lock we don't own. */
330 if (ASMAtomicReadU32(&pThis->cReaders) == 0)
331 {
332 AssertMsgFailed(("Not owner of %p\n", pThis));
333 return VERR_NOT_OWNER;
334 }
335#endif
336 ASMAtomicDecU32(&pThis->cReaders);
337 int rc = pthread_rwlock_unlock(&pThis->RWLock);
338 if (rc)
339 {
340 ASMAtomicIncU32(&pThis->cReaders);
341 AssertMsgFailed(("Failed read unlock read-write sem %p, rc=%d.\n", RWSem, rc));
342 return RTErrConvertFromErrno(rc);
343 }
344 return VINF_SUCCESS;
345}
346
347
348DECL_FORCE_INLINE(int) rtSemRWRequestWrite(RTSEMRW RWSem, unsigned cMillies, PCRTLOCKVALIDATORSRCPOS pSrcPos)
349{
350 /*
351 * Validate input.
352 */
353 struct RTSEMRWINTERNAL *pThis = RWSem;
354 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
355 AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC,
356 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
357 VERR_INVALID_HANDLE);
358 /*
359 * Recursion?
360 */
361 pthread_t Self = pthread_self();
362 pthread_t Writer;
363 ATOMIC_GET_PTHREAD_T(&pThis->Writer, &Writer);
364 if (Writer == Self)
365 {
366#ifdef RTSEMRW_STRICT
367 int rc9 = RTLockValidatorRecordRecursion(&pThis->ValidatorWrite, pSrcPos);
368 if (RT_FAILURE(rc9))
369 return rc9;
370#endif
371 Assert(pThis->cWrites < INT32_MAX);
372 pThis->cWrites++;
373 return VINF_SUCCESS;
374 }
375
376 /*
377 * Try lock it.
378 */
379#ifdef RTSEMRW_STRICT
380 RTTHREAD hThreadSelf = RTThreadSelfAutoAdopt();
381#else
382 RTTHREAD hThreadSelf = RTThreadSelf();
383#endif
384 if (cMillies)
385 {
386#ifdef RTSEMRW_STRICT
387 int rc9 = RTLockValidatorCheckWriteOrderBlocking(&pThis->ValidatorWrite, &pThis->ValidatorRead,
388 hThreadSelf, RTTHREADSTATE_RW_WRITE, true, pSrcPos);
389 if (RT_FAILURE(rc9))
390 return rc9;
391#endif
392 RTThreadBlocking(hThreadSelf, RTTHREADSTATE_RW_WRITE);
393 }
394
395 if (cMillies == RT_INDEFINITE_WAIT)
396 {
397 /* take rwlock */
398 int rc = pthread_rwlock_wrlock(&pThis->RWLock);
399 RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_RW_WRITE);
400 if (rc)
401 {
402 AssertMsgFailed(("Failed write lock read-write sem %p, rc=%d.\n", RWSem, rc));
403 return RTErrConvertFromErrno(rc);
404 }
405 }
406 else
407 {
408#ifdef RT_OS_DARWIN
409 AssertMsgFailed(("Not implemented on Darwin yet because of incomplete pthreads API."));
410 return VERR_NOT_IMPLEMENTED;
411#else /* !RT_OS_DARWIN */
412 /*
413 * Get current time and calc end of wait time.
414 */
415 struct timespec ts = {0,0};
416 clock_gettime(CLOCK_REALTIME, &ts);
417 if (cMillies != 0)
418 {
419 ts.tv_nsec += (cMillies % 1000) * 1000000;
420 ts.tv_sec += cMillies / 1000;
421 if (ts.tv_nsec >= 1000000000)
422 {
423 ts.tv_nsec -= 1000000000;
424 ts.tv_sec++;
425 }
426 }
427
428 /* take rwlock */
429 int rc = pthread_rwlock_timedwrlock(&pThis->RWLock, &ts);
430 RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_RW_WRITE);
431 if (rc)
432 {
433 AssertMsg(rc == ETIMEDOUT, ("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));
434 return RTErrConvertFromErrno(rc);
435 }
436#endif /* !RT_OS_DARWIN */
437 }
438
439 ATOMIC_SET_PTHREAD_T(&pThis->Writer, Self);
440 pThis->cWrites = 1;
441 Assert(!pThis->cReaders);
442#ifdef RTSEMRW_STRICT
443 RTLockValidatorSetOwner(&pThis->ValidatorWrite, hThreadSelf, pSrcPos);
444#endif
445 return VINF_SUCCESS;
446}
447
448
449RTDECL(int) RTSemRWRequestWrite(RTSEMRW RWSem, unsigned cMillies)
450{
451#ifndef RTSEMRW_STRICT
452 return rtSemRWRequestWrite(RWSem, cMillies, NULL);
453#else
454 RTLOCKVALIDATORSRCPOS SrcPos = RTLOCKVALIDATORSRCPOS_INIT_NORMAL_API();
455 return rtSemRWRequestWrite(RWSem, cMillies, &SrcPos);
456#endif
457}
458
459
460RTDECL(int) RTSemRWRequestWriteDebug(RTSEMRW RWSem, unsigned cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL)
461{
462 RTLOCKVALIDATORSRCPOS SrcPos = RTLOCKVALIDATORSRCPOS_INIT_DEBUG_API();
463 return rtSemRWRequestWrite(RWSem, cMillies, &SrcPos);
464}
465
466
467RTDECL(int) RTSemRWRequestWriteNoResume(RTSEMRW RWSem, unsigned cMillies)
468{
469 /* EINTR isn't returned by the wait functions we're using. */
470#ifndef RTSEMRW_STRICT
471 return rtSemRWRequestWrite(RWSem, cMillies, NULL);
472#else
473 RTLOCKVALIDATORSRCPOS SrcPos = RTLOCKVALIDATORSRCPOS_INIT_NORMAL_API();
474 return rtSemRWRequestWrite(RWSem, cMillies, &SrcPos);
475#endif
476}
477
478
479RTDECL(int) RTSemRWRequestWriteNoResumeDebug(RTSEMRW RWSem, unsigned cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL)
480{
481 /* EINTR isn't returned by the wait functions we're using. */
482 RTLOCKVALIDATORSRCPOS SrcPos = RTLOCKVALIDATORSRCPOS_INIT_DEBUG_API();
483 return rtSemRWRequestWrite(RWSem, cMillies, &SrcPos);
484}
485
486
487RTDECL(int) RTSemRWReleaseWrite(RTSEMRW RWSem)
488{
489 /*
490 * Validate input.
491 */
492 struct RTSEMRWINTERNAL *pThis = RWSem;
493 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
494 AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC,
495 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
496 VERR_INVALID_HANDLE);
497
498 /*
499 * Verify ownership and implement recursion.
500 */
501 pthread_t Self = pthread_self();
502 pthread_t Writer;
503 ATOMIC_GET_PTHREAD_T(&pThis->Writer, &Writer);
504 AssertMsgReturn(Writer == Self, ("pThis=%p\n", pThis), VERR_NOT_OWNER);
505 AssertReturn(pThis->cWriterReads == 0 || pThis->cWrites > 1, VERR_WRONG_ORDER);
506
507 if (pThis->cWrites > 1)
508 {
509#ifdef RTSEMRW_STRICT
510 int rc9 = RTLockValidatorUnwindRecursion(&pThis->ValidatorWrite);
511 if (RT_FAILURE(rc9))
512 return rc9;
513#endif
514 pThis->cWrites--;
515 return VINF_SUCCESS;
516 }
517 pThis->cWrites--;
518
519 /*
520 * Try unlock it.
521 */
522#ifdef RTSEMRW_STRICT
523 int rc9 = RTLockValidatorCheckAndRelease(&pThis->ValidatorWrite);
524 if (RT_FAILURE(rc9))
525 return rc9;
526#endif
527
528 ATOMIC_SET_PTHREAD_T(&pThis->Writer, (pthread_t)-1);
529 int rc = pthread_rwlock_unlock(&pThis->RWLock);
530 if (rc)
531 {
532 AssertMsgFailed(("Failed write unlock read-write sem %p, rc=%d.\n", RWSem, rc));
533 return RTErrConvertFromErrno(rc);
534 }
535
536 return VINF_SUCCESS;
537}
538
539
540RTDECL(bool) RTSemRWIsWriteOwner(RTSEMRW RWSem)
541{
542 /*
543 * Validate input.
544 */
545 struct RTSEMRWINTERNAL *pThis = RWSem;
546 AssertPtrReturn(pThis, false);
547 AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC,
548 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
549 false);
550
551 /*
552 * Check ownership.
553 */
554 pthread_t Self = pthread_self();
555 pthread_t Writer;
556 ATOMIC_GET_PTHREAD_T(&pThis->Writer, &Writer);
557 return Writer == Self;
558}
559
560
561RTDECL(uint32_t) RTSemRWGetWriteRecursion(RTSEMRW RWSem)
562{
563 /*
564 * Validate input.
565 */
566 struct RTSEMRWINTERNAL *pThis = RWSem;
567 AssertPtrReturn(pThis, 0);
568 AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC,
569 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
570 0);
571
572 /*
573 * Return the requested data.
574 */
575 return pThis->cWrites;
576}
577
578
579RTDECL(uint32_t) RTSemRWGetWriterReadRecursion(RTSEMRW RWSem)
580{
581 /*
582 * Validate input.
583 */
584 struct RTSEMRWINTERNAL *pThis = RWSem;
585 AssertPtrReturn(pThis, 0);
586 AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC,
587 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
588 0);
589
590 /*
591 * Return the requested data.
592 */
593 return pThis->cWriterReads;
594}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette