VirtualBox

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

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

semeventmulti-r0drv-solaris.c: High resolution timeout hacking in progress (disabled).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 22.7 KB
Line 
1/* $Id: semeventmulti-r0drv-solaris.c 33070 2010-10-12 14:43:05Z vboxsync $ */
2/** @file
3 * IPRT - Multiple Release Event Semaphores, Ring-0 Driver, Solaris.
4 */
5
6/*
7 * Copyright (C) 2006-2010 Oracle Corporation
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#include "internal/iprt.h"
33#include <iprt/semaphore.h>
34
35#include <iprt/assert.h>
36#include <iprt/asm.h>
37#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
38# include <iprt/asm-amd64-x86.h>
39#endif
40#include <iprt/err.h>
41#include <iprt/lockvalidator.h>
42#include <iprt/mem.h>
43#include <iprt/mp.h>
44#include <iprt/thread.h>
45#include <iprt/time.h>
46#include "internal/magics.h"
47
48
49/*******************************************************************************
50* Defined Constants And Macros *
51*******************************************************************************/
52/** @name fStateAndGen values
53 * @{ */
54/** The state bit number. */
55#define RTSEMEVENTMULTISOL_STATE_BIT 0
56/** The state mask. */
57#define RTSEMEVENTMULTISOL_STATE_MASK RT_BIT_32(RTSEMEVENTMULTISOL_STATE_BIT)
58/** The generation mask. */
59#define RTSEMEVENTMULTISOL_GEN_MASK ~RTSEMEVENTMULTISOL_STATE_MASK
60/** The generation shift. */
61#define RTSEMEVENTMULTISOL_GEN_SHIFT 1
62/** The initial variable value. */
63#define RTSEMEVENTMULTISOL_STATE_GEN_INIT UINT32_C(0xfffffffc)
64/** @} */
65
66
67/*******************************************************************************
68* Structures and Typedefs *
69*******************************************************************************/
70/**
71 * Solaris multiple release event semaphore.
72 */
73typedef struct RTSEMEVENTMULTIINTERNAL
74{
75 /** Magic value (RTSEMEVENTMULTI_MAGIC). */
76 uint32_t volatile u32Magic;
77 /** The number of references. */
78 uint32_t volatile cRefs;
79 /** The object state bit and generation counter.
80 * The generation counter is incremented every time the object is
81 * signalled. */
82 uint32_t volatile fStateAndGen;
83 /** The Solaris mutex protecting this structure and pairing up the with the cv. */
84 kmutex_t Mtx;
85 /** The Solaris condition variable. */
86 kcondvar_t Cnd;
87} RTSEMEVENTMULTIINTERNAL, *PRTSEMEVENTMULTIINTERNAL;
88
89
90
91RTDECL(int) RTSemEventMultiCreate(PRTSEMEVENTMULTI phEventMultiSem)
92{
93 return RTSemEventMultiCreateEx(phEventMultiSem, 0 /*fFlags*/, NIL_RTLOCKVALCLASS, NULL);
94}
95
96
97RTDECL(int) RTSemEventMultiCreateEx(PRTSEMEVENTMULTI phEventMultiSem, uint32_t fFlags, RTLOCKVALCLASS hClass,
98 const char *pszNameFmt, ...)
99{
100 AssertReturn(!(fFlags & ~RTSEMEVENTMULTI_FLAGS_NO_LOCK_VAL), VERR_INVALID_PARAMETER);
101 AssertPtrReturn(phEventMultiSem, VERR_INVALID_POINTER);
102 RT_ASSERT_PREEMPTIBLE();
103
104 AssertCompile(sizeof(RTSEMEVENTMULTIINTERNAL) > sizeof(void *));
105 PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)RTMemAlloc(sizeof(*pThis));
106 if (pThis)
107 {
108 pThis->u32Magic = RTSEMEVENTMULTI_MAGIC;
109 pThis->cRefs = 1;
110 pThis->fStateAndGen = RTSEMEVENTMULTISOL_STATE_GEN_INIT;
111 mutex_init(&pThis->Mtx, "IPRT Multiple Release Event Semaphore", MUTEX_DRIVER, (void *)ipltospl(DISP_LEVEL));
112 cv_init(&pThis->Cnd, "IPRT CV", CV_DRIVER, NULL);
113
114 *phEventMultiSem = pThis;
115 return VINF_SUCCESS;
116 }
117 return VERR_NO_MEMORY;
118}
119
120
121/**
122 * Retain a reference to the semaphore.
123 *
124 * @param pThis The semaphore.
125 */
126DECLINLINE(void) rtR0SemEventMultiSolRetain(PRTSEMEVENTMULTIINTERNAL pThis)
127{
128 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
129 Assert(cRefs && cRefs < 100000);
130}
131
132
133/**
134 * Destructor that is called when cRefs == 0.
135 *
136 * @param pThis The instance to destroy.
137 */
138static void rtSemEventMultiDtor(PRTSEMEVENTMULTIINTERNAL pThis)
139{
140 Assert(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC);
141 cv_destroy(&pThis->Cnd);
142 mutex_destroy(&pThis->Mtx);
143 RTMemFree(pThis);
144}
145
146
147/**
148 * Release a reference, destroy the thing if necessary.
149 *
150 * @param pThis The semaphore.
151 */
152DECLINLINE(void) rtR0SemEventMultiSolRelease(PRTSEMEVENTMULTIINTERNAL pThis)
153{
154 if (RT_UNLIKELY(ASMAtomicDecU32(&pThis->cRefs) == 0))
155 rtSemEventMultiDtor(pThis);
156}
157
158
159
160RTDECL(int) RTSemEventMultiDestroy(RTSEMEVENTMULTI hEventMultiSem)
161{
162 PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
163 if (pThis == NIL_RTSEMEVENTMULTI)
164 return VINF_SUCCESS;
165 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
166 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);
167 AssertMsgReturn(pThis->cRefs > 0, ("pThis=%p cRefs=%d\n", pThis, pThis->cRefs), VERR_INVALID_HANDLE);
168 RT_ASSERT_INTS_ON();
169
170 mutex_enter(&pThis->Mtx);
171
172 /* Invalidate the handle and wake up all threads that might be waiting on the semaphore. */
173 Assert(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC);
174 ASMAtomicWriteU32(&pThis->u32Magic, RTSEMEVENTMULTI_MAGIC_DEAD);
175 ASMAtomicAndU32(&pThis->fStateAndGen, RTSEMEVENTMULTISOL_GEN_MASK);
176 cv_broadcast(&pThis->Cnd);
177
178 /* Drop the reference from RTSemEventMultiCreateEx. */
179 mutex_exit(&pThis->Mtx);
180 rtR0SemEventMultiSolRelease(pThis);
181
182 return VINF_SUCCESS;
183}
184
185
186RTDECL(int) RTSemEventMultiSignal(RTSEMEVENTMULTI hEventMultiSem)
187{
188 PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
189 RT_ASSERT_PREEMPT_CPUID_VAR();
190
191 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
192 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC,
193 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
194 VERR_INVALID_HANDLE);
195 RT_ASSERT_INTS_ON();
196 rtR0SemEventMultiSolRetain(pThis);
197
198 /*
199 * If we're in interrupt context we need to unpin the underlying current
200 * thread as this could lead to a deadlock (see #4259 for the full explanation)
201 *
202 * Note! See remarks about preemption in RTSemEventSignal.
203 */
204 int fAcquired = mutex_tryenter(&pThis->Mtx);
205 if (!fAcquired)
206 {
207 if (curthread->t_intr && getpil() < DISP_LEVEL)
208 {
209 RTTHREADPREEMPTSTATE PreemptState = RTTHREADPREEMPTSTATE_INITIALIZER;
210 RTThreadPreemptDisable(&PreemptState);
211 preempt();
212 RTThreadPreemptRestore(&PreemptState);
213 }
214 mutex_enter(&pThis->Mtx);
215 }
216 Assert(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC);
217
218 /*
219 * Do the job.
220 */
221 uint32_t fNew = ASMAtomicUoReadU32(&pThis->fStateAndGen);
222 fNew += 1 << RTSEMEVENTMULTISOL_GEN_SHIFT;
223 fNew |= RTSEMEVENTMULTISOL_STATE_MASK;
224 ASMAtomicWriteU32(&pThis->fStateAndGen, fNew);
225
226 cv_broadcast(&pThis->Cnd);
227
228 mutex_exit(&pThis->Mtx);
229
230 rtR0SemEventMultiSolRelease(pThis);
231 RT_ASSERT_PREEMPT_CPUID();
232 return VINF_SUCCESS;
233}
234
235
236RTDECL(int) RTSemEventMultiReset(RTSEMEVENTMULTI hEventMultiSem)
237{
238 PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
239 RT_ASSERT_PREEMPT_CPUID_VAR();
240
241 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
242 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC,
243 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
244 VERR_INVALID_HANDLE);
245 RT_ASSERT_INTS_ON();
246 rtR0SemEventMultiSolRetain(pThis);
247
248 /*
249 * If we're in interrupt context we need to unpin the underlying current
250 * thread as this could lead to a deadlock (see #4259 for the full explanation)
251 *
252 * Note! See remarks about preemption in RTSemEventSignal.
253 */
254 int fAcquired = mutex_tryenter(&pThis->Mtx);
255 if (!fAcquired)
256 {
257 if (curthread->t_intr && getpil() < DISP_LEVEL)
258 {
259 RTTHREADPREEMPTSTATE PreemptState = RTTHREADPREEMPTSTATE_INITIALIZER;
260 RTThreadPreemptDisable(&PreemptState);
261 preempt();
262 RTThreadPreemptRestore(&PreemptState);
263 }
264 mutex_enter(&pThis->Mtx);
265 }
266 Assert(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC);
267
268 /*
269 * Do the job (could be done without the lock, but play safe).
270 */
271 ASMAtomicAndU32(&pThis->fStateAndGen, ~RTSEMEVENTMULTISOL_STATE_MASK);
272
273 mutex_exit(&pThis->Mtx);
274
275 rtR0SemEventMultiSolRelease(pThis);
276 RT_ASSERT_PREEMPT_CPUID();
277 return VINF_SUCCESS;
278}
279
280#if 0 /* NEW_STUFF - not working yet :-) */
281
282typedef struct RTR0SEMSOLWAIT
283{
284 /** The absolute timeout given as nano seconds since the start of the
285 * monotonic clock. */
286 uint64_t uNsAbsTimeout;
287 /** The timeout in nano seconds relative to the start of the wait. */
288 uint64_t cNsRelTimeout;
289 /** The native timeout value. */
290 union
291 {
292 /** The timeout (abs lbolt) when fHighRes is false. */
293 clock_t lTimeout;
294 } u;
295 /** Set if we use high resolution timeouts. */
296 bool fHighRes;
297 /** Set if it's an indefinite wait. */
298 bool fIndefinite;
299 /** Set if we've already timed out.
300 * Set by rtR0SemSolWaitDoIt or rtR0SemSolWaitHighResTimeout, read by
301 * rtR0SemSolWaitHasTimedOut. */
302 bool volatile fTimedOut;
303 /** Whether the wait was interrupted. */
304 bool fInterrupted;
305 /** Interruptible or uninterruptible wait. */
306 bool fInterruptible;
307 /** The thread to wake up. */
308 kthread_t *pThread;
309} RTR0SEMSOLWAIT;
310typedef RTR0SEMSOLWAIT *PRTR0SEMSOLWAIT;
311
312
313/**
314 * Initializes a wait.
315 *
316 * The caller MUST check the wait condition BEFORE calling this function or the
317 * timeout logic will be flawed.
318 *
319 * @returns VINF_SUCCESS or VERR_TIMEOUT.
320 * @param pWait The wait structure.
321 * @param fFlags The wait flags.
322 * @param uTimeout The timeout.
323 * @param pWaitQueue The wait queue head.
324 */
325DECLINLINE(int) rtR0SemSolWaitInit(PRTR0SEMSOLWAIT pWait, uint32_t fFlags, uint64_t uTimeout)
326{
327 /*
328 * Process the flags and timeout.
329 */
330 if (!(fFlags & RTSEMWAIT_FLAGS_INDEFINITE))
331 {
332 if (fFlags & RTSEMWAIT_FLAGS_MILLISECS)
333 uTimeout = uTimeout < UINT64_MAX / UINT32_C(1000000) * UINT32_C(1000000)
334 ? uTimeout * UINT32_C(1000000)
335 : UINT64_MAX;
336 if (uTimeout == UINT64_MAX)
337 fFlags |= RTSEMWAIT_FLAGS_INDEFINITE;
338 else
339 {
340 uint64_t u64Now;
341 if (fFlags & RTSEMWAIT_FLAGS_RELATIVE)
342 {
343 if (uTimeout == 0)
344 return VERR_TIMEOUT;
345
346 u64Now = RTTimeSystemNanoTS();
347 pWait->cNsRelTimeout = uTimeout;
348 pWait->uNsAbsTimeout = u64Now + uTimeout;
349 if (pWait->uNsAbsTimeout < u64Now) /* overflow */
350 fFlags |= RTSEMWAIT_FLAGS_INDEFINITE;
351 }
352 else
353 {
354 u64Now = RTTimeSystemNanoTS();
355 if (u64Now >= uTimeout)
356 return VERR_TIMEOUT;
357
358 pWait->cNsRelTimeout = uTimeout - u64Now;
359 pWait->uNsAbsTimeout = uTimeout;
360 }
361 }
362 }
363
364 if (!(fFlags & RTSEMWAIT_FLAGS_INDEFINITE))
365 {
366 pWait->fIndefinite = false;
367 if ( (fFlags & (RTSEMWAIT_FLAGS_NANOSECS | RTSEMWAIT_FLAGS_ABSOLUTE))
368 || pWait->cNsRelTimeout < UINT32_C(1000000000) / 100 /*Hz*/ * 4)
369 pWait->fHighRes = true;
370 else
371 {
372#if 1
373 uint64_t cTicks = NSEC_TO_TICK_ROUNDUP(uTimeout);
374#else
375 uint64_t cTicks = drv_usectohz((clock_t)(uTimeout / 1000));
376#endif
377 if (cTicks >= LONG_MAX)
378 fFlags |= RTSEMWAIT_FLAGS_INDEFINITE;
379 else
380 {
381 pWait->u.lTimeout = ddi_get_lbolt() + cTicks;
382 pWait->fHighRes = false;
383 }
384 }
385 }
386
387 if (fFlags & RTSEMWAIT_FLAGS_INDEFINITE)
388 {
389 pWait->fIndefinite = true;
390 pWait->fHighRes = false;
391 pWait->uNsAbsTimeout = UINT64_MAX;
392 pWait->cNsRelTimeout = UINT64_MAX;
393 pWait->u.lTimeout = LONG_MAX;
394 }
395
396 pWait->fTimedOut = false;
397 pWait->fInterrupted = false;
398 pWait->fInterruptible = !!(fFlags & RTSEMWAIT_FLAGS_INTERRUPTIBLE);
399 pWait->pThread = curthread;
400
401 return VINF_SUCCESS;
402}
403
404
405/**
406 * Cyclic timeout callback that sets the timeout indicator and wakes up the
407 * waiting thread.
408 *
409 * @param pvUser The wait structure.
410 */
411static void rtR0SemSolWaitHighResTimeout(void *pvUser)
412{
413 PRTR0SEMSOLWAIT pWait = (PRTR0SEMSOLWAIT)pvUser;
414 kthread_t *pThread = pWait->pThread;
415 if (VALID_PTR(pThread)) /* paranoia */
416 {
417 ASMAtomicWriteBool(&pWait->fTimedOut, true);
418 setrun(pThread);
419 }
420}
421
422
423/**
424 * Do the actual wait.
425 *
426 * @param pWait The wait structure.
427 * @param pCnd The condition variable to wait on.
428 * @param pMtx The mutex related to the condition variable.
429 * The caller has entered this.
430 */
431DECLINLINE(void) rtR0SemSolWaitDoIt(PRTR0SEMSOLWAIT pWait, kcondvar_t *pCnd, kmutex_t *pMtx)
432{
433 int rc = 1;
434 if (pWait->fIndefinite)
435 {
436 /*
437 * No timeout - easy.
438 */
439 if (pWait->fInterruptible)
440 rc = cv_wait_sig(pCnd, pMtx);
441 else
442 cv_wait(pCnd, pMtx);
443 }
444 else if (pWait->fHighRes)
445 {
446 /*
447 * High resolution timeout - arm a one-shot cyclic for waking up
448 * the thread at the desired time.
449 */
450 cyc_handler_t Cyh;
451 Cyh.cyh_arg = pWait;
452 Cyh.cyh_func = rtR0SemSolWaitHighResTimeout;
453 Cyh.cyh_level = CY_LOW_LEVEL; /// @todo try CY_LOCK_LEVEL and CY_HIGH_LEVEL?
454
455 cyc_time_t Cyt;
456 Cyt.cyt_when = pWait->uNsAbsTimeout;
457 Cyt.cyt_interval = 0;
458
459 mutex_enter(&cpu_lock);
460 cyclic_id_t idCy = cyclic_add(&Cyh, &Cyt);
461 mutex_exit(&cpu_lock);
462
463 if (pWait->fInterruptible)
464 rc = cv_wait_sig(pCnd, pMtx);
465 else
466 cv_wait(pCnd, pMtx);
467
468 mutex_enter(&cpu_lock);
469 cyclic_remove(idCy);
470 mutex_exit(&cpu_lock);
471 }
472 else
473 {
474 /*
475 * Normal timeout.
476 */
477 if (pWait->fInterruptible)
478 rc = cv_timedwait_sig(pCnd, pMtx, pWait->u.lTimeout);
479 else
480 rc = cv_timedwait(pCnd, pMtx, pWait->u.lTimeout);
481 }
482
483 /* Above zero means normal wake-up. */
484 if (rc > 0)
485 return;
486
487 /* Timeout is signalled by -1. */
488 if (rc == -1)
489 pWait->fTimedOut = true;
490 /* Interruption is signalled by 0. */
491 else
492 {
493 AssertMsg(rc == 0, ("rc=%d\n", rc));
494 pWait->fInterrupted = true;
495 }
496}
497
498
499/**
500 * Checks if a solaris wait was interrupted.
501 *
502 * @returns true / false
503 * @param pWait The wait structure.
504 * @remarks This shall be called before the first rtR0SemSolWaitDoIt().
505 */
506DECLINLINE(bool) rtR0SemSolWaitWasInterrupted(PRTR0SEMSOLWAIT pWait)
507{
508 return pWait->fInterrupted;
509}
510
511
512/**
513 * Checks if a solaris wait has timed out.
514 *
515 * @returns true / false
516 * @param pWait The wait structure.
517 */
518DECLINLINE(bool) rtR0SemSolWaitHasTimedOut(PRTR0SEMSOLWAIT pWait)
519{
520 return pWait->fTimedOut;
521}
522
523
524/**
525 * Deletes a solaris wait.
526 *
527 * @param pWait The wait structure.
528 */
529DECLINLINE(void) rtR0SemSolWaitDelete(PRTR0SEMSOLWAIT pWait)
530{
531 pWait->pThread = NULL;
532}
533
534
535
536/**
537 * Worker for RTSemEventMultiWaitEx and RTSemEventMultiWaitExDebug.
538 *
539 * @returns VBox status code.
540 * @param pThis The event semaphore.
541 * @param fFlags See RTSemEventMultiWaitEx.
542 * @param uTimeout See RTSemEventMultiWaitEx.
543 * @param pSrcPos The source code position of the wait.
544 */
545static int rtR0SemEventMultiSolWait(PRTSEMEVENTMULTIINTERNAL pThis, uint32_t fFlags, uint64_t uTimeout,
546 PCRTLOCKVALSRCPOS pSrcPos)
547{
548 uint32_t fOrgStateAndGen;
549 int rc;
550
551 /*
552 * Validate the input.
553 */
554 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
555 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
556 AssertReturn(RTSEMWAIT_FLAGS_ARE_VALID(fFlags), VERR_INVALID_PARAMETER);
557 rtR0SemEventMultiSolRetain(pThis);
558 mutex_enter(&pThis->Mtx); /* this could be moved down to the else, but play safe for now. */
559
560 /*
561 * Is the event already signalled or do we have to wait?
562 */
563 fOrgStateAndGen = ASMAtomicUoReadU32(&pThis->fStateAndGen);
564 if (fOrgStateAndGen & RTSEMEVENTMULTISOL_STATE_MASK)
565 rc = VINF_SUCCESS;
566 else
567 {
568 /*
569 * We have to wait.
570 */
571 RTR0SEMSOLWAIT Wait;
572 rtR0SemSolWaitInit(&Wait, fFlags, uTimeout);
573 for (;;)
574 {
575 /* The destruction test. */
576 if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC))
577 rc = VERR_SEM_DESTROYED;
578 else
579 {
580 /* Check the exit conditions. */
581 if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC))
582 rc = VERR_SEM_DESTROYED;
583 else if (ASMAtomicUoReadU32(&pThis->fStateAndGen) != fOrgStateAndGen)
584 rc = VINF_SUCCESS;
585 else if (rtR0SemSolWaitHasTimedOut(&Wait))
586 rc = VERR_TIMEOUT;
587 else if (rtR0SemSolWaitWasInterrupted(&Wait))
588 rc = VERR_INTERRUPTED;
589 else
590 {
591 /* Do the wait and then recheck the conditions. */
592 rtR0SemSolWaitDoIt(&Wait, &pThis->Cnd, &pThis->Mtx);
593 continue;
594 }
595 }
596 break;
597 }
598 rtR0SemSolWaitDelete(&Wait);
599 }
600
601 mutex_exit(&pThis->Mtx);
602 rtR0SemEventMultiSolRelease(pThis);
603 return rc;
604}
605
606
607
608#undef RTSemEventMultiWaitEx
609RTDECL(int) RTSemEventMultiWaitEx(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout)
610{
611#ifndef RTSEMEVENT_STRICT
612 return rtR0SemEventMultiSolWait(hEventMultiSem, fFlags, uTimeout, NULL);
613#else
614 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
615 return rtR0SemEventMultiSolWait(hEventMultiSem, fFlags, uTimeout, &SrcPos);
616#endif
617}
618
619
620RTDECL(int) RTSemEventMultiWaitExDebug(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout,
621 RTHCUINTPTR uId, RT_SRC_POS_DECL)
622{
623 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
624 return rtR0SemEventMultiSolWait(hEventMultiSem, fFlags, uTimeout, &SrcPos);
625}
626
627
628#include "../../generic/RTSemEventMultiWait-2-ex-generic.cpp"
629#include "../../generic/RTSemEventMultiWaitNoResume-2-ex-generic.cpp"
630
631#else /* OLD_STUFF */
632
633/**
634 * Translate milliseconds into ticks and go to sleep using the right method.
635 *
636 * @retval >0 on normal or spurious wake-up.
637 * @retval -1 on timeout.
638 * @retval 0 on signal.
639 */
640static int rtSemEventMultiWaitWorker(PRTSEMEVENTMULTIINTERNAL pThis, RTMSINTERVAL cMillies, bool fInterruptible)
641{
642 int rc;
643 if (cMillies != RT_INDEFINITE_WAIT)
644 {
645 clock_t cTicks = drv_usectohz((clock_t)(cMillies * 1000L));
646 clock_t cTimeout = ddi_get_lbolt();
647 cTimeout += cTicks;
648 if (fInterruptible)
649 rc = cv_timedwait_sig(&pThis->Cnd, &pThis->Mtx, cTimeout);
650 else
651 rc = cv_timedwait(&pThis->Cnd, &pThis->Mtx, cTimeout);
652 }
653 else
654 {
655 if (fInterruptible)
656 rc = cv_wait_sig(&pThis->Cnd, &pThis->Mtx);
657 else
658 {
659 cv_wait(&pThis->Cnd, &pThis->Mtx);
660 rc = 1;
661 }
662 }
663 return rc;
664}
665
666
667static int rtSemEventMultiWait(RTSEMEVENTMULTI hEventMultiSem, RTMSINTERVAL cMillies, bool fInterruptible)
668{
669 int rc;
670 PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
671 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
672 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC,
673 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
674 VERR_INVALID_HANDLE);
675 rtR0SemEventMultiSolRetain(pThis);
676 if (cMillies)
677 RT_ASSERT_PREEMPTIBLE();
678
679 mutex_enter(&pThis->Mtx);
680 Assert(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC);
681
682 if (pThis->fStateAndGen & RTSEMEVENTMULTISOL_STATE_MASK)
683 rc = VINF_SUCCESS;
684 else if (!cMillies)
685 rc = VERR_TIMEOUT;
686 else
687 {
688 /* This loop is only for continuing after a spurious wake-up. */
689 for (;;)
690 {
691 uint32_t const uSignalGenBeforeWait = pThis->fStateAndGen;
692 rc = rtSemEventMultiWaitWorker(pThis, cMillies, fInterruptible);
693 if (rc > 0)
694 {
695 if (RT_LIKELY(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC))
696 {
697 if (pThis->fStateAndGen == uSignalGenBeforeWait)
698 continue; /* Spurious wake-up, go back to waiting. */
699
700 /* Retured due to call to cv_signal() or cv_broadcast(). */
701 rc = VINF_SUCCESS;
702 }
703 else
704 /* We're being destroyed. */
705 rc = VERR_SEM_DESTROYED;
706 }
707 else if (rc == -1)
708 /* Returned due to timeout being reached. */
709 rc = VERR_TIMEOUT;
710 else
711 rc = VERR_INTERRUPTED;
712 /* Returned due to pending signal. */
713 break;
714 }
715 }
716
717 mutex_exit(&pThis->Mtx);
718 rtR0SemEventMultiSolRelease(pThis);
719 return rc;
720}
721
722
723RTDECL(int) RTSemEventMultiWait(RTSEMEVENTMULTI hEventMultiSem, RTMSINTERVAL cMillies)
724{
725 return rtSemEventMultiWait(hEventMultiSem, cMillies, false /* not interruptible */);
726}
727
728
729RTDECL(int) RTSemEventMultiWaitNoResume(RTSEMEVENTMULTI hEventMultiSem, RTMSINTERVAL cMillies)
730{
731 return rtSemEventMultiWait(hEventMultiSem, cMillies, true /* interruptible */);
732}
733
734#endif
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