VirtualBox

source: vbox/trunk/src/VBox/Runtime/r0drv/solaris/semeventmulti-r0drv-solaris.c@ 28800

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

Automated rebranding to Oracle copyright/license strings via filemuncher

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.0 KB
Line 
1/* $Id: semeventmulti-r0drv-solaris.c 28800 2010-04-27 08:22:32Z vboxsync $ */
2/** @file
3 * IPRT - Multiple Release Event Semaphores, Ring-0 Driver, Solaris.
4 */
5
6/*
7 * Copyright (C) 2006-2007 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#include <iprt/err.h>
38#include <iprt/mem.h>
39#include <iprt/mp.h>
40#include <iprt/thread.h>
41#include "internal/magics.h"
42
43
44/*******************************************************************************
45* Structures and Typedefs *
46*******************************************************************************/
47/**
48 * FreeBSD multiple release event semaphore.
49 */
50typedef struct RTSEMEVENTMULTIINTERNAL
51{
52 /** Magic value (RTSEMEVENTMULTI_MAGIC). */
53 uint32_t volatile u32Magic;
54 /** The number of waiting threads. */
55 uint32_t volatile cWaiters;
56 /** Set if the event object is signaled. */
57 uint8_t volatile fSignaled;
58 /** The number of threads in the process of waking up. */
59 uint32_t volatile cWaking;
60 /** The Solaris mutex protecting this structure and pairing up the with the cv. */
61 kmutex_t Mtx;
62 /** The Solaris condition variable. */
63 kcondvar_t Cnd;
64} RTSEMEVENTMULTIINTERNAL, *PRTSEMEVENTMULTIINTERNAL;
65
66
67
68RTDECL(int) RTSemEventMultiCreate(PRTSEMEVENTMULTI phEventMultiSem)
69{
70 return RTSemEventMultiCreateEx(phEventMultiSem, 0 /*fFlags*/, NIL_RTLOCKVALCLASS, NULL);
71}
72
73
74RTDECL(int) RTSemEventMultiCreateEx(PRTSEMEVENTMULTI phEventMultiSem, uint32_t fFlags, RTLOCKVALCLASS hClass,
75 const char *pszNameFmt, ...)
76{
77 AssertReturn(!(fFlags & ~RTSEMEVENTMULTI_FLAGS_NO_LOCK_VAL), VERR_INVALID_PARAMETER);
78 AssertPtrReturn(phEventMultiSem, VERR_INVALID_POINTER);
79 RT_ASSERT_PREEMPTIBLE();
80
81 AssertCompile(sizeof(RTSEMEVENTMULTIINTERNAL) > sizeof(void *));
82 PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)RTMemAlloc(sizeof(*pThis));
83 if (pThis)
84 {
85 pThis->u32Magic = RTSEMEVENTMULTI_MAGIC;
86 pThis->cWaiters = 0;
87 pThis->cWaking = 0;
88 pThis->fSignaled = 0;
89 mutex_init(&pThis->Mtx, "IPRT Multiple Release Event Semaphore", MUTEX_DRIVER, (void *)ipltospl(DISP_LEVEL));
90 cv_init(&pThis->Cnd, "IPRT CV", CV_DRIVER, NULL);
91
92 *phEventMultiSem = pThis;
93 return VINF_SUCCESS;
94 }
95 return VERR_NO_MEMORY;
96}
97
98
99RTDECL(int) RTSemEventMultiDestroy(RTSEMEVENTMULTI hEventMultiSem)
100{
101 PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
102 if (pThis == NIL_RTSEMEVENTMULTI)
103 return VINF_SUCCESS;
104 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
105 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);
106 RT_ASSERT_INTS_ON();
107
108 mutex_enter(&pThis->Mtx);
109 ASMAtomicIncU32(&pThis->u32Magic); /* make the handle invalid */
110 if (pThis->cWaiters > 0)
111 {
112 /* abort waiting thread, last man cleans up. */
113 ASMAtomicXchgU32(&pThis->cWaking, pThis->cWaking + pThis->cWaiters);
114 cv_broadcast(&pThis->Cnd);
115 mutex_exit(&pThis->Mtx);
116 }
117 else if (pThis->cWaking)
118 /* the last waking thread is gonna do the cleanup */
119 mutex_exit(&pThis->Mtx);
120 else
121 {
122 mutex_exit(&pThis->Mtx);
123 cv_destroy(&pThis->Cnd);
124 mutex_destroy(&pThis->Mtx);
125 RTMemFree(pThis);
126 }
127
128 return VINF_SUCCESS;
129}
130
131
132RTDECL(int) RTSemEventMultiSignal(RTSEMEVENTMULTI hEventMultiSem)
133{
134 PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
135 RT_ASSERT_PREEMPT_CPUID_VAR();
136
137 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
138 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC,
139 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
140 VERR_INVALID_HANDLE);
141 RT_ASSERT_INTS_ON();
142
143 /*
144 * If we're in interrupt context we need to unpin the underlying current
145 * thread as this could lead to a deadlock (see #4259 for the full explanation)
146 *
147 * Note! See remarks about preemption in RTSemEventSignal.
148 */
149 int fAcquired = mutex_tryenter(&pThis->Mtx);
150 if (!fAcquired)
151 {
152 if (curthread->t_intr && getpil() < DISP_LEVEL)
153 {
154 RTTHREADPREEMPTSTATE PreemptState = RTTHREADPREEMPTSTATE_INITIALIZER;
155 RTThreadPreemptDisable(&PreemptState);
156 preempt();
157 RTThreadPreemptRestore(&PreemptState);
158 }
159 mutex_enter(&pThis->Mtx);
160 }
161
162 ASMAtomicXchgU8(&pThis->fSignaled, true);
163 if (pThis->cWaiters > 0)
164 {
165 ASMAtomicXchgU32(&pThis->cWaking, pThis->cWaking + pThis->cWaiters);
166 ASMAtomicXchgU32(&pThis->cWaiters, 0);
167 cv_broadcast(&pThis->Cnd);
168 }
169
170 mutex_exit(&pThis->Mtx);
171
172 RT_ASSERT_PREEMPT_CPUID();
173 return VINF_SUCCESS;
174}
175
176
177RTDECL(int) RTSemEventMultiReset(RTSEMEVENTMULTI hEventMultiSem)
178{
179 PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
180 RT_ASSERT_PREEMPT_CPUID_VAR();
181
182 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
183 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC,
184 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
185 VERR_INVALID_HANDLE);
186 RT_ASSERT_INTS_ON();
187
188 /*
189 * If we're in interrupt context we need to unpin the underlying current
190 * thread as this could lead to a deadlock (see #4259 for the full explanation)
191 *
192 * Note! See remarks about preemption in RTSemEventSignal.
193 */
194 int fAcquired = mutex_tryenter(&pThis->Mtx);
195 if (!fAcquired)
196 {
197 if (curthread->t_intr && getpil() < DISP_LEVEL)
198 {
199 RTTHREADPREEMPTSTATE PreemptState = RTTHREADPREEMPTSTATE_INITIALIZER;
200 RTThreadPreemptDisable(&PreemptState);
201 preempt();
202 RTThreadPreemptRestore(&PreemptState);
203 }
204 mutex_enter(&pThis->Mtx);
205 }
206
207 ASMAtomicXchgU8(&pThis->fSignaled, false);
208 mutex_exit(&pThis->Mtx);
209
210 RT_ASSERT_PREEMPT_CPUID();
211 return VINF_SUCCESS;
212}
213
214
215static int rtSemEventMultiWait(RTSEMEVENTMULTI hEventMultiSem, RTMSINTERVAL cMillies, bool fInterruptible)
216{
217 int rc;
218 PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
219 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
220 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC,
221 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
222 VERR_INVALID_HANDLE);
223 if (cMillies)
224 RT_ASSERT_PREEMPTIBLE();
225
226 mutex_enter(&pThis->Mtx);
227
228 if (pThis->fSignaled)
229 rc = VINF_SUCCESS;
230 else if (!cMillies)
231 rc = VERR_TIMEOUT;
232 else
233 {
234 ASMAtomicIncU32(&pThis->cWaiters);
235
236 /*
237 * Translate milliseconds into ticks and go to sleep.
238 */
239 if (cMillies != RT_INDEFINITE_WAIT)
240 {
241 clock_t cTicks = drv_usectohz((clock_t)(cMillies * 1000L));
242 clock_t cTimeout = ddi_get_lbolt();
243 cTimeout += cTicks;
244 if (fInterruptible)
245 rc = cv_timedwait_sig(&pThis->Cnd, &pThis->Mtx, cTimeout);
246 else
247 rc = cv_timedwait(&pThis->Cnd, &pThis->Mtx, cTimeout);
248 }
249 else
250 {
251 if (fInterruptible)
252 rc = cv_wait_sig(&pThis->Cnd, &pThis->Mtx);
253 else
254 {
255 cv_wait(&pThis->Cnd, &pThis->Mtx);
256 rc = 1;
257 }
258 }
259 if (rc > 0)
260 {
261 /* Retured due to call to cv_signal() or cv_broadcast() */
262 if (RT_LIKELY(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC))
263 {
264 rc = VINF_SUCCESS;
265 ASMAtomicDecU32(&pThis->cWaking);
266 }
267 else
268 {
269 rc = VERR_SEM_DESTROYED;
270 if (!ASMAtomicDecU32(&pThis->cWaking))
271 {
272 mutex_exit(&pThis->Mtx);
273 cv_destroy(&pThis->Cnd);
274 mutex_destroy(&pThis->Mtx);
275 RTMemFree(pThis);
276 return rc;
277 }
278 }
279 }
280 else if (rc == -1)
281 {
282 /* Returned due to timeout being reached */
283 if (pThis->cWaiters > 0)
284 ASMAtomicDecU32(&pThis->cWaiters);
285 rc = VERR_TIMEOUT;
286 }
287 else
288 {
289 /* Returned due to pending signal */
290 if (pThis->cWaiters > 0)
291 ASMAtomicDecU32(&pThis->cWaiters);
292 rc = VERR_INTERRUPTED;
293 }
294 }
295
296 mutex_exit(&pThis->Mtx);
297 return rc;
298}
299
300
301RTDECL(int) RTSemEventMultiWait(RTSEMEVENTMULTI hEventMultiSem, RTMSINTERVAL cMillies)
302{
303 return rtSemEventMultiWait(hEventMultiSem, cMillies, false /* not interruptible */);
304}
305
306
307RTDECL(int) RTSemEventMultiWaitNoResume(RTSEMEVENTMULTI hEventMultiSem, RTMSINTERVAL cMillies)
308{
309 return rtSemEventMultiWait(hEventMultiSem, cMillies, true /* interruptible */);
310}
311
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette