Beispiel #1
0
/**
 * Try to place an entry in an mbox if there is a free slot.
 */
err_t sys_mbox_trypost(sys_mbox_t *pvMbox, void *msg)
{
    int rc;
    struct sys_mbox *mbox = NULL;
    AssertReturn(pvMbox && *pvMbox, ERR_ARG);
    mbox = (struct sys_mbox*)*pvMbox;

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

    if (((mbox)->head + 1) % MBOX_ENTRIES_MAX == (mbox)->tail)
    {
        /* (mbox) is full */
        rc = LWIPMutexRelease((mbox)->mutex);
        AssertRC(rc);
        return ERR_MEM;
    }

    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);
    return ERR_OK;
}
Beispiel #2
0
/**
 * Try to get an entry from an mbox.
 */
u32_t sys_arch_mbox_tryfetch(sys_mbox_t *pvMbox, void **msg)
{
    int rc;
    struct sys_mbox *mbox = NULL;
    if (!pvMbox || !*pvMbox) return SYS_MBOX_EMPTY;
    mbox = (struct sys_mbox*)*pvMbox;

    rc = LWIPMutexRequest((mbox)->mutex);
    AssertRC(rc);
    if ((mbox)->head == (mbox)->tail)
    {
        /* (mbox) is empty, don't wait */
        rc = LWIPMutexRelease((mbox)->mutex);
        AssertRC(rc);
	return SYS_MBOX_EMPTY;
    }
    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);
    return 0;
}
SUPDECL(int) SUPSemEventMultiReset(PSUPDRVSESSION pSession, SUPSEMEVENTMULTI hEventMulti)
{
    int         rc;
    uint32_t    h32;
    PSUPDRVOBJ  pObj;

    /*
     * Input validation.
     */
    AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
    h32 = (uint32_t)(uintptr_t)hEventMulti;
    if (h32 != (uintptr_t)hEventMulti)
        return VERR_INVALID_HANDLE;
    pObj = (PSUPDRVOBJ)RTHandleTableLookupWithCtx(pSession->hHandleTable, h32, SUPDRV_HANDLE_CTX_EVENT_MULTI);
    if (!pObj)
        return VERR_INVALID_HANDLE;

    /*
     * Do the job.
     */
    rc = RTSemEventMultiReset((RTSEMEVENTMULTI)pObj->pvUser1);

    SUPR0ObjRelease(pObj, pSession);
    return rc;
}
Beispiel #4
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);
}
Beispiel #5
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;
}
/**
 * Suspends the thread.
 *
 * This can be called at the power off / suspend notifications to suspend the
 * PDM thread a bit early. The thread will be automatically suspend upon
 * completion of the device/driver notification cycle.
 *
 * The caller is responsible for serializing the control operations on the
 * thread. That basically means, always do these calls from the EMT.
 *
 * @returns VBox status code.
 * @param   pThread     The PDM thread.
 */
VMMR3DECL(int) PDMR3ThreadSuspend(PPDMTHREAD pThread)
{
    /*
     * Assert sanity.
     */
    AssertPtrReturn(pThread, VERR_INVALID_POINTER);
    AssertReturn(pThread->u32Version == PDMTHREAD_VERSION, VERR_INVALID_MAGIC);
    Assert(pThread->Thread != RTThreadSelf());

    /*
     * This is a noop if the thread is already suspended.
     */
    if (pThread->enmState == PDMTHREADSTATE_SUSPENDED)
        return VINF_SUCCESS;

    /*
     * Change the state to resuming and kick the thread.
     */
    int rc = RTSemEventMultiReset(pThread->Internal.s.BlockEvent);
    if (RT_SUCCESS(rc))
    {
        rc = RTThreadUserReset(pThread->Thread);
        if (RT_SUCCESS(rc))
        {
            rc = VERR_WRONG_ORDER;
            if (pdmR3AtomicCmpXchgState(pThread, PDMTHREADSTATE_SUSPENDING, PDMTHREADSTATE_RUNNING))
            {
                rc = pdmR3ThreadWakeUp(pThread);
                if (RT_SUCCESS(rc))
                {
                    /*
                     * Wait for the thread to reach the suspended state.
                     */
                    if (pThread->enmState != PDMTHREADSTATE_SUSPENDED)
                        rc = RTThreadUserWait(pThread->Thread, 60*1000);
                    if (    RT_SUCCESS(rc)
                        &&  pThread->enmState != PDMTHREADSTATE_SUSPENDED)
                        rc = VERR_PDM_THREAD_IPE_2;
                    if (RT_SUCCESS(rc))
                        return rc;
                }
            }
        }
    }

    /*
     * Something failed, initialize termination.
     */
    AssertMsgFailed(("PDMR3ThreadSuspend -> rc=%Rrc enmState=%d suspending '%s'\n",
                     rc, pThread->enmState, RTThreadGetName(pThread->Thread)));
    pdmR3ThreadBailOut(pThread);
    return rc;
}
Beispiel #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::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;
}
Beispiel #8
0
/**
 * Reset the user event.
 *
 * @returns     iprt status code.
 * @param       Thread          The thread to reset.
 */
RTDECL(int) RTThreadUserReset(RTTHREAD Thread)
{
    int     rc;
    PRTTHREADINT  pThread = rtThreadGet(Thread);
    if (pThread)
    {
        rc = RTSemEventMultiReset(pThread->EventUser);
        rtThreadRelease(pThread);
    }
    else
        rc = VERR_INVALID_HANDLE;
    return rc;
}
static void testBasics(void)
{
    RTTestISub("Basics");

    RTSEMEVENTMULTI hSem;
    RTTESTI_CHECK_RC_RETV(RTSemEventMultiCreate(&hSem), VINF_SUCCESS);

    /* The semaphore is created in a reset state, calling reset explicitly
       shouldn't make any difference. */
    testBasicsWaitTimeout(hSem, 0);
    RTTESTI_CHECK_RC_RETV(RTSemEventMultiReset(hSem), VINF_SUCCESS);
    testBasicsWaitTimeout(hSem, 1);
    if (RTTestIErrorCount())
        return;

    /* When signalling the semaphore all successive wait calls shall
       succeed, signalling it again should make no difference. */
    RTTESTI_CHECK_RC_RETV(RTSemEventMultiSignal(hSem), VINF_SUCCESS);
    testBasicsWaitSuccess(hSem, 2);
    if (RTTestIErrorCount())
        return;

    /* After resetting it we should time out again. */
    RTTESTI_CHECK_RC_RETV(RTSemEventMultiReset(hSem), VINF_SUCCESS);
    testBasicsWaitTimeout(hSem, 3);
    if (RTTestIErrorCount())
        return;

    /* The number of resets or signal calls shouldn't matter. */
    RTTESTI_CHECK_RC_RETV(RTSemEventMultiReset(hSem), VINF_SUCCESS);
    RTTESTI_CHECK_RC_RETV(RTSemEventMultiReset(hSem), VINF_SUCCESS);
    RTTESTI_CHECK_RC_RETV(RTSemEventMultiReset(hSem), VINF_SUCCESS);
    testBasicsWaitTimeout(hSem, 4);

    RTTESTI_CHECK_RC_RETV(RTSemEventMultiSignal(hSem), VINF_SUCCESS);
    RTTESTI_CHECK_RC_RETV(RTSemEventMultiSignal(hSem), VINF_SUCCESS);
    RTTESTI_CHECK_RC_RETV(RTSemEventMultiSignal(hSem), VINF_SUCCESS);
    RTTESTI_CHECK_RC_RETV(RTSemEventMultiSignal(hSem), VINF_SUCCESS);
    RTTESTI_CHECK_RC_RETV(RTSemEventMultiSignal(hSem), VINF_SUCCESS);
    testBasicsWaitSuccess(hSem, 5);

    RTTESTI_CHECK_RC_RETV(RTSemEventMultiReset(hSem), VINF_SUCCESS);
    testBasicsWaitTimeout(hSem, 6);

    /* Destroy it. */
    RTTESTI_CHECK_RC_RETV(RTSemEventMultiDestroy(hSem), VINF_SUCCESS);
    RTTESTI_CHECK_RC_RETV(RTSemEventMultiDestroy(NIL_RTSEMEVENTMULTI), VINF_SUCCESS);

    /* Whether it is reset (above), signalled or not used shouldn't matter.  */
    RTTESTI_CHECK_RC_RETV(RTSemEventMultiCreate(&hSem), VINF_SUCCESS);
    RTTESTI_CHECK_RC_RETV(RTSemEventMultiSignal(hSem), VINF_SUCCESS);
    RTTESTI_CHECK_RC_RETV(RTSemEventMultiDestroy(hSem), VINF_SUCCESS);

    RTTESTI_CHECK_RC_RETV(RTSemEventMultiCreate(&hSem), VINF_SUCCESS);
    RTTESTI_CHECK_RC_RETV(RTSemEventMultiDestroy(hSem), VINF_SUCCESS);

    RTTestISubDone();
}
/**
 * Called by the PDM thread instead of RTThreadSleep.
 *
 * The difference is that the sleep will be interrupted on state change. The
 * thread must be in the running state, otherwise it will return immediately.
 *
 * @returns VBox status code.
 * @retval  VINF_SUCCESS on success or state change.
 * @retval  VERR_INTERRUPTED on signal or APC.
 *
 * @param   pThread     The PDM thread.
 * @param   cMillies    The number of milliseconds to sleep.
 */
