VirtualBox

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

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

IPRT,PDMCritSect: More lock validator refactoring.

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