VirtualBox

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

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

IPRT,PDMCritSect,Main: Moved code dealing with lock counting from RTThread to RTLockValidator. Fixed thread termination assertion on windows.

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