VirtualBox

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

Last change on this file since 8245 was 8245, checked in by vboxsync, 17 years ago

rebranding: IPRT files again.

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