VirtualBox

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

Last change on this file since 69111 was 69111, checked in by vboxsync, 7 years ago

(C) year

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