VirtualBox

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

Last change on this file since 5999 was 5999, checked in by vboxsync, 17 years ago

The Giant CDDL Dual-License Header Change.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 8.1 KB
Line 
1/* $Id: semeventmulti-r0drv-solaris.c 5999 2007-12-07 15:05:06Z vboxsync $ */
2/** @file
3 * innotek Portable Runtime - Multiple Release Event Semaphores, Ring-0 Driver, Solaris.
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.215389.xyz. 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
33#include <iprt/semaphore.h>
34#include <iprt/alloc.h>
35#include <iprt/asm.h>
36#include <iprt/assert.h>
37#include <iprt/err.h>
38
39#include "internal/magics.h"
40
41
42/*******************************************************************************
43* Structures and Typedefs *
44*******************************************************************************/
45/**
46 * FreeBSD multiple release event semaphore.
47 */
48typedef struct RTSEMEVENTMULTIINTERNAL
49{
50 /** Magic value (RTSEMEVENTMULTI_MAGIC). */
51 uint32_t volatile u32Magic;
52 /** The number of waiting threads. */
53 uint32_t volatile cWaiters;
54 /** Set if the event object is signaled. */
55 uint8_t volatile fSignaled;
56 /** The number of threads in the process of waking up. */
57 uint32_t volatile cWaking;
58 /** The Solaris mutex protecting this structure and pairing up the with the cv. */
59 kmutex_t Mtx;
60 /** The Solaris condition variable. */
61 kcondvar_t Cnd;
62} RTSEMEVENTMULTIINTERNAL, *PRTSEMEVENTMULTIINTERNAL;
63
64
65RTDECL(int) RTSemEventMultiCreate(PRTSEMEVENTMULTI pEventMultiSem)
66{
67 Assert(sizeof(RTSEMEVENTMULTIINTERNAL) > sizeof(void *));
68 AssertPtrReturn(pEventMultiSem, VERR_INVALID_POINTER);
69
70 PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)RTMemAlloc(sizeof(*pThis));
71 if (pThis)
72 {
73 pThis->u32Magic = RTSEMEVENTMULTI_MAGIC;
74 pThis->cWaiters = 0;
75 pThis->cWaking = 0;
76 pThis->fSignaled = 0;
77 mutex_init(&pThis->Mtx, "IPRT Multiple Release Event Semaphore", MUTEX_DRIVER, NULL);
78 cv_init(&pThis->Cnd, "IPRT CV", CV_DRIVER, NULL);
79 *pEventMultiSem = pThis;
80 return VINF_SUCCESS;
81 }
82 return VERR_NO_MEMORY;
83}
84
85
86RTDECL(int) RTSemEventMultiDestroy(RTSEMEVENTMULTI EventMultiSem)
87{
88 if (EventMultiSem == NIL_RTSEMEVENTMULTI) /* don't bitch */
89 return VERR_INVALID_HANDLE;
90 PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)EventMultiSem;
91 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
92 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC,
93 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
94 VERR_INVALID_HANDLE);
95
96 mutex_enter(&pThis->Mtx);
97 ASMAtomicIncU32(&pThis->u32Magic); /* make the handle invalid */
98 if (pThis->cWaiters > 0)
99 {
100 /* abort waiting thread, last man cleans up. */
101 ASMAtomicXchgU32(&pThis->cWaking, pThis->cWaking + pThis->cWaiters);
102 cv_broadcast(&pThis->Cnd);
103 mutex_exit(&pThis->Mtx);
104 }
105 else if (pThis->cWaking)
106 /* the last waking thread is gonna do the cleanup */
107 mutex_exit(&pThis->Mtx);
108 else
109 {
110 mutex_exit(&pThis->Mtx);
111 cv_destroy(&pThis->Cnd);
112 mutex_destroy(&pThis->Mtx);
113 RTMemFree(pThis);
114 }
115
116 return VINF_SUCCESS;
117}
118
119
120RTDECL(int) RTSemEventMultiSignal(RTSEMEVENTMULTI EventMultiSem)
121{
122 PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)EventMultiSem;
123 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
124 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC,
125 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
126 VERR_INVALID_HANDLE);
127
128 mutex_enter(&pThis->Mtx);
129
130 ASMAtomicXchgU8(&pThis->fSignaled, true);
131 if (pThis->cWaiters > 0)
132 {
133 ASMAtomicXchgU32(&pThis->cWaking, pThis->cWaking + pThis->cWaiters);
134 ASMAtomicXchgU32(&pThis->cWaiters, 0);
135 cv_signal(&pThis->Cnd);
136 }
137
138 mutex_exit(&pThis->Mtx);
139 return VINF_SUCCESS;
140}
141
142
143RTDECL(int) RTSemEventMultiReset(RTSEMEVENTMULTI EventMultiSem)
144{
145 PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)EventMultiSem;
146 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
147 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC,
148 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
149 VERR_INVALID_HANDLE);
150
151 mutex_enter(&pThis->Mtx);
152 ASMAtomicXchgU8(&pThis->fSignaled, false);
153 mutex_exit(&pThis->Mtx);
154 return VINF_SUCCESS;
155}
156
157
158static int rtSemEventMultiWait(RTSEMEVENTMULTI EventMultiSem, unsigned cMillies, bool fInterruptible)
159{
160 int rc;
161 PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)EventMultiSem;
162 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
163 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC,
164 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
165 VERR_INVALID_HANDLE);
166
167 mutex_enter(&pThis->Mtx);
168
169 if (pThis->fSignaled)
170 rc = VINF_SUCCESS;
171 else
172 {
173 ASMAtomicIncU32(&pThis->cWaiters);
174
175 /*
176 * Translate milliseconds into ticks and go to sleep.
177 */
178 if (cMillies != RT_INDEFINITE_WAIT)
179 {
180 clock_t cTicks = drv_usectohz((clock_t)(cMillies * 1000L));
181 clock_t timeout = ddi_get_lbolt();
182 timeout += cTicks;
183 if (fInterruptible)
184 rc = cv_timedwait_sig(&pThis->Cnd, &pThis->Mtx, timeout);
185 else
186 rc = cv_timedwait(&pThis->Cnd, &pThis->Mtx, timeout);
187 }
188 else
189 {
190 if (fInterruptible)
191 rc = cv_wait_sig(&pThis->Cnd, &pThis->Mtx);
192 else
193 {
194 cv_wait(&pThis->Cnd, &pThis->Mtx);
195 rc = 1;
196 }
197 }
198 if (rc > 0)
199 {
200 /* Retured due to call to cv_signal() or cv_broadcast() */
201 if (RT_LIKELY(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC))
202 rc = VINF_SUCCESS;
203 else
204 {
205 rc = VERR_SEM_DESTROYED;
206 if (!ASMAtomicDecU32(&pThis->cWaking))
207 {
208 mutex_exit(&pThis->Mtx);
209 cv_destroy(&pThis->Cnd);
210 mutex_destroy(&pThis->Mtx);
211 RTMemFree(pThis);
212 return rc;
213 }
214 }
215 ASMAtomicDecU32(&pThis->cWaking);
216 }
217 else if (rc == -1)
218 {
219 /* Returned due to timeout being reached */
220 if (pThis->cWaiters > 0)
221 ASMAtomicDecU32(&pThis->cWaiters);
222 rc = VERR_TIMEOUT;
223 }
224 else
225 {
226 /* Returned due to pending signal */
227 if (pThis->cWaiters > 0)
228 ASMAtomicDecU32(&pThis->cWaiters);
229 rc = VERR_INTERRUPTED;
230 }
231 }
232
233 mutex_exit(&pThis->Mtx);
234 return rc;
235}
236
237
238RTDECL(int) RTSemEventMultiWait(RTSEMEVENTMULTI EventMultiSem, unsigned cMillies)
239{
240 return rtSemEventMultiWait(EventMultiSem, cMillies, false /* not interruptible */);
241}
242
243
244RTDECL(int) RTSemEventMultiWaitNoResume(RTSEMEVENTMULTI EventMultiSem, unsigned cMillies)
245{
246 return rtSemEventMultiWait(EventMultiSem, cMillies, true /* interruptible */);
247}
248
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