VirtualBox

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

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

IPRT,PDMCritSect: Fixing critsect regression; contains under construction rw deadlock detection code.

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