VirtualBox

source: vbox/trunk/src/VBox/Runtime/r0drv/solaris/semmutex-r0drv-solaris.c@ 33868

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

scm cleanup.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 10.6 KB
Line 
1/* $Id: semmutex-r0drv-solaris.c 30013 2010-06-03 14:40:59Z vboxsync $ */
2/** @file
3 * IPRT - Mutex Semaphores, Ring-0 Driver, Solaris.
4 */
5
6/*
7 * Copyright (C) 2006-2010 Oracle Corporation
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/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#include "the-solaris-kernel.h"
32#include "internal/iprt.h"
33#include <iprt/semaphore.h>
34
35#include <iprt/assert.h>
36#include <iprt/asm.h>
37#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
38# include <iprt/asm-amd64-x86.h>
39#endif
40#include <iprt/mem.h>
41#include <iprt/err.h>
42#include <iprt/list.h>
43#include <iprt/thread.h>
44
45#include "internal/magics.h"
46
47
48/*******************************************************************************
49* Structures and Typedefs *
50*******************************************************************************/
51/**
52 * Wrapper for the solaris semaphore structure.
53 */
54typedef struct RTSEMMUTEXINTERNAL
55{
56 /** Magic value (RTSEMMUTEX_MAGIC). */
57 uint32_t u32Magic;
58 /** The number of recursions. */
59 uint32_t cRecursions;
60 /** The number of threads waiting for the mutex. */
61 uint32_t volatile cWaiters;
62 /** The number of threads referencing us. */
63 uint32_t volatile cRefs;
64 /** The owner thread, NIL_RTNATIVETHREAD if none. */
65 RTNATIVETHREAD hOwnerThread;
66 /** The mutex object for synchronization. */
67 kmutex_t Mtx;
68 /** The condition variable for synchronization. */
69 kcondvar_t Cnd;
70} RTSEMMUTEXINTERNAL, *PRTSEMMUTEXINTERNAL;
71
72
73RTDECL(int) RTSemMutexCreate(PRTSEMMUTEX phMtx)
74{
75 /*
76 * Allocate.
77 */
78 PRTSEMMUTEXINTERNAL pThis = (PRTSEMMUTEXINTERNAL)RTMemAlloc(sizeof(*pThis));
79 if (RT_UNLIKELY(!pThis))
80 return VERR_NO_MEMORY;
81
82 /*
83 * Initialize.
84 */
85 pThis->u32Magic = RTSEMMUTEX_MAGIC;
86 pThis->cRecursions = 0;
87 pThis->cWaiters = 0;
88 pThis->cRefs = 1;
89 pThis->hOwnerThread = NIL_RTNATIVETHREAD;
90 mutex_init(&pThis->Mtx, "IPRT Mutex", MUTEX_DRIVER, (void *)ipltospl(DISP_LEVEL));
91 cv_init(&pThis->Cnd, "IPRT CVM", CV_DRIVER, NULL);
92 *phMtx = pThis;
93 return VINF_SUCCESS;
94}
95
96
97RTDECL(int) RTSemMutexDestroy(RTSEMMUTEX hMtx)
98{
99 PRTSEMMUTEXINTERNAL pThis = hMtx;
100
101 /*
102 * Validate.
103 */
104 if (pThis == NIL_RTSEMMUTEX)
105 return VINF_SUCCESS;
106 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
107 AssertMsgReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, ("u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), VERR_INVALID_HANDLE);
108
109 mutex_enter(&pThis->Mtx);
110
111 ASMAtomicDecU32(&pThis->cRefs);
112
113 /*
114 * Invalidate the magic to indicate the mutex is being destroyed.
115 */
116 ASMAtomicIncU32(&pThis->u32Magic);
117 if (pThis->cWaiters > 0)
118 {
119 /*
120 * Wake up all waiters, last waiter thread cleans up.
121 */
122 cv_broadcast(&pThis->Cnd);
123 mutex_exit(&pThis->Mtx);
124 }
125 else if (pThis->cRefs == 0)
126 {
127 /*
128 * We're the last waiter, destroy.
129 */
130 mutex_exit(&pThis->Mtx);
131 cv_destroy(&pThis->Cnd);
132 mutex_destroy(&pThis->Mtx);
133 RTMemFree(pThis);
134 }
135 else
136 {
137 /*
138 * We're not the last waiting thread to be woken up. Just relinquish & bail.
139 */
140 mutex_exit(&pThis->Mtx);
141 }
142
143 return VINF_SUCCESS;
144}
145
146
147/**
148 * Worker for rtSemMutexSolarisRequest that handles the case where we go to sleep.
149 *
150 * @returns VINF_SUCCESS, VERR_INTERRUPTED, or VERR_SEM_DESTROYED.
151 * Returns without owning the mutex.
152 * @param pThis The mutex instance.
153 * @param cMillies The timeout, must be > 0 or RT_INDEFINITE_WAIT.
154 * @param fInterruptible The wait type.
155 *
156 * @remarks This needs to be called with the mutex object held!
157 */
158static int rtSemMutexSolarisRequestSleep(PRTSEMMUTEXINTERNAL pThis, RTMSINTERVAL cMillies,
159 bool fInterruptible)
160{
161 int rc = VERR_GENERAL_FAILURE;
162 Assert(cMillies > 0);
163
164 /*
165 * Now we wait (sleep; although might spin and then sleep) & reference the mutex.
166 */
167 ASMAtomicIncU32(&pThis->cWaiters);
168 ASMAtomicIncU32(&pThis->cRefs);
169
170 if (cMillies != RT_INDEFINITE_WAIT)
171 {
172 clock_t cTicks = drv_usectohz((clock_t)(cMillies * 1000L));
173 clock_t cTimeout = ddi_get_lbolt();
174 cTimeout += cTicks;
175 if (fInterruptible)
176 rc = cv_timedwait_sig(&pThis->Cnd, &pThis->Mtx, cTimeout);
177 else
178 rc = cv_timedwait(&pThis->Cnd, &pThis->Mtx, cTimeout);
179 }
180 else
181 {
182 if (fInterruptible)
183 rc = cv_wait_sig(&pThis->Cnd, &pThis->Mtx);
184 else
185 {
186 cv_wait(&pThis->Cnd, &pThis->Mtx);
187 rc = 1;
188 }
189 }
190
191 ASMAtomicDecU32(&pThis->cWaiters);
192 if (rc > 0)
193 {
194 if (pThis->u32Magic == RTSEMMUTEX_MAGIC)
195 {
196 if (pThis->hOwnerThread == NIL_RTNATIVETHREAD)
197 {
198 /*
199 * Woken up by a release from another thread.
200 */
201 Assert(pThis->cRecursions == 0);
202 pThis->cRecursions = 1;
203 pThis->hOwnerThread = RTThreadNativeSelf();
204 rc = VINF_SUCCESS;
205 }
206 else
207 {
208 /*
209 * Interrupted by some signal.
210 */
211 rc = VERR_INTERRUPTED;
212 }
213 }
214 else
215 {
216 /*
217 * Awakened due to the destruction-in-progress broadcast.
218 * We will cleanup if we're the last waiter.
219 */
220 rc = VERR_SEM_DESTROYED;
221 }
222 }
223 else if (rc == -1)
224 {
225 /*
226 * Timed out.
227 */
228 rc = VERR_TIMEOUT;
229 }
230 else
231 {
232 /*
233 * Condition may not have been met, returned due to pending signal.
234 */
235 rc = VERR_INTERRUPTED;
236 }
237
238 if (!ASMAtomicDecU32(&pThis->cRefs))
239 {
240 Assert(RT_FAILURE_NP(rc));
241 mutex_exit(&pThis->Mtx);
242 cv_destroy(&pThis->Cnd);
243 mutex_destroy(&pThis->Mtx);
244 RTMemFree(pThis);
245 return rc;
246 }
247
248 return rc;
249}
250
251
252/**
253 * Internal worker.
254 */
255DECLINLINE(int) rtSemMutexSolarisRequest(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies, bool fInterruptible)
256{
257 PRTSEMMUTEXINTERNAL pThis = hMutexSem;
258 int rc = VERR_GENERAL_FAILURE;
259
260 /*
261 * Validate.
262 */
263 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
264 AssertMsgReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, ("u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), VERR_INVALID_HANDLE);
265 Assert(pThis->cRefs >= 1);
266
267 /*
268 * Lock it and check if it's a recursion.
269 */
270 mutex_enter(&pThis->Mtx);
271 if (pThis->hOwnerThread == RTThreadNativeSelf())
272 {
273 pThis->cRecursions++;
274 Assert(pThis->cRecursions > 1);
275 Assert(pThis->cRecursions < 256);
276 rc = VINF_SUCCESS;
277 }
278 /*
279 * Not a recursion, claim the unowned mutex if we're there are no waiters.
280 */
281 else if ( pThis->hOwnerThread == NIL_RTNATIVETHREAD
282 && pThis->cWaiters == 0)
283 {
284 pThis->cRecursions = 1;
285 pThis->hOwnerThread = RTThreadNativeSelf();
286 rc = VINF_SUCCESS;
287 }
288 /*
289 * A polling call?
290 */
291 else if (cMillies == 0)
292 rc = VERR_TIMEOUT;
293 /*
294 * No, we really need to get to sleep.
295 */
296 else
297 rc = rtSemMutexSolarisRequestSleep(pThis, cMillies, fInterruptible);
298
299 mutex_exit(&pThis->Mtx);
300 return rc;
301}
302
303
304#undef RTSemMutexRequest
305RTDECL(int) RTSemMutexRequest(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies)
306{
307 return rtSemMutexSolarisRequest(hMutexSem, cMillies, false /*fInterruptible*/);
308}
309
310
311RTDECL(int) RTSemMutexRequestDebug(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL)
312{
313 return RTSemMutexRequest(hMutexSem, cMillies);
314}
315
316
317#undef RTSemMutexRequestNoResume
318RTDECL(int) RTSemMutexRequestNoResume(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies)
319{
320 return rtSemMutexSolarisRequest(hMutexSem, cMillies, true /*fInterruptible*/);
321}
322
323
324RTDECL(int) RTSemMutexRequestNoResumeDebug(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL)
325{
326 return RTSemMutexRequestNoResume(hMutexSem, cMillies);
327}
328
329
330RTDECL(int) RTSemMutexRelease(RTSEMMUTEX hMtx)
331{
332 PRTSEMMUTEXINTERNAL pThis = hMtx;
333 int rc;
334
335 /*
336 * Validate.
337 */
338 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
339 AssertMsgReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, ("u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), VERR_INVALID_HANDLE);
340
341 /*
342 * Take the lock and release one recursion.
343 */
344 mutex_enter(&pThis->Mtx);
345 if (pThis->hOwnerThread == RTThreadNativeSelf())
346 {
347 Assert(pThis->cRecursions > 0);
348 if (--pThis->cRecursions == 0)
349 {
350 pThis->hOwnerThread = NIL_RTNATIVETHREAD;
351
352 /*
353 * If there are any waiters, signal one of them.
354 */
355 if (pThis->cWaiters > 0)
356 cv_signal(&pThis->Cnd);
357 }
358 rc = VINF_SUCCESS;
359 }
360 else
361 rc = VERR_NOT_OWNER;
362
363 mutex_exit(&pThis->Mtx);
364 return rc;
365}
366
367
368RTDECL(bool) RTSemMutexIsOwned(RTSEMMUTEX hMutexSem)
369{
370 PRTSEMMUTEXINTERNAL pThis = hMutexSem;
371 bool fOwned = false;
372
373 /*
374 * Validate.
375 */
376 AssertPtrReturn(pThis, false);
377 AssertMsgReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, ("u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), false);
378
379 /*
380 * Check if this is the owner.
381 */
382 mutex_enter(&pThis->Mtx);
383 fOwned = pThis->hOwnerThread != NIL_RTNATIVETHREAD;
384 mutex_exit(&pThis->Mtx);
385
386 return fOwned;
387}
388
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