38
38
# include <iprt/asm-amd64-x86.h>
40
40
#include <iprt/err.h>
41
#include <iprt/lockvalidator.h>
41
42
#include <iprt/mem.h>
42
43
#include <iprt/mp.h>
43
44
#include <iprt/thread.h>
45
#include <iprt/time.h>
44
46
#include "internal/magics.h"
47
#include "semeventwait-r0drv-solaris.h"
50
/*******************************************************************************
51
* Defined Constants And Macros *
52
*******************************************************************************/
53
/** @name fStateAndGen values
55
/** The state bit number. */
56
#define RTSEMEVENTMULTISOL_STATE_BIT 0
57
/** The state mask. */
58
#define RTSEMEVENTMULTISOL_STATE_MASK RT_BIT_32(RTSEMEVENTMULTISOL_STATE_BIT)
59
/** The generation mask. */
60
#define RTSEMEVENTMULTISOL_GEN_MASK ~RTSEMEVENTMULTISOL_STATE_MASK
61
/** The generation shift. */
62
#define RTSEMEVENTMULTISOL_GEN_SHIFT 1
63
/** The initial variable value. */
64
#define RTSEMEVENTMULTISOL_STATE_GEN_INIT UINT32_C(0xfffffffc)
47
68
/*******************************************************************************
48
69
* Structures and Typedefs *
49
70
*******************************************************************************/
51
* FreeBSD multiple release event semaphore.
72
* Solaris multiple release event semaphore.
53
74
typedef struct RTSEMEVENTMULTIINTERNAL
55
76
/** Magic value (RTSEMEVENTMULTI_MAGIC). */
56
77
uint32_t volatile u32Magic;
57
/** The number of waiting threads. */
58
uint32_t volatile cWaiters;
59
/** Set if the event object is signaled. */
60
uint8_t volatile fSignaled;
61
/** The number of threads in the process of waking up. */
62
uint32_t volatile cWaking;
78
/** The number of references. */
79
uint32_t volatile cRefs;
80
/** The object state bit and generation counter.
81
* The generation counter is incremented every time the object is
83
uint32_t volatile fStateAndGen;
63
84
/** The Solaris mutex protecting this structure and pairing up the with the cv. */
65
86
/** The Solaris condition variable. */
106
165
return VINF_SUCCESS;
107
166
AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
108
167
AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);
111
mutex_enter(&pThis->Mtx);
112
ASMAtomicIncU32(&pThis->u32Magic); /* make the handle invalid */
113
if (pThis->cWaiters > 0)
115
/* abort waiting thread, last man cleans up. */
116
ASMAtomicXchgU32(&pThis->cWaking, pThis->cWaking + pThis->cWaiters);
117
cv_broadcast(&pThis->Cnd);
118
mutex_exit(&pThis->Mtx);
120
else if (pThis->cWaking)
121
/* the last waking thread is gonna do the cleanup */
122
mutex_exit(&pThis->Mtx);
125
mutex_exit(&pThis->Mtx);
126
cv_destroy(&pThis->Cnd);
127
mutex_destroy(&pThis->Mtx);
135
RTDECL(int) RTSemEventMultiSignal(RTSEMEVENTMULTI hEventMultiSem)
137
PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
138
RT_ASSERT_PREEMPT_CPUID_VAR();
140
AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
141
AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC,
142
("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
143
VERR_INVALID_HANDLE);
147
* If we're in interrupt context we need to unpin the underlying current
148
* thread as this could lead to a deadlock (see #4259 for the full explanation)
150
* Note! See remarks about preemption in RTSemEventSignal.
152
int fAcquired = mutex_tryenter(&pThis->Mtx);
155
if (curthread->t_intr && getpil() < DISP_LEVEL)
157
RTTHREADPREEMPTSTATE PreemptState = RTTHREADPREEMPTSTATE_INITIALIZER;
158
RTThreadPreemptDisable(&PreemptState);
160
RTThreadPreemptRestore(&PreemptState);
162
mutex_enter(&pThis->Mtx);
165
ASMAtomicXchgU8(&pThis->fSignaled, true);
166
if (pThis->cWaiters > 0)
168
ASMAtomicXchgU32(&pThis->cWaking, pThis->cWaking + pThis->cWaiters);
169
ASMAtomicXchgU32(&pThis->cWaiters, 0);
170
cv_broadcast(&pThis->Cnd);
173
mutex_exit(&pThis->Mtx);
175
RT_ASSERT_PREEMPT_CPUID();
180
RTDECL(int) RTSemEventMultiReset(RTSEMEVENTMULTI hEventMultiSem)
182
PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
183
RT_ASSERT_PREEMPT_CPUID_VAR();
185
AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
186
AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC,
187
("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
188
VERR_INVALID_HANDLE);
192
* If we're in interrupt context we need to unpin the underlying current
193
* thread as this could lead to a deadlock (see #4259 for the full explanation)
195
* Note! See remarks about preemption in RTSemEventSignal.
197
int fAcquired = mutex_tryenter(&pThis->Mtx);
200
if (curthread->t_intr && getpil() < DISP_LEVEL)
202
RTTHREADPREEMPTSTATE PreemptState = RTTHREADPREEMPTSTATE_INITIALIZER;
203
RTThreadPreemptDisable(&PreemptState);
205
RTThreadPreemptRestore(&PreemptState);
207
mutex_enter(&pThis->Mtx);
210
ASMAtomicXchgU8(&pThis->fSignaled, false);
211
mutex_exit(&pThis->Mtx);
213
RT_ASSERT_PREEMPT_CPUID();
218
static int rtSemEventMultiWait(RTSEMEVENTMULTI hEventMultiSem, RTMSINTERVAL cMillies, bool fInterruptible)
221
PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
222
AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
223
AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC,
224
("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
225
VERR_INVALID_HANDLE);
227
RT_ASSERT_PREEMPTIBLE();
229
mutex_enter(&pThis->Mtx);
231
if (pThis->fSignaled)
168
AssertMsgReturn(pThis->cRefs > 0, ("pThis=%p cRefs=%d\n", pThis, pThis->cRefs), VERR_INVALID_HANDLE);
171
mutex_enter(&pThis->Mtx);
173
/* Invalidate the handle and wake up all threads that might be waiting on the semaphore. */
174
Assert(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC);
175
ASMAtomicWriteU32(&pThis->u32Magic, RTSEMEVENTMULTI_MAGIC_DEAD);
176
ASMAtomicAndU32(&pThis->fStateAndGen, RTSEMEVENTMULTISOL_GEN_MASK);
177
cv_broadcast(&pThis->Cnd);
179
/* Drop the reference from RTSemEventMultiCreateEx. */
180
mutex_exit(&pThis->Mtx);
181
rtR0SemEventMultiSolRelease(pThis);
187
RTDECL(int) RTSemEventMultiSignal(RTSEMEVENTMULTI hEventMultiSem)
189
PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
190
RT_ASSERT_PREEMPT_CPUID_VAR();
192
AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
193
AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC,
194
("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
195
VERR_INVALID_HANDLE);
197
rtR0SemEventMultiSolRetain(pThis);
198
rtR0SemSolWaitEnterMutexWithUnpinningHack(&pThis->Mtx);
199
Assert(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC);
204
uint32_t fNew = ASMAtomicUoReadU32(&pThis->fStateAndGen);
205
fNew += 1 << RTSEMEVENTMULTISOL_GEN_SHIFT;
206
fNew |= RTSEMEVENTMULTISOL_STATE_MASK;
207
ASMAtomicWriteU32(&pThis->fStateAndGen, fNew);
209
cv_broadcast(&pThis->Cnd);
211
mutex_exit(&pThis->Mtx);
213
rtR0SemEventMultiSolRelease(pThis);
214
RT_ASSERT_PREEMPT_CPUID();
219
RTDECL(int) RTSemEventMultiReset(RTSEMEVENTMULTI hEventMultiSem)
221
PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
222
RT_ASSERT_PREEMPT_CPUID_VAR();
224
AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
225
AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC,
226
("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
227
VERR_INVALID_HANDLE);
230
rtR0SemEventMultiSolRetain(pThis);
231
rtR0SemSolWaitEnterMutexWithUnpinningHack(&pThis->Mtx);
232
Assert(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC);
235
* Do the job (could be done without the lock, but play safe).
237
ASMAtomicAndU32(&pThis->fStateAndGen, ~RTSEMEVENTMULTISOL_STATE_MASK);
239
mutex_exit(&pThis->Mtx);
240
rtR0SemEventMultiSolRelease(pThis);
242
RT_ASSERT_PREEMPT_CPUID();
248
* Worker for RTSemEventMultiWaitEx and RTSemEventMultiWaitExDebug.
250
* @returns VBox status code.
251
* @param pThis The event semaphore.
252
* @param fFlags See RTSemEventMultiWaitEx.
253
* @param uTimeout See RTSemEventMultiWaitEx.
254
* @param pSrcPos The source code position of the wait.
256
static int rtR0SemEventMultiSolWait(PRTSEMEVENTMULTIINTERNAL pThis, uint32_t fFlags, uint64_t uTimeout,
257
PCRTLOCKVALSRCPOS pSrcPos)
259
uint32_t fOrgStateAndGen;
263
* Validate the input.
265
AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
266
AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
267
AssertReturn(RTSEMWAIT_FLAGS_ARE_VALID(fFlags), VERR_INVALID_PARAMETER);
268
rtR0SemEventMultiSolRetain(pThis);
269
mutex_enter(&pThis->Mtx); /* this could be moved down to the else, but play safe for now. */
272
* Is the event already signalled or do we have to wait?
274
fOrgStateAndGen = ASMAtomicUoReadU32(&pThis->fStateAndGen);
275
if (fOrgStateAndGen & RTSEMEVENTMULTISOL_STATE_MASK)
232
276
rc = VINF_SUCCESS;
237
ASMAtomicIncU32(&pThis->cWaiters);
240
* Translate milliseconds into ticks and go to sleep.
242
if (cMillies != RT_INDEFINITE_WAIT)
244
clock_t cTicks = drv_usectohz((clock_t)(cMillies * 1000L));
245
clock_t cTimeout = ddi_get_lbolt();
248
rc = cv_timedwait_sig(&pThis->Cnd, &pThis->Mtx, cTimeout);
250
rc = cv_timedwait(&pThis->Cnd, &pThis->Mtx, cTimeout);
255
rc = cv_wait_sig(&pThis->Cnd, &pThis->Mtx);
258
cv_wait(&pThis->Cnd, &pThis->Mtx);
264
/* Retured due to call to cv_signal() or cv_broadcast() */
265
if (RT_LIKELY(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC))
268
ASMAtomicDecU32(&pThis->cWaking);
272
rc = VERR_SEM_DESTROYED;
273
if (!ASMAtomicDecU32(&pThis->cWaking))
283
rc = rtR0SemSolWaitInit(&Wait, fFlags, uTimeout);
288
/* The destruction test. */
289
if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC))
290
rc = VERR_SEM_DESTROYED;
275
mutex_exit(&pThis->Mtx);
276
cv_destroy(&pThis->Cnd);
277
mutex_destroy(&pThis->Mtx);
293
/* Check the exit conditions. */
294
if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC))
295
rc = VERR_SEM_DESTROYED;
296
else if (ASMAtomicUoReadU32(&pThis->fStateAndGen) != fOrgStateAndGen)
298
else if (rtR0SemSolWaitHasTimedOut(&Wait))
300
else if (rtR0SemSolWaitWasInterrupted(&Wait))
301
rc = VERR_INTERRUPTED;
304
/* Do the wait and then recheck the conditions. */
305
rtR0SemSolWaitDoIt(&Wait, &pThis->Cnd, &pThis->Mtx);
285
/* Returned due to timeout being reached */
286
if (pThis->cWaiters > 0)
287
ASMAtomicDecU32(&pThis->cWaiters);
292
/* Returned due to pending signal */
293
if (pThis->cWaiters > 0)
294
ASMAtomicDecU32(&pThis->cWaiters);
295
rc = VERR_INTERRUPTED;
311
rtR0SemSolWaitDelete(&Wait);
299
315
mutex_exit(&pThis->Mtx);
316
rtR0SemEventMultiSolRelease(pThis);
304
RTDECL(int) RTSemEventMultiWait(RTSEMEVENTMULTI hEventMultiSem, RTMSINTERVAL cMillies)
306
return rtSemEventMultiWait(hEventMultiSem, cMillies, false /* not interruptible */);
310
RTDECL(int) RTSemEventMultiWaitNoResume(RTSEMEVENTMULTI hEventMultiSem, RTMSINTERVAL cMillies)
312
return rtSemEventMultiWait(hEventMultiSem, cMillies, true /* interruptible */);
322
#undef RTSemEventMultiWaitEx
323
RTDECL(int) RTSemEventMultiWaitEx(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout)
325
#ifndef RTSEMEVENT_STRICT
326
return rtR0SemEventMultiSolWait(hEventMultiSem, fFlags, uTimeout, NULL);
328
RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
329
return rtR0SemEventMultiSolWait(hEventMultiSem, fFlags, uTimeout, &SrcPos);
334
RTDECL(int) RTSemEventMultiWaitExDebug(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout,
335
RTHCUINTPTR uId, RT_SRC_POS_DECL)
337
RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
338
return rtR0SemEventMultiSolWait(hEventMultiSem, fFlags, uTimeout, &SrcPos);
342
RTDECL(uint32_t) RTSemEventMultiGetResolution(void)
344
return rtR0SemSolWaitGetResolution();