static void testBasicsWaitSuccess(RTSEMEVENTMULTI hSem, unsigned i)
{
    RTTESTI_CHECK_RC_RETV(RTSemEventMultiWait(hSem, 0), VINF_SUCCESS);
    RTTESTI_CHECK_RC_RETV(RTSemEventMultiWait(hSem, RT_INDEFINITE_WAIT), VINF_SUCCESS);
#if 0
    RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitNoResume(hSem, 0), VINF_SUCCESS);
    RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitNoResume(hSem, RT_INDEFINITE_WAIT), VINF_SUCCESS);
#else
    RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitEx(hSem,
                          RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_NANOSECS | RTSEMWAIT_FLAGS_RELATIVE,
                          0),
                          VINF_SUCCESS);
    RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitEx(hSem, RTSEMWAIT_FLAGS_RESUME   | RTSEMWAIT_FLAGS_INDEFINITE, 0), VINF_SUCCESS);
    RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitEx(hSem, RTSEMWAIT_FLAGS_NORESUME | RTSEMWAIT_FLAGS_INDEFINITE, 0), VINF_SUCCESS);
    RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitEx(hSem,
                          RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_NANOSECS | RTSEMWAIT_FLAGS_ABSOLUTE,
                          RTTimeSystemNanoTS() + 1000*i),
                          VINF_SUCCESS);
    RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitEx(hSem,
                          RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_NANOSECS | RTSEMWAIT_FLAGS_ABSOLUTE,
                          RTTimeNanoTS() + 1000*i),
                          VINF_SUCCESS);
    RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitEx(hSem,
                          RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_NANOSECS | RTSEMWAIT_FLAGS_ABSOLUTE,
                          0),
                          VINF_SUCCESS);
    RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitEx(hSem,
                          RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_NANOSECS | RTSEMWAIT_FLAGS_ABSOLUTE,
                          _1G),
                          VINF_SUCCESS);
    RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitEx(hSem,
                          RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_NANOSECS | RTSEMWAIT_FLAGS_ABSOLUTE,
                          UINT64_MAX),
                          VINF_SUCCESS);


    RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitEx(hSem,
                          RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_MILLISECS | RTSEMWAIT_FLAGS_ABSOLUTE,
                          RTTimeSystemMilliTS() + 1000*i),
                          VINF_SUCCESS);
    RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitEx(hSem,
                          RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_MILLISECS | RTSEMWAIT_FLAGS_ABSOLUTE,
                          RTTimeMilliTS() + 1000*i),
                          VINF_SUCCESS);
    RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitEx(hSem,
                          RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_MILLISECS | RTSEMWAIT_FLAGS_ABSOLUTE,
                          0),
                          VINF_SUCCESS);
    RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitEx(hSem,
                          RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_MILLISECS | RTSEMWAIT_FLAGS_ABSOLUTE,
                          _1M),
                          VINF_SUCCESS);
    RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitEx(hSem,
                          RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_MILLISECS | RTSEMWAIT_FLAGS_ABSOLUTE,
                          UINT64_MAX),
                          VINF_SUCCESS);
#endif
}
static DECLCALLBACK(int) test1Thread1(RTTHREAD ThreadSelf, void *pvUser)
{
    RTSEMEVENTMULTI hSem = *(PRTSEMEVENTMULTI)pvUser;

    uint64_t u64 = RTTimeSystemMilliTS();
    RTTEST_CHECK_RC(g_hTest, RTSemEventMultiWait(hSem, 1000), VERR_TIMEOUT);
    u64 = RTTimeSystemMilliTS() - u64;
    RTTEST_CHECK_MSG(g_hTest, u64 < 1500 && u64 > 950, (g_hTest, "u64=%llu\n", u64));

    RTTEST_CHECK_RC(g_hTest, RTSemEventMultiWait(hSem, 2000), VINF_SUCCESS);
    return VINF_SUCCESS;
}
static void testBasicsWaitTimeout(RTSEMEVENTMULTI hSem, unsigned i)
{
    RTTESTI_CHECK_RC_RETV(RTSemEventMultiWait(hSem, 0), VERR_TIMEOUT);
#if 0
    RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitNoResume(hSem, 0), VERR_TIMEOUT);
#else
    RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitEx(hSem,
                          RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_NANOSECS | RTSEMWAIT_FLAGS_RELATIVE,
                          0),
                          VERR_TIMEOUT);
    RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitEx(hSem,
                          RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_NANOSECS | RTSEMWAIT_FLAGS_ABSOLUTE,
                          RTTimeSystemNanoTS() + 1000*i),
                          VERR_TIMEOUT);
    RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitEx(hSem,
                          RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_NANOSECS | RTSEMWAIT_FLAGS_ABSOLUTE,
                          RTTimeNanoTS() + 1000*i),
                          VERR_TIMEOUT);

    RTTESTI_CHECK_RC_RETV(RTSemEventMultiWaitEx(hSem,
                          RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_MILLISECS | RTSEMWAIT_FLAGS_RELATIVE,
                          0),
                          VERR_TIMEOUT);
#endif
}
/**
 * Called by the PDM thread in response to a wakeup call with
 * suspending as the new state.
 *
 * The thread will block in side this call until the state is changed in
 * response to a VM state change or to the device/driver/whatever calling the
 * PDMR3ThreadResume API.
 *
 * @returns VBox status code.
 *          On failure, terminate the thread.
 * @param   pThread     The PDM thread.
 */
VMMR3DECL(int) PDMR3ThreadIAmSuspending(PPDMTHREAD pThread)
{
    /*
     * Assert sanity.
     */
    AssertPtr(pThread);
    AssertReturn(pThread->u32Version == PDMTHREAD_VERSION, VERR_INVALID_MAGIC);
    Assert(pThread->Thread == RTThreadSelf() || pThread->enmState == PDMTHREADSTATE_INITIALIZING);
    PDMTHREADSTATE enmState = pThread->enmState;
    Assert(     enmState == PDMTHREADSTATE_SUSPENDING
           ||   enmState == PDMTHREADSTATE_INITIALIZING);

    /*
     * Update the state, notify the control thread (the API caller) and go to sleep.
     */
    int rc = VERR_WRONG_ORDER;
    if (pdmR3AtomicCmpXchgState(pThread, PDMTHREADSTATE_SUSPENDED, enmState))
    {
        rc = RTThreadUserSignal(pThread->Thread);
        if (RT_SUCCESS(rc))
        {
            rc = RTSemEventMultiWait(pThread->Internal.s.BlockEvent, RT_INDEFINITE_WAIT);
            if (    RT_SUCCESS(rc)
                &&  pThread->enmState != PDMTHREADSTATE_SUSPENDED)
                return rc;

            if (RT_SUCCESS(rc))
                rc = VERR_PDM_THREAD_IPE_2;
        }
    }

    AssertMsgFailed(("rc=%d enmState=%d\n", rc, pThread->enmState));
    pdmR3ThreadBailMeOut(pThread);
    return rc;
}
示例#5
0
/**
 * Place an entry in an mbox.
 */
void sys_mbox_post(sys_mbox_t mbox, void *msg)
{
    int rc;

    Assert(mbox != NULL);
    rc = LWIPMutexRequest(mbox->mutex, RT_INDEFINITE_WAIT);
    AssertRC(rc);
    while ((mbox->head + 1) % MBOX_ENTRIES_MAX == mbox->tail)
    {
        /* mbox is full, have to wait until a slot becomes available. */
        rc = LWIPMutexRelease(mbox->mutex);
        AssertRC(rc);
        rc = RTSemEventMultiWait(mbox->nonfull, RT_INDEFINITE_WAIT);
        AssertRC(rc);
        rc = LWIPMutexRequest(mbox->mutex, RT_INDEFINITE_WAIT);
        AssertRC(rc);
    }
    if (mbox->head == mbox->tail)
    {
        rc = RTSemEventMultiSignal(mbox->nonempty);
        AssertRC(rc);
    }
    mbox->apvEntries[mbox->head] = msg;
    mbox->head++;
    mbox->head %= MBOX_ENTRIES_MAX;
    if ((mbox->head + 1) % MBOX_ENTRIES_MAX == mbox->tail)
    {
        rc = RTSemEventMultiReset(mbox->nonfull);
        AssertRC(rc);
    }
    rc = LWIPMutexRelease(mbox->mutex);
    AssertRC(rc);
}
static DECLCALLBACK(int) test1Thread2(RTTHREAD ThreadSelf, void *pvUser)
{
    RTSEMEVENTMULTI hSem = *(PRTSEMEVENTMULTI)pvUser;
    RT_NOREF_PV(ThreadSelf);

    RTTEST_CHECK_RC(g_hTest, RTSemEventMultiWait(hSem, RT_INDEFINITE_WAIT), VINF_SUCCESS);
    return VINF_SUCCESS;
}
示例#7
0
/**
 * @note XPCOM: when this method is not called on the main XPCOM thread, it
 *       simply blocks the thread until mCompletedSem is signalled. If the
 *       thread has its own event queue (hmm, what for?) that it must run, then
 *       calling this method will definitely freeze event processing.
 */
STDMETHODIMP Progress::WaitForOperationCompletion(ULONG aOperation, LONG aTimeout)
{
    LogFlowThisFuncEnter();
    LogFlowThisFunc(("aOperation=%d, aTimeout=%d\n", aOperation, aTimeout));

    AutoCaller autoCaller(this);
    if (FAILED(autoCaller.rc())) return autoCaller.rc();

    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);

    CheckComArgExpr(aOperation, aOperation < m_cOperations);

    /* if we're already completed or if the given operation is already done,
     * then take a shortcut */
    if (    !mCompleted
         && aOperation >= m_ulCurrentOperation)
    {
        int vrc = VINF_SUCCESS;
        bool fForever = aTimeout < 0;
        int64_t timeLeft = aTimeout;
        int64_t lastTime = RTTimeMilliTS();

        while (    !mCompleted && aOperation >= m_ulCurrentOperation
                && (fForever || timeLeft > 0))
        {
            mWaitersCount ++;
            alock.release();
            vrc = RTSemEventMultiWait(mCompletedSem,
                                      fForever ? RT_INDEFINITE_WAIT : (unsigned) timeLeft);
            alock.acquire();
            mWaitersCount--;

            /* the last waiter resets the semaphore */
            if (mWaitersCount == 0)
                RTSemEventMultiReset(mCompletedSem);

            if (RT_FAILURE(vrc) && vrc != VERR_TIMEOUT)
                break;

            if (!fForever)
            {
                int64_t now = RTTimeMilliTS();
                timeLeft -= now - lastTime;
                lastTime = now;
            }
        }

        if (RT_FAILURE(vrc) && vrc != VERR_TIMEOUT)
            return setError(E_FAIL,
                            tr("Failed to wait for the operation completion (%Rrc)"),
                            vrc);
    }

    LogFlowThisFuncLeave();

    return S_OK;
}
示例#8
0
/**
 * @note XPCOM: when this method is not called on the main XPCOM thread, it
 *       simply blocks the thread until mCompletedSem is signalled. If the
 *       thread has its own event queue (hmm, what for?) that it must run, then
 *       calling this method will definitely freeze event processing.
 */
STDMETHODIMP Progress::WaitForCompletion(LONG aTimeout)
{
    LogFlowThisFuncEnter();
    LogFlowThisFunc(("aTimeout=%d\n", aTimeout));

    AutoCaller autoCaller(this);
    if (FAILED(autoCaller.rc())) return autoCaller.rc();

    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);

    /* if we're already completed, take a shortcut */
    if (!mCompleted)
    {
        int vrc = VINF_SUCCESS;
        bool fForever = aTimeout < 0;
        int64_t timeLeft = aTimeout;
        int64_t lastTime = RTTimeMilliTS();

        while (!mCompleted && (fForever || timeLeft > 0))
        {
            mWaitersCount++;
            alock.release();
            vrc = RTSemEventMultiWait(mCompletedSem,
                                      fForever ? RT_INDEFINITE_WAIT : (RTMSINTERVAL)timeLeft);
            alock.acquire();
            mWaitersCount--;

            /* the last waiter resets the semaphore */
            if (mWaitersCount == 0)
                RTSemEventMultiReset(mCompletedSem);

            if (RT_FAILURE(vrc) && vrc != VERR_TIMEOUT)
                break;

            if (!fForever)
            {
                int64_t now = RTTimeMilliTS();
                timeLeft -= now - lastTime;
                lastTime = now;
            }
        }

        if (RT_FAILURE(vrc) && vrc != VERR_TIMEOUT)
            return setError(VBOX_E_IPRT_ERROR,
                            tr("Failed to wait for the task completion (%Rrc)"),
                            vrc);
    }

    LogFlowThisFuncLeave();

    return S_OK;
}
示例#9
0
/**
 * Wait for the user event, resume on interruption.
 *
 * @returns     iprt status code.
 * @param       Thread          The thread to wait for.
 * @param       cMillies        The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for
 *                              an indefinite wait.
 */
RTDECL(int) RTThreadUserWait(RTTHREAD Thread, RTMSINTERVAL cMillies)
{
    int             rc;
    PRTTHREADINT    pThread = rtThreadGet(Thread);
    if (pThread)
    {
        rc = RTSemEventMultiWait(pThread->EventUser, cMillies);
        rtThreadRelease(pThread);
    }
    else
        rc = VERR_INVALID_HANDLE;
    return rc;
}
示例#10
0
/**
 * Wait for the thread to terminate.
 *
 * @returns     iprt status code.
 * @param       Thread          The thread to wait for.
 * @param       cMillies        The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for
 *                              an indefinite wait.
 * @param       prc             Where to store the return code of the thread. Optional.
 * @param       fAutoResume     Whether or not to resume the wait on VERR_INTERRUPTED.
 */
static int rtThreadWait(RTTHREAD Thread, RTMSINTERVAL cMillies, int *prc, bool fAutoResume)
{
    int rc = VERR_INVALID_HANDLE;
    if (Thread != NIL_RTTHREAD)
    {
        PRTTHREADINT pThread = rtThreadGet(Thread);
        if (pThread)
        {
            if (pThread->fFlags & RTTHREADFLAGS_WAITABLE)
            {
                if (fAutoResume)
                    rc = RTSemEventMultiWait(pThread->EventTerminated, cMillies);
                else
                    rc = RTSemEventMultiWaitNoResume(pThread->EventTerminated, cMillies);
                if (RT_SUCCESS(rc))
                {
                    if (prc)
                        *prc = pThread->rc;

                    /*
                     * If the thread is marked as waitable, we'll do one additional
                     * release in order to free up the thread structure (see how we
                     * init cRef in rtThreadAlloc()).
                     */
                    if (ASMAtomicBitTestAndClear(&pThread->fFlags, RTTHREADFLAGS_WAITABLE_BIT))
                    {
                        rtThreadRelease(pThread);
#ifdef IN_RING0
                        /*
                         * IPRT termination kludge. Call native code to make sure
                         * the last thread is really out of IPRT to prevent it from
                         * crashing after we destroyed the spinlock in rtThreadTerm.
                         */
                        if (   ASMAtomicReadU32(&g_cThreadInTree) == 1
                            && ASMAtomicReadU32(&pThread->cRefs) > 1)
                            rtThreadNativeWaitKludge(pThread);
#endif
                    }
                }
            }
            else
            {
                rc = VERR_THREAD_NOT_WAITABLE;
                AssertRC(rc);
            }
            rtThreadRelease(pThread);
        }
    }
    return rc;
}
示例#11
0
/**
 * Thread that allocates
 * @returns
 * @param   hThreadSelf         The thread.
 * @param   pvArg               Pointer to fUseCache.
 */
static DECLCALLBACK(int) tst3Thread(RTTHREAD hThreadSelf, void *pvArg)
{
    PTST3THREAD     pThread     = (PTST3THREAD)(pvArg);
    size_t          cbObject    = pThread->cbObject;
    uint64_t        cIterations = 0;

    /* wait for the kick-off */
    RTTEST_CHECK_RC_OK(g_hTest, RTSemEventMultiWait(pThread->hEvt, RT_INDEFINITE_WAIT));

    /* allocate and free loop */
    if (pThread->fUseCache)
    {
        while (!g_fTst3Stop)
        {
            void *apv[64];
            for (unsigned i = 0; i < RT_ELEMENTS(apv); i++)
            {
                apv[i] = RTMemCacheAlloc(g_hMemCache);
                RTTEST_CHECK(g_hTest, apv[i] != NULL);
            }
            for (unsigned i = 0; i < RT_ELEMENTS(apv); i++)
                RTMemCacheFree(g_hMemCache, apv[i]);

            cIterations += RT_ELEMENTS(apv);
        }
    }
    else
    {
        while (!g_fTst3Stop)
        {
            void *apv[64];

            for (unsigned i = 0; i < RT_ELEMENTS(apv); i++)
            {
                apv[i] = RTMemAlloc(cbObject);
                RTTEST_CHECK(g_hTest, apv[i] != NULL);
            }

            for (unsigned i = 0; i < RT_ELEMENTS(apv); i++)
                RTMemFree(apv[i]);

            cIterations += RT_ELEMENTS(apv);
        }
    }

    /* report back the status */
    pThread->cIterations = cIterations;
    return VINF_SUCCESS;
}
示例#12
0
static DECLCALLBACK(int) Once2Thread(RTTHREAD hThread, void *pvUser)
{
    NOREF(hThread); NOREF(pvUser);

    int rc = RTSemEventMultiWait(g_hEventMulti, RT_INDEFINITE_WAIT);
    if (RT_FAILURE(rc))
        return rc;
    rc = RTOnce(&g_Once2, Once2CB, (void *)42);
    if (RT_SUCCESS(rc))
    {
        if (!ASMAtomicUoReadBool(&g_fOnce2Ready))
        {
            RTPrintf("tstOnce: ERROR - Once2CB: Not initialized!\n");
            g_cErrors++;
        }
    }
    return rc;
}
示例#13
0
文件: sys_arch.c 项目: bayasist/vbox
/**
 * Place an entry in an mbox, waiting for a free slot if necessary.
 */
void sys_mbox_post(sys_mbox_t *pvMbox, void *msg)
{
    int rc;
    struct sys_mbox *mbox = NULL;
    Assert(pvMbox && *pvMbox);
    mbox = (struct sys_mbox*)*pvMbox;

    rc = LWIPMutexRequest((mbox)->mutex);
    AssertRC(rc);

    while (((mbox)->head + 1) % MBOX_ENTRIES_MAX == (mbox)->tail)
    {
        /* (mbox) is full, have to wait until a slot becomes available. */
        rc = LWIPMutexRelease((mbox)->mutex);
        AssertRC(rc);

        rc = RTSemEventMultiWait((mbox)->nonfull, RT_INDEFINITE_WAIT);
        AssertRC(rc);

        rc = LWIPMutexRequest((mbox)->mutex);
        AssertRC(rc);
    }

    if ((mbox)->head == (mbox)->tail)
    {
        rc = RTSemEventMultiSignal((mbox)->nonempty);
        AssertRC(rc);
    }
    (mbox)->apvEntries[(mbox)->head] = msg;
    (mbox)->head++;
    (mbox)->head %= MBOX_ENTRIES_MAX;
    if (((mbox)->head + 1) % MBOX_ENTRIES_MAX == (mbox)->tail)
    {
        rc = RTSemEventMultiReset((mbox)->nonfull);
        AssertRC(rc);
    }
    rc = LWIPMutexRelease((mbox)->mutex);
    AssertRC(rc);
}
示例#14
0
/**
 * Wait for the thread to terminate.
 *
 * @returns     iprt status code.
 * @param       Thread          The thread to wait for.
 * @param       cMillies        The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for
 *                              an indefinite wait.
 * @param       prc             Where to store the return code of the thread. Optional.
 * @param       fAutoResume     Whether or not to resume the wait on VERR_INTERRUPTED.
 */
static int rtThreadWait(RTTHREAD Thread, RTMSINTERVAL cMillies, int *prc, bool fAutoResume)
{
    int rc = VERR_INVALID_HANDLE;
    if (Thread != NIL_RTTHREAD)
    {
        PRTTHREADINT pThread = rtThreadGet(Thread);
        if (pThread)
        {
            if (pThread->fFlags & RTTHREADFLAGS_WAITABLE)
            {
                if (fAutoResume)
                    rc = RTSemEventMultiWait(pThread->EventTerminated, cMillies);
                else
                    rc = RTSemEventMultiWaitNoResume(pThread->EventTerminated, cMillies);
                if (RT_SUCCESS(rc))
                {
                    if (prc)
                        *prc = pThread->rc;

                    /*
                     * If the thread is marked as waitable, we'll do one additional
                     * release in order to free up the thread structure (see how we
                     * init cRef in rtThreadAlloc()).
                     */
                    if (ASMAtomicBitTestAndClear(&pThread->fFlags, RTTHREADFLAGS_WAITABLE_BIT))
                        rtThreadRelease(pThread);
                }
            }
            else
            {
                rc = VERR_THREAD_NOT_WAITABLE;
                AssertRC(rc);
            }
            rtThreadRelease(pThread);
        }
    }
    return rc;
}
示例#15
0
/**
 * Get an entry from an mbox.
 */
u32_t sys_arch_mbox_fetch(sys_mbox_t mbox, void **msg, u32_t timeout)
{
    int rc;
    RTMSINTERVAL cMillies;
    uint64_t tsStart, tsEnd;

    Assert(mbox != NULL);
    tsStart = RTTimeMilliTS();
    if (timeout == 0)
        cMillies = RT_INDEFINITE_WAIT;
    else
        cMillies = timeout;
    rc = LWIPMutexRequest(mbox->mutex, cMillies);
    if (rc == VERR_TIMEOUT)
        return SYS_ARCH_TIMEOUT;
    AssertRC(rc);
    while (mbox->head == mbox->tail)
    {
        /* mbox is empty, have to wait until a slot is filled. */
        rc = LWIPMutexRelease(mbox->mutex);
        AssertRC(rc);
        if (timeout != 0)
        {
            tsEnd = RTTimeMilliTS();
            if (tsEnd - tsStart >= cMillies)
                return SYS_ARCH_TIMEOUT;
            cMillies -= tsEnd - tsStart;
        }
        rc = RTSemEventMultiWait(mbox->nonempty, cMillies);
        if (rc == VERR_TIMEOUT)
            return SYS_ARCH_TIMEOUT;
        AssertRC(rc);
        if (timeout != 0)
        {
            tsEnd = RTTimeMilliTS();
            if (tsEnd - tsStart >= cMillies)
                return SYS_ARCH_TIMEOUT;
            cMillies -= tsEnd - tsStart;
        }
        rc = LWIPMutexRequest(mbox->mutex, cMillies);
        if (rc == VERR_TIMEOUT)
            return SYS_ARCH_TIMEOUT;
        AssertRC(rc);
    }
    if ((mbox->head + 1) % MBOX_ENTRIES_MAX == mbox->tail)
    {
        rc = RTSemEventMultiSignal(mbox->nonfull);
        AssertRC(rc);
    }
    if (msg != NULL)
        *msg = mbox->apvEntries[mbox->tail];
    mbox->tail++;
    mbox->tail %= MBOX_ENTRIES_MAX;
    rc = RTSemEventMultiSignal(mbox->nonfull);
    if (mbox->head == mbox->tail)
    {
        rc = RTSemEventMultiReset(mbox->nonempty);
        AssertRC(rc);
    }
    rc = LWIPMutexRelease(mbox->mutex);
    AssertRC(rc);
    tsEnd = RTTimeMilliTS();
    return tsEnd - tsStart;
}
示例#16
0
DECL_FORCE_INLINE(int) rtSemRWRequestRead(RTSEMRW hRWSem, RTMSINTERVAL cMillies, bool fInterruptible, PCRTLOCKVALSRCPOS pSrcPos)
{
    /*
     * Validate handle.
     */
    struct RTSEMRWINTERNAL *pThis = hRWSem;
    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
    AssertReturn(pThis->u32Magic == RTSEMRW_MAGIC, VERR_INVALID_HANDLE);

    RTMSINTERVAL    cMilliesInitial = cMillies;
    uint64_t        tsStart = 0;
    if (cMillies != RT_INDEFINITE_WAIT && cMillies != 0)
        tsStart = RTTimeNanoTS();

#ifdef RTSEMRW_STRICT
    RTTHREAD hThreadSelf = RTThreadSelfAutoAdopt();
    if (cMillies > 0)
    {
        int rc9;
        if (pThis->hWriter != NIL_RTTHREAD && pThis->hWriter == RTThreadNativeSelf())
            rc9 = RTLockValidatorRecExclCheckOrder(&pThis->ValidatorWrite, hThreadSelf, pSrcPos, cMillies);
        else
            rc9 = RTLockValidatorRecSharedCheckOrder(&pThis->ValidatorRead, hThreadSelf, pSrcPos, cMillies);
        if (RT_FAILURE(rc9))
            return rc9;
    }
#endif

    /*
     * Take critsect.
     */
    int rc = RTCritSectEnter(&pThis->CritSect);
    if (RT_FAILURE(rc))
    {
        AssertMsgFailed(("RTCritSectEnter failed on rwsem %p, rc=%Rrc\n", hRWSem, rc));
        return rc;
    }

    /*
     * Check if the state of affairs allows read access.
     * Do not block further readers if there is a writer waiting, as
     * that will break/deadlock reader recursion.
     */
    if (    pThis->hWriter == NIL_RTNATIVETHREAD
#if 0
        && (   !pThis->cWritesWaiting
            ||  pThis->cReads)
#endif
       )
    {
        pThis->cReads++;
        Assert(pThis->cReads > 0);
#ifdef RTSEMRW_STRICT
        RTLockValidatorRecSharedAddOwner(&pThis->ValidatorRead, hThreadSelf, pSrcPos);
#endif

        RTCritSectLeave(&pThis->CritSect);
        return VINF_SUCCESS;
    }

    RTNATIVETHREAD hNativeSelf = pThis->CritSect.NativeThreadOwner;
    if (pThis->hWriter == hNativeSelf)
    {
#ifdef RTSEMRW_STRICT
        int rc9 = RTLockValidatorRecExclRecursionMixed(&pThis->ValidatorWrite, &pThis->ValidatorRead.Core, pSrcPos);
        if (RT_FAILURE(rc9))
        {
            RTCritSectLeave(&pThis->CritSect);
            return rc9;
        }
#endif

        pThis->cWriterReads++;
        Assert(pThis->cWriterReads > 0);

        RTCritSectLeave(&pThis->CritSect);
        return VINF_SUCCESS;
    }

    RTCritSectLeave(&pThis->CritSect);

    /*
     * Wait till it's ready for reading.
     */
    if (cMillies == 0)
        return VERR_TIMEOUT;

#ifndef RTSEMRW_STRICT
    RTTHREAD hThreadSelf = RTThreadSelf();
#endif
    for (;;)
    {
        if (cMillies != RT_INDEFINITE_WAIT)
        {
            int64_t tsDelta = RTTimeNanoTS() - tsStart;
            if (tsDelta >= 1000000)
            {
                tsDelta /= 1000000;
                if ((uint64_t)tsDelta < cMilliesInitial)
                    cMilliesInitial = (RTMSINTERVAL)tsDelta;
                else
                    cMilliesInitial = 1;
            }
        }
#ifdef RTSEMRW_STRICT
        rc = RTLockValidatorRecSharedCheckBlocking(&pThis->ValidatorRead, hThreadSelf, pSrcPos, true,
                                                   cMillies, RTTHREADSTATE_RW_READ, false);
        if (RT_FAILURE(rc))
            break;
#else
        RTThreadBlocking(hThreadSelf, RTTHREADSTATE_RW_READ, false);
#endif
        int rcWait;
        if (fInterruptible)
            rcWait = rc = RTSemEventMultiWaitNoResume(pThis->ReadEvent, cMillies);
        else
            rcWait = rc = RTSemEventMultiWait(pThis->ReadEvent, cMillies);
        RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_RW_READ);
        if (RT_FAILURE(rc) && rc != VERR_TIMEOUT) /* handle timeout below */
        {
            AssertMsgRC(rc, ("RTSemEventMultiWait failed on rwsem %p, rc=%Rrc\n", hRWSem, rc));
            break;
        }

        if (pThis->u32Magic != RTSEMRW_MAGIC)
        {
            rc = VERR_SEM_DESTROYED;
            break;
        }

        /*
         * Re-take critsect and repeat the check we did before the loop.
         */
        rc = RTCritSectEnter(&pThis->CritSect);
        if (RT_FAILURE(rc))
        {
            AssertMsgFailed(("RTCritSectEnter failed on rwsem %p, rc=%Rrc\n", hRWSem, rc));
            break;
        }

        if (    pThis->hWriter == NIL_RTNATIVETHREAD
#if 0
            && (   !pThis->cWritesWaiting
                ||  pThis->cReads)
#endif
           )
        {
            pThis->cReads++;
            Assert(pThis->cReads > 0);
#ifdef RTSEMRW_STRICT
            RTLockValidatorRecSharedAddOwner(&pThis->ValidatorRead, hThreadSelf, pSrcPos);
#endif

            RTCritSectLeave(&pThis->CritSect);
            return VINF_SUCCESS;
        }

        RTCritSectLeave(&pThis->CritSect);

        /*
         * Quit if the wait already timed out.
         */
        if (rcWait == VERR_TIMEOUT)
        {
            rc = VERR_TIMEOUT;
            break;
        }
    }

    /* failed */
    return rc;
}
/** @copydoc VBOXSERVICE::pfnWorker */
DECLCALLBACK(int) VBoxServiceVMStatsWorker(bool volatile *pfShutdown)
{
    int rc = VINF_SUCCESS;

    /* Start monitoring of the stat event change event. */
    rc = VbglR3CtlFilterMask(VMMDEV_EVENT_STATISTICS_INTERVAL_CHANGE_REQUEST, 0);
    if (RT_FAILURE(rc))
    {
        VBoxServiceVerbose(3, "VBoxServiceVMStatsWorker: VbglR3CtlFilterMask failed with %d\n", rc);
        return rc;
    }

    /*
     * Tell the control thread that it can continue
     * spawning services.
     */
    RTThreadUserSignal(RTThreadSelf());

    /*
     * Now enter the loop retrieving runtime data continuously.
     */
    for (;;)
    {
        uint32_t fEvents = 0;
        RTMSINTERVAL cWaitMillies;

        /* Check if an update interval change is pending. */
        rc = VbglR3WaitEvent(VMMDEV_EVENT_STATISTICS_INTERVAL_CHANGE_REQUEST, 0 /* no wait */, &fEvents);
        if (    RT_SUCCESS(rc)
            &&  (fEvents & VMMDEV_EVENT_STATISTICS_INTERVAL_CHANGE_REQUEST))
        {
            VbglR3StatQueryInterval(&gCtx.cMsStatInterval);
        }

        if (gCtx.cMsStatInterval)
        {
            VBoxServiceVMStatsReport();
            cWaitMillies = gCtx.cMsStatInterval;
        }
        else
            cWaitMillies = 3000;

        /*
         * Block for a while.
         *
         * The event semaphore takes care of ignoring interruptions and it
         * allows us to implement service wakeup later.
         */
        if (*pfShutdown)
            break;
        int rc2 = RTSemEventMultiWait(g_VMStatEvent, cWaitMillies);
        if (*pfShutdown)
            break;
        if (rc2 != VERR_TIMEOUT && RT_FAILURE(rc2))
        {
            VBoxServiceError("VBoxServiceVMStatsWorker: RTSemEventMultiWait failed; rc2=%Rrc\n", rc2);
            rc = rc2;
            break;
        }
    }

    /* Cancel monitoring of the stat event change event. */
    rc = VbglR3CtlFilterMask(0, VMMDEV_EVENT_STATISTICS_INTERVAL_CHANGE_REQUEST);
    if (RT_FAILURE(rc))
        VBoxServiceVerbose(3, "VBoxServiceVMStatsWorker: VbglR3CtlFilterMask failed with %d\n", rc);

    RTSemEventMultiDestroy(g_VMStatEvent);
    g_VMStatEvent = NIL_RTSEMEVENTMULTI;

    VBoxServiceVerbose(3, "VBoxStatsThread: finished statistics change request thread\n");
    return 0;
}
static DECLCALLBACK(int) gimDevR3DbgRecvThread(RTTHREAD hThreadSelf, void *pvUser)
{
    RT_NOREF1(hThreadSelf);

    /*
     * Validate.
     */
    PPDMDEVINS pDevIns = (PPDMDEVINS)pvUser;
    AssertReturn(pDevIns, VERR_INVALID_PARAMETER);
    PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);

    PGIMDEV pThis = PDMINS_2_DATA(pDevIns, PGIMDEV);
    AssertReturn(pThis, VERR_INVALID_POINTER);
    AssertReturn(pThis->DbgSetup.cbDbgRecvBuf, VERR_INTERNAL_ERROR);
    AssertReturn(pThis->Dbg.hDbgRecvThreadSem != NIL_RTSEMEVENTMULTI, VERR_INTERNAL_ERROR_2);
    AssertReturn(pThis->Dbg.pvDbgRecvBuf, VERR_INTERNAL_ERROR_3);

    PVM pVM = PDMDevHlpGetVM(pDevIns);
    AssertReturn(pVM, VERR_INVALID_POINTER);

    PPDMISTREAM pDbgDrvStream = pThis->Dbg.pDbgDrvStream;
    AssertReturn(pDbgDrvStream, VERR_INVALID_POINTER);

    for (;;)
    {
        /*
         * Read incoming debug data.
         */
        size_t cbRead = pThis->DbgSetup.cbDbgRecvBuf;
        int rc = pDbgDrvStream->pfnRead(pDbgDrvStream, pThis->Dbg.pvDbgRecvBuf, &cbRead);
        if (   RT_SUCCESS(rc)
            && cbRead > 0)
        {
            /*
             * Notify the consumer thread.
             */
            if (ASMAtomicReadBool(&pThis->Dbg.fDbgRecvBufRead) == false)
            {
                if (pThis->DbgSetup.pfnDbgRecvBufAvail)
                    pThis->DbgSetup.pfnDbgRecvBufAvail(pVM);
                pThis->Dbg.cbDbgRecvBufRead = cbRead;
                RTSemEventMultiReset(pThis->Dbg.hDbgRecvThreadSem);
                ASMAtomicWriteBool(&pThis->Dbg.fDbgRecvBufRead, true);
            }

            /*
             * Wait until the consumer thread has acknowledged reading of the
             * current buffer or we're asked to shut down.
             *
             * It is important that we do NOT re-invoke 'pfnRead' before the
             * current buffer is consumed, otherwise we risk data corruption.
             */
            while (   ASMAtomicReadBool(&pThis->Dbg.fDbgRecvBufRead) == true
                   && !pThis->fDbgRecvThreadShutdown)
            {
                RTSemEventMultiWait(pThis->Dbg.hDbgRecvThreadSem, RT_INDEFINITE_WAIT);
            }
        }
#ifdef RT_OS_LINUX
        else if (rc == VERR_NET_CONNECTION_REFUSED)
        {
            /*
             * With the current, simplistic PDMISTREAM interface, this is the best we can do.
             * Even using RTSocketSelectOne[Ex] on Linux returns immediately with 'ready-to-read'
             * on localhost UDP sockets that are not connected on the other end.
             */
            /** @todo Fix socket waiting semantics on localhost Linux unconnected UDP sockets. */
            RTThreadSleep(400);
        }
#endif
        else if (   rc != VINF_TRY_AGAIN
                 && rc != VERR_TRY_AGAIN
                 && rc != VERR_NET_CONNECTION_RESET_BY_PEER)
        {
            LogRel(("GIMDev: Debug thread terminating with rc=%Rrc\n", rc));
            break;
        }

        if (pThis->fDbgRecvThreadShutdown)
        {
            LogRel(("GIMDev: Debug thread shutting down\n"));
            break;
        }
    }

    return VINF_SUCCESS;
}
示例#19
0
/**
 * @interface_method_impl{VBOXSERVICE,pfnWorker}
 */
