VirtualBox

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

Last change on this file was 98103, checked in by vboxsync, 17 months ago

Copyright year updates by scm.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use