VirtualBox

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

Last change on this file since 10450 was 8653, checked in by vboxsync, 16 years ago

Added RTSemRWIsWriteOwner, RTSemRWGetWriteRecursion and RTSemRWGetWriterReadRecursion.

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette