VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/posix/semmutex-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: 7.5 KB
Line 
1/* $Id: semmutex-posix.cpp 6738 2008-02-01 21:45:27Z vboxsync $ */
2/** @file
3 * innotek Portable Runtime - Mutex 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 Mutex semaphore. */
46struct RTSEMMUTEXINTERNAL
47{
48 /** pthread mutex. */
49 pthread_mutex_t Mutex;
50 /** The owner of the mutex. */
51 volatile pthread_t Owner;
52 /** Nesting count. */
53 volatile uint32_t cNesting;
54};
55
56
57
58/**
59 * Validate a Mutex semaphore handle passed to one of the interface.
60 *
61 * @returns true if valid.
62 * @returns false if invalid.
63 * @param pIntMutexSem Pointer to the mutex semaphore to validate.
64 */
65inline bool rtsemMutexValid(struct RTSEMMUTEXINTERNAL *pIntMutexSem)
66{
67 if ((uintptr_t)pIntMutexSem < 0x10000)
68 return false;
69
70 if (pIntMutexSem->cNesting == (uint32_t)~0)
71 return false;
72
73 return true;
74}
75
76
77RTDECL(int) RTSemMutexCreate(PRTSEMMUTEX pMutexSem)
78{
79 int rc;
80
81 /*
82 * Allocate semaphore handle.
83 */
84 struct RTSEMMUTEXINTERNAL *pIntMutexSem = (struct RTSEMMUTEXINTERNAL *)RTMemAlloc(sizeof(struct RTSEMMUTEXINTERNAL));
85 if (pIntMutexSem)
86 {
87 /*
88 * Create the semaphore.
89 */
90 pthread_mutexattr_t MutexAttr;
91 rc = pthread_mutexattr_init(&MutexAttr);
92 if (!rc)
93 {
94 rc = pthread_mutex_init(&pIntMutexSem->Mutex, &MutexAttr);
95 if (!rc)
96 {
97 pthread_mutexattr_destroy(&MutexAttr);
98
99 pIntMutexSem->Owner = (pthread_t)-1;
100 pIntMutexSem->cNesting = 0;
101
102 *pMutexSem = pIntMutexSem;
103 return VINF_SUCCESS;
104 }
105 pthread_mutexattr_destroy(&MutexAttr);
106 }
107 RTMemFree(pIntMutexSem);
108 }
109 else
110 rc = VERR_NO_MEMORY;
111
112 return rc;
113}
114
115
116RTDECL(int) RTSemMutexDestroy(RTSEMMUTEX MutexSem)
117{
118 /*
119 * Validate input.
120 */
121 if (!rtsemMutexValid(MutexSem))
122 {
123 AssertMsgFailed(("Invalid handle %p!\n", MutexSem));
124 return VERR_INVALID_HANDLE;
125 }
126
127 /*
128 * Try destroy it.
129 */
130 struct RTSEMMUTEXINTERNAL *pIntMutexSem = MutexSem;
131 int rc = pthread_mutex_destroy(&pIntMutexSem->Mutex);
132 if (rc)
133 {
134 AssertMsgFailed(("Failed to destroy mutex sem %p, rc=%d.\n", MutexSem, rc));
135 return RTErrConvertFromErrno(rc);
136 }
137
138 /*
139 * Free the memory and be gone.
140 */
141 pIntMutexSem->Owner = (pthread_t)-1;
142 pIntMutexSem->cNesting = ~0;
143 RTMemTmpFree(pIntMutexSem);
144
145 return VINF_SUCCESS;
146}
147
148
149RTDECL(int) RTSemMutexRequest(RTSEMMUTEX MutexSem, unsigned cMillies)
150{
151 /*
152 * Validate input.
153 */
154 if (!rtsemMutexValid(MutexSem))
155 {
156 AssertMsgFailed(("Invalid handle %p!\n", MutexSem));
157 return VERR_INVALID_HANDLE;
158 }
159
160 /*
161 * Check if nested request.
162 */
163 pthread_t Self = pthread_self();
164 struct RTSEMMUTEXINTERNAL *pIntMutexSem = MutexSem;
165 if ( pIntMutexSem->Owner == Self
166 && pIntMutexSem->cNesting > 0)
167 {
168 pIntMutexSem->cNesting++;
169 return VINF_SUCCESS;
170 }
171
172 /*
173 * Lock it.
174 */
175 if (cMillies == RT_INDEFINITE_WAIT)
176 {
177 /* take mutex */
178 int rc = pthread_mutex_lock(&pIntMutexSem->Mutex);
179 if (rc)
180 {
181 AssertMsgFailed(("Failed to lock mutex sem %p, rc=%d.\n", MutexSem, rc)); NOREF(rc);
182 return RTErrConvertFromErrno(rc);
183 }
184 }
185 else
186 {
187#ifdef RT_OS_DARWIN
188 AssertMsgFailed(("Not implemented on Darwin yet because of incomplete pthreads API."));
189 return VERR_NOT_IMPLEMENTED;
190#else /* !RT_OS_DARWIN */
191 /*
192 * Get current time and calc end of wait time.
193 */
194 struct timespec ts = {0,0};
195 clock_gettime(CLOCK_REALTIME, &ts);
196 if (cMillies != 0)
197 {
198 ts.tv_nsec += (cMillies % 1000) * 1000000;
199 ts.tv_sec += cMillies / 1000;
200 if (ts.tv_nsec >= 1000000000)
201 {
202 ts.tv_nsec -= 1000000000;
203 ts.tv_sec++;
204 }
205 }
206
207 /* take mutex */
208 int rc = pthread_mutex_timedlock(&pIntMutexSem->Mutex, &ts);
209 if (rc)
210 {
211 AssertMsg(rc == ETIMEDOUT, ("Failed to lock mutex sem %p, rc=%d.\n", MutexSem, rc)); NOREF(rc);
212 return RTErrConvertFromErrno(rc);
213 }
214#endif /* !RT_OS_DARWIN */
215 }
216
217 /*
218 * Set the owner and nesting.
219 */
220 pIntMutexSem->Owner = Self;
221 ASMAtomicXchgU32(&pIntMutexSem->cNesting, 1);
222
223 return VINF_SUCCESS;
224}
225
226
227RTDECL(int) RTSemMutexRequestNoResume(RTSEMMUTEX MutexSem, unsigned cMillies)
228{
229 /* EINTR isn't returned by the wait functions we're using. */
230 return RTSemMutexRequest(MutexSem, cMillies);
231}
232
233
234RTDECL(int) RTSemMutexRelease(RTSEMMUTEX MutexSem)
235{
236 /*
237 * Validate input.
238 */
239 if (!rtsemMutexValid(MutexSem))
240 {
241 AssertMsgFailed(("Invalid handle %p!\n", MutexSem));
242 return VERR_INVALID_HANDLE;
243 }
244
245 /*
246 * Check if nested.
247 */
248 pthread_t Self = pthread_self();
249 struct RTSEMMUTEXINTERNAL *pIntMutexSem = MutexSem;
250 if ( pIntMutexSem->Owner != Self
251 || pIntMutexSem->cNesting == (uint32_t)~0)
252 {
253 AssertMsgFailed(("Not owner of mutex %p!! Self=%08x Owner=%08x cNesting=%d\n",
254 pIntMutexSem, Self, pIntMutexSem->Owner, pIntMutexSem->cNesting));
255 return VERR_NOT_OWNER;
256 }
257
258 /*
259 * If nested we'll just pop a nesting.
260 */
261 if (pIntMutexSem->cNesting > 1)
262 {
263 pIntMutexSem->cNesting--;
264 return VINF_SUCCESS;
265 }
266
267 /*
268 * Clear the state. (cNesting == 1)
269 */
270 pIntMutexSem->Owner = (pthread_t)-1;
271 ASMAtomicXchgU32(&pIntMutexSem->cNesting, 0);
272
273 /*
274 * Unlock mutex semaphore.
275 */
276 int rc = pthread_mutex_unlock(&pIntMutexSem->Mutex);
277 if (rc)
278 {
279 AssertMsgFailed(("Failed to unlock mutex sem %p, rc=%d.\n", MutexSem, rc)); NOREF(rc);
280 return RTErrConvertFromErrno(rc);
281 }
282
283 return VINF_SUCCESS;
284}
285
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