VirtualBox

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

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

IPRT: Added lock validator hooks to semrw-posix.cpp.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 17.1 KB
Line 
1/* $Id: semrw-posix.cpp 25498 2009-12-18 16:44:17Z 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 /* Alignment padding. */
76 uint32_t u32Padding;
77 /** Number of write recursions. */
78 uint32_t cWrites;
79 /** Number of read recursions by the writer. */
80 uint32_t cWriterReads;
81 /** The write owner of the lock. */
82 volatile pthread_t Writer;
83 /** pthread rwlock. */
84 pthread_rwlock_t RWLock;
85#ifdef RTSEMRW_STRICT
86 /** The validator record for the writer. */
87 RTLOCKVALIDATORREC ValidatorWrite;
88 /** The validator record for the readers. */
89 RTLOCKVALIDATORSHARED ValidatorRead;
90#endif
91};
92
93
94RTDECL(int) RTSemRWCreate(PRTSEMRW pRWSem)
95{
96 int rc;
97
98 /*
99 * Allocate handle.
100 */
101 struct RTSEMRWINTERNAL *pThis = (struct RTSEMRWINTERNAL *)RTMemAlloc(sizeof(struct RTSEMRWINTERNAL));
102 if (pThis)
103 {
104 /*
105 * Create the rwlock.
106 */
107 pthread_rwlockattr_t Attr;
108 rc = pthread_rwlockattr_init(&Attr);
109 if (!rc)
110 {
111 rc = pthread_rwlock_init(&pThis->RWLock, &Attr);
112 if (!rc)
113 {
114 pThis->u32Magic = RTSEMRW_MAGIC;
115 pThis->u32Padding = 0;
116 pThis->cWrites = 0;
117 pThis->cWriterReads = 0;
118 pThis->Writer = (pthread_t)-1;
119#ifdef RTSEMRW_STRICT
120 RTLockValidatorRecInit(&pThis->ValidatorWrite, NIL_RTLOCKVALIDATORCLASS, RTLOCKVALIDATOR_SUB_CLASS_NONE, NULL, pThis);
121 RTLockValidatorSharedRecInit(&pThis->ValidatorRead, NIL_RTLOCKVALIDATORCLASS, RTLOCKVALIDATOR_SUB_CLASS_NONE, NULL, pThis);
122#endif
123 *pRWSem = pThis;
124 return VINF_SUCCESS;
125 }
126 }
127
128 rc = RTErrConvertFromErrno(rc);
129 RTMemFree(pThis);
130 }
131 else
132 rc = VERR_NO_MEMORY;
133
134 return rc;
135}
136
137
138RTDECL(int) RTSemRWDestroy(RTSEMRW RWSem)
139{
140 /*
141 * Validate input, nil handle is fine.
142 */
143 struct RTSEMRWINTERNAL *pThis = RWSem;
144 if (pThis == NIL_RTSEMRW)
145 return VINF_SUCCESS;
146 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
147 AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC,
148 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
149 VERR_INVALID_HANDLE);
150 Assert(pThis->Writer == (pthread_t)-1);
151 Assert(!pThis->cWrites);
152 Assert(!pThis->cWriterReads);
153
154 /*
155 * Try destroy it.
156 */
157 AssertReturn(ASMAtomicCmpXchgU32(&pThis->u32Magic, ~RTSEMRW_MAGIC, RTSEMRW_MAGIC), VERR_INVALID_HANDLE);
158 int rc = pthread_rwlock_destroy(&pThis->RWLock);
159 if (!rc)
160 {
161#ifdef RTSEMRW_STRICT
162 RTLockValidatorSharedRecDelete(&pThis->ValidatorRead);
163 RTLockValidatorRecDelete(&pThis->ValidatorWrite);
164#endif
165 RTMemFree(pThis);
166 rc = VINF_SUCCESS;
167 }
168 else
169 {
170 ASMAtomicWriteU32(&pThis->u32Magic, RTSEMRW_MAGIC);
171 AssertMsgFailed(("Failed to destroy read-write sem %p, rc=%d.\n", RWSem, rc));
172 rc = RTErrConvertFromErrno(rc);
173 }
174
175 return rc;
176}
177
178
179RTDECL(int) RTSemRWRequestRead(RTSEMRW RWSem, unsigned cMillies)
180{
181 PRTLOCKVALIDATORSRCPOS pSrcPos = NULL;
182
183 /*
184 * Validate input.
185 */
186 struct RTSEMRWINTERNAL *pThis = RWSem;
187 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
188 AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC,
189 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
190 VERR_INVALID_HANDLE);
191
192 /*
193 * Check if it's the writer (implement write+read recursion).
194 */
195 pthread_t Self = pthread_self();
196 pthread_t Writer;
197 ATOMIC_GET_PTHREAD_T(&pThis->Writer, &Writer);
198 if (Writer == Self)
199 {
200#ifdef RTSEMRW_STRICT
201 int rc9 = RTLockValidatorRecordReadWriteRecursion(&pThis->ValidatorWrite, &pThis->ValidatorRead, pSrcPos);
202 if (RT_FAILURE(rc9))
203 return rc9;
204#endif
205 Assert(pThis->cWriterReads < INT32_MAX);
206 pThis->cWriterReads++;
207 return VINF_SUCCESS;
208 }
209
210 /*
211 * Try lock it.
212 */
213#ifdef RTSEMRW_STRICT
214 RTTHREAD hThreadSelf = RTThreadSelfAutoAdopt();
215#else
216 RTTHREAD hThreadSelf = RTThreadSelf();
217#endif
218 if (cMillies > 0)
219 {
220#ifdef RTSEMRW_STRICT
221 int rc9 = RTLockValidatorCheckReadOrderBlocking(&pThis->ValidatorRead, &pThis->ValidatorWrite,
222 hThreadSelf, RTTHREADSTATE_RW_READ, false, pSrcPos);
223 if (RT_FAILURE(rc9))
224 return rc9;
225#endif
226 RTThreadBlocking(hThreadSelf, RTTHREADSTATE_RW_READ);
227 }
228
229 if (cMillies == RT_INDEFINITE_WAIT)
230 {
231 /* take rwlock */
232 int rc = pthread_rwlock_rdlock(&pThis->RWLock);
233 RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_RW_READ);
234 if (rc)
235 {
236 AssertMsgFailed(("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));
237 return RTErrConvertFromErrno(rc);
238 }
239 }
240 else
241 {
242#ifdef RT_OS_DARWIN
243 AssertMsgFailed(("Not implemented on Darwin yet because of incomplete pthreads API."));
244 return VERR_NOT_IMPLEMENTED;
245
246#else /* !RT_OS_DARWIN */
247 /*
248 * Get current time and calc end of wait time.
249 */
250 struct timespec ts = {0,0};
251 clock_gettime(CLOCK_REALTIME, &ts);
252 if (cMillies != 0)
253 {
254 ts.tv_nsec += (cMillies % 1000) * 1000000;
255 ts.tv_sec += cMillies / 1000;
256 if (ts.tv_nsec >= 1000000000)
257 {
258 ts.tv_nsec -= 1000000000;
259 ts.tv_sec++;
260 }
261 }
262
263 /* take rwlock */
264 int rc = pthread_rwlock_timedrdlock(&pThis->RWLock, &ts);
265 RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_RW_READ);
266 if (rc)
267 {
268 AssertMsg(rc == ETIMEDOUT, ("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));
269 return RTErrConvertFromErrno(rc);
270 }
271#endif /* !RT_OS_DARWIN */
272 }
273
274#ifdef RTSEMRW_STRICT
275 RTLockValidatorAddReadOwner(&pThis->ValidatorRead, hThreadSelf, pSrcPos);
276#endif
277 return VINF_SUCCESS;
278}
279
280
281RTDECL(int) RTSemRWRequestReadNoResume(RTSEMRW RWSem, unsigned cMillies)
282{
283 /* EINTR isn't returned by the wait functions we're using. */
284 return RTSemRWRequestRead(RWSem, cMillies);
285}
286
287
288RTDECL(int) RTSemRWReleaseRead(RTSEMRW RWSem)
289{
290 /*
291 * Validate input.
292 */
293 struct RTSEMRWINTERNAL *pThis = RWSem;
294 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
295 AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC,
296 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
297 VERR_INVALID_HANDLE);
298
299 /*
300 * Check if it's the writer.
301 */
302 pthread_t Self = pthread_self();
303 pthread_t Writer;
304 ATOMIC_GET_PTHREAD_T(&pThis->Writer, &Writer);
305 if (Writer == Self)
306 {
307 AssertMsgReturn(pThis->cWriterReads > 0, ("pThis=%p\n", pThis), VERR_NOT_OWNER);
308#ifdef RTSEMRW_STRICT
309 int rc9 = RTLockValidatorUnwindReadWriteRecursion(&pThis->ValidatorWrite, &pThis->ValidatorRead);
310 if (RT_FAILURE(rc9))
311 return rc9;
312#endif
313 pThis->cWriterReads--;
314 return VINF_SUCCESS;
315 }
316
317 /*
318 * Try unlock it.
319 */
320#ifdef RTSEMRW_STRICT
321 int rc9 = RTLockValidatorCheckAndReleaseReadOwner(&pThis->ValidatorRead, RTThreadSelf());
322 if (RT_FAILURE(rc9))
323 return rc9;
324#endif
325 int rc = pthread_rwlock_unlock(&pThis->RWLock);
326 if (rc)
327 {
328 AssertMsgFailed(("Failed read unlock read-write sem %p, rc=%d.\n", RWSem, rc));
329 return RTErrConvertFromErrno(rc);
330 }
331 return VINF_SUCCESS;
332}
333
334
335DECL_FORCE_INLINE(int) rtSemRWRequestWrite(RTSEMRW RWSem, unsigned cMillies, PCRTLOCKVALIDATORSRCPOS pSrcPos)
336{
337 /*
338 * Validate input.
339 */
340 struct RTSEMRWINTERNAL *pThis = RWSem;
341 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
342 AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC,
343 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
344 VERR_INVALID_HANDLE);
345 /*
346 * Recursion?
347 */
348 pthread_t Self = pthread_self();
349 pthread_t Writer;
350 ATOMIC_GET_PTHREAD_T(&pThis->Writer, &Writer);
351 if (Writer == Self)
352 {
353#ifdef RTSEMRW_STRICT
354 int rc9 = RTLockValidatorRecordRecursion(&pThis->ValidatorWrite, pSrcPos);
355 if (RT_FAILURE(rc9))
356 return rc9;
357#endif
358 Assert(pThis->cWrites < INT32_MAX);
359 pThis->cWrites++;
360 return VINF_SUCCESS;
361 }
362
363 /*
364 * Try lock it.
365 */
366#ifdef RTSEMRW_STRICT
367 RTTHREAD hThreadSelf = RTThreadSelfAutoAdopt();
368#else
369 RTTHREAD hThreadSelf = RTThreadSelf();
370#endif
371 if (cMillies)
372 {
373#ifdef RTSEMRW_STRICT
374 int rc9 = RTLockValidatorCheckWriteOrderBlocking(&pThis->ValidatorWrite, &pThis->ValidatorRead,
375 hThreadSelf, RTTHREADSTATE_RW_WRITE, true, pSrcPos);
376 if (RT_FAILURE(rc9))
377 return rc9;
378#endif
379 RTThreadBlocking(hThreadSelf, RTTHREADSTATE_RW_WRITE);
380 }
381
382 if (cMillies == RT_INDEFINITE_WAIT)
383 {
384 /* take rwlock */
385 int rc = pthread_rwlock_wrlock(&pThis->RWLock);
386 RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_RW_WRITE);
387 if (rc)
388 {
389 AssertMsgFailed(("Failed write lock read-write sem %p, rc=%d.\n", RWSem, rc));
390 return RTErrConvertFromErrno(rc);
391 }
392 }
393 else
394 {
395#ifdef RT_OS_DARWIN
396 AssertMsgFailed(("Not implemented on Darwin yet because of incomplete pthreads API."));
397 return VERR_NOT_IMPLEMENTED;
398#else /* !RT_OS_DARWIN */
399 /*
400 * Get current time and calc end of wait time.
401 */
402 struct timespec ts = {0,0};
403 clock_gettime(CLOCK_REALTIME, &ts);
404 if (cMillies != 0)
405 {
406 ts.tv_nsec += (cMillies % 1000) * 1000000;
407 ts.tv_sec += cMillies / 1000;
408 if (ts.tv_nsec >= 1000000000)
409 {
410 ts.tv_nsec -= 1000000000;
411 ts.tv_sec++;
412 }
413 }
414
415 /* take rwlock */
416 int rc = pthread_rwlock_timedwrlock(&pThis->RWLock, &ts);
417 RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_RW_WRITE);
418 if (rc)
419 {
420 AssertMsg(rc == ETIMEDOUT, ("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));
421 return RTErrConvertFromErrno(rc);
422 }
423#endif /* !RT_OS_DARWIN */
424 }
425
426 ATOMIC_SET_PTHREAD_T(&pThis->Writer, Self);
427 pThis->cWrites = 1;
428#ifdef RTSEMRW_STRICT
429 RTLockValidatorSetOwner(&pThis->ValidatorWrite, hThreadSelf, pSrcPos);
430#endif
431 return VINF_SUCCESS;
432}
433
434
435RTDECL(int) RTSemRWRequestWrite(RTSEMRW RWSem, unsigned cMillies)
436{
437#ifndef RTSEMRW_STRICT
438 return rtSemRWRequestWrite(RWSem, cMillies, NULL);
439#else
440 RTLOCKVALIDATORSRCPOS SrcPos = RTLOCKVALIDATORSRCPOS_INIT_NORMAL_API();
441 return rtSemRWRequestWrite(RWSem, cMillies, &SrcPos);
442#endif
443}
444
445
446RTDECL(int) RTSemRWRequestWriteDebug(RTSEMRW RWSem, unsigned cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL)
447{
448 RTLOCKVALIDATORSRCPOS SrcPos = RTLOCKVALIDATORSRCPOS_INIT_DEBUG_API();
449 return rtSemRWRequestWrite(RWSem, cMillies, &SrcPos);
450}
451
452
453RTDECL(int) RTSemRWRequestWriteNoResume(RTSEMRW RWSem, unsigned cMillies)
454{
455 /* EINTR isn't returned by the wait functions we're using. */
456#ifndef RTSEMRW_STRICT
457 return rtSemRWRequestWrite(RWSem, cMillies, NULL);
458#else
459 RTLOCKVALIDATORSRCPOS SrcPos = RTLOCKVALIDATORSRCPOS_INIT_NORMAL_API();
460 return rtSemRWRequestWrite(RWSem, cMillies, &SrcPos);
461#endif
462}
463
464
465RTDECL(int) RTSemRWRequestWriteNoResumeDebug(RTSEMRW RWSem, unsigned cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL)
466{
467 /* EINTR isn't returned by the wait functions we're using. */
468 RTLOCKVALIDATORSRCPOS SrcPos = RTLOCKVALIDATORSRCPOS_INIT_DEBUG_API();
469 return rtSemRWRequestWrite(RWSem, cMillies, &SrcPos);
470}
471
472
473RTDECL(int) RTSemRWReleaseWrite(RTSEMRW RWSem)
474{
475 /*
476 * Validate input.
477 */
478 struct RTSEMRWINTERNAL *pThis = RWSem;
479 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
480 AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC,
481 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
482 VERR_INVALID_HANDLE);
483
484 /*
485 * Verify ownership and implement recursion.
486 */
487 pthread_t Self = pthread_self();
488 pthread_t Writer;
489 ATOMIC_GET_PTHREAD_T(&pThis->Writer, &Writer);
490 AssertMsgReturn(Writer == Self, ("pThis=%p\n", pThis), VERR_NOT_OWNER);
491 AssertReturn(pThis->cWriterReads == 0 || pThis->cWrites > 1, VERR_WRONG_ORDER);
492
493 if (pThis->cWrites > 1)
494 {
495#ifdef RTSEMRW_STRICT
496 int rc9 = RTLockValidatorUnwindRecursion(&pThis->ValidatorWrite);
497 if (RT_FAILURE(rc9))
498 return rc9;
499#endif
500 pThis->cWrites--;
501 return VINF_SUCCESS;
502 }
503 pThis->cWrites--;
504
505 /*
506 * Try unlock it.
507 */
508#ifdef RTSEMRW_STRICT
509 int rc9 = RTLockValidatorCheckAndRelease(&pThis->ValidatorWrite);
510 if (RT_FAILURE(rc9))
511 return rc9;
512#endif
513
514 ATOMIC_SET_PTHREAD_T(&pThis->Writer, (pthread_t)-1);
515 int rc = pthread_rwlock_unlock(&pThis->RWLock);
516 if (rc)
517 {
518 AssertMsgFailed(("Failed write unlock read-write sem %p, rc=%d.\n", RWSem, rc));
519 return RTErrConvertFromErrno(rc);
520 }
521
522 return VINF_SUCCESS;
523}
524
525
526RTDECL(bool) RTSemRWIsWriteOwner(RTSEMRW RWSem)
527{
528 /*
529 * Validate input.
530 */
531 struct RTSEMRWINTERNAL *pThis = RWSem;
532 AssertPtrReturn(pThis, false);
533 AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC,
534 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
535 false);
536
537 /*
538 * Check ownership.
539 */
540 pthread_t Self = pthread_self();
541 pthread_t Writer;
542 ATOMIC_GET_PTHREAD_T(&pThis->Writer, &Writer);
543 return Writer == Self;
544}
545
546
547RTDECL(uint32_t) RTSemRWGetWriteRecursion(RTSEMRW RWSem)
548{
549 /*
550 * Validate input.
551 */
552 struct RTSEMRWINTERNAL *pThis = RWSem;
553 AssertPtrReturn(pThis, 0);
554 AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC,
555 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
556 0);
557
558 /*
559 * Return the requested data.
560 */
561 return pThis->cWrites;
562}
563
564
565RTDECL(uint32_t) RTSemRWGetWriterReadRecursion(RTSEMRW RWSem)
566{
567 /*
568 * Validate input.
569 */
570 struct RTSEMRWINTERNAL *pThis = RWSem;
571 AssertPtrReturn(pThis, 0);
572 AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC,
573 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
574 0);
575
576 /*
577 * Return the requested data.
578 */
579 return pThis->cWriterReads;
580}
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