VirtualBox

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

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

IPRT,PDMCritSect: More lock validation.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 16.1 KB
Line 
1/* $Id: semrw-posix.cpp 25467 2009-12-17 15:16:55Z 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.virtualbox.org. 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, RTSEMRW_STRICT_POS_DECL)
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, RTSEMRW_STRICT_POS_ARGS);
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, RTSEMRW_STRICT_POS_ARGS);
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, uId, RT_SRC_POS_ARGS);
360 if (RT_FAILURE(rc9))
361 return rc9;
362#else
363 RTThreadBlocking(hThreadSelf, RTTHREADSTATE_RW_WRITE);
364#endif
365 }
366
367 if (cMillies == RT_INDEFINITE_WAIT)
368 {
369 /* take rwlock */
370 int rc = pthread_rwlock_wrlock(&pThis->RWLock);
371 RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_RW_WRITE);
372 if (rc)
373 {
374 AssertMsgFailed(("Failed write lock read-write sem %p, rc=%d.\n", RWSem, rc));
375 return RTErrConvertFromErrno(rc);
376 }
377 }
378 else
379 {
380#ifdef RT_OS_DARWIN
381 AssertMsgFailed(("Not implemented on Darwin yet because of incomplete pthreads API."));
382 return VERR_NOT_IMPLEMENTED;
383#else /* !RT_OS_DARWIN */
384 /*
385 * Get current time and calc end of wait time.
386 */
387 struct timespec ts = {0,0};
388 clock_gettime(CLOCK_REALTIME, &ts);
389 if (cMillies != 0)
390 {
391 ts.tv_nsec += (cMillies % 1000) * 1000000;
392 ts.tv_sec += cMillies / 1000;
393 if (ts.tv_nsec >= 1000000000)
394 {
395 ts.tv_nsec -= 1000000000;
396 ts.tv_sec++;
397 }
398 }
399
400 /* take rwlock */
401 int rc = pthread_rwlock_timedwrlock(&pThis->RWLock, &ts);
402 RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_RW_WRITE);
403 if (rc)
404 {
405 AssertMsg(rc == ETIMEDOUT, ("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));
406 return RTErrConvertFromErrno(rc);
407 }
408#endif /* !RT_OS_DARWIN */
409 }
410
411 ATOMIC_SET_PTHREAD_T(&pThis->Writer, Self);
412 pThis->cWrites = 1;
413#ifdef RTSEMRW_STRICT
414 RTLockValidatorSetOwner(&pThis->ValidatorRec, hThreadSelf, RTSEMRW_STRICT_POS_ARGS);
415#endif
416 return VINF_SUCCESS;
417}
418
419
420RTDECL(int) RTSemRWRequestWrite(RTSEMRW RWSem, unsigned cMillies)
421{
422#ifndef RTSEMRW_STRICT
423 return rtSemRWRequestWrite(RWSem, cMillies, RTSEMRW_STRICT_POS_ARGS);
424#else
425 return RTSemRWRequestWriteDebug(RWSem, cMillies, (uintptr_t)ASMReturnAddress(), RT_SRC_POS);
426#endif
427}
428
429
430RTDECL(int) RTSemRWRequestWriteDebug(RTSEMRW RWSem, unsigned cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL)
431{
432#ifdef RTSEMRW_STRICT
433 return rtSemRWRequestWrite(RWSem, cMillies, RTSEMRW_STRICT_POS_ARGS);
434#else
435 return RTSemRWRequestWrite(RWSem, cMillies);
436#endif
437}
438
439
440RTDECL(int) RTSemRWRequestWriteNoResume(RTSEMRW RWSem, unsigned cMillies)
441{
442 /* EINTR isn't returned by the wait functions we're using. */
443#ifndef RTSEMRW_STRICT
444 return RTSemRWRequestWrite(RWSem, cMillies);
445#else
446 return RTSemRWRequestWriteDebug(RWSem, cMillies, (uintptr_t)ASMReturnAddress(), RT_SRC_POS);
447#endif
448}
449
450
451RTDECL(int) RTSemRWRequestWriteNoResumeDebug(RTSEMRW RWSem, unsigned cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL)
452{
453 /* EINTR isn't returned by the wait functions we're using. */
454#ifdef RTSEMRW_STRICT
455 return RTSemRWRequestWriteDebug(RWSem, cMillies, RTSEMRW_STRICT_POS_ARGS);
456#else
457 return RTSemRWRequestWrite(RWSem, cMillies);
458#endif
459}
460
461
462RTDECL(int) RTSemRWReleaseWrite(RTSEMRW RWSem)
463{
464 /*
465 * Validate input.
466 */
467 struct RTSEMRWINTERNAL *pThis = RWSem;
468 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
469 AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC,
470 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
471 VERR_INVALID_HANDLE);
472
473 /*
474 * Verify ownership and implement recursion.
475 */
476 pthread_t Self = pthread_self();
477 pthread_t Writer;
478 ATOMIC_GET_PTHREAD_T(&pThis->Writer, &Writer);
479 AssertMsgReturn(Writer == Self, ("pThis=%p\n", pThis), VERR_NOT_OWNER);
480 AssertReturn(pThis->cWriterReads == 0 || pThis->cWrites > 1, VERR_WRONG_ORDER);
481
482 pThis->cWrites--;
483 if (pThis->cWrites)
484 {
485#ifdef RTSEMRW_STRICT
486 RTLockValidatorRecordUnwind(&pThis->ValidatorRec);
487#endif
488 return VINF_SUCCESS;
489 }
490
491 /*
492 * Try unlock it.
493 */
494#ifdef RTSEMRW_STRICT
495 RTLockValidatorCheckReleaseOrder(&pThis->ValidatorRec);
496 RTLockValidatorUnsetOwner(&pThis->ValidatorRec);
497#endif
498
499 ATOMIC_SET_PTHREAD_T(&pThis->Writer, (pthread_t)-1);
500 int rc = pthread_rwlock_unlock(&pThis->RWLock);
501 if (rc)
502 {
503 AssertMsgFailed(("Failed write unlock read-write sem %p, rc=%d.\n", RWSem, rc));
504 return RTErrConvertFromErrno(rc);
505 }
506
507 return VINF_SUCCESS;
508}
509
510
511RTDECL(bool) RTSemRWIsWriteOwner(RTSEMRW RWSem)
512{
513 /*
514 * Validate input.
515 */
516 struct RTSEMRWINTERNAL *pThis = RWSem;
517 AssertPtrReturn(pThis, false);
518 AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC,
519 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
520 false);
521
522 /*
523 * Check ownership.
524 */
525 pthread_t Self = pthread_self();
526 pthread_t Writer;
527 ATOMIC_GET_PTHREAD_T(&pThis->Writer, &Writer);
528 return Writer == Self;
529}
530
531
532RTDECL(uint32_t) RTSemRWGetWriteRecursion(RTSEMRW RWSem)
533{
534 /*
535 * Validate input.
536 */
537 struct RTSEMRWINTERNAL *pThis = RWSem;
538 AssertPtrReturn(pThis, 0);
539 AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC,
540 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
541 0);
542
543 /*
544 * Return the requested data.
545 */
546 return pThis->cWrites;
547}
548
549
550RTDECL(uint32_t) RTSemRWGetWriterReadRecursion(RTSEMRW RWSem)
551{
552 /*
553 * Validate input.
554 */
555 struct RTSEMRWINTERNAL *pThis = RWSem;
556 AssertPtrReturn(pThis, 0);
557 AssertMsgReturn(pThis->u32Magic == RTSEMRW_MAGIC,
558 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
559 0);
560
561 /*
562 * Return the requested data.
563 */
564 return pThis->cWriterReads;
565}
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