/** * Worker for RTSemEventWaitEx and RTSemEventWaitExDebug. * * @returns VBox status code. * @param pThis The event semaphore. * @param fFlags See RTSemEventWaitEx. * @param uTimeout See RTSemEventWaitEx. * @param pSrcPos The source code position of the wait. */ static int rtR0SemEventLnxWait(PRTSEMEVENTINTERNAL pThis, uint32_t fFlags, uint64_t uTimeout, PCRTLOCKVALSRCPOS pSrcPos) { int rc; /* * Validate the input. */ AssertPtrReturn(pThis, VERR_INVALID_PARAMETER); AssertMsgReturn(pThis->u32Magic == RTSEMEVENT_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER); AssertReturn(RTSEMWAIT_FLAGS_ARE_VALID(fFlags), VERR_INVALID_PARAMETER); rtR0SemEventLnxRetain(pThis); /* * Try grab the event without setting up the wait. */ if ( 1 /** @todo check if there are someone waiting already - waitqueue_active, but then what do we do below? */ && ASMAtomicCmpXchgU32(&pThis->fState, 0, 1)) rc = VINF_SUCCESS; else { /* * We have to wait. */ RTR0SEMLNXWAIT Wait; rc = rtR0SemLnxWaitInit(&Wait, fFlags, uTimeout, &pThis->Head); if (RT_SUCCESS(rc)) { IPRT_DEBUG_SEMS_STATE(pThis, 'E'); for (;;) { /* The destruction test. */ if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENT_MAGIC)) rc = VERR_SEM_DESTROYED; else { rtR0SemLnxWaitPrepare(&Wait); /* Check the exit conditions. */ if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENT_MAGIC)) rc = VERR_SEM_DESTROYED; else if (ASMAtomicCmpXchgU32(&pThis->fState, 0, 1)) rc = VINF_SUCCESS; else if (rtR0SemLnxWaitHasTimedOut(&Wait)) rc = VERR_TIMEOUT; else if (rtR0SemLnxWaitWasInterrupted(&Wait)) rc = VERR_INTERRUPTED; else { /* Do the wait and then recheck the conditions. */ rtR0SemLnxWaitDoIt(&Wait); continue; } } break; } rtR0SemLnxWaitDelete(&Wait); IPRT_DEBUG_SEMS_STATE_RC(pThis, 'E', rc); } } rtR0SemEventLnxRelease(pThis); return rc; }
/** * Worker for RTSemEventMultiWaitEx and RTSemEventMultiWaitExDebug. * * @returns VBox status code. * @param pThis The event semaphore. * @param fFlags See RTSemEventMultiWaitEx. * @param uTimeout See RTSemEventMultiWaitEx. * @param pSrcPos The source code position of the wait. */ static int rtR0SemEventMultiLnxWait(PRTSEMEVENTMULTIINTERNAL pThis, uint32_t fFlags, uint64_t uTimeout, PCRTLOCKVALSRCPOS pSrcPos) { uint32_t fOrgStateAndGen; int rc; /* * Validate the input. */ AssertPtrReturn(pThis, VERR_INVALID_PARAMETER); AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER); AssertReturn(RTSEMWAIT_FLAGS_ARE_VALID(fFlags), VERR_INVALID_PARAMETER); rtR0SemEventMultiLnxRetain(pThis); /* * Is the event already signalled or do we have to wait? */ fOrgStateAndGen = ASMAtomicUoReadU32(&pThis->fStateAndGen); if (fOrgStateAndGen & RTSEMEVENTMULTILNX_STATE_MASK) rc = VINF_SUCCESS; else { /* * We have to wait. */ RTR0SEMLNXWAIT Wait; rc = rtR0SemLnxWaitInit(&Wait, fFlags, uTimeout, &pThis->Head); if (RT_SUCCESS(rc)) { IPRT_DEBUG_SEMS_STATE(pThis, 'E'); for (;;) { /* The destruction test. */ if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC)) rc = VERR_SEM_DESTROYED; else { rtR0SemLnxWaitPrepare(&Wait); /* Check the exit conditions. */ if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC)) rc = VERR_SEM_DESTROYED; else if (ASMAtomicUoReadU32(&pThis->fStateAndGen) != fOrgStateAndGen) rc = VINF_SUCCESS; else if (rtR0SemLnxWaitHasTimedOut(&Wait)) rc = VERR_TIMEOUT; else if (rtR0SemLnxWaitWasInterrupted(&Wait)) rc = VERR_INTERRUPTED; else { /* Do the wait and then recheck the conditions. */ rtR0SemLnxWaitDoIt(&Wait); continue; } } break; } rtR0SemLnxWaitDelete(&Wait); IPRT_DEBUG_SEMS_STATE_RC(pThis, 'E', rc); } } rtR0SemEventMultiLnxRelease(pThis); return rc; }