VirtualBox

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

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

split up the linux and posix semaphore implementations (ring-3) to avoid code duplication and make it easier to select one or the other for each of the semaphore types.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 9.4 KB
Line 
1/* $Id: semrw-posix.cpp 6738 2008-02-01 21:45:27Z vboxsync $ */
2/** @file
3 * innotek Portable Runtime - Read-Write Semaphore, POSIX.
4 */
5
6/*
7 * Copyright (C) 2006-2007 innotek GmbH
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
27/*******************************************************************************
28* Header Files *
29*******************************************************************************/
30#include <iprt/semaphore.h>
31#include <iprt/assert.h>
32#include <iprt/alloc.h>
33#include <iprt/asm.h>
34#include <iprt/err.h>
35
36#include <errno.h>
37#include <pthread.h>
38#include <unistd.h>
39#include <sys/time.h>
40
41
42/*******************************************************************************
43* Structures and Typedefs *
44*******************************************************************************/
45/** Posix internal representation of a read-write semaphore. */
46struct RTSEMRWINTERNAL
47{
48 /** pthread rwlock. */
49 pthread_rwlock_t RWLock;
50 /** Variable to check if initialized.
51 * 0 is uninitialized, ~0 is inititialized. */
52 volatile unsigned uCheck;
53 /** The write owner of the lock. */
54 volatile pthread_t WROwner;
55};
56
57
58
59/**
60 * Validate a read-write semaphore handle passed to one of the interface.
61 *
62 * @returns true if valid.
63 * @returns false if invalid.
64 * @param pIntRWSem Pointer to the read-write semaphore to validate.
65 */
66inline bool rtsemRWValid(struct RTSEMRWINTERNAL *pIntRWSem)
67{
68 if ((uintptr_t)pIntRWSem < 0x10000)
69 return false;
70
71 if (pIntRWSem->uCheck != (unsigned)~0)
72 return false;
73
74 return true;
75}
76
77
78RTDECL(int) RTSemRWCreate(PRTSEMRW pRWSem)
79{
80 int rc;
81
82 /*
83 * Allocate handle.
84 */
85 struct RTSEMRWINTERNAL *pIntRWSem = (struct RTSEMRWINTERNAL *)RTMemAlloc(sizeof(struct RTSEMRWINTERNAL));
86 if (pIntRWSem)
87 {
88 /*
89 * Create the rwlock.
90 */
91 pthread_rwlockattr_t Attr;
92 rc = pthread_rwlockattr_init(&Attr);
93 if (!rc)
94 {
95 rc = pthread_rwlock_init(&pIntRWSem->RWLock, &Attr);
96 if (!rc)
97 {
98 pIntRWSem->uCheck = ~0;
99 pIntRWSem->WROwner = (pthread_t)-1;
100 *pRWSem = pIntRWSem;
101 return VINF_SUCCESS;
102 }
103 }
104
105 rc = RTErrConvertFromErrno(rc);
106 RTMemFree(pIntRWSem);
107 }
108 else
109 rc = VERR_NO_MEMORY;
110
111 return rc;
112}
113
114
115RTDECL(int) RTSemRWDestroy(RTSEMRW RWSem)
116{
117 /*
118 * Validate input.
119 */
120 if (!rtsemRWValid(RWSem))
121 {
122 AssertMsgFailed(("Invalid handle %p!\n", RWSem));
123 return VERR_INVALID_HANDLE;
124 }
125
126 /*
127 * Try destroy it.
128 */
129 struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
130 int rc = pthread_rwlock_destroy(&pIntRWSem->RWLock);
131 if (!rc)
132 {
133 pIntRWSem->uCheck = 0;
134 RTMemFree(pIntRWSem);
135 rc = VINF_SUCCESS;
136 }
137 else
138 {
139 AssertMsgFailed(("Failed to destroy read-write sem %p, rc=%d.\n", RWSem, rc));
140 rc = RTErrConvertFromErrno(rc);
141 }
142
143 return rc;
144}
145
146
147RTDECL(int) RTSemRWRequestRead(RTSEMRW RWSem, unsigned cMillies)
148{
149 /*
150 * Validate input.
151 */
152 if (!rtsemRWValid(RWSem))
153 {
154 AssertMsgFailed(("Invalid handle %p!\n", RWSem));
155 return VERR_INVALID_HANDLE;
156 }
157
158 /*
159 * Try lock it.
160 */
161 struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
162 if (cMillies == RT_INDEFINITE_WAIT)
163 {
164 /* take rwlock */
165 int rc = pthread_rwlock_rdlock(&pIntRWSem->RWLock);
166 if (rc)
167 {
168 AssertMsgFailed(("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));
169 return RTErrConvertFromErrno(rc);
170 }
171 }
172 else
173 {
174#ifdef RT_OS_DARWIN
175 AssertMsgFailed(("Not implemented on Darwin yet because of incomplete pthreads API."));
176 return VERR_NOT_IMPLEMENTED;
177#else /* !RT_OS_DARWIN */
178 /*
179 * Get current time and calc end of wait time.
180 */
181 struct timespec ts = {0,0};
182 clock_gettime(CLOCK_REALTIME, &ts);
183 if (cMillies != 0)
184 {
185 ts.tv_nsec += (cMillies % 1000) * 1000000;
186 ts.tv_sec += cMillies / 1000;
187 if (ts.tv_nsec >= 1000000000)
188 {
189 ts.tv_nsec -= 1000000000;
190 ts.tv_sec++;
191 }
192 }
193
194 /* take rwlock */
195 int rc = pthread_rwlock_timedrdlock(&pIntRWSem->RWLock, &ts);
196 if (rc)
197 {
198 AssertMsg(rc == ETIMEDOUT, ("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));
199 return RTErrConvertFromErrno(rc);
200 }
201#endif /* !RT_OS_DARWIN */
202 }
203
204 return VINF_SUCCESS;
205}
206
207
208RTDECL(int) RTSemRWRequestReadNoResume(RTSEMRW RWSem, unsigned cMillies)
209{
210 /* EINTR isn't returned by the wait functions we're using. */
211 return RTSemRWRequestRead(RWSem, cMillies);
212}
213
214
215RTDECL(int) RTSemRWReleaseRead(RTSEMRW RWSem)
216{
217 /*
218 * Validate input.
219 */
220 if (!rtsemRWValid(RWSem))
221 {
222 AssertMsgFailed(("Invalid handle %p!\n", RWSem));
223 return VERR_INVALID_HANDLE;
224 }
225
226 /*
227 * Try unlock it.
228 */
229 struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
230 if (pIntRWSem->WROwner == pthread_self())
231 {
232 AssertMsgFailed(("Tried to read unlock when write owner - read-write sem %p.\n", RWSem));
233 return VERR_NOT_OWNER;
234 }
235 int rc = pthread_rwlock_unlock(&pIntRWSem->RWLock);
236 if (rc)
237 {
238 AssertMsgFailed(("Failed read unlock read-write sem %p, rc=%d.\n", RWSem, rc));
239 return RTErrConvertFromErrno(rc);
240 }
241
242 return VINF_SUCCESS;
243}
244
245
246RTDECL(int) RTSemRWRequestWrite(RTSEMRW RWSem, unsigned cMillies)
247{
248 /*
249 * Validate input.
250 */
251 if (!rtsemRWValid(RWSem))
252 {
253 AssertMsgFailed(("Invalid handle %p!\n", RWSem));
254 return VERR_INVALID_HANDLE;
255 }
256
257 /*
258 * Try lock it.
259 */
260 struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
261 if (cMillies == RT_INDEFINITE_WAIT)
262 {
263 /* take rwlock */
264 int rc = pthread_rwlock_wrlock(&pIntRWSem->RWLock);
265 if (rc)
266 {
267 AssertMsgFailed(("Failed write lock read-write sem %p, rc=%d.\n", RWSem, rc));
268 return RTErrConvertFromErrno(rc);
269 }
270 }
271 else
272 {
273#ifdef RT_OS_DARWIN
274 AssertMsgFailed(("Not implemented on Darwin yet because of incomplete pthreads API."));
275 return VERR_NOT_IMPLEMENTED;
276#else /* !RT_OS_DARWIN */
277 /*
278 * Get current time and calc end of wait time.
279 */
280 struct timespec ts = {0,0};
281 clock_gettime(CLOCK_REALTIME, &ts);
282 if (cMillies != 0)
283 {
284 ts.tv_nsec += (cMillies % 1000) * 1000000;
285 ts.tv_sec += cMillies / 1000;
286 if (ts.tv_nsec >= 1000000000)
287 {
288 ts.tv_nsec -= 1000000000;
289 ts.tv_sec++;
290 }
291 }
292
293 /* take rwlock */
294 int rc = pthread_rwlock_timedwrlock(&pIntRWSem->RWLock, &ts);
295 if (rc)
296 {
297 AssertMsg(rc == ETIMEDOUT, ("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));
298 return RTErrConvertFromErrno(rc);
299 }
300#endif /* !RT_OS_DARWIN */
301 }
302
303#ifdef RT_OS_SOLARIS
304 ASMAtomicXchgSize(&pIntRWSem->WROwner, pthread_self());
305#else
306 ASMAtomicXchgPtr((void * volatile *)&pIntRWSem->WROwner, (void *)pthread_self());
307#endif
308
309 return VINF_SUCCESS;
310}
311
312
313RTDECL(int) RTSemRWRequestWriteNoResume(RTSEMRW RWSem, unsigned cMillies)
314{
315 /* EINTR isn't returned by the wait functions we're using. */
316 return RTSemRWRequestWrite(RWSem, cMillies);
317}
318
319
320RTDECL(int) RTSemRWReleaseWrite(RTSEMRW RWSem)
321{
322 /*
323 * Validate input.
324 */
325 if (!rtsemRWValid(RWSem))
326 {
327 AssertMsgFailed(("Invalid handle %p!\n", RWSem));
328 return VERR_INVALID_HANDLE;
329 }
330
331 /*
332 * Try unlock it.
333 */
334 pthread_t Self = pthread_self();
335 struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
336 if (pIntRWSem->WROwner != Self)
337 {
338 AssertMsgFailed(("Not Write owner!\n"));
339 return VERR_NOT_OWNER;
340 }
341
342 /*
343 * Try unlock it.
344 */
345#ifdef RT_OS_SOLARIS
346 ASMAtomicXchgSize(&pIntRWSem->WROwner, (pthread_t)-1);
347#else
348 AssertMsg(sizeof(pthread_t) == sizeof(void *), ("pthread_t is not the size of a pointer but %d bytes\n", sizeof(pthread_t)));
349 ASMAtomicXchgPtr((void * volatile *)&pIntRWSem->WROwner, (void *)(pthread_t)-1);
350#endif
351 int rc = pthread_rwlock_unlock(&pIntRWSem->RWLock);
352 if (rc)
353 {
354 AssertMsgFailed(("Failed write unlock read-write sem %p, rc=%d.\n", RWSem, rc));
355 return RTErrConvertFromErrno(rc);
356 }
357
358 return VINF_SUCCESS;
359}
360
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