DECLCALLBACK(int) vgsvcTimeSyncWorker(bool volatile *pfShutdown)
{
    RTTIME Time;
    char sz[64];
    int rc = VINF_SUCCESS;

    /*
     * Tell the control thread that it can continue spawning services.
     */
    RTThreadUserSignal(RTThreadSelf());

    /*
     * The Work Loop.
     */
    for (;;)
    {
        /*
         * Try get a reliable time reading.
         */
        int cTries = 3;
        do
        {
            /* query it. */
            RTTIMESPEC GuestNow0, GuestNow, HostNow;
            RTTimeNow(&GuestNow0);
            int rc2 = VbglR3GetHostTime(&HostNow);
            if (RT_FAILURE(rc2))
            {
                if (g_cTimeSyncErrors++ < 10)
                    VGSvcError("vgsvcTimeSyncWorker: VbglR3GetHostTime failed; rc2=%Rrc\n", rc2);
                break;
            }
            RTTimeNow(&GuestNow);

            /* calc latency and check if it's ok. */
            RTTIMESPEC GuestElapsed = GuestNow;
            RTTimeSpecSub(&GuestElapsed, &GuestNow0);
            if ((uint32_t)RTTimeSpecGetMilli(&GuestElapsed) < g_TimeSyncMaxLatency)
            {
                /*
                 * Set the time once after we were restored.
                 * (Of course only if the drift is bigger than MinAdjust)
                 */
                uint32_t TimeSyncSetThreshold = g_TimeSyncSetThreshold;
                if (g_fTimeSyncSetOnRestore)
                {
                    uint64_t idNewSession = g_idTimeSyncSession;
                    VbglR3GetSessionId(&idNewSession);
                    if (idNewSession != g_idTimeSyncSession)
                    {
                        VGSvcVerbose(3, "vgsvcTimeSyncWorker: The VM session ID changed, forcing resync.\n");
                        TimeSyncSetThreshold = 0;
                        g_idTimeSyncSession  = idNewSession;
                    }
                }

                /*
                 * Calculate the adjustment threshold and the current drift.
                 */
                uint32_t MinAdjust = RTTimeSpecGetMilli(&GuestElapsed) * g_TimeSyncLatencyFactor;
                if (MinAdjust < g_TimeSyncMinAdjust)
                    MinAdjust = g_TimeSyncMinAdjust;

                RTTIMESPEC Drift = HostNow;
                RTTimeSpecSub(&Drift, &GuestNow);
                if (RTTimeSpecGetMilli(&Drift) < 0)
                    MinAdjust += g_TimeSyncMinAdjust; /* extra buffer against moving time backwards. */

                RTTIMESPEC AbsDrift = Drift;
                RTTimeSpecAbsolute(&AbsDrift);
                if (g_cVerbosity >= 3)
                {
                    VGSvcVerbose(3, "vgsvcTimeSyncWorker: Host:    %s    (MinAdjust: %RU32 ms)\n",
                                 RTTimeToString(RTTimeExplode(&Time, &HostNow), sz, sizeof(sz)), MinAdjust);
                    VGSvcVerbose(3, "vgsvcTimeSyncWorker: Guest: - %s => %RDtimespec drift\n",
                                 RTTimeToString(RTTimeExplode(&Time, &GuestNow), sz, sizeof(sz)), &Drift);
                }

                uint32_t AbsDriftMilli = RTTimeSpecGetMilli(&AbsDrift);
                if (AbsDriftMilli > MinAdjust)
                {
                    /*
                     * Ok, the drift is above the threshold.
                     *
                     * Try a gradual adjustment first, if that fails or the drift is
                     * too big, fall back on just setting the time.
                     */

                    if (    AbsDriftMilli > TimeSyncSetThreshold
                        ||  g_fTimeSyncSetNext
                        ||  !vgsvcTimeSyncAdjust(&Drift))
                    {
                        vgsvcTimeSyncCancelAdjust();
                        vgsvcTimeSyncSet(&Drift);
                    }
                }
                else
                    vgsvcTimeSyncCancelAdjust();
                break;
            }
            VGSvcVerbose(3, "vgsvcTimeSyncWorker: %RDtimespec: latency too high (%RDtimespec) sleeping 1s\n", GuestElapsed);
            RTThreadSleep(1000);
        } while (--cTries > 0);

        /* Clear the set-next/set-start flag. */
        g_fTimeSyncSetNext = false;

        /*
         * Block for a while.
         *
         * The event semaphore takes care of ignoring interruptions and it
         * allows us to implement service wakeup later.
         */
        if (*pfShutdown)
            break;
        int rc2 = RTSemEventMultiWait(g_TimeSyncEvent, g_TimeSyncInterval);
        if (*pfShutdown)
            break;
        if (rc2 != VERR_TIMEOUT && RT_FAILURE(rc2))
        {
            VGSvcError("vgsvcTimeSyncWorker: RTSemEventMultiWait failed; rc2=%Rrc\n", rc2);
            rc = rc2;
            break;
        }
    }

    vgsvcTimeSyncCancelAdjust();
    RTSemEventMultiDestroy(g_TimeSyncEvent);
    g_TimeSyncEvent = NIL_RTSEMEVENTMULTI;
    return rc;
}
/** @copydoc VBOXSERVICE::pfnWorker */
DECLCALLBACK(int) VBoxServiceVMInfoWorker(bool volatile *pfShutdown)
{
    int rc;

    /*
     * Tell the control thread that it can continue
     * spawning services.
     */
    RTThreadUserSignal(RTThreadSelf());

#ifdef RT_OS_WINDOWS
    /* Required for network information (must be called per thread). */
    WSADATA wsaData;
    if (WSAStartup(MAKEWORD(2, 2), &wsaData))
        VBoxServiceError("VMInfo/Network: WSAStartup failed! Error: %Rrc\n", RTErrConvertFromWin32(WSAGetLastError()));
#endif /* RT_OS_WINDOWS */

    /*
     * Write the fixed properties first.
     */
    vboxserviceVMInfoWriteFixedProperties();

    /*
     * Now enter the loop retrieving runtime data continuously.
     */
    for (;;)
    {
        rc = vboxserviceVMInfoWriteUsers();
        if (RT_FAILURE(rc))
            break;

        rc = vboxserviceVMInfoWriteNetwork();
        if (RT_FAILURE(rc))
            break;

        /*
         * Flush all properties if we were restored.
         */
        uint64_t idNewSession = g_idVMInfoSession;
        VbglR3GetSessionId(&idNewSession);
        if (idNewSession != g_idVMInfoSession)
        {
            VBoxServiceVerbose(3, "VMInfo: The VM session ID changed, flushing all properties\n");
            vboxserviceVMInfoWriteFixedProperties();
            VBoxServicePropCacheFlush(&g_VMInfoPropCache);
            g_idVMInfoSession = idNewSession;
        }

        /*
         * Block for a while.
         *
         * The event semaphore takes care of ignoring interruptions and it
         * allows us to implement service wakeup later.
         */
        if (*pfShutdown)
            break;
        int rc2 = RTSemEventMultiWait(g_hVMInfoEvent, g_cMsVMInfoInterval);
        if (*pfShutdown)
            break;
        if (rc2 != VERR_TIMEOUT && RT_FAILURE(rc2))
        {
            VBoxServiceError("VMInfo: RTSemEventMultiWait failed; rc2=%Rrc\n", rc2);
            rc = rc2;
            break;
        }
        else if (RT_LIKELY(RT_SUCCESS(rc2)))
        {
            /* Reset event semaphore if it got triggered. */
            rc2 = RTSemEventMultiReset(g_hVMInfoEvent);
            if (RT_FAILURE(rc2))
                rc2 = VBoxServiceError("VMInfo: RTSemEventMultiReset failed; rc2=%Rrc\n", rc2);
        }
    }

#ifdef RT_OS_WINDOWS
    WSACleanup();
#endif

    return rc;
}
示例#21
0
/**
 * Windows Service Main.
 *
 * This is invoked when the service is started and should not return until
 * the service has been stopped.
 *
 * @param   cArgs           Argument count.
 * @param   papszArgs       Argument vector.
 */
static VOID WINAPI supSvcWinServiceMain(DWORD cArgs, LPSTR *papszArgs)
{
    LogFlowFuncEnter();

    /*
     * Register the control handler function for the service and report to SCM.
     */
    Assert(g_u32SupSvcWinStatus == SERVICE_STOPPED);
    g_hSupSvcWinCtrlHandler = RegisterServiceCtrlHandlerEx(SUPSVC_SERVICE_NAME, supSvcWinServiceCtrlHandlerEx, NULL);
    if (g_hSupSvcWinCtrlHandler)
    {
        DWORD err = ERROR_GEN_FAILURE;
        if (supSvcWinSetServiceStatus(SERVICE_START_PENDING, 3000, NO_ERROR))
        {
            /*
             * Parse arguments.
             */
            static const RTOPTIONDEF s_aOptions[] =
            {
                { "--dummy", 'd', RTGETOPT_REQ_NOTHING }
            };
            int iArg = 1; /* the first arg is the service name */
            int ch;
            int rc = 0;
            RTGETOPTUNION Value;
            while (   !rc
                   && (ch = RTGetOpt(cArgs, papszArgs, s_aOptions, RT_ELEMENTS(s_aOptions), &iArg, &Value)))
                switch (ch)
                {
                    default:    rc = supSvcLogGetOptError("main", ch, cArgs, papszArgs, iArg, &Value); break;
                }
            if (iArg != cArgs)
                rc = supSvcLogTooManyArgsError("main", cArgs, papszArgs, iArg);
            if (!rc)
            {
                /*
                 * Create the event semaphore we'll be waiting on and
                 * then instantiate the actual services.
                 */
                int rc = RTSemEventMultiCreate(&g_hSupSvcWinEvent);
                if (RT_SUCCESS(rc))
                {
                    rc = supSvcCreateAndStartServices();
                    if (RT_SUCCESS(rc))
                    {
                        /*
                         * Update the status and enter the work loop.
                         *
                         * The work loop is just a dummy wait here as the services run
                         * in independent threads.
                         */
                        if (supSvcWinSetServiceStatus(SERVICE_RUNNING, 0, 0))
                        {
                            LogFlow(("supSvcWinServiceMain: calling RTSemEventMultiWait\n"));
                            rc = RTSemEventMultiWait(g_hSupSvcWinEvent, RT_INDEFINITE_WAIT);
                            if (RT_SUCCESS(rc))
                            {
                                LogFlow(("supSvcWinServiceMain: woke up\n"));
                                err = NO_ERROR;
                            }
                            else
                                supSvcLogError("RTSemEventWait failed, rc=%Rrc", rc);
                        }
                        else
                        {
                            err = GetLastError();
                            supSvcLogError("SetServiceStatus failed, err=%d", err);
                        }

                        /*
                         * Destroy the service instances, stopping them if
                         * they're still running (weird failure cause).
                         */
                        supSvcStopAndDestroyServices();
                    }

                    RTSemEventMultiDestroy(g_hSupSvcWinEvent);
                    g_hSupSvcWinEvent = NIL_RTSEMEVENTMULTI;
                }
                else
                    supSvcLogError("RTSemEventMultiCreate failed, rc=%Rrc", rc);
            }
            /* else: bad args */
        }
        else
        {
            err = GetLastError();
            supSvcLogError("SetServiceStatus failed, err=%d", err);
        }
        supSvcWinSetServiceStatus(SERVICE_STOPPED, 0, err);
    }
    else
        supSvcLogError("RegisterServiceCtrlHandlerEx failed, err=%d", GetLastError());
    LogFlowFuncLeave();
}