VMMR3DECL(int) PDMR3ThreadSleep(PPDMTHREAD pThread, RTMSINTERVAL cMillies)
{
    /*
     * Assert sanity.
     */
    AssertReturn(pThread->enmState > PDMTHREADSTATE_INVALID && pThread->enmState < PDMTHREADSTATE_TERMINATED, VERR_PDM_THREAD_IPE_2);
    AssertReturn(pThread->Thread == RTThreadSelf(), VERR_PDM_THREAD_INVALID_CALLER);

    /*
     * Reset the event semaphore, check the state and sleep.
     */
    RTSemEventMultiReset(pThread->Internal.s.SleepEvent);
    if (pThread->enmState != PDMTHREADSTATE_RUNNING)
        return VINF_SUCCESS;
    return RTSemEventMultiWaitNoResume(pThread->Internal.s.SleepEvent, cMillies);
}
Beispiel #11
0
/**
 * Initializes the sub-progress object that represents a specific operation of
 * the whole task.
 *
 * Objects initialized with this method are then combined together into the
 * single task using a Progress instance, so it doesn't require the
 * parent, initiator, description and doesn't create an ID. Note that calling
 * respective getter methods on an object initialized with this method is
 * useless. Such objects are used only to provide a separate wait semaphore and
 * store individual operation descriptions.
 *
 * @param aCancelable       Flag whether the task maybe canceled.
 * @param aOperationCount   Number of sub-operations within this task (at least 1).
 * @param aOperationDescription Description of the individual operation.
 */
HRESULT Progress::init(BOOL aCancelable,
                       ULONG aOperationCount,
                       Utf8Str aOperationDescription)
{
    LogFlowThisFunc(("aOperationDescription=\"%s\"\n", aOperationDescription.c_str()));

    /* Enclose the state transition NotReady->InInit->Ready */
    AutoInitSpan autoInitSpan(this);
    AssertReturn(autoInitSpan.isOk(), E_FAIL);

    HRESULT rc = S_OK;
    /* Guarantees subclasses call this method at the proper time */
    NOREF(autoInitSpan);

    if (FAILED(rc)) return rc;

    mCancelable = aCancelable;

    // for this variant we assume for now that all operations are weighed "1"
    // and equal total weight = operation count
    m_cOperations = aOperationCount;
    m_ulTotalOperationsWeight = aOperationCount;
    m_ulOperationsCompletedWeight = 0;
    m_ulCurrentOperation = 0;
    m_operationDescription = aOperationDescription;
    m_ulCurrentOperationWeight = 1;
    m_ulOperationPercent = 0;

    int vrc = RTSemEventMultiCreate(&mCompletedSem);
    ComAssertRCRet(vrc, E_FAIL);

    RTSemEventMultiReset(mCompletedSem);

    /* Confirm a successful initialization when it's the case */
    if (SUCCEEDED(rc))
        autoInitSpan.setSucceeded();

    return rc;
}
Beispiel #12
0
/**
 * 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);
}
Beispiel #13
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;
}
Beispiel #14
0
DECL_FORCE_INLINE(int) rtSemRWRequestWrite(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 = NIL_RTTHREAD;
    if (cMillies)
    {
        hThreadSelf = RTThreadSelfAutoAdopt();
        int rc9 = RTLockValidatorRecExclCheckOrder(&pThis->ValidatorWrite, 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 write access.
     */
    RTNATIVETHREAD hNativeSelf = pThis->CritSect.NativeThreadOwner;
    if (    !pThis->cReads
        &&  (   (   !pThis->cWrites
                 && (   !pThis->cWritesWaiting /* play fair if we can wait */
                     || !cMillies)
                )
             || pThis->hWriter == hNativeSelf
            )
       )
    {
        /*
         * Reset the reader event semaphore if necessary.
         */
        if (pThis->fNeedResetReadEvent)
        {
            pThis->fNeedResetReadEvent = false;
            rc = RTSemEventMultiReset(pThis->ReadEvent);
            AssertMsgRC(rc, ("Failed to reset readers, rwsem %p, rc=%Rrc.\n", hRWSem, rc));
        }

        pThis->cWrites++;
        pThis->hWriter = hNativeSelf;
#ifdef RTSEMRW_STRICT
        RTLockValidatorRecExclSetOwner(&pThis->ValidatorWrite, hThreadSelf, pSrcPos, pThis->cWrites == 1);
#endif
        RTCritSectLeave(&pThis->CritSect);
        return VINF_SUCCESS;
    }

    /*
     * Signal writer presence.
     */
    if (cMillies != 0)
        pThis->cWritesWaiting++;

    RTCritSectLeave(&pThis->CritSect);

    /*
     * Wait till it's ready for writing.
     */
    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 = RTLockValidatorRecExclCheckBlocking(&pThis->ValidatorWrite, hThreadSelf, pSrcPos, true,
                                                 cMillies, RTTHREADSTATE_RW_WRITE, false);
        if (RT_FAILURE(rc))
            break;
#else
        RTThreadBlocking(hThreadSelf, RTTHREADSTATE_RW_WRITE, false);
#endif
        int rcWait;
        if (fInterruptible)
            rcWait = rc = RTSemEventWaitNoResume(pThis->WriteEvent, cMillies);
        else
            rcWait = rc = RTSemEventWait(pThis->WriteEvent, cMillies);
        RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_RW_WRITE);
        if (RT_UNLIKELY(RT_FAILURE_NP(rc) && rc != VERR_TIMEOUT)) /* timeouts are handled below */
        {
            AssertMsgRC(rc, ("RTSemEventWait failed on rwsem %p, rc=%Rrc\n", hRWSem, rc));
            break;
        }

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

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

        if (!pThis->cReads && (!pThis->cWrites || pThis->hWriter == hNativeSelf))
        {
            /*
             * Reset the reader event semaphore if necessary.
             */
            if (pThis->fNeedResetReadEvent)
            {
                pThis->fNeedResetReadEvent = false;
                rc = RTSemEventMultiReset(pThis->ReadEvent);
                AssertMsgRC(rc, ("Failed to reset readers, rwsem %p, rc=%Rrc.\n", hRWSem, rc));
            }

            pThis->cWrites++;
            pThis->hWriter = hNativeSelf;
            pThis->cWritesWaiting--;
#ifdef RTSEMRW_STRICT
            RTLockValidatorRecExclSetOwner(&pThis->ValidatorWrite, hThreadSelf, pSrcPos, true);
#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;
        }
    }

    /*
     * Timeout/error case, clean up.
     */
    if (pThis->u32Magic == RTSEMRW_MAGIC)
    {
        RTCritSectEnter(&pThis->CritSect);
        /* Adjust this counter, whether we got the critsect or not. */
        pThis->cWritesWaiting--;
        RTCritSectLeave(&pThis->CritSect);
    }
    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;
}
Beispiel #16
0
/**
 * Initializes the normal progress object. With this variant, one can have
 * an arbitrary number of sub-operation which IProgress can analyze to
 * have a weighted progress computed.
 *
 * For example, say that one IProgress is supposed to track the cloning
 * of two hard disk images, which are 100 MB and 1000 MB in size, respectively,
 * and each of these hard disks should be one sub-operation of the IProgress.
 *
 * Obviously the progress would be misleading if the progress displayed 50%
 * after the smaller image was cloned and would then take much longer for
 * the second half.
 *
 * With weighted progress, one can invoke the following calls:
 *
 * 1) create progress object with cOperations = 2 and ulTotalOperationsWeight =
 *    1100 (100 MB plus 1100, but really the weights can be any ULONG); pass
 *    in ulFirstOperationWeight = 100 for the first sub-operation
 *
 * 2) Then keep calling setCurrentOperationProgress() with a percentage
 *    for the first image; the total progress will increase up to a value
 *    of 9% (100MB / 1100MB * 100%).
 *
 * 3) Then call setNextOperation with the second weight (1000 for the megabytes
 *    of the second disk).
 *
 * 4) Then keep calling setCurrentOperationProgress() with a percentage for
 *    the second image, where 100% of the operation will then yield a 100%
 *    progress of the entire task.
 *
 * Weighting is optional; you can simply assign a weight of 1 to each operation
 * and pass ulTotalOperationsWeight == cOperations to this constructor (but
 * for that variant and for backwards-compatibility a simpler constructor exists
 * in ProgressImpl.h as well).
 *
 * Even simpler, if you need no sub-operations at all, pass in cOperations =
 * ulTotalOperationsWeight = ulFirstOperationWeight = 1.
 *
 * @param aParent       Parent object (only for server-side Progress objects).
 * @param aInitiator    Initiator of the task (for server-side objects. Can be
 *                      NULL which means initiator = parent, otherwise must not
 *                      be NULL).
 * @param aDescription  Overall task description.
 * @param aCancelable   Flag whether the task maybe canceled.
 * @param cOperations   Number of operations within this task (at least 1).
 * @param ulTotalOperationsWeight Total weight of operations; must be the sum of ulFirstOperationWeight and
 *                          what is later passed with each subsequent setNextOperation() call.
 * @param bstrFirstOperationDescription Description of the first operation.
 * @param ulFirstOperationWeight Weight of first sub-operation.
 */
HRESULT Progress::init(
#if !defined(VBOX_COM_INPROC)
                       VirtualBox *aParent,
#endif
                       IUnknown *aInitiator,
                       Utf8Str aDescription,
                       BOOL aCancelable,
                       ULONG cOperations,
                       ULONG ulTotalOperationsWeight,
                       Utf8Str aFirstOperationDescription,
                       ULONG ulFirstOperationWeight)
{
    LogFlowThisFunc(("aDescription=\"%s\", cOperations=%d, ulTotalOperationsWeight=%d, aFirstOperationDescription=\"%s\", ulFirstOperationWeight=%d\n",
                     aDescription.c_str(),
                     cOperations,
                     ulTotalOperationsWeight,
                     aFirstOperationDescription.c_str(),
                     ulFirstOperationWeight));

    AssertReturn(ulTotalOperationsWeight >= 1, E_INVALIDARG);

    /* Enclose the state transition NotReady->InInit->Ready */
    AutoInitSpan autoInitSpan(this);
    AssertReturn(autoInitSpan.isOk(), E_FAIL);

    HRESULT rc = S_OK;

//    rc = Progress::init(
//#if !defined(VBOX_COM_INPROC)
//                        aParent,
//#endif
//                         aInitiator, aDescription, FALSE, aId);
// NA
#if !defined(VBOX_COM_INPROC)
    AssertReturn(aParent, E_INVALIDARG);
#else
    AssertReturn(aInitiator, E_INVALIDARG);
#endif

#if !defined(VBOX_COM_INPROC)
    /* share parent weakly */
    unconst(mParent) = aParent;
#endif

#if !defined(VBOX_COM_INPROC)
    /* assign (and therefore addref) initiator only if it is not VirtualBox
     * (to avoid cycling); otherwise mInitiator will remain null which means
     * that it is the same as the parent */
    if (aInitiator)
    {
        ComObjPtr<VirtualBox> pVirtualBox(mParent);
        if (!(pVirtualBox == aInitiator))
            unconst(mInitiator) = aInitiator;
    }
#else
    unconst(mInitiator) = aInitiator;
#endif

    unconst(mId).create();

#if !defined(VBOX_COM_INPROC)
    /* add to the global collection of progress operations (note: after
     * creating mId) */
    mParent->i_addProgress(this);
#endif

    unconst(mDescription) = aDescription;


// end of assertion


    if (FAILED(rc)) return rc;

    mCancelable = aCancelable;

    m_cOperations = cOperations;
    m_ulTotalOperationsWeight = ulTotalOperationsWeight;
    m_ulOperationsCompletedWeight = 0;
    m_ulCurrentOperation = 0;
    m_operationDescription = aFirstOperationDescription;
    m_ulCurrentOperationWeight = ulFirstOperationWeight;
    m_ulOperationPercent = 0;

    int vrc = RTSemEventMultiCreate(&mCompletedSem);
    ComAssertRCRet(vrc, E_FAIL);

    RTSemEventMultiReset(mCompletedSem);

    /* Confirm a successful initialization when it's the case */
    if (SUCCEEDED(rc))
        autoInitSpan.setSucceeded();

    return rc;
}
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;
}