/**
 * A fallback method in case something goes wrong with the normal
 * I/O manager.
 */
DECLCALLBACK(int) pdmacFileAioMgrFailsafe(RTTHREAD hThreadSelf, void *pvUser)
{
    int             rc      = VINF_SUCCESS;
    PPDMACEPFILEMGR pAioMgr = (PPDMACEPFILEMGR)pvUser;
    NOREF(hThreadSelf);

    while (   (pAioMgr->enmState == PDMACEPFILEMGRSTATE_RUNNING)
           || (pAioMgr->enmState == PDMACEPFILEMGRSTATE_SUSPENDING))
    {
        ASMAtomicWriteBool(&pAioMgr->fWaitingEventSem, true);
        if (!ASMAtomicReadBool(&pAioMgr->fWokenUp))
            rc = RTSemEventWait(pAioMgr->EventSem, pAioMgr->msBwLimitExpired);
        ASMAtomicWriteBool(&pAioMgr->fWaitingEventSem, false);
        Assert(RT_SUCCESS(rc) || rc == VERR_TIMEOUT);

        LogFlow(("Got woken up\n"));
        ASMAtomicWriteBool(&pAioMgr->fWokenUp, false);

        /* Process endpoint events first. */
        PPDMASYNCCOMPLETIONENDPOINTFILE pEndpoint = pAioMgr->pEndpointsHead;
        while (pEndpoint)
        {
            pAioMgr->msBwLimitExpired = RT_INDEFINITE_WAIT;
            rc = pdmacFileAioMgrFailsafeProcessEndpoint(pAioMgr, pEndpoint);
            AssertRC(rc);
            pEndpoint = pEndpoint->AioMgr.pEndpointNext;
        }

        /* Now check for an external blocking event. */
        if (pAioMgr->fBlockingEventPending)
        {
            switch (pAioMgr->enmBlockingEvent)
            {
                case PDMACEPFILEAIOMGRBLOCKINGEVENT_ADD_ENDPOINT:
                {
                    PPDMASYNCCOMPLETIONENDPOINTFILE pEndpointNew = pAioMgr->BlockingEventData.AddEndpoint.pEndpoint;
                    AssertMsg(VALID_PTR(pEndpointNew), ("Adding endpoint event without a endpoint to add\n"));

                    pEndpointNew->enmState = PDMASYNCCOMPLETIONENDPOINTFILESTATE_ACTIVE;

                    pEndpointNew->AioMgr.pEndpointNext = pAioMgr->pEndpointsHead;
                    pEndpointNew->AioMgr.pEndpointPrev = NULL;
                    if (pAioMgr->pEndpointsHead)
                        pAioMgr->pEndpointsHead->AioMgr.pEndpointPrev = pEndpointNew;
                    pAioMgr->pEndpointsHead = pEndpointNew;

                    pAioMgr->cEndpoints++;

                    /*
                     * Process the task list the first time. There might be pending requests
                     * if the endpoint was migrated from another endpoint.
                     */
                    rc = pdmacFileAioMgrFailsafeProcessEndpoint(pAioMgr, pEndpointNew);
                    AssertRC(rc);
                    break;
                }
                case PDMACEPFILEAIOMGRBLOCKINGEVENT_REMOVE_ENDPOINT:
                {
                    PPDMASYNCCOMPLETIONENDPOINTFILE pEndpointRemove = pAioMgr->BlockingEventData.RemoveEndpoint.pEndpoint;
                    AssertMsg(VALID_PTR(pEndpointRemove), ("Removing endpoint event without a endpoint to remove\n"));

                    pEndpointRemove->enmState = PDMASYNCCOMPLETIONENDPOINTFILESTATE_REMOVING;

                    PPDMASYNCCOMPLETIONENDPOINTFILE pPrev = pEndpointRemove->AioMgr.pEndpointPrev;
                    PPDMASYNCCOMPLETIONENDPOINTFILE pNext = pEndpointRemove->AioMgr.pEndpointNext;

                    if (pPrev)
                        pPrev->AioMgr.pEndpointNext = pNext;
                    else
                        pAioMgr->pEndpointsHead = pNext;

                    if (pNext)
                        pNext->AioMgr.pEndpointPrev = pPrev;

                    pAioMgr->cEndpoints--;
                    break;
                }
                case PDMACEPFILEAIOMGRBLOCKINGEVENT_CLOSE_ENDPOINT:
                {
                    PPDMASYNCCOMPLETIONENDPOINTFILE pEndpointClose = pAioMgr->BlockingEventData.CloseEndpoint.pEndpoint;
                    AssertMsg(VALID_PTR(pEndpointClose), ("Close endpoint event without a endpoint to Close\n"));

                    pEndpointClose->enmState = PDMASYNCCOMPLETIONENDPOINTFILESTATE_CLOSING;

                    /* Make sure all tasks finished. */
                    rc = pdmacFileAioMgrFailsafeProcessEndpoint(pAioMgr, pEndpointClose);
                    AssertRC(rc);
                    break;
                }
                case PDMACEPFILEAIOMGRBLOCKINGEVENT_SHUTDOWN:
                    pAioMgr->enmState = PDMACEPFILEMGRSTATE_SHUTDOWN;
                    break;
                case PDMACEPFILEAIOMGRBLOCKINGEVENT_SUSPEND:
                    pAioMgr->enmState = PDMACEPFILEMGRSTATE_SUSPENDING;
                    break;
                case PDMACEPFILEAIOMGRBLOCKINGEVENT_RESUME:
                    pAioMgr->enmState = PDMACEPFILEMGRSTATE_RUNNING;
                    break;
                default:
                    AssertMsgFailed(("Invalid event type %d\n", pAioMgr->enmBlockingEvent));
            }

            ASMAtomicWriteBool(&pAioMgr->fBlockingEventPending, false);
            pAioMgr->enmBlockingEvent = PDMACEPFILEAIOMGRBLOCKINGEVENT_INVALID;

            /* Release the waiting thread. */
            rc = RTSemEventSignal(pAioMgr->EventSemBlock);
            AssertRC(rc);
        }
    }

    return rc;
}
Ejemplo n.º 2
0
/**
 *  Interprets a string and assigns it to a USBFilter field.
 *
 *  (This function is also used by HostUSBDeviceFilter.)
 *
 *  @param  aFilter     The filter.
 *  @param  aIdx        The field index.
 *  @param  aStr        The input string.
 *  @param  aName       The field name for use in the error string.
 *  @param  aErrStr     Where to return the error string on failure.
 *
 *  @return COM status code.
 *  @remark The idea was to have this as a static function, but tr() doesn't wanna work without a class :-/
 */
/*static*/ HRESULT USBDeviceFilter::usbFilterFieldFromString(PUSBFILTER aFilter,
                                                             USBFILTERIDX aIdx,
                                                             const Utf8Str &aValue,
                                                             Utf8Str &aErrStr)
{
    int vrc;
//     Utf8Str str (aStr);
    if (aValue.isEmpty())
        vrc = USBFilterSetIgnore(aFilter, aIdx);
    else
    {
        const char *pcszValue = aValue.c_str();
        if (USBFilterIsNumericField(aIdx))
        {
            /* Is it a lonely number? */
            char *pszNext;
            uint64_t u64;
            vrc = RTStrToUInt64Ex(pcszValue, &pszNext, 16, &u64);
            if (RT_SUCCESS(vrc))
                pszNext = RTStrStripL (pszNext);
            if (    vrc == VINF_SUCCESS
                &&  !*pszNext)
            {
                if (u64 > 0xffff)
                {
                    // there was a bug writing out "-1" values in earlier versions, which got
                    // written as "FFFFFFFF"; make sure we don't fail on those
                    if (u64 == 0xffffffff)
                        u64 = 0xffff;
                    else
                    {
                        aErrStr = Utf8StrFmt(tr("The %s value '%s' is too big (max 0xFFFF)"), describeUSBFilterIdx(aIdx), pcszValue);
                        return E_INVALIDARG;
                    }
                }

                vrc = USBFilterSetNumExact(aFilter, aIdx, (uint16_t)u64, true /* fMustBePresent */);
            }
            else
                vrc = USBFilterSetNumExpression(aFilter, aIdx, pcszValue, true /* fMustBePresent */);
        }
        else
        {
            /* Any wildcard in the string? */
            Assert(USBFilterIsStringField(aIdx));
            if (    strchr(pcszValue, '*')
                ||  strchr(pcszValue, '?')
                /* || strchr (psz, '[') - later */
                )
                vrc = USBFilterSetStringPattern(aFilter, aIdx, pcszValue, true /* fMustBePresent */);
            else
                vrc = USBFilterSetStringExact(aFilter, aIdx, pcszValue, true /* fMustBePresent */);
        }
    }

    if (RT_FAILURE(vrc))
    {
        if (vrc == VERR_INVALID_PARAMETER)
        {
            aErrStr = Utf8StrFmt(tr("The %s filter expression '%s' is not valid"), describeUSBFilterIdx(aIdx), aValue.c_str());
            return E_INVALIDARG;
        }
        if (vrc == VERR_BUFFER_OVERFLOW)
        {
            aErrStr = Utf8StrFmt(tr("Insufficient expression space for the '%s' filter expression '%s'"), describeUSBFilterIdx(aIdx), aValue.c_str());
            return E_FAIL;
        }
        AssertRC(vrc);
        aErrStr = Utf8StrFmt(tr("Encountered unexpected status %Rrc when setting '%s' to '%s'"), vrc, describeUSBFilterIdx(aIdx), aValue.c_str());
        return E_FAIL;
    }

    return S_OK;
}
Ejemplo n.º 3
0
int GuestFile::onFileNotify(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
{
    AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
    AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);

    LogFlowThisFuncEnter();

    if (pSvcCbData->mParms < 3)
        return VERR_INVALID_PARAMETER;

    int vrc = VINF_SUCCESS;

    int idx = 1; /* Current parameter index. */
    CALLBACKDATA_FILE_NOTIFY dataCb;
    /* pSvcCb->mpaParms[0] always contains the context ID. */
    pSvcCbData->mpaParms[idx++].getUInt32(&dataCb.uType);
    pSvcCbData->mpaParms[idx++].getUInt32(&dataCb.rc);

    FileStatus_T fileStatus = FileStatus_Undefined;
    int guestRc = (int)dataCb.rc; /* uint32_t vs. int. */

    LogFlowFunc(("uType=%RU32, guestRc=%Rrc\n",
                 dataCb.uType, guestRc));

    if (RT_FAILURE(guestRc))
    {
        int rc2 = setFileStatus(FileStatus_Error, guestRc);
        AssertRC(rc2);

        rc2 = signalWaitEventInternal(pCbCtx,
                                      guestRc, NULL /* pPayload */);
        AssertRC(rc2);

        return VINF_SUCCESS; /* Report to the guest. */
    }

    switch (dataCb.uType)
    {
        case GUEST_FILE_NOTIFYTYPE_ERROR:
        {
            int rc2 = setFileStatus(FileStatus_Error, guestRc);
            AssertRC(rc2);

            break;
        }

        case GUEST_FILE_NOTIFYTYPE_OPEN:
        {
            if (pSvcCbData->mParms == 4)
            {
                pSvcCbData->mpaParms[idx++].getUInt32(&dataCb.u.open.uHandle);

                {
                    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
                    AssertMsg(mData.mID == VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pCbCtx->uContextID),
                              ("File ID %RU32 does not match context ID %RU32\n", mData.mID,
                              VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pCbCtx->uContextID)));

                    /* Set the initial offset. On the guest the whole opening operation
                     * would fail if an initial seek isn't possible. */
                    mData.mOffCurrent = mData.mOpenInfo.mInitialOffset;
                }

                /* Set the process status. */
                int rc2 = setFileStatus(FileStatus_Open, guestRc);
                AssertRC(rc2);
            }
            else
                vrc = VERR_NOT_SUPPORTED;

            break;
        }

        case GUEST_FILE_NOTIFYTYPE_CLOSE:
        {
            int rc2 = setFileStatus(FileStatus_Closed, guestRc);
            AssertRC(rc2);

            break;
        }

        case GUEST_FILE_NOTIFYTYPE_READ:
        {
            if (pSvcCbData->mParms == 4)
            {
                pSvcCbData->mpaParms[idx++].getPointer(&dataCb.u.read.pvData,
                                                       &dataCb.u.read.cbData);
                uint32_t cbRead = dataCb.u.read.cbData;

                AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);

                mData.mOffCurrent += cbRead;

                alock.release();

                com::SafeArray<BYTE> data((size_t)cbRead);
                data.initFrom((BYTE*)dataCb.u.read.pvData, cbRead);

                fireGuestFileReadEvent(mEventSource, mSession, this, mData.mOffCurrent,
                                       cbRead, ComSafeArrayAsInParam(data));
            }
            else
                vrc = VERR_NOT_SUPPORTED;
            break;
        }

        case GUEST_FILE_NOTIFYTYPE_WRITE:
        {
            if (pSvcCbData->mParms == 4)
            {
                pSvcCbData->mpaParms[idx++].getUInt32(&dataCb.u.write.cbWritten);

                AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);

                mData.mOffCurrent += dataCb.u.write.cbWritten;
                uint64_t uOffCurrent = mData.mOffCurrent;

                alock.release();

                fireGuestFileWriteEvent(mEventSource, mSession, this, uOffCurrent,
                                        dataCb.u.write.cbWritten);
            }
            else
                vrc = VERR_NOT_SUPPORTED;
            break;
        }

        case GUEST_FILE_NOTIFYTYPE_SEEK:
        {
            if (pSvcCbData->mParms == 4)
            {
                pSvcCbData->mpaParms[idx++].getUInt64(&dataCb.u.seek.uOffActual);

                AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);

                mData.mOffCurrent = dataCb.u.seek.uOffActual;

                alock.release();

                fireGuestFileOffsetChangedEvent(mEventSource, mSession, this,
                                                dataCb.u.seek.uOffActual, 0 /* Processed */);
            }
            else
                vrc = VERR_NOT_SUPPORTED;
            break;
        }

        case GUEST_FILE_NOTIFYTYPE_TELL:
        {
            if (pSvcCbData->mParms == 4)
            {
                pSvcCbData->mpaParms[idx++].getUInt64(&dataCb.u.tell.uOffActual);

                AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);

                mData.mOffCurrent = dataCb.u.tell.uOffActual;

                alock.release();

                fireGuestFileOffsetChangedEvent(mEventSource, mSession, this,
                                                dataCb.u.tell.uOffActual, 0 /* Processed */);
            }
            else
                vrc = VERR_NOT_SUPPORTED;
            break;
        }

        default:
            vrc = VERR_NOT_SUPPORTED;
            break;
    }

    if (RT_SUCCESS(vrc))
    {
        GuestWaitEventPayload payload(dataCb.uType, &dataCb, sizeof(dataCb));
        int rc2 = signalWaitEventInternal(pCbCtx, guestRc, &payload);
        AssertRC(rc2);
    }

    LogFlowThisFunc(("uType=%RU32, guestRc=%Rrc\n",
                     dataCb.uType, dataCb.rc));

    LogFlowFuncLeaveRC(vrc);
    return vrc;
}
Ejemplo n.º 4
0
/**
 * Initialize the network shaper.
 *
 * @returns VBox status code
 * @param   pVM Pointer to the VM.
 */
int pdmR3NetShaperInit(PVM pVM)
{
    LogFlowFunc((": pVM=%p\n", pVM));

    VM_ASSERT_EMT(pVM);

    PPDMNETSHAPER pNetShaper = NULL;

    int rc = MMR3HeapAllocZEx(pVM, MM_TAG_PDM_NET_SHAPER,
                              sizeof(PDMNETSHAPER),
                              (void **)&pNetShaper);
    if (RT_SUCCESS(rc))
    {
        PCFGMNODE pCfgRoot      = CFGMR3GetRoot(pVM);
        PCFGMNODE pCfgNetShaper = CFGMR3GetChild(CFGMR3GetChild(pCfgRoot, "PDM"), "NetworkShaper");

        pNetShaper->pVM = pVM;
        rc = RTCritSectInit(&pNetShaper->cs);
        if (RT_SUCCESS(rc))
        {
            /* Create all bandwidth groups. */
            PCFGMNODE pCfgBwGrp = CFGMR3GetChild(pCfgNetShaper, "BwGroups");

            if (pCfgBwGrp)
            {
                for (PCFGMNODE pCur = CFGMR3GetFirstChild(pCfgBwGrp); pCur; pCur = CFGMR3GetNextChild(pCur))
                {
                    uint64_t cbMax;
                    size_t cchName = CFGMR3GetNameLen(pCur) + 1;
                    char *pszBwGrpId = (char *)RTMemAllocZ(cchName);

                    if (!pszBwGrpId)
                    {
                        rc = VERR_NO_MEMORY;
                        break;
                    }

                    rc = CFGMR3GetName(pCur, pszBwGrpId, cchName);
                    AssertRC(rc);

                    if (RT_SUCCESS(rc))
                        rc = CFGMR3QueryU64(pCur, "Max", &cbMax);
                    if (RT_SUCCESS(rc))
                        rc = pdmNsBwGroupCreate(pNetShaper, pszBwGrpId, cbMax);

                    RTMemFree(pszBwGrpId);

                    if (RT_FAILURE(rc))
                        break;
                }
            }

            if (RT_SUCCESS(rc))
            {
                PUVM pUVM = pVM->pUVM;
                AssertMsg(!pUVM->pdm.s.pNetShaper,
                          ("Network shaper was already initialized\n"));

                char szDesc[256];
                static unsigned iThread;

                RTStrPrintf(szDesc, sizeof(szDesc), "PDMNSTXThread-%d", ++iThread);
                rc = PDMR3ThreadCreate(pVM, &pNetShaper->hTxThread, pNetShaper,
                                       pdmR3NsTxThread, pdmR3NsTxWakeUp, 0,
                                       RTTHREADTYPE_IO, szDesc);
                if (RT_SUCCESS(rc))
                {
                    pUVM->pdm.s.pNetShaper = pNetShaper;
                    return VINF_SUCCESS;
                }
            }

            RTCritSectDelete(&pNetShaper->cs);
        }
        MMR3HeapFree(pNetShaper);
    }

    LogFlowFunc((": pVM=%p rc=%Rrc\n", pVM, rc));
    return rc;
}
Ejemplo n.º 5
0
DECLINLINE(int) vboxPciVmLock(PVBOXRAWPCIDRVVM pThis)
{
    int rc = RTSemFastMutexRequest(pThis->hFastMtx);
    AssertRC(rc);
    return rc;
}
Ejemplo n.º 6
0
/**
 * @interface_method_impl{PDMINVRAMCONNECTOR,pfnVarStoreSeqPut}
 */
DECLCALLBACK(int) drvNvram_VarStoreSeqPut(PPDMINVRAMCONNECTOR pInterface, int idxVariable,
        PCRTUUID pVendorUuid, const char *pszName, size_t cchName,
        uint32_t fAttributes, uint8_t const *pbValue, size_t cbValue)
{
    PNVRAM pThis = RT_FROM_MEMBER(pInterface, NVRAM, INvramConnector);
    int    rc    = VINF_SUCCESS;

    if (pThis->fPermanentSave && pThis->pNvram)
    {
        char    szExtraName[256];
        size_t  offValueNm = RTStrPrintf(szExtraName, sizeof(szExtraName) - 16,
                                         NVRAM_CFGM_OVERLAY_PATH "/%04u/", idxVariable);

        char    szUuid[RTUUID_STR_LENGTH];
        int rc2 = RTUuidToStr(pVendorUuid, szUuid, sizeof(szUuid));
        AssertRC(rc2);

        char    szAttribs[32];
        if (fAttributes != NVRAM_DEFAULT_ATTRIB)
            RTStrPrintf(szAttribs, sizeof(szAttribs), "%#x", fAttributes);
        else
            szAttribs[0] = '\0';

        char   *pszValue = drvNvram_binaryToCfgmString(pbValue, cbValue);
        if (pszValue)
        {
            const char *apszTodo[] =
            {
                "Name",     pszName,
                "Uuid",     szUuid,
                "Value",    pszValue,
                "Attribs",  szAttribs,
            };
            for (unsigned i = 0; i < RT_ELEMENTS(apszTodo); i += 2)
            {
                if (!apszTodo[i + 1][0])
                    continue;

                Assert(strlen(apszTodo[i]) < 16);
                strcpy(szExtraName + offValueNm, apszTodo[i]);
                try
                {
                    HRESULT hrc = pThis->pNvram->getParent()->i_machine()->SetExtraData(Bstr(szExtraName).raw(),
                                  Bstr(apszTodo[i + 1]).raw());
                    if (FAILED(hrc))
                    {
                        LogRel(("drvNvram_deleteVar: SetExtraData(%s,%s) returned %Rhrc\n", szExtraName, apszTodo[i + 1], hrc));
                        rc = Global::vboxStatusCodeFromCOM(hrc);
                    }
                }
                catch (...)
                {
                    LogRel(("drvNvram_deleteVar: SetExtraData(%s,%s) threw exception\n", szExtraName, apszTodo[i + 1]));
                    rc = VERR_UNEXPECTED_EXCEPTION;
                }
            }
        }
        else
            rc = VERR_NO_MEMORY;
        RTMemFree(pszValue);
    }

    NOREF(cchName);
    LogFlowFuncLeaveRC(rc);
    return rc;
}
Ejemplo n.º 7
0
int main(int argc, char **argv)
{
    RTEXITCODE rcExit;

    /*
     * Init globals and such.
     */
    int rc = RTR3InitExe(argc, &argv, 0);
    if (RT_FAILURE(rc))
        return RTMsgInitFailure(rc);
    g_pszProgName = RTPathFilename(argv[0]);
#ifdef DEBUG
    rc = RTCritSectInit(&g_csLog);
    AssertRC(rc);
#endif

#ifdef VBOXSERVICE_TOOLBOX
    /*
     * Run toolbox code before all other stuff since these things are simpler
     * shell/file/text utility like programs that just happens to be inside
     * VBoxService and shouldn't be subject to /dev/vboxguest, pid-files and
     * global mutex restrictions.
     */
    if (VBoxServiceToolboxMain(argc, argv, &rcExit))
        return rcExit;
#endif

    /*
     * Connect to the kernel part before daemonizing so we can fail and
     * complain if there is some kind of problem.  We need to initialize the
     * guest lib *before* we do the pre-init just in case one of services needs
     * do to some initial stuff with it.
     */
    VBoxServiceVerbose(2, "Calling VbgR3Init()\n");
    rc = VbglR3Init();
    if (RT_FAILURE(rc))
    {
        if (rc == VERR_ACCESS_DENIED)
            return RTMsgErrorExit(RTEXITCODE_FAILURE, "Insufficient privileges to start %s! Please start with Administrator/root privileges!\n",
                                  g_pszProgName);
        return RTMsgErrorExit(RTEXITCODE_FAILURE, "VbglR3Init failed with rc=%Rrc\n", rc);
    }

#ifdef RT_OS_WINDOWS
    /*
     * Check if we're the specially spawned VBoxService.exe process that
     * handles page fusion.  This saves an extra executable.
     */
    if (    argc == 2
            &&  !strcmp(argv[1], "--pagefusionfork"))
        return VBoxServicePageSharingInitFork();
#endif

    char szLogFile[RTPATH_MAX + 128] = "";

    /*
     * Parse the arguments.
     *
     * Note! This code predates RTGetOpt, thus the manual parsing.
     */
    bool fDaemonize = true;
    bool fDaemonized = false;
    for (int i = 1; i < argc; i++)
    {
        const char *psz = argv[i];
        if (*psz != '-')
            return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Unknown argument '%s'\n", psz);
        psz++;

        /* translate long argument to short */
        if (*psz == '-')
        {
            psz++;
            size_t cch = strlen(psz);
#define MATCHES(strconst)       (   cch == sizeof(strconst) - 1 \
                                 && !memcmp(psz, strconst, sizeof(strconst) - 1) )
            if (MATCHES("foreground"))
                psz = "f";
            else if (MATCHES("verbose"))
                psz = "v";
            else if (MATCHES("version"))
                psz = "V";
            else if (MATCHES("help"))
                psz = "h";
            else if (MATCHES("interval"))
                psz = "i";
#ifdef RT_OS_WINDOWS
            else if (MATCHES("register"))
                psz = "r";
            else if (MATCHES("unregister"))
                psz = "u";
#endif
            else if (MATCHES("logfile"))
                psz = "l";
            else if (MATCHES("daemonized"))
            {
                fDaemonized = true;
                continue;
            }
            else
            {
                bool fFound = false;

                if (cch > sizeof("enable-") && !memcmp(psz, "enable-", sizeof("enable-") - 1))
                    for (unsigned j = 0; !fFound && j < RT_ELEMENTS(g_aServices); j++)
                        if ((fFound = !RTStrICmp(psz + sizeof("enable-") - 1, g_aServices[j].pDesc->pszName)))
                            g_aServices[j].fEnabled = true;

                if (cch > sizeof("disable-") && !memcmp(psz, "disable-", sizeof("disable-") - 1))
                    for (unsigned j = 0; !fFound && j < RT_ELEMENTS(g_aServices); j++)
                        if ((fFound = !RTStrICmp(psz + sizeof("disable-") - 1, g_aServices[j].pDesc->pszName)))
                            g_aServices[j].fEnabled = false;

                if (cch > sizeof("only-") && !memcmp(psz, "only-", sizeof("only-") - 1))
                    for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
                    {
                        g_aServices[j].fEnabled = !RTStrICmp(psz + sizeof("only-") - 1, g_aServices[j].pDesc->pszName);
                        if (g_aServices[j].fEnabled)
                            fFound = true;
                    }

                if (!fFound)
                {
                    rcExit = vboxServiceLazyPreInit();
                    if (rcExit != RTEXITCODE_SUCCESS)
                        return rcExit;
                    for (unsigned j = 0; !fFound && j < RT_ELEMENTS(g_aServices); j++)
                    {
                        rc = g_aServices[j].pDesc->pfnOption(NULL, argc, argv, &i);
                        fFound = rc == VINF_SUCCESS;
                        if (fFound)
                            break;
                        if (rc != -1)
                            return rc;
                    }
                }
                if (!fFound)
                    return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Unknown option '%s'\n", argv[i]);
                continue;
            }
#undef MATCHES
        }

        /* handle the string of short options. */
        do
        {
            switch (*psz)
            {
            case 'i':
                rc = VBoxServiceArgUInt32(argc, argv, psz + 1, &i,
                                          &g_DefaultInterval, 1, (UINT32_MAX / 1000) - 1);
                if (rc)
                    return rc;
                psz = NULL;
                break;

            case 'f':
                fDaemonize = false;
                break;

            case 'v':
                g_cVerbosity++;
                break;

            case 'V':
                RTPrintf("%sr%s\n", RTBldCfgVersion(), RTBldCfgRevisionStr());
                return RTEXITCODE_SUCCESS;

            case 'h':
            case '?':
                return vboxServiceUsage();

#ifdef RT_OS_WINDOWS
            case 'r':
                return VBoxServiceWinInstall();

            case 'u':
                return VBoxServiceWinUninstall();
#endif

            case 'l':
            {
                rc = VBoxServiceArgString(argc, argv, psz + 1, &i,
                                          szLogFile, sizeof(szLogFile));
                if (rc)
                    return rc;
                psz = NULL;
                break;
            }

            default:
            {
                rcExit = vboxServiceLazyPreInit();
                if (rcExit != RTEXITCODE_SUCCESS)
                    return rcExit;

                bool fFound = false;
                for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
                {
                    rc = g_aServices[j].pDesc->pfnOption(&psz, argc, argv, &i);
                    fFound = rc == VINF_SUCCESS;
                    if (fFound)
                        break;
                    if (rc != -1)
                        return rc;
                }
                if (!fFound)
                    return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Unknown option '%c' (%s)\n", *psz, argv[i]);
                break;
            }
            }
        } while (psz && *++psz);
    }

    /* Check that at least one service is enabled. */
    if (vboxServiceCountEnabledServices() == 0)
        return RTMsgErrorExit(RTEXITCODE_SYNTAX, "At least one service must be enabled\n");

    rc = VBoxServiceLogCreate(strlen(szLogFile) ? szLogFile : NULL);
    if (RT_FAILURE(rc))
        return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to create release log (%s, %Rrc)",
                              strlen(szLogFile) ? szLogFile : "<None>", rc);

    /* Call pre-init if we didn't do it already. */
    rcExit = vboxServiceLazyPreInit();
    if (rcExit != RTEXITCODE_SUCCESS)
        return rcExit;

#ifdef RT_OS_WINDOWS
    /*
     * Make sure only one instance of VBoxService runs at a time.  Create a
     * global mutex for that.
     *
     * Note! The \\Global\ namespace was introduced with Win2K, thus the
     *       version check.
     * Note! If the mutex exists CreateMutex will open it and set last error to
     *       ERROR_ALREADY_EXISTS.
     */
    OSVERSIONINFOEX OSInfoEx;
    RT_ZERO(OSInfoEx);
    OSInfoEx.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);

    SetLastError(NO_ERROR);
    HANDLE hMutexAppRunning;
    if (    GetVersionEx((LPOSVERSIONINFO)&OSInfoEx)
            &&  OSInfoEx.dwPlatformId == VER_PLATFORM_WIN32_NT
            &&  OSInfoEx.dwMajorVersion >= 5 /* NT 5.0 a.k.a W2K */)
        hMutexAppRunning = CreateMutex(NULL, FALSE, "Global\\" VBOXSERVICE_NAME);
    else
        hMutexAppRunning = CreateMutex(NULL, FALSE, VBOXSERVICE_NAME);
    if (hMutexAppRunning == NULL)
    {
        DWORD dwErr = GetLastError();
        if (   dwErr == ERROR_ALREADY_EXISTS
                || dwErr == ERROR_ACCESS_DENIED)
        {
            VBoxServiceError("%s is already running! Terminating.", g_pszProgName);
            return RTEXITCODE_FAILURE;
        }

        VBoxServiceError("CreateMutex failed with last error %u! Terminating", GetLastError());
        return RTEXITCODE_FAILURE;
    }

#else  /* !RT_OS_WINDOWS */
    /** @todo Add PID file creation here? */
#endif /* !RT_OS_WINDOWS */

    VBoxServiceVerbose(0, "%s r%s started. Verbose level = %d\n",
                       RTBldCfgVersion(), RTBldCfgRevisionStr(), g_cVerbosity);

    /*
     * Daemonize if requested.
     */
    if (fDaemonize && !fDaemonized)
    {
#ifdef RT_OS_WINDOWS
        VBoxServiceVerbose(2, "Starting service dispatcher ...\n");
        rcExit = VBoxServiceWinEnterCtrlDispatcher();
#else
        VBoxServiceVerbose(1, "Daemonizing...\n");
        rc = VbglR3Daemonize(false /* fNoChDir */, false /* fNoClose */);
        if (RT_FAILURE(rc))
            return VBoxServiceError("Daemon failed: %Rrc\n", rc);
        /* in-child */
#endif
    }
#ifdef RT_OS_WINDOWS
    else
#endif
    {
        /*
         * Windows: We're running the service as a console application now. Start the
         *          services, enter the main thread's run loop and stop them again
         *          when it returns.
         *
         * POSIX:   This is used for both daemons and console runs. Start all services
         *          and return immediately.
         */
#ifdef RT_OS_WINDOWS
# ifndef RT_OS_NT4
        /* Install console control handler. */
        if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE)VBoxServiceConsoleControlHandler, TRUE /* Add handler */))
        {
            VBoxServiceError("Unable to add console control handler, error=%ld\n", GetLastError());
            /* Just skip this error, not critical. */
        }
# endif /* !RT_OS_NT4 */
#endif /* RT_OS_WINDOWS */
        rc = VBoxServiceStartServices();
        rcExit = RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
        if (RT_SUCCESS(rc))
            VBoxServiceMainWait();
#ifdef RT_OS_WINDOWS
# ifndef RT_OS_NT4
        /* Uninstall console control handler. */
        if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE)NULL, FALSE /* Remove handler */))
        {
            VBoxServiceError("Unable to remove console control handler, error=%ld\n", GetLastError());
            /* Just skip this error, not critical. */
        }
# endif /* !RT_OS_NT4 */
#else /* !RT_OS_WINDOWS */
        /* On Windows - since we're running as a console application - we already stopped all services
         * through the console control handler. So only do the stopping of services here on other platforms
         * where the break/shutdown/whatever signal was just received. */
        VBoxServiceStopServices();
#endif /* RT_OS_WINDOWS */
    }
    VBoxServiceReportStatus(VBoxGuestFacilityStatus_Terminated);

#ifdef RT_OS_WINDOWS
    /*
     * Cleanup mutex.
     */
    CloseHandle(hMutexAppRunning);
#endif

    VBoxServiceVerbose(0, "Ended.\n");

#ifdef DEBUG
    RTCritSectDelete(&g_csLog);
    //RTMemTrackerDumpAllToStdOut();
#endif

    VBoxServiceLogDestroy();

    return rcExit;
}
static DWORD WINAPI vboxServiceWinCtrlHandler(DWORD dwControl, DWORD dwEventType, LPVOID lpEventData, LPVOID lpContext)
#endif
{
    DWORD rcRet = NO_ERROR;

#ifdef TARGET_NT4
    VBoxServiceVerbose(2, "Control handler: Control=%#x\n", dwControl);
#else
    VBoxServiceVerbose(2, "Control handler: Control=%#x, EventType=%#x\n", dwControl, dwEventType);
#endif

    switch (dwControl)
    {
        case SERVICE_CONTROL_INTERROGATE:
            vboxServiceWinSetStatus(g_dwWinServiceLastStatus, 0);
            break;

        case SERVICE_CONTROL_STOP:
        case SERVICE_CONTROL_SHUTDOWN:
        {
            vboxServiceWinSetStatus(SERVICE_STOP_PENDING, 0);

            int rc2 = VBoxServiceStopServices();
            if (RT_FAILURE(rc2))
                rcRet = ERROR_GEN_FAILURE;
            else
            {
                rc2 = VBoxServiceReportStatus(VBoxGuestFacilityStatus_Terminated);
                AssertRC(rc2);
            }

            vboxServiceWinSetStatus(SERVICE_STOPPED, 0);
            break;
        }

# ifndef TARGET_NT4
        case SERVICE_CONTROL_SESSIONCHANGE: /* Only Windows 2000 and up. */
        {
            AssertPtr(lpEventData);
            PWTSSESSION_NOTIFICATION pNotify = (PWTSSESSION_NOTIFICATION)lpEventData;
            Assert(pNotify->cbSize == sizeof(WTSSESSION_NOTIFICATION));

            VBoxServiceVerbose(1, "Control handler: %s (Session=%ld, Event=%#x)\n",
                               vboxServiceWTSStateToString(dwEventType),
                               pNotify->dwSessionId, dwEventType);

            /* Handle all events, regardless of dwEventType. */
            int rc2 = VBoxServiceVMInfoSignal();
            AssertRC(rc2);
            break;
        }
# endif /* !TARGET_NT4 */

        default:
            VBoxServiceVerbose(1, "Control handler: Function not implemented: %#x\n", dwControl);
            rcRet = ERROR_CALL_NOT_IMPLEMENTED;
            break;
    }

#ifndef TARGET_NT4
    return rcRet;
#endif
}
VBoxDbgConsole::VBoxDbgConsole(VBoxDbgGui *a_pDbgGui, QWidget *a_pParent/* = NULL*/, IVirtualBox *a_pVirtualBox/* = NULL */)
    : VBoxDbgBaseWindow(a_pDbgGui, a_pParent, "Console"), m_pOutput(NULL), m_pInput(NULL), m_fInputRestoreFocus(false),
    m_pszInputBuf(NULL), m_cbInputBuf(0), m_cbInputBufAlloc(0),
    m_pszOutputBuf(NULL), m_cbOutputBuf(0), m_cbOutputBufAlloc(0),
    m_pTimer(NULL), m_fUpdatePending(false), m_Thread(NIL_RTTHREAD), m_EventSem(NIL_RTSEMEVENT),
    m_fTerminate(false), m_fThreadTerminated(false)
{
    /*
     * Create the output text box.
     */
    m_pOutput = new VBoxDbgConsoleOutput(this, a_pVirtualBox);

    /* try figure a suitable size */
    QLabel *pLabel = new QLabel(      "11111111111111111111111111111111111111111111111111111111111111111111111111111112222222222", this);
    pLabel->setFont(m_pOutput->font());
    QSize Size = pLabel->sizeHint();
    delete pLabel;
    Size.setWidth((int)(Size.width() * 1.10));
    Size.setHeight(Size.width() / 2);
    resize(Size);

    /*
     * Create the input combo box (with a label).
     */
    QHBoxLayout *pLayout = new QHBoxLayout();
    //pLayout->setSizeConstraint(QLayout::SetMaximumSize);

    pLabel = new QLabel(" Command ");
    pLayout->addWidget(pLabel);
    pLabel->setMaximumSize(pLabel->sizeHint());
    pLabel->setAlignment(Qt::AlignCenter);

    m_pInput = new VBoxDbgConsoleInput(NULL);
    pLayout->addWidget(m_pInput);
    m_pInput->setDuplicatesEnabled(false);
    connect(m_pInput, SIGNAL(commandSubmitted(const QString &)), this, SLOT(commandSubmitted(const QString &)));

# if 0//def Q_WS_MAC
    pLabel = new QLabel("  ");
    pLayout->addWidget(pLabel);
    pLabel->setMaximumSize(20, m_pInput->sizeHint().height() + 6);
    pLabel->setMinimumSize(20, m_pInput->sizeHint().height() + 6);
# endif

    QWidget *pHBox = new QWidget(this);
    pHBox->setLayout(pLayout);

    m_pInput->setEnabled(false);    /* (we'll get a ready notification) */


    /*
     * Vertical layout box on the whole widget.
     */
    QVBoxLayout *pVLayout = new QVBoxLayout();
    pVLayout->setContentsMargins(0, 0, 0, 0);
    pVLayout->setSpacing(5);
    pVLayout->addWidget(m_pOutput);
    pVLayout->addWidget(pHBox);
    setLayout(pVLayout);

    /*
     * The tab order is from input to output, not the other way around as it is by default.
     */
    setTabOrder(m_pInput, m_pOutput);
    m_fInputRestoreFocus = true; /* hack */

    /*
     * Setup the timer.
     */
    m_pTimer = new QTimer(this);
    connect(m_pTimer, SIGNAL(timeout()), SLOT(updateOutput()));

    /*
     * Init the backend structure.
     */
    m_Back.Core.pfnInput   = backInput;
    m_Back.Core.pfnRead    = backRead;
    m_Back.Core.pfnWrite   = backWrite;
    m_Back.Core.pfnSetReady = backSetReady;
    m_Back.pSelf = this;

    /*
     * Create the critical section, the event semaphore and the debug console thread.
     */
    int rc = RTCritSectInit(&m_Lock);
    AssertRC(rc);

    rc = RTSemEventCreate(&m_EventSem);
    AssertRC(rc);

    rc = RTThreadCreate(&m_Thread, backThread, this, 0, RTTHREADTYPE_DEBUGGER, RTTHREADFLAGS_WAITABLE, "VBoxDbgC");
    AssertRC(rc);
    if (RT_FAILURE(rc))
        m_Thread = NIL_RTTHREAD;

    /*
     * Shortcuts.
     */
    m_pFocusToInput = new QAction("", this);
    m_pFocusToInput->setShortcut(QKeySequence("Ctrl+L"));
    addAction(m_pFocusToInput);
    connect(m_pFocusToInput, SIGNAL(triggered(bool)), this, SLOT(actFocusToInput()));

    m_pFocusToOutput = new QAction("", this);
    m_pFocusToOutput->setShortcut(QKeySequence("Ctrl+O"));
    addAction(m_pFocusToOutput);
    connect(m_pFocusToOutput, SIGNAL(triggered(bool)), this, SLOT(actFocusToOutput()));

    addAction(m_pOutput->m_pBlackOnWhiteAction);
    addAction(m_pOutput->m_pGreenOnBlackAction);
    addAction(m_pOutput->m_pCourierFontAction);
    addAction(m_pOutput->m_pMonospaceFontAction);
}
Ejemplo n.º 10
0
/**
 * Sets up a test file creating the I/O thread.
 *
 * @returns VBox status code.
 * @param   pVM          Pointer to the shared VM instance structure.
 * @param   pTestFile    Pointer to the uninitialized test file structure.
 * @param   iTestId      Unique test id.
 */
static int tstPDMACStressTestFileOpen(PVM pVM, PPDMACTESTFILE pTestFile, unsigned iTestId)
{
    int rc = VERR_NO_MEMORY;

    /* Size is a multiple of 512 */
    pTestFile->cbFileMax     = RTRandU64Ex(FILE_SIZE_MIN, FILE_SIZE_MAX) & ~(511UL);
    pTestFile->cbFileCurr    = 0;
    pTestFile->cbFileSegment = RTRandU32Ex(SEGMENT_SIZE_MIN, RT_MIN(pTestFile->cbFileMax, SEGMENT_SIZE_MAX)) & ~((size_t)511);

    Assert(pTestFile->cbFileMax >= pTestFile->cbFileSegment);

    /* Set up the segments array. */
    pTestFile->cSegments  = pTestFile->cbFileMax / pTestFile->cbFileSegment;
    pTestFile->cSegments += ((pTestFile->cbFileMax % pTestFile->cbFileSegment) > 0) ? 1 : 0;

    pTestFile->paSegs = (PPDMACTESTFILESEG)RTMemAllocZ(pTestFile->cSegments * sizeof(PDMACTESTFILESEG));
    if (pTestFile->paSegs)
    {
        /* Init the segments */
        for (unsigned i = 0; i < pTestFile->cSegments; i++)
        {
            PPDMACTESTFILESEG pSeg = &pTestFile->paSegs[i];

            pSeg->off       = (RTFOFF)i * pTestFile->cbFileSegment;
            pSeg->cbSegment = pTestFile->cbFileSegment;

            /* Let the buffer point to a random position in the test pattern. */
            uint32_t offTestPattern = RTRandU64Ex(0, g_cbTestPattern - pSeg->cbSegment);

            pSeg->pbData = g_pbTestPattern + offTestPattern;
        }

        /* Init task array. */
        pTestFile->cTasksActiveMax = RTRandU32Ex(1, TASK_ACTIVE_MAX);
        pTestFile->paTasks         = (PPDMACTESTFILETASK)RTMemAllocZ(pTestFile->cTasksActiveMax * sizeof(PDMACTESTFILETASK));
        if (pTestFile->paTasks)
        {
            /* Create the template */
            char szDesc[256];

            RTStrPrintf(szDesc, sizeof(szDesc), "Template-%d", iTestId);
            rc = PDMR3AsyncCompletionTemplateCreateInternal(pVM, &pTestFile->pTemplate, tstPDMACStressTestFileTaskCompleted, pTestFile, szDesc);
            if (RT_SUCCESS(rc))
            {
                /* Open the endpoint now. Because async completion endpoints cannot create files we have to do it before. */
                char szFile[RTPATH_MAX];

                RTStrPrintf(szFile, sizeof(szFile), "tstPDMAsyncCompletionStress-%d.tmp", iTestId);

                RTFILE FileTmp;
                rc = RTFileOpen(&FileTmp, szFile, RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_NONE);
                if (RT_SUCCESS(rc))
                {
                    RTFileClose(FileTmp);

                    rc = PDMR3AsyncCompletionEpCreateForFile(&pTestFile->hEndpoint, szFile, 0, pTestFile->pTemplate);
                    if (RT_SUCCESS(rc))
                    {
                        char szThreadDesc[256];

                        pTestFile->fRunning = true;

                        /* Create the thread creating the I/O for the given file. */
                        RTStrPrintf(szThreadDesc, sizeof(szThreadDesc), "PDMACThread-%d", iTestId);
                        rc = PDMR3ThreadCreate(pVM, &pTestFile->hThread, pTestFile, tstPDMACTestFileThread,
                                               NULL, 0, RTTHREADTYPE_IO, szThreadDesc);
                        if (RT_SUCCESS(rc))
                        {
                            rc = PDMR3ThreadResume(pTestFile->hThread);
                            AssertRC(rc);

                            RTPrintf(TESTCASE ": Created test file %s cbFileMax=%llu cbFileSegment=%u cSegments=%u cTasksActiveMax=%u\n",
                                     szFile, pTestFile->cbFileMax, pTestFile->cbFileSegment, pTestFile->cSegments, pTestFile->cTasksActiveMax);
                            return VINF_SUCCESS;
                        }

                        PDMR3AsyncCompletionEpClose(pTestFile->hEndpoint);
                    }

                    RTFileDelete(szFile);
                }

                PDMR3AsyncCompletionTemplateDestroy(pTestFile->pTemplate);
            }

            RTMemFree(pTestFile->paTasks);
        }
        else
            rc = VERR_NO_MEMORY;

        RTMemFree(pTestFile->paSegs);
    }
    else
        rc = VERR_NO_MEMORY;

    RTPrintf(TESTCASE ": Opening test file with id %d failed rc=%Rrc\n", iTestId, rc);

    return rc;
}
Ejemplo n.º 11
0
static uint32_t parallel_ioport_read(void *opaque, uint32_t addr, int *pRC)
{
    ParallelState *s = (ParallelState *)opaque;
    uint32_t ret = ~0U;

    *pRC = VINF_SUCCESS;

    addr &= 7;
    switch(addr) {
    default:
    case 0:
        if (!(s->reg_control & LPT_CONTROL_ENABLE_BIDIRECT))
            ret = s->reg_data;
        else
        {
#ifndef IN_RING3
            *pRC = VINF_IOM_HC_IOPORT_READ;
#else
            if (RT_LIKELY(s->pDrvHostParallelConnector))
            {
                size_t cbRead;
                int rc = s->pDrvHostParallelConnector->pfnRead(s->pDrvHostParallelConnector, &s->reg_data, &cbRead);
                Log(("parallel_io_port_read: read 0x%X\n", s->reg_data));
                AssertRC(rc);
            }
            ret = s->reg_data;
#endif
        }
        break;
    case 1:
#ifndef IN_RING3
        *pRC = VINF_IOM_HC_IOPORT_READ;
#else
        if (RT_LIKELY(s->pDrvHostParallelConnector))
        {
            int rc = s->pDrvHostParallelConnector->pfnReadStatus(s->pDrvHostParallelConnector, &s->reg_status);
            AssertRC(rc);
        }
        ret = s->reg_status;
        parallel_clear_irq(s);
#endif
        break;
    case 2:
        ret = s->reg_control;
        break;
    case 3:
        ret = s->reg_epp_addr;
        break;
    case 4:
        ret = s->reg_epp_data;
        break;
    case 5:
        break;
    case 6:
        break;
    case 7:
        break;
    }
    LogFlow(("parallel: read addr=0x%02x val=0x%02x\n", addr, ret));
    return ret;
}
Ejemplo n.º 12
0
/**
 * Resolve APIs not present on older windows versions.
 */
void VGSvcWinResolveApis(void)
{
    RTLDRMOD hLdrMod;
#define RESOLVE_SYMBOL(a_fn) do { RT_CONCAT(g_pfn, a_fn) = (decltype(a_fn) *)RTLdrGetFunction(hLdrMod, #a_fn); } while (0)

    /* From ADVAPI32.DLL: */
    int rc = RTLdrLoadSystem("advapi32.dll", true /*fNoUnload*/, &hLdrMod);
    AssertRC(rc);
    if (RT_SUCCESS(rc))
    {
        RESOLVE_SYMBOL(RegisterServiceCtrlHandlerExA);
        RESOLVE_SYMBOL(ChangeServiceConfig2A);
        RESOLVE_SYMBOL(GetNamedSecurityInfoA);
        RESOLVE_SYMBOL(SetEntriesInAclA);
        RESOLVE_SYMBOL(SetNamedSecurityInfoA);
        RESOLVE_SYMBOL(LsaNtStatusToWinError);
        RTLdrClose(hLdrMod);
    }

    /* From KERNEL32.DLL: */
    rc = RTLdrLoadSystem("kernel32.dll", true /*fNoUnload*/, &hLdrMod);
    AssertRC(rc);
    if (RT_SUCCESS(rc))
    {
        RESOLVE_SYMBOL(CreateToolhelp32Snapshot);
        RESOLVE_SYMBOL(Process32First);
        RESOLVE_SYMBOL(Process32Next);
        RESOLVE_SYMBOL(Module32First);
        RESOLVE_SYMBOL(Module32Next);
        RESOLVE_SYMBOL(GetSystemTimeAdjustment);
        RESOLVE_SYMBOL(SetSystemTimeAdjustment);
        RTLdrClose(hLdrMod);
    }

    /* From NTDLL.DLL: */
    rc = RTLdrLoadSystem("ntdll.dll", true /*fNoUnload*/, &hLdrMod);
    AssertRC(rc);
    if (RT_SUCCESS(rc))
    {
        RESOLVE_SYMBOL(ZwQuerySystemInformation);
        RTLdrClose(hLdrMod);
    }

    /* From IPHLPAPI.DLL: */
    rc = RTLdrLoadSystem("iphlpapi.dll", true /*fNoUnload*/, &hLdrMod);
    if (RT_SUCCESS(rc))
    {
        RESOLVE_SYMBOL(GetAdaptersInfo);
        RTLdrClose(hLdrMod);
    }

    /* From WS2_32.DLL: */
    rc = RTLdrLoadSystem("ws2_32.dll", true /*fNoUnload*/, &hLdrMod);
    if (RT_SUCCESS(rc))
    {
        RESOLVE_SYMBOL(WSAStartup);
        RESOLVE_SYMBOL(WSACleanup);
        RESOLVE_SYMBOL(WSASocketA);
        RESOLVE_SYMBOL(WSAIoctl);
        RESOLVE_SYMBOL(WSAGetLastError);
        RESOLVE_SYMBOL(closesocket);
        RESOLVE_SYMBOL(inet_ntoa);
        RTLdrClose(hLdrMod);
    }
}
Ejemplo n.º 13
0
RTDECL(int) RTUriFileCreateEx(const char *pszPath, uint32_t fPathStyle, char **ppszUri, size_t cbUri, size_t *pcchUri)
{
    /*
     * Validate and adjust input. (RTPathParse check pszPath out for us)
     */
    if (pcchUri)
    {
        AssertPtrReturn(pcchUri, VERR_INVALID_POINTER);
        *pcchUri = ~(size_t)0;
    }
    AssertPtrReturn(ppszUri, VERR_INVALID_POINTER);
    AssertReturn(!(fPathStyle & ~RTPATH_STR_F_STYLE_MASK) && fPathStyle != RTPATH_STR_F_STYLE_RESERVED, VERR_INVALID_FLAGS);
    if (fPathStyle == RTPATH_STR_F_STYLE_HOST)
        fPathStyle = RTPATH_STYLE;

    /*
     * Let the RTPath code parse the stuff (no reason to duplicate path parsing
     * and get it slightly wrong here).
     */
    RTPATHPARSED ParsedPath;
    int rc = RTPathParse(pszPath, &ParsedPath, sizeof(ParsedPath), fPathStyle);
    if (RT_SUCCESS(rc) || rc == VERR_BUFFER_OVERFLOW)
    {
        /* Skip leading slashes. */
        if (ParsedPath.fProps & RTPATH_PROP_ROOT_SLASH)
        {
            if (fPathStyle == RTPATH_STR_F_STYLE_DOS)
                while (pszPath[0] == '/' || pszPath[0] == '\\')
                    pszPath++;
            else
                while (pszPath[0] == '/')
                    pszPath++;
        }
        const size_t cchPath = strlen(pszPath);

        /*
         * Calculate the encoded length and figure destination buffering.
         */
        static const char s_szPrefix[] = "file:///";
        size_t const      cchPrefix    = sizeof(s_szPrefix) - (ParsedPath.fProps & RTPATH_PROP_UNC ? 2 : 1);
        size_t cchEncoded = rtUriCalcEncodedLength(pszPath, cchPath, fPathStyle != RTPATH_STR_F_STYLE_DOS);

        if (pcchUri)
            *pcchUri = cchEncoded;

        char  *pszDst;
        char  *pszFreeMe = NULL;
        if (!cbUri || *ppszUri == NULL)
        {
            cbUri = RT_MAX(cbUri, cchPrefix + cchEncoded + 1);
            *ppszUri = pszFreeMe = pszDst = RTStrAlloc(cbUri);
            AssertReturn(pszDst, VERR_NO_STR_MEMORY);
        }
        else if (cchEncoded < cbUri)
            pszDst = *ppszUri;
        else
            return VERR_BUFFER_OVERFLOW;

        /*
         * Construct the URI.
         */
        memcpy(pszDst, s_szPrefix, cchPrefix);
        pszDst[cchPrefix] = '\0';
        rc = rtUriEncodeIntoBuffer(pszPath, cchPath, fPathStyle != RTPATH_STR_F_STYLE_DOS, &pszDst[cchPrefix], cbUri - cchPrefix);
        if (RT_SUCCESS(rc))
        {
            Assert(strlen(pszDst) == cbUri - 1);
            if (fPathStyle == RTPATH_STR_F_STYLE_DOS)
                RTPathChangeToUnixSlashes(pszDst, true /*fForce*/);
            return VINF_SUCCESS;
        }

        AssertRC(rc); /* Impossible! rtUriCalcEncodedLength or something above is busted! */
        if (pszFreeMe)
            RTStrFree(pszFreeMe);
    }
    return rc;
}
Ejemplo n.º 14
0
/**
 * Open a USB device and create a backend instance for it.
 *
 * @returns VBox status code.
 */
static DECLCALLBACK(int) usbProxyWinOpen(PUSBPROXYDEV pProxyDev, const char *pszAddress, void *pvBackend)
{
    PPRIV_USBW32 pPriv = USBPROXYDEV_2_DATA(pProxyDev, PPRIV_USBW32);

    int rc = VINF_SUCCESS;
    pPriv->cAllocatedUrbs = 32;
    pPriv->paHandles    = (PHANDLE)RTMemAllocZ(sizeof(pPriv->paHandles[0]) * pPriv->cAllocatedUrbs);
    pPriv->paQueuedUrbs = (PQUEUED_URB *)RTMemAllocZ(sizeof(pPriv->paQueuedUrbs[0]) * pPriv->cAllocatedUrbs);
    if (    pPriv->paQueuedUrbs
        &&  pPriv->paHandles)
    {
        /*
         * Open the device.
         */
        pPriv->hDev = CreateFile(pszAddress,
                                 GENERIC_READ | GENERIC_WRITE,
                                 FILE_SHARE_WRITE | FILE_SHARE_READ,
                                 NULL, // no SECURITY_ATTRIBUTES structure
                                 OPEN_EXISTING, // No special create flags
                                 FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, // overlapped IO
                                 NULL); // No template file
        if (pPriv->hDev != INVALID_HANDLE_VALUE)
        {
            Log(("usbProxyWinOpen: hDev=%p\n", pPriv->hDev));

            /*
             * Check the version
             */
            USBSUP_VERSION  version = {0};
            DWORD           cbReturned = 0;
            if (DeviceIoControl(pPriv->hDev, SUPUSB_IOCTL_GET_VERSION, NULL, 0, &version, sizeof(version), &cbReturned, NULL))
            {
                if (!(    version.u32Major != USBDRV_MAJOR_VERSION
                      ||  version.u32Minor <  USBDRV_MINOR_VERSION))
                {
                    USBSUP_CLAIMDEV in;
                    in.bInterfaceNumber = 0;

                    cbReturned = 0;
                    if (DeviceIoControl(pPriv->hDev, SUPUSB_IOCTL_USB_CLAIM_DEVICE, &in, sizeof(in), &in, sizeof(in), &cbReturned, NULL))
                    {
                        if (in.fClaimed)
                        {
                            pPriv->fClaimed = true;
#if 0 /** @todo this needs to be enabled if windows chooses a default config. Test with the TrekStor GO Stick. */
                            pProxyDev->iActiveCfg = 1;
                            pProxyDev->cIgnoreSetConfigs = 1;
#endif

                            rc = RTCritSectInit(&pPriv->CritSect);
                            AssertRC(rc);
                            pPriv->hEventWakeup     = CreateEvent(NULL, FALSE, FALSE, NULL);
                            Assert(pPriv->hEventWakeup);

                            pPriv->paHandles[0] = pPriv->hEventWakeup;

                            return VINF_SUCCESS;
                        }

                        rc = VERR_GENERAL_FAILURE;
                        Log(("usbproxy: unable to claim device %x (%s)!!\n", pPriv->hDev, pszAddress));
                    }
                }
                else
                {
                    rc = VERR_VERSION_MISMATCH;
                    Log(("usbproxy: Version mismatch: %d.%d != %d.%d (cur)\n",
                         version.u32Major, version.u32Minor, USBDRV_MAJOR_VERSION, USBDRV_MINOR_VERSION));
                }
            }

            /* Convert last error if necessary */
            if (RT_SUCCESS(rc))
            {
                DWORD dwErr = GetLastError();
                Log(("usbproxy: last error %d\n", dwErr));
                rc = RTErrConvertFromWin32(dwErr);
            }

            CloseHandle(pPriv->hDev);
            pPriv->hDev = INVALID_HANDLE_VALUE;
        }
        else
        {
            Log(("usbproxy: FAILED to open '%s'! last error %d\n", pszAddress, GetLastError()));
            rc = VERR_FILE_NOT_FOUND;
        }
    }
    else
        rc = VERR_NO_MEMORY;

    RTMemFree(pPriv->paQueuedUrbs);
    RTMemFree(pPriv->paHandles);
    return rc;
}
/**
 * Leaves a critical section entered with PDMCritSectEnter().
 *
 * @returns Indication whether we really exited the critical section.
 * @retval  VINF_SUCCESS if we really exited.
 * @retval  VINF_SEM_NESTED if we only reduced the nesting count.
 * @retval  VERR_NOT_OWNER if you somehow ignore release assertions.
 *
 * @param   pCritSect           The PDM critical section to leave.
 */
VMMDECL(int) PDMCritSectLeave(PPDMCRITSECT pCritSect)
{
    AssertMsg(pCritSect->s.Core.u32Magic == RTCRITSECT_MAGIC, ("%p %RX32\n", pCritSect, pCritSect->s.Core.u32Magic));
    Assert(pCritSect->s.Core.u32Magic == RTCRITSECT_MAGIC);

    /* Check for NOP sections before asserting ownership. */
    if (pCritSect->s.Core.fFlags & RTCRITSECT_FLAGS_NOP)
        return VINF_SUCCESS;

    /*
     * Always check that the caller is the owner (screw performance).
     */
    RTNATIVETHREAD const hNativeSelf = pdmCritSectGetNativeSelf(pCritSect);
    AssertReleaseMsgReturn(pCritSect->s.Core.NativeThreadOwner == hNativeSelf,
                           ("%p %s: %p != %p; cLockers=%d cNestings=%d\n", pCritSect, R3STRING(pCritSect->s.pszName),
                            pCritSect->s.Core.NativeThreadOwner, hNativeSelf,
                            pCritSect->s.Core.cLockers, pCritSect->s.Core.cNestings),
                           VERR_NOT_OWNER);
    Assert(pCritSect->s.Core.cNestings >= 1);

    /*
     * Nested leave.
     */
    if (pCritSect->s.Core.cNestings > 1)
    {
        ASMAtomicDecS32(&pCritSect->s.Core.cNestings);
        Assert(pCritSect->s.Core.cNestings >= 1);
        ASMAtomicDecS32(&pCritSect->s.Core.cLockers);
        Assert(pCritSect->s.Core.cLockers >= 0);
        return VINF_SEM_NESTED;
    }

#ifdef IN_RING0
# if 0 /** @todo Make SUPSemEventSignal interrupt safe (handle table++) and enable this for: defined(RT_OS_LINUX) || defined(RT_OS_OS2) */
    if (1) /* SUPSemEventSignal is safe */
# else
    if (ASMIntAreEnabled())
# endif
#endif
#if defined(IN_RING3) || defined(IN_RING0)
    {
        /*
         * Leave for real.
         */
        /* update members. */
        SUPSEMEVENT hEventToSignal  = pCritSect->s.hEventToSignal;
        pCritSect->s.hEventToSignal = NIL_SUPSEMEVENT;
# ifdef IN_RING3
#  if defined(PDMCRITSECT_STRICT)
        if (pCritSect->s.Core.pValidatorRec->hThread != NIL_RTTHREAD)
            RTLockValidatorRecExclReleaseOwnerUnchecked(pCritSect->s.Core.pValidatorRec);
#  endif
        Assert(!pCritSect->s.Core.pValidatorRec || pCritSect->s.Core.pValidatorRec->hThread == NIL_RTTHREAD);
# endif
        ASMAtomicAndU32(&pCritSect->s.Core.fFlags, ~PDMCRITSECT_FLAGS_PENDING_UNLOCK);
        ASMAtomicWriteHandle(&pCritSect->s.Core.NativeThreadOwner, NIL_RTNATIVETHREAD);
        ASMAtomicDecS32(&pCritSect->s.Core.cNestings);
        Assert(pCritSect->s.Core.cNestings == 0);

        /* stop and decrement lockers. */
        STAM_PROFILE_ADV_STOP(&pCritSect->s.StatLocked, l);
        ASMCompilerBarrier();
        if (ASMAtomicDecS32(&pCritSect->s.Core.cLockers) >= 0)
        {
            /* Someone is waiting, wake up one of them. */
            SUPSEMEVENT     hEvent   = (SUPSEMEVENT)pCritSect->s.Core.EventSem;
            PSUPDRVSESSION  pSession = pCritSect->s.CTX_SUFF(pVM)->pSession;
            int rc = SUPSemEventSignal(pSession, hEvent);
            AssertRC(rc);
        }

        /* Signal exit event. */
        if (hEventToSignal != NIL_SUPSEMEVENT)
        {
            Log8(("Signalling %#p\n", hEventToSignal));
            int rc = SUPSemEventSignal(pCritSect->s.CTX_SUFF(pVM)->pSession, hEventToSignal);
            AssertRC(rc);
        }

# if defined(DEBUG_bird) && defined(IN_RING0)
        VMMTrashVolatileXMMRegs();
# endif
    }
#endif  /* IN_RING3 || IN_RING0 */
#ifdef IN_RING0
    else
#endif
#if defined(IN_RING0) || defined(IN_RC)
    {
        /*
         * Try leave it.
         */
        if (pCritSect->s.Core.cLockers == 0)
        {
            ASMAtomicWriteS32(&pCritSect->s.Core.cNestings, 0);
            RTNATIVETHREAD hNativeThread = pCritSect->s.Core.NativeThreadOwner;
            ASMAtomicAndU32(&pCritSect->s.Core.fFlags, ~PDMCRITSECT_FLAGS_PENDING_UNLOCK);
            STAM_PROFILE_ADV_STOP(&pCritSect->s.StatLocked, l);

            ASMAtomicWriteHandle(&pCritSect->s.Core.NativeThreadOwner, NIL_RTNATIVETHREAD);
            if (ASMAtomicCmpXchgS32(&pCritSect->s.Core.cLockers, -1, 0))
                return VINF_SUCCESS;

            /* darn, someone raced in on us. */
            ASMAtomicWriteHandle(&pCritSect->s.Core.NativeThreadOwner, hNativeThread);
            STAM_PROFILE_ADV_START(&pCritSect->s.StatLocked, l);
            Assert(pCritSect->s.Core.cNestings == 0);
            ASMAtomicWriteS32(&pCritSect->s.Core.cNestings, 1);
        }
        ASMAtomicOrU32(&pCritSect->s.Core.fFlags, PDMCRITSECT_FLAGS_PENDING_UNLOCK);

        /*
         * Queue the request.
         */
        PVM         pVM   = pCritSect->s.CTX_SUFF(pVM);     AssertPtr(pVM);
        PVMCPU      pVCpu = VMMGetCpu(pVM);                 AssertPtr(pVCpu);
        uint32_t    i     = pVCpu->pdm.s.cQueuedCritSectLeaves++;
        LogFlow(("PDMCritSectLeave: [%d]=%p => R3\n", i, pCritSect));
        AssertFatal(i < RT_ELEMENTS(pVCpu->pdm.s.apQueuedCritSectLeaves));
        pVCpu->pdm.s.apQueuedCritSectLeaves[i] = MMHyperCCToR3(pVM, pCritSect);
        VMCPU_FF_SET(pVCpu, VMCPU_FF_PDM_CRITSECT);
        VMCPU_FF_SET(pVCpu, VMCPU_FF_TO_R3);
        STAM_REL_COUNTER_INC(&pVM->pdm.s.StatQueuedCritSectLeaves);
        STAM_REL_COUNTER_INC(&pCritSect->s.StatContentionRZUnlock);
    }
#endif /* IN_RING0 || IN_RC */

    return VINF_SUCCESS;
}
Ejemplo n.º 16
0
/**
 * Deregister one(/all) info handler(s) owned by a driver.
 *
 * @returns VBox status code.
 * @param   pVM         Pointer to the VM.
 * @param   pDrvIns     Driver instance.
 * @param   pszName     The identifier of the info. If NULL all owned by the driver.
 */
VMMR3DECL(int) DBGFR3InfoDeregisterDriver(PVM pVM, PPDMDRVINS pDrvIns, const char *pszName)
{
    LogFlow(("DBGFR3InfoDeregisterDriver: pDrvIns=%p pszName=%p:{%s}\n", pDrvIns, pszName, pszName));

    /*
     * Validate input.
     */
    if (!pDrvIns)
    {
        AssertMsgFailed(("!pDrvIns\n"));
        return VERR_INVALID_PARAMETER;
    }
    size_t cchName = pszName ? strlen(pszName) : 0;

    /*
     * Enumerate the info handlers and free the requested entries.
     */
    int rc = RTCritSectEnter(&pVM->dbgf.s.InfoCritSect);
    AssertRC(rc);
    rc = VERR_FILE_NOT_FOUND;
    PDBGFINFO pPrev = NULL;
    PDBGFINFO pInfo = pVM->dbgf.s.pInfoFirst;
    if (pszName)
    {
        /*
         * Free a specific one.
         */
        for (; pInfo; pPrev = pInfo, pInfo = pInfo->pNext)
            if (    pInfo->enmType == DBGFINFOTYPE_DRV
                &&  pInfo->u.Drv.pDrvIns == pDrvIns
                &&  pInfo->cchName == cchName
                &&  !strcmp(pInfo->szName, pszName))
            {
                if (pPrev)
                    pPrev->pNext = pInfo->pNext;
                else
                    pVM->dbgf.s.pInfoFirst = pInfo->pNext;
                MMR3HeapFree(pInfo);
                rc = VINF_SUCCESS;
                break;
            }
    }
    else
    {
        /*
         * Free all owned by the driver.
         */
        for (; pInfo; pPrev = pInfo, pInfo = pInfo->pNext)
            if (    pInfo->enmType == DBGFINFOTYPE_DRV
                &&  pInfo->u.Drv.pDrvIns == pDrvIns)
            {
                if (pPrev)
                    pPrev->pNext = pInfo->pNext;
                else
                    pVM->dbgf.s.pInfoFirst = pInfo->pNext;
                MMR3HeapFree(pInfo);
                pInfo = pPrev;
            }
        rc = VINF_SUCCESS;
    }
    int rc2 = RTCritSectLeave(&pVM->dbgf.s.InfoCritSect);
    AssertRC(rc2);
    AssertRC(rc);
    LogFlow(("DBGFR3InfoDeregisterDriver: returns %Rrc\n", rc));
    return rc;
}
Ejemplo n.º 17
0
/**
 *  Entry point.
 */
extern "C" DECLEXPORT(int) TrustedMain(int argc, char **argv, char **envp)
{
    int rcRet = 0; /* error count */
    PPDMASYNCCOMPLETIONENDPOINT pEndpointSrc, pEndpointDst;

    RTR3InitExe(argc, &argv, RTR3INIT_FLAGS_SUPLIB);

    if (argc != 3)
    {
        RTPrintf(TESTCASE ": Usage is ./tstPDMAsyncCompletion <source> <dest>\n");
        return 1;
    }

    PVM pVM;
    PUVM pUVM;
    int rc = VMR3Create(1, NULL, NULL, NULL, NULL, NULL, &pVM, &pUVM);
    if (RT_SUCCESS(rc))
    {
        /*
         * Little hack to avoid the VM_ASSERT_EMT assertion.
         */
        RTTlsSet(pVM->pUVM->vm.s.idxTLS, &pVM->pUVM->aCpus[0]);
        pVM->pUVM->aCpus[0].pUVM = pVM->pUVM;
        pVM->pUVM->aCpus[0].vm.s.NativeThreadEMT = RTThreadNativeSelf();

        /*
         * Create the template.
         */
        PPDMASYNCCOMPLETIONTEMPLATE pTemplate;
        rc = PDMR3AsyncCompletionTemplateCreateInternal(pVM, &pTemplate, AsyncTaskCompleted, NULL, "Test");
        if (RT_FAILURE(rc))
        {
            RTPrintf(TESTCASE ": Error while creating the template!! rc=%d\n", rc);
            return 1;
        }

        /*
         * Create event semaphore.
         */
        rc = RTSemEventCreate(&g_FinishedEventSem);
        AssertRC(rc);

        /*
         * Create the temporary buffers.
         */
        for (unsigned i=0; i < NR_TASKS; i++)
        {
            g_AsyncCompletionTasksBuffer[i] = (uint8_t *)RTMemAllocZ(BUFFER_SIZE);
            if (!g_AsyncCompletionTasksBuffer[i])
            {
                RTPrintf(TESTCASE ": out of memory!\n");
                return ++rcRet;
            }
        }

        /* Create the destination as the async completion API can't do this. */
        RTFILE FileTmp;
        rc = RTFileOpen(&FileTmp, argv[2], RTFILE_O_READWRITE | RTFILE_O_OPEN_CREATE | RTFILE_O_DENY_NONE);
        if (RT_FAILURE(rc))
        {
            RTPrintf(TESTCASE ": Error while creating the destination!! rc=%d\n", rc);
            return ++rcRet;
        }
        RTFileClose(FileTmp);

        /* Create our file endpoint */
        rc = PDMR3AsyncCompletionEpCreateForFile(&pEndpointSrc, argv[1], 0, pTemplate);
        if (RT_SUCCESS(rc))
        {
            rc = PDMR3AsyncCompletionEpCreateForFile(&pEndpointDst, argv[2], 0, pTemplate);
            if (RT_SUCCESS(rc))
            {
                PDMR3PowerOn(pVM);

                /* Wait for all threads to finish initialization. */
                RTThreadSleep(100);

                int fReadPass = true;
                uint64_t cbSrc;
                size_t   offSrc = 0;
                size_t   offDst = 0;
                uint32_t cTasksUsed = 0;

                rc = PDMR3AsyncCompletionEpGetSize(pEndpointSrc, &cbSrc);
                if (RT_SUCCESS(rc))
                {
                    /* Copy the data. */
                    for (;;)
                    {
                        if (fReadPass)
                        {
                            cTasksUsed = (BUFFER_SIZE * NR_TASKS) <= (cbSrc - offSrc)
                                         ? NR_TASKS
                                         :   ((cbSrc - offSrc) / BUFFER_SIZE)
                                           + ((cbSrc - offSrc) % BUFFER_SIZE) > 0
                                         ? 1
                                         : 0;

                            g_cTasksLeft = cTasksUsed;

                            for (uint32_t i = 0; i < cTasksUsed; i++)
                            {
                                size_t cbRead = ((size_t)offSrc + BUFFER_SIZE) <= cbSrc ? BUFFER_SIZE : cbSrc - offSrc;
                                RTSGSEG DataSeg;

                                DataSeg.pvSeg = g_AsyncCompletionTasksBuffer[i];
                                DataSeg.cbSeg = cbRead;

                                rc = PDMR3AsyncCompletionEpRead(pEndpointSrc, offSrc, &DataSeg, 1, cbRead, NULL,
                                                                &g_AsyncCompletionTasks[i]);
                                AssertRC(rc);
                                offSrc += cbRead;
                                if (offSrc == cbSrc)
                                    break;
                            }
                        }
                        else
                        {
                            g_cTasksLeft = cTasksUsed;

                            for (uint32_t i = 0; i < cTasksUsed; i++)
                            {
                                size_t cbWrite = (offDst + BUFFER_SIZE) <= cbSrc ? BUFFER_SIZE : cbSrc - offDst;
                                RTSGSEG DataSeg;

                                DataSeg.pvSeg = g_AsyncCompletionTasksBuffer[i];
                                DataSeg.cbSeg = cbWrite;

                                rc = PDMR3AsyncCompletionEpWrite(pEndpointDst, offDst, &DataSeg, 1, cbWrite, NULL,
                                                                 &g_AsyncCompletionTasks[i]);
                                AssertRC(rc);
                                offDst += cbWrite;
                                if (offDst == cbSrc)
                                    break;
                            }
                        }

                        rc = RTSemEventWait(g_FinishedEventSem, RT_INDEFINITE_WAIT);
                        AssertRC(rc);

                        if (!fReadPass && (offDst == cbSrc))
                            break;
                        else if (fReadPass)
                            fReadPass = false;
                        else
                        {
                            cTasksUsed = 0;
                            fReadPass = true;
                        }
                    }
                }
                else
                {
                    RTPrintf(TESTCASE ": Error querying size of the endpoint!! rc=%d\n", rc);
                    rcRet++;
                }

                PDMR3PowerOff(pVM);
                PDMR3AsyncCompletionEpClose(pEndpointDst);
            }
            PDMR3AsyncCompletionEpClose(pEndpointSrc);
        }

        rc = VMR3Destroy(pUVM);
        AssertMsg(rc == VINF_SUCCESS, ("%s: Destroying VM failed rc=%Rrc!!\n", __FUNCTION__, rc));
        VMR3ReleaseUVM(pUVM);

        /*
         * Clean up.
         */
        for (uint32_t i = 0; i < NR_TASKS; i++)
        {
            RTMemFree(g_AsyncCompletionTasksBuffer[i]);
        }
    }
    else
    {
        RTPrintf(TESTCASE ": failed to create VM!! rc=%Rrc\n", rc);
        rcRet++;
    }

    return rcRet;
}
Ejemplo n.º 18
0
/**
 * Worker for DBGFR3Info and DBGFR3InfoEx.
 *
 * @returns VBox status code.
 * @param   pVM                 Pointer to the VM.
 * @param   idCpu               Which CPU to run EMT bound handlers on.
 *                              VMCPUID_ANY or a valid CPU ID.
 * @param   pszName             What to dump.
 * @param   pszArgs             Arguments, optional.
 * @param   pHlp                Output helper, optional.
 */
static DECLCALLBACK(int) dbgfR3Info(PVM pVM, VMCPUID idCpu, const char *pszName, const char *pszArgs, PCDBGFINFOHLP pHlp)
{
    /*
     * Validate input.
     */
    AssertPtrReturn(pszName, VERR_INVALID_POINTER);
    if (pHlp)
    {
        if (    !pHlp->pfnPrintf
            ||  !pHlp->pfnPrintfV)
        {
            AssertMsgFailed(("A pHlp member is missing!\n"));
            return VERR_INVALID_PARAMETER;
        }
    }
    else
        pHlp = &g_dbgfR3InfoLogHlp;

    /*
     * Find the info handler.
     */
    size_t cchName = strlen(pszName);
    int rc = RTCritSectEnter(&pVM->dbgf.s.InfoCritSect);
    AssertRC(rc);
    PDBGFINFO pInfo = pVM->dbgf.s.pInfoFirst;
    for (; pInfo; pInfo = pInfo->pNext)
        if (    pInfo->cchName == cchName
            &&  !memcmp(pInfo->szName, pszName, cchName))
            break;
    if (pInfo)
    {
        /*
         * Found it.
         *      Make a copy of it on the stack so we can leave the crit sect.
         *      Switch on the type and invoke the handler.
         */
        DBGFINFO Info = *pInfo;
        rc = RTCritSectLeave(&pVM->dbgf.s.InfoCritSect);
        AssertRC(rc);
        rc = VINF_SUCCESS;
        switch (Info.enmType)
        {
            case DBGFINFOTYPE_DEV:
                if (Info.fFlags & DBGFINFO_FLAGS_RUN_ON_EMT)
                    rc = VMR3ReqCallVoidWait(pVM, idCpu, (PFNRT)Info.u.Dev.pfnHandler, 3, Info.u.Dev.pDevIns, pHlp, pszArgs);
                else
                    Info.u.Dev.pfnHandler(Info.u.Dev.pDevIns, pHlp, pszArgs);
                break;

            case DBGFINFOTYPE_DRV:
                if (Info.fFlags & DBGFINFO_FLAGS_RUN_ON_EMT)
                    rc = VMR3ReqCallVoidWait(pVM, idCpu, (PFNRT)Info.u.Drv.pfnHandler, 3, Info.u.Drv.pDrvIns, pHlp, pszArgs);
                else
                    Info.u.Drv.pfnHandler(Info.u.Drv.pDrvIns, pHlp, pszArgs);
                break;

            case DBGFINFOTYPE_INT:
                if (Info.fFlags & DBGFINFO_FLAGS_RUN_ON_EMT)
                    rc = VMR3ReqCallVoidWait(pVM, idCpu, (PFNRT)Info.u.Int.pfnHandler, 3, pVM, pHlp, pszArgs);
                else
                    Info.u.Int.pfnHandler(pVM, pHlp, pszArgs);
                break;

            case DBGFINFOTYPE_EXT:
                if (Info.fFlags & DBGFINFO_FLAGS_RUN_ON_EMT)
                    rc = VMR3ReqCallVoidWait(pVM, idCpu, (PFNRT)Info.u.Ext.pfnHandler, 3, Info.u.Ext.pvUser, pHlp, pszArgs);
                else
                    Info.u.Ext.pfnHandler(Info.u.Ext.pvUser, pHlp, pszArgs);
                break;

            default:
                AssertMsgFailedReturn(("Invalid info type enmType=%d\n", Info.enmType), VERR_IPE_NOT_REACHED_DEFAULT_CASE);
        }
    }
    else
    {
        rc = RTCritSectLeave(&pVM->dbgf.s.InfoCritSect);
        AssertRC(rc);
        rc = VERR_FILE_NOT_FOUND;
    }
    return rc;
}
Ejemplo n.º 19
0
/**
 * Stops and terminates the services.
 *
 * This should be called even when VBoxServiceStartServices fails so it can
 * clean up anything that we succeeded in starting.
 */
int VBoxServiceStopServices(void)
{
    VBoxServiceReportStatus(VBoxGuestFacilityStatus_Terminating);

    /*
     * Signal all the services.
     */
    for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
        ASMAtomicWriteBool(&g_aServices[j].fShutdown, true);

    /*
     * Do the pfnStop callback on all running services.
     */
    for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
        if (g_aServices[j].fStarted)
        {
            VBoxServiceVerbose(3, "Calling stop function for service '%s' ...\n", g_aServices[j].pDesc->pszName);
            g_aServices[j].pDesc->pfnStop();
        }

    /*
     * Wait for all the service threads to complete.
     */
    int rc = VINF_SUCCESS;
    for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
    {
        if (!g_aServices[j].fEnabled) /* Only stop services which were started before. */
            continue;
        if (g_aServices[j].Thread != NIL_RTTHREAD)
        {
            VBoxServiceVerbose(2, "Waiting for service '%s' to stop ...\n", g_aServices[j].pDesc->pszName);
            int rc2 = VINF_SUCCESS;
            for (int i = 0; i < 30; i++) /* Wait 30 seconds in total */
            {
                rc2 = RTThreadWait(g_aServices[j].Thread, 1000 /* Wait 1 second */, NULL);
                if (RT_SUCCESS(rc2))
                    break;
#ifdef RT_OS_WINDOWS
                /* Notify SCM that it takes a bit longer ... */
                VBoxServiceWinSetStopPendingStatus(i + j*32);
#endif
            }
            if (RT_FAILURE(rc2))
            {
                VBoxServiceError("Service '%s' failed to stop. (%Rrc)\n", g_aServices[j].pDesc->pszName, rc2);
                rc = rc2;
            }
        }
        VBoxServiceVerbose(3, "Terminating service '%s' (%d) ...\n", g_aServices[j].pDesc->pszName, j);
        g_aServices[j].pDesc->pfnTerm();
    }

#ifdef RT_OS_WINDOWS
    /*
     * Wake up and tell the main() thread that we're shutting down (it's
     * sleeping in VBoxServiceMainWait).
     */
    ASMAtomicWriteBool(&g_fWindowsServiceShutdown, true);
    if (g_hEvtWindowsService != NIL_RTSEMEVENT)
    {
        VBoxServiceVerbose(3, "Stopping the main thread...\n");
        int rc2 = RTSemEventSignal(g_hEvtWindowsService);
        AssertRC(rc2);
    }
#endif

    VBoxServiceVerbose(2, "Stopping services returning: %Rrc\n", rc);
    VBoxServiceReportStatus(RT_SUCCESS(rc) ? VBoxGuestFacilityStatus_Paused : VBoxGuestFacilityStatus_Failed);
    return rc;
}
Ejemplo n.º 20
0
/**
 * Display several info items.
 *
 * This is intended used by the fatal error dump only.
 *
 * @returns
 * @param   pVM             Pointer to the VM.
 * @param   pszIncludePat   Simple string pattern of info items to include.
 * @param   pszExcludePat   Simple string pattern of info items to exclude.
 * @param   pszSepFmt       Item separator format string.  The item name will be
 *                          given as parameter.
 * @param   pHlp            The output helper functions.  If NULL the logger
 *                          will be used.
 *
 * @threads EMT
 */
VMMR3DECL(int) DBGFR3InfoMulti(PVM pVM, const char *pszIncludePat, const char *pszExcludePat, const char *pszSepFmt,
                               PCDBGFINFOHLP pHlp)
{
    /*
     * Validate input.
     */
    VM_ASSERT_EMT_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
    AssertPtrReturn(pszIncludePat, VERR_INVALID_POINTER);
    AssertPtrReturn(pszExcludePat, VERR_INVALID_POINTER);
    if (pHlp)
    {
        AssertPtrReturn(pHlp->pfnPrintf, VERR_INVALID_POINTER);
        AssertPtrReturn(pHlp->pfnPrintfV, VERR_INVALID_POINTER);
    }
    else
        pHlp = &g_dbgfR3InfoLogHlp;

    size_t const cchIncludePat = strlen(pszIncludePat);
    size_t const cchExcludePat = strlen(pszExcludePat);
    const char *pszArgs = "";

    /*
     * Enumerate the info handlers and call the ones matching.
     * Note! We won't leave the critical section here...
     */
    int rc = RTCritSectEnter(&pVM->dbgf.s.InfoCritSect);
    AssertRC(rc);
    rc = VWRN_NOT_FOUND;
    for (PDBGFINFO pInfo = pVM->dbgf.s.pInfoFirst; pInfo; pInfo = pInfo->pNext)
    {
        if (   RTStrSimplePatternMultiMatch(pszIncludePat, cchIncludePat, pInfo->szName, pInfo->cchName, NULL)
            && !RTStrSimplePatternMultiMatch(pszExcludePat, cchExcludePat, pInfo->szName, pInfo->cchName, NULL))
        {
            pHlp->pfnPrintf(pHlp, pszSepFmt, pInfo->szName);
            rc = VINF_SUCCESS;
            switch (pInfo->enmType)
            {
                case DBGFINFOTYPE_DEV:
                    if (pInfo->fFlags & DBGFINFO_FLAGS_RUN_ON_EMT)
                        rc = VMR3ReqCallVoidWait(pVM, VMCPUID_ANY, (PFNRT)pInfo->u.Dev.pfnHandler, 3, pInfo->u.Dev.pDevIns, pHlp, pszArgs);
                    else
                        pInfo->u.Dev.pfnHandler(pInfo->u.Dev.pDevIns, pHlp, pszArgs);
                    break;

                case DBGFINFOTYPE_DRV:
                    if (pInfo->fFlags & DBGFINFO_FLAGS_RUN_ON_EMT)
                        rc = VMR3ReqCallVoidWait(pVM, VMCPUID_ANY, (PFNRT)pInfo->u.Drv.pfnHandler, 3, pInfo->u.Drv.pDrvIns, pHlp, pszArgs);
                    else
                        pInfo->u.Drv.pfnHandler(pInfo->u.Drv.pDrvIns, pHlp, pszArgs);
                    break;

                case DBGFINFOTYPE_INT:
                    if (pInfo->fFlags & DBGFINFO_FLAGS_RUN_ON_EMT)
                        rc = VMR3ReqCallVoidWait(pVM, VMCPUID_ANY, (PFNRT)pInfo->u.Int.pfnHandler, 3, pVM, pHlp, pszArgs);
                    else
                        pInfo->u.Int.pfnHandler(pVM, pHlp, pszArgs);
                    break;

                case DBGFINFOTYPE_EXT:
                    if (pInfo->fFlags & DBGFINFO_FLAGS_RUN_ON_EMT)
                        rc = VMR3ReqCallVoidWait(pVM, VMCPUID_ANY, (PFNRT)pInfo->u.Ext.pfnHandler, 3, pInfo->u.Ext.pvUser, pHlp, pszArgs);
                    else
                        pInfo->u.Ext.pfnHandler(pInfo->u.Ext.pvUser, pHlp, pszArgs);
                    break;

                default:
                    AssertMsgFailedReturn(("Invalid info type enmType=%d\n", pInfo->enmType), VERR_IPE_NOT_REACHED_DEFAULT_CASE);
            }
        }
    }
    int rc2 = RTCritSectLeave(&pVM->dbgf.s.InfoCritSect);
    AssertRC(rc2);

    return rc;
}
Ejemplo n.º 21
0
/**
 * Executes command from debugger.
 * The caller is responsible for waiting or resuming execution based on the
 * value returned in the *pfResumeExecution indicator.
 *
 * @returns VBox status. (clearify!)
 * @param   pVM                 Pointer to the VM.
 * @param   enmCmd              The command in question.
 * @param   pCmdData            Pointer to the command data.
 * @param   pfResumeExecution   Where to store the resume execution / continue waiting indicator.
 */
static int dbgfR3VMMCmd(PVM pVM, DBGFCMD enmCmd, PDBGFCMDDATA pCmdData, bool *pfResumeExecution)
{
    bool    fSendEvent;
    bool    fResume;
    int     rc = VINF_SUCCESS;

    NOREF(pCmdData); /* for later */

    switch (enmCmd)
    {
        /*
         * Halt is answered by an event say that we've halted.
         */
        case DBGFCMD_HALT:
        {
            pVM->dbgf.s.DbgEvent.enmType = DBGFEVENT_HALT_DONE;
            pVM->dbgf.s.DbgEvent.enmCtx  = dbgfR3FigureEventCtx(pVM);
            fSendEvent = true;
            fResume = false;
            break;
        }


        /*
         * Resume is not answered we'll just resume execution.
         */
        case DBGFCMD_GO:
        {
            fSendEvent = false;
            fResume = true;
            break;
        }

        /** @todo implement (and define) the rest of the commands. */

        /*
         * Disable breakpoints and stuff.
         * Send an everythings cool event to the debugger thread and resume execution.
         */
        case DBGFCMD_DETACH_DEBUGGER:
        {
            ASMAtomicWriteBool(&pVM->dbgf.s.fAttached, false);
            pVM->dbgf.s.DbgEvent.enmType = DBGFEVENT_DETACH_DONE;
            pVM->dbgf.s.DbgEvent.enmCtx  = DBGFEVENTCTX_OTHER;
            fSendEvent = true;
            fResume = true;
            break;
        }

        /*
         * The debugger has detached successfully.
         * There is no reply to this event.
         */
        case DBGFCMD_DETACHED_DEBUGGER:
        {
            fSendEvent = false;
            fResume = true;
            break;
        }

        /*
         * Single step, with trace into.
         */
        case DBGFCMD_SINGLE_STEP:
        {
            Log2(("Single step\n"));
            rc = VINF_EM_DBG_STEP;
            /** @todo SMP */
            PVMCPU pVCpu = VMMGetCpu0(pVM);
            pVCpu->dbgf.s.fSingleSteppingRaw = true;
            fSendEvent = false;
            fResume = true;
            break;
        }

        /*
         * Default is to send an invalid command event.
         */
        default:
        {
            pVM->dbgf.s.DbgEvent.enmType = DBGFEVENT_INVALID_COMMAND;
            pVM->dbgf.s.DbgEvent.enmCtx  = dbgfR3FigureEventCtx(pVM);
            fSendEvent = true;
            fResume = false;
            break;
        }
    }

    /*
     * Send pending event.
     */
    if (fSendEvent)
    {
        Log2(("DBGF: Emulation thread: sending event %d\n", pVM->dbgf.s.DbgEvent.enmType));
        int rc2 = RTSemPing(&pVM->dbgf.s.PingPong);
        if (RT_FAILURE(rc2))
        {
            AssertRC(rc2);
            *pfResumeExecution = true;
            return rc2;
        }
    }

    /*
     * Return.
     */
    *pfResumeExecution = fResume;
    return rc;
}
Ejemplo n.º 22
0
/**
 * Initialize a new thread, this actually creates the thread.
 *
 * @returns VBox status code.
 * @param   pVM         Pointer to the VM.
 * @param   ppThread    Where the thread instance data handle is.
 * @param   cbStack     The stack size, see RTThreadCreate().
 * @param   enmType     The thread type, see RTThreadCreate().
 * @param   pszName     The thread name, see RTThreadCreate().
 */
static int pdmR3ThreadInit(PVM pVM, PPPDMTHREAD ppThread, size_t cbStack, RTTHREADTYPE enmType, const char *pszName)
{
    PPDMTHREAD  pThread = *ppThread;
    PUVM        pUVM    = pVM->pUVM;

    /*
     * Initialize the remainder of the structure.
     */
    pThread->Internal.s.pVM = pVM;

    int rc = RTSemEventMultiCreate(&pThread->Internal.s.BlockEvent);
    if (RT_SUCCESS(rc))
    {
        rc = RTSemEventMultiCreate(&pThread->Internal.s.SleepEvent);
        if (RT_SUCCESS(rc))
        {
            /*
             * Create the thread and wait for it to initialize.
             * The newly created thread will set the PDMTHREAD::Thread member.
             */
            RTTHREAD Thread;
            rc = RTThreadCreate(&Thread, pdmR3ThreadMain, pThread, cbStack, enmType, RTTHREADFLAGS_WAITABLE, pszName);
            if (RT_SUCCESS(rc))
            {
                rc = RTThreadUserWait(Thread, 60*1000);
                if (    RT_SUCCESS(rc)
                    &&  pThread->enmState != PDMTHREADSTATE_SUSPENDED)
                    rc = VERR_PDM_THREAD_IPE_2;
                if (RT_SUCCESS(rc))
                {
                    /*
                     * Insert it into the thread list.
                     */
                    RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
                    pThread->Internal.s.pNext = NULL;
                    if (pUVM->pdm.s.pThreadsTail)
                        pUVM->pdm.s.pThreadsTail->Internal.s.pNext = pThread;
                    else
                        pUVM->pdm.s.pThreads = pThread;
                    pUVM->pdm.s.pThreadsTail = pThread;
                    RTCritSectLeave(&pUVM->pdm.s.ListCritSect);

                    rc = RTThreadUserReset(Thread);
                    AssertRC(rc);
                    return rc;
                }

                /* bailout */
                RTThreadWait(Thread, 60*1000, NULL);
            }
            RTSemEventMultiDestroy(pThread->Internal.s.SleepEvent);
            pThread->Internal.s.SleepEvent = NIL_RTSEMEVENTMULTI;
        }
        RTSemEventMultiDestroy(pThread->Internal.s.BlockEvent);
        pThread->Internal.s.BlockEvent = NIL_RTSEMEVENTMULTI;
    }
    MMHyperFree(pVM, pThread);
    *ppThread = NULL;

    return rc;
}
Ejemplo n.º 23
0
/** @copydoc VBOXSERVICE::pfnInit */
static DECLCALLBACK(int) VBoxServiceTimeSyncInit(void)
{
    /*
     * If not specified, find the right interval default.
     * Then create the event sem to block on.
     */
    if (!g_TimeSyncInterval)
        g_TimeSyncInterval = g_DefaultInterval * 1000;
    if (!g_TimeSyncInterval)
        g_TimeSyncInterval = 10 * 1000;

    VbglR3GetSessionId(&g_idTimeSyncSession);
    /* The status code is ignored as this information is not available with VBox < 3.2.10. */

    int rc = RTSemEventMultiCreate(&g_TimeSyncEvent);
    AssertRC(rc);
#ifdef RT_OS_WINDOWS
    if (RT_SUCCESS(rc))
    {
        /*
         * Adjust privileges of this process so we can make system time adjustments.
         */
        if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &g_hTokenProcess))
        {
            TOKEN_PRIVILEGES tkPriv;
            RT_ZERO(tkPriv);
            tkPriv.PrivilegeCount = 1;
            tkPriv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
            if (LookupPrivilegeValue(NULL, SE_SYSTEMTIME_NAME, &tkPriv.Privileges[0].Luid))
            {
                DWORD cbRet = sizeof(g_TkOldPrivileges);
                if (AdjustTokenPrivileges(g_hTokenProcess, FALSE, &tkPriv, sizeof(TOKEN_PRIVILEGES), &g_TkOldPrivileges, &cbRet))
                    rc = VINF_SUCCESS;
                else
                {
                    DWORD dwErr = GetLastError();
                    rc = RTErrConvertFromWin32(dwErr);
                    VBoxServiceError("VBoxServiceTimeSyncInit: Adjusting token privileges (SE_SYSTEMTIME_NAME) failed with status code %u/%Rrc!\n", dwErr, rc);
                }
            }
            else
            {
                DWORD dwErr = GetLastError();
                rc = RTErrConvertFromWin32(dwErr);
                VBoxServiceError("VBoxServiceTimeSyncInit: Looking up token privileges (SE_SYSTEMTIME_NAME) failed with status code %u/%Rrc!\n", dwErr, rc);
            }
            if (RT_FAILURE(rc))
            {
                CloseHandle(g_hTokenProcess);
                g_hTokenProcess = NULL;
            }
        }
        else
        {
            DWORD dwErr = GetLastError();
            rc = RTErrConvertFromWin32(dwErr);
            VBoxServiceError("VBoxServiceTimeSyncInit: Opening process token (SE_SYSTEMTIME_NAME) failed with status code %u/%Rrc!\n", dwErr, rc);
            g_hTokenProcess = NULL;
        }
    }

    if (GetSystemTimeAdjustment(&g_dwWinTimeAdjustment, &g_dwWinTimeIncrement, &g_bWinTimeAdjustmentDisabled))
        VBoxServiceVerbose(3, "VBoxServiceTimeSyncInit: Initially %ld (100ns) units per %ld (100 ns) units interval, disabled=%d\n",
                           g_dwWinTimeAdjustment, g_dwWinTimeIncrement, g_bWinTimeAdjustmentDisabled ? 1 : 0);
    else
    {
        DWORD dwErr = GetLastError();
        rc = RTErrConvertFromWin32(dwErr);
        VBoxServiceError("VBoxServiceTimeSyncInit: Could not get time adjustment values! Last error: %ld!\n", dwErr);
    }
#endif /* RT_OS_WINDOWS */

    return rc;
}
Ejemplo n.º 24
0
/**
 * Destroys a PDM thread.
 *
 * This will wakeup the thread, tell it to terminate, and wait for it terminate.
 *
 * @returns VBox status code.
 *          This reflects the success off destroying the thread and not the exit code
 *          of the thread as this is stored in *pRcThread.
 * @param   pThread         The thread to destroy.
 * @param   pRcThread       Where to store the thread exit code. Optional.
 * @thread  The emulation thread (EMT).
 */
VMMR3DECL(int) PDMR3ThreadDestroy(PPDMTHREAD pThread, int *pRcThread)
{
    /*
     * Assert sanity.
     */
    AssertPtrReturn(pThread, VERR_INVALID_POINTER);
    AssertReturn(pThread->u32Version == PDMTHREAD_VERSION, VERR_INVALID_MAGIC);
    Assert(pThread->Thread != RTThreadSelf());
    AssertPtrNullReturn(pRcThread, VERR_INVALID_POINTER);
    PVM pVM = pThread->Internal.s.pVM;
    VM_ASSERT_EMT(pVM);
    PUVM pUVM = pVM->pUVM;

    /*
     * Advance the thread to the terminating state.
     */
    int rc = VINF_SUCCESS;
    if (pThread->enmState <= PDMTHREADSTATE_TERMINATING)
    {
        for (;;)
        {
            PDMTHREADSTATE enmState = pThread->enmState;
            switch (enmState)
            {
                case PDMTHREADSTATE_RUNNING:
                    if (!pdmR3AtomicCmpXchgState(pThread, PDMTHREADSTATE_TERMINATING, enmState))
                        continue;
                    rc = pdmR3ThreadWakeUp(pThread);
                    break;

                case PDMTHREADSTATE_SUSPENDED:
                case PDMTHREADSTATE_SUSPENDING:
                case PDMTHREADSTATE_RESUMING:
                case PDMTHREADSTATE_INITIALIZING:
                    if (!pdmR3AtomicCmpXchgState(pThread, PDMTHREADSTATE_TERMINATING, enmState))
                        continue;
                    break;

                case PDMTHREADSTATE_TERMINATING:
                case PDMTHREADSTATE_TERMINATED:
                    break;

                default:
                    AssertMsgFailed(("enmState=%d\n", enmState));
                    rc = VERR_PDM_THREAD_IPE_2;
                    break;
            }
            break;
        }
    }
    int rc2 = RTSemEventMultiSignal(pThread->Internal.s.BlockEvent);
    AssertRC(rc2);

    /*
     * Wait for it to terminate and the do cleanups.
     */
    rc2 = RTThreadWait(pThread->Thread, RT_SUCCESS(rc) ? 60*1000 : 150, pRcThread);
    if (RT_SUCCESS(rc2))
    {
        /* make it invalid. */
        pThread->u32Version = 0xffffffff;
        pThread->enmState = PDMTHREADSTATE_INVALID;
        pThread->Thread = NIL_RTTHREAD;

        /* unlink */
        RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
        if (pUVM->pdm.s.pThreads == pThread)
        {
            pUVM->pdm.s.pThreads = pThread->Internal.s.pNext;
            if (!pThread->Internal.s.pNext)
                pUVM->pdm.s.pThreadsTail = NULL;
        }
        else
        {
            PPDMTHREAD pPrev = pUVM->pdm.s.pThreads;
            while (pPrev && pPrev->Internal.s.pNext != pThread)
                pPrev = pPrev->Internal.s.pNext;
            Assert(pPrev);
            if (pPrev)
                pPrev->Internal.s.pNext = pThread->Internal.s.pNext;
            if (!pThread->Internal.s.pNext)
                pUVM->pdm.s.pThreadsTail = pPrev;
        }
        pThread->Internal.s.pNext = NULL;
        RTCritSectLeave(&pUVM->pdm.s.ListCritSect);

        /* free the resources */
        RTSemEventMultiDestroy(pThread->Internal.s.BlockEvent);
        pThread->Internal.s.BlockEvent = NIL_RTSEMEVENTMULTI;

        RTSemEventMultiDestroy(pThread->Internal.s.SleepEvent);
        pThread->Internal.s.SleepEvent = NIL_RTSEMEVENTMULTI;

        MMR3HeapFree(pThread);
    }
    else if (RT_SUCCESS(rc))
        rc = rc2;

    return rc;
}
Ejemplo n.º 25
0
DECLINLINE(int) vboxPciGlobalsLock(PVBOXRAWPCIGLOBALS pGlobals)
{
    int rc = RTSemFastMutexRequest(pGlobals->hFastMtx);
    AssertRC(rc);
    return rc;
}
Ejemplo n.º 26
0
/**
 * The PDM thread function.
 *
 * @returns return from pfnThread.
 *
 * @param   Thread  The thread handle.
 * @param   pvUser  Pointer to the PDMTHREAD structure.
 */
static DECLCALLBACK(int) pdmR3ThreadMain(RTTHREAD Thread, void *pvUser)
{
    PPDMTHREAD pThread = (PPDMTHREAD)pvUser;
    Log(("PDMThread: Initializing thread %RTthrd / %p / '%s'...\n", Thread, pThread, RTThreadGetName(Thread)));
    pThread->Thread = Thread;

    PUVM pUVM = pThread->Internal.s.pVM->pUVM;
    if (   pUVM->pVmm2UserMethods
        && pUVM->pVmm2UserMethods->pfnNotifyPdmtInit)
        pUVM->pVmm2UserMethods->pfnNotifyPdmtInit(pUVM->pVmm2UserMethods, pUVM);

    /*
     * The run loop.
     *
     * It handles simple thread functions which returns when they see a suspending
     * request and leaves the PDMR3ThreadIAmSuspending and PDMR3ThreadIAmRunning
     * parts to us.
     */
    int rc;
    for (;;)
    {
        switch (pThread->Internal.s.enmType)
        {
            case PDMTHREADTYPE_DEVICE:
                rc = pThread->u.Dev.pfnThread(pThread->u.Dev.pDevIns, pThread);
                break;

            case PDMTHREADTYPE_USB:
                rc = pThread->u.Usb.pfnThread(pThread->u.Usb.pUsbIns, pThread);
                break;

            case PDMTHREADTYPE_DRIVER:
                rc = pThread->u.Drv.pfnThread(pThread->u.Drv.pDrvIns, pThread);
                break;

            case PDMTHREADTYPE_INTERNAL:
                rc = pThread->u.Int.pfnThread(pThread->Internal.s.pVM, pThread);
                break;

            case PDMTHREADTYPE_EXTERNAL:
                rc = pThread->u.Ext.pfnThread(pThread);
                break;

            default:
                AssertMsgFailed(("%d\n", pThread->Internal.s.enmType));
                rc = VERR_PDM_THREAD_IPE_1;
                break;
        }
        if (RT_FAILURE(rc))
            break;

        /*
         * If this is a simple thread function, the state will be suspending
         * or initializing now. If it isn't we're supposed to terminate.
         */
        if (    pThread->enmState != PDMTHREADSTATE_SUSPENDING
            &&  pThread->enmState != PDMTHREADSTATE_INITIALIZING)
        {
            Assert(pThread->enmState == PDMTHREADSTATE_TERMINATING);
            break;
        }
        rc = PDMR3ThreadIAmSuspending(pThread);
        if (RT_FAILURE(rc))
            break;
        if (pThread->enmState != PDMTHREADSTATE_RESUMING)
        {
            Assert(pThread->enmState == PDMTHREADSTATE_TERMINATING);
            break;
        }

        rc = PDMR3ThreadIAmRunning(pThread);
        if (RT_FAILURE(rc))
            break;
    }

    if (RT_FAILURE(rc))
        LogRel(("PDMThread: Thread '%s' (%RTthrd) quit unexpectedly with rc=%Rrc.\n", RTThreadGetName(Thread), Thread, rc));

    /*
     * Advance the state to terminating and then on to terminated.
     */
    for (;;)
    {
        PDMTHREADSTATE enmState = pThread->enmState;
        if (    enmState == PDMTHREADSTATE_TERMINATING
            ||  pdmR3AtomicCmpXchgState(pThread, PDMTHREADSTATE_TERMINATING, enmState))
            break;
    }

    ASMAtomicXchgSize(&pThread->enmState, PDMTHREADSTATE_TERMINATED);
    int rc2 = RTThreadUserSignal(Thread); AssertRC(rc2);

    if (   pUVM->pVmm2UserMethods
        && pUVM->pVmm2UserMethods->pfnNotifyPdmtTerm)
        pUVM->pVmm2UserMethods->pfnNotifyPdmtTerm(pUVM->pVmm2UserMethods, pUVM);
    Log(("PDMThread: Terminating thread %RTthrd / %p / '%s': %Rrc\n", Thread, pThread, RTThreadGetName(Thread), rc));
    return rc;
}
Ejemplo n.º 27
0
RTDECL(int) RTReqQueueProcess(RTREQQUEUE hQueue, RTMSINTERVAL cMillies)
{
    LogFlow(("RTReqProcess %x\n", hQueue));

    /*
     * Check input.
     */
    PRTREQQUEUEINT pQueue = hQueue;
    AssertPtrReturn(pQueue, VERR_INVALID_HANDLE);
    AssertReturn(pQueue->u32Magic == RTREQQUEUE_MAGIC, VERR_INVALID_HANDLE);

    /*
     * Process loop.
     *
     * We do not repeat the outer loop if we've got an informational status code
     * since that code needs processing by our caller.
     */
    int rc = VINF_SUCCESS;
    while (rc <= VINF_SUCCESS)
    {
        /*
         * Get pending requests.
         */
        PRTREQ pReqs = ASMAtomicXchgPtrT(&pQueue->pReqs, NULL, PRTREQ);
        if (!pReqs)
        {
            ASMAtomicWriteBool(&pQueue->fBusy, false); /* this aint 100% perfect, but it's good enough for now... */
            /** @todo We currently don't care if the entire time wasted here is larger than
             *        cMillies */
            rc = RTSemEventWait(pQueue->EventSem, cMillies);
            if (rc != VINF_SUCCESS)
                break;
            continue;
        }
        ASMAtomicWriteBool(&pQueue->fBusy, true);

        /*
         * Reverse the list to process it in FIFO order.
         */
        PRTREQ pReq = pReqs;
        if (pReq->pNext)
            Log2(("RTReqProcess: 2+ requests: %p %p %p\n", pReq, pReq->pNext, pReq->pNext->pNext));
        pReqs = NULL;
        while (pReq)
        {
            Assert(pReq->enmState == RTREQSTATE_QUEUED);
            Assert(pReq->uOwner.hQueue == pQueue);
            PRTREQ pCur = pReq;
            pReq = pReq->pNext;
            pCur->pNext = pReqs;
            pReqs = pCur;
        }


        /*
         * Process the requests.
         */
        while (pReqs)
        {
            /* Unchain the first request and advance the list. */
            pReq = pReqs;
            pReqs = pReqs->pNext;
            pReq->pNext = NULL;

            /* Process the request */
            rc = rtReqProcessOne(pReq);
            AssertRC(rc);
            if (rc != VINF_SUCCESS)
                break; /** @todo r=bird: we're dropping requests here! Add 2nd queue that can hold them. (will fix when writing a testcase)  */
        }
    }

    LogFlow(("RTReqProcess: returns %Rrc\n", rc));
    return rc;
}
/**
 * Deals with the contended case in ring-3 and ring-0.
 *
 * @retval  VINF_SUCCESS on success.
 * @retval  VERR_SEM_DESTROYED if destroyed.
 *
 * @param   pCritSect           The critsect.
 * @param   hNativeSelf         The native thread handle.
 */
static int pdmR3R0CritSectEnterContended(PPDMCRITSECT pCritSect, RTNATIVETHREAD hNativeSelf, PCRTLOCKVALSRCPOS pSrcPos)
{
    /*
     * Start waiting.
     */
    if (ASMAtomicIncS32(&pCritSect->s.Core.cLockers) == 0)
        return pdmCritSectEnterFirst(pCritSect, hNativeSelf, pSrcPos);
# ifdef IN_RING3
    STAM_COUNTER_INC(&pCritSect->s.StatContentionR3);
# else
    STAM_COUNTER_INC(&pCritSect->s.StatContentionRZLock);
# endif

    /*
     * The wait loop.
     */
    PSUPDRVSESSION  pSession    = pCritSect->s.CTX_SUFF(pVM)->pSession;
    SUPSEMEVENT     hEvent      = (SUPSEMEVENT)pCritSect->s.Core.EventSem;
# ifdef IN_RING3
#  ifdef PDMCRITSECT_STRICT
    RTTHREAD        hThreadSelf = RTThreadSelfAutoAdopt();
    int rc2 = RTLockValidatorRecExclCheckOrder(pCritSect->s.Core.pValidatorRec, hThreadSelf, pSrcPos, RT_INDEFINITE_WAIT);
    if (RT_FAILURE(rc2))
        return rc2;
#  else
    RTTHREAD        hThreadSelf = RTThreadSelf();
#  endif
# endif
    for (;;)
    {
        /*
         * Do the wait.
         *
         * In ring-3 this gets cluttered by lock validation and thread state
         * maintainence.
         *
         * In ring-0 we have to deal with the possibility that the thread has
         * been signalled and the interruptible wait function returning
         * immediately.  In that case we do normal R0/RC rcBusy handling.
         */
# ifdef IN_RING3
#  ifdef PDMCRITSECT_STRICT
        int rc9 = RTLockValidatorRecExclCheckBlocking(pCritSect->s.Core.pValidatorRec, hThreadSelf, pSrcPos,
                                                      !(pCritSect->s.Core.fFlags & RTCRITSECT_FLAGS_NO_NESTING),
                                                      RT_INDEFINITE_WAIT, RTTHREADSTATE_CRITSECT, true);
        if (RT_FAILURE(rc9))
            return rc9;
#  else
        RTThreadBlocking(hThreadSelf, RTTHREADSTATE_CRITSECT, true);
#  endif
        int rc = SUPSemEventWaitNoResume(pSession, hEvent, RT_INDEFINITE_WAIT);
        RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_CRITSECT);
# else  /* IN_RING0 */
        int rc = SUPSemEventWaitNoResume(pSession, hEvent, RT_INDEFINITE_WAIT);
# endif /* IN_RING0 */

        /*
         * Deal with the return code and critsect destruction.
         */
        if (RT_UNLIKELY(pCritSect->s.Core.u32Magic != RTCRITSECT_MAGIC))
            return VERR_SEM_DESTROYED;
        if (rc == VINF_SUCCESS)
            return pdmCritSectEnterFirst(pCritSect, hNativeSelf, pSrcPos);
        AssertMsg(rc == VERR_INTERRUPTED, ("rc=%Rrc\n", rc));

# ifdef IN_RING0
        /* Something is pending (signal, APC, debugger, whatever), just go back
           to ring-3 so the kernel can deal with it when leaving kernel context.

           Note! We've incremented cLockers already and cannot safely decrement
                 it without creating a race with PDMCritSectLeave, resulting in
                 spurious wakeups. */
        PVM     pVM   = pCritSect->s.CTX_SUFF(pVM); AssertPtr(pVM);
        PVMCPU  pVCpu = VMMGetCpu(pVM);             AssertPtr(pVCpu);
        rc = VMMRZCallRing3(pVM, pVCpu, VMMCALLRING3_VM_R0_PREEMPT, NULL);
        AssertRC(rc);
# endif
    }
    /* won't get here */
}
Ejemplo n.º 29
0
/**
 * Construct a disk integrity driver instance.
 *
 * @copydoc FNPDMDRVCONSTRUCT
 */
static DECLCALLBACK(int) drvdiskintConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
{
    int rc = VINF_SUCCESS;
    PDRVDISKINTEGRITY pThis = PDMINS_2_DATA(pDrvIns, PDRVDISKINTEGRITY);
    LogFlow(("drvdiskintConstruct: iInstance=%d\n", pDrvIns->iInstance));
    PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);

    /*
     * Validate configuration.
     */
    if (!CFGMR3AreValuesValid(pCfg, "CheckConsistency\0"
                                    "TraceRequests\0"
                                    "CheckIntervalMs\0"
                                    "ExpireIntervalMs\0"
                                    "CheckDoubleCompletions\0"
                                    "HistorySize\0"
                                    "IoLog\0"))
        return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;

    rc = CFGMR3QueryBoolDef(pCfg, "CheckConsistency", &pThis->fCheckConsistency, false);
    AssertRC(rc);
    rc = CFGMR3QueryBoolDef(pCfg, "TraceRequests", &pThis->fTraceRequests, false);
    AssertRC(rc);
    rc = CFGMR3QueryU32Def(pCfg, "CheckIntervalMs", &pThis->uCheckIntervalMs, 5000); /* 5 seconds */
    AssertRC(rc);
    rc = CFGMR3QueryU32Def(pCfg, "ExpireIntervalMs", &pThis->uExpireIntervalMs, 20000); /* 20 seconds */
    AssertRC(rc);
    rc = CFGMR3QueryBoolDef(pCfg, "CheckDoubleCompletions", &pThis->fCheckDoubleCompletion, false);
    AssertRC(rc);
    rc = CFGMR3QueryU32Def(pCfg, "HistorySize", &pThis->cEntries, 512);
    AssertRC(rc);

    char *pszIoLogFilename = NULL;
    rc = CFGMR3QueryStringAlloc(pCfg, "IoLog", &pszIoLogFilename);
    Assert(RT_SUCCESS(rc) || rc == VERR_CFGM_VALUE_NOT_FOUND);

    /*
     * Initialize most of the data members.
     */
    pThis->pDrvIns                       = pDrvIns;

    /* IBase. */
    pDrvIns->IBase.pfnQueryInterface     = drvdiskintQueryInterface;

    /* IMedia */
    pThis->IMedia.pfnRead                = drvdiskintRead;
    pThis->IMedia.pfnWrite               = drvdiskintWrite;
    pThis->IMedia.pfnFlush               = drvdiskintFlush;
    pThis->IMedia.pfnGetSize             = drvdiskintGetSize;
    pThis->IMedia.pfnIsReadOnly          = drvdiskintIsReadOnly;
    pThis->IMedia.pfnBiosGetPCHSGeometry = drvdiskintBiosGetPCHSGeometry;
    pThis->IMedia.pfnBiosSetPCHSGeometry = drvdiskintBiosSetPCHSGeometry;
    pThis->IMedia.pfnBiosGetLCHSGeometry = drvdiskintBiosGetLCHSGeometry;
    pThis->IMedia.pfnBiosSetLCHSGeometry = drvdiskintBiosSetLCHSGeometry;
    pThis->IMedia.pfnGetUuid             = drvdiskintGetUuid;

    /* IMediaAsync */
    pThis->IMediaAsync.pfnStartRead      = drvdiskintStartRead;
    pThis->IMediaAsync.pfnStartWrite     = drvdiskintStartWrite;
    pThis->IMediaAsync.pfnStartFlush     = drvdiskintStartFlush;

    /* IMediaAsyncPort. */
    pThis->IMediaAsyncPort.pfnTransferCompleteNotify  = drvdiskintAsyncTransferCompleteNotify;

    /* IMediaPort. */
    pThis->IMediaPort.pfnQueryDeviceLocation = drvdiskintQueryDeviceLocation;

    /* Query the media port interface above us. */
    pThis->pDrvMediaPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIMEDIAPORT);
    if (!pThis->pDrvMediaPort)
        return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_MISSING_INTERFACE_BELOW,
                                N_("No media port inrerface above"));

    /* Try to attach async media port interface above.*/
    pThis->pDrvMediaAsyncPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIMEDIAASYNCPORT);

    /*
     * Try attach driver below and query it's media interface.
     */
    PPDMIBASE pBase;
    rc = PDMDrvHlpAttach(pDrvIns, fFlags, &pBase);
    if (RT_FAILURE(rc))
        return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
                                   N_("Failed to attach driver below us! %Rrc"), rc);

    pThis->pDrvMedia = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIA);
    if (!pThis->pDrvMedia)
        return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_MISSING_INTERFACE_BELOW,
                                N_("No media or async media interface below"));

    pThis->pDrvMediaAsync = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIAASYNC);

    if (pThis->pDrvMedia->pfnDiscard)
        pThis->IMedia.pfnDiscard = drvdiskintDiscard;

    if (pThis->fCheckConsistency)
    {
        /* Create the AVL tree. */
        pThis->pTreeSegments = (PAVLRFOFFTREE)RTMemAllocZ(sizeof(AVLRFOFFTREE));
        if (!pThis->pTreeSegments)
            rc = VERR_NO_MEMORY;
    }

    if (pThis->fTraceRequests)
    {
        for (unsigned i = 0; i < RT_ELEMENTS(pThis->apReqActive); i++)
        {
            pThis->apReqActive[i].pIoReq  = NULL;
            pThis->apReqActive[i].tsStart = 0;
        }

        pThis->iNextFreeSlot = 0;

        /* Init event semaphore. */
        rc = RTSemEventCreate(&pThis->SemEvent);
        AssertRC(rc);
        pThis->fRunning = true;
        rc = RTThreadCreate(&pThis->hThread, drvdiskIntIoReqExpiredCheck, pThis,
                            0, RTTHREADTYPE_INFREQUENT_POLLER, 0, "DiskIntegrity");
        AssertRC(rc);
    }

    if (pThis->fCheckDoubleCompletion)
    {
        pThis->iEntry = 0;
        pThis->papIoReq = (PDRVDISKAIOREQ *)RTMemAllocZ(pThis->cEntries * sizeof(PDRVDISKAIOREQ));
        AssertPtr(pThis->papIoReq);
    }

    if (pszIoLogFilename)
    {
        rc = VDDbgIoLogCreate(&pThis->hIoLogger, pszIoLogFilename, VDDBG_IOLOG_LOG_DATA);
        MMR3HeapFree(pszIoLogFilename);
    }

    return rc;
}
Ejemplo n.º 30
0
/**
 * Initializes the COM runtime.
 *
 * This method must be called on each thread of the client application that
 * wants to access COM facilities. The initialization must be performed before
 * calling any other COM method or attempting to instantiate COM objects.
 *
 * On platforms using XPCOM, this method uses the following scheme to search for
 * XPCOM runtime:
 *
 * 1. If the VBOX_APP_HOME environment variable is set, the path it specifies
 *    is used to search XPCOM libraries and components. If this method fails to
 *    initialize XPCOM runtime using this path, it will immediately return a
 *    failure and will NOT check for other paths as described below.
 *
 * 2. If VBOX_APP_HOME is not set, this methods tries the following paths in the
 *    given order:
 *
 *    a) Compiled-in application data directory (as returned by
 *       RTPathAppPrivateArch())
 *    b) "/usr/lib/virtualbox" (Linux only)
 *    c) "/opt/VirtualBox" (Linux only)
 *
 *    The first path for which the initialization succeeds will be used.
 *
 * On MS COM platforms, the COM runtime is provided by the system and does not
 * need to be searched for.
 *
 * Once the COM subsystem is no longer necessary on a given thread, Shutdown()
 * must be called to free resources allocated for it. Note that a thread may
 * call Initialize() several times but for each of tese calls there must be a
 * corresponding Shutdown() call.
 *
 * @return S_OK on success and a COM result code in case of failure.
 */
HRESULT Initialize(bool fGui)
{
    HRESULT rc = E_FAIL;

#if !defined(VBOX_WITH_XPCOM)

    /*
     * We initialize COM in GUI thread in STA, to be compliant with QT and
     * OLE requirments (for example to allow D&D), while other threads
     * initialized in regular MTA. To allow fast proxyless access from
     * GUI thread to COM objects, we explicitly provide our COM objects
     * with free threaded marshaller.
     * !!!!! Please think twice before touching this code !!!!!
     */
    DWORD flags = fGui ?
                  COINIT_APARTMENTTHREADED
                | COINIT_SPEED_OVER_MEMORY
                :
                  COINIT_MULTITHREADED
                | COINIT_DISABLE_OLE1DDE
                | COINIT_SPEED_OVER_MEMORY;

    rc = CoInitializeEx(NULL, flags);

    /* the overall result must be either S_OK or S_FALSE (S_FALSE means
     * "already initialized using the same apartment model") */
    AssertMsg(rc == S_OK || rc == S_FALSE, ("rc=%08X\n", rc));

    /* To be flow compatible with the XPCOM case, we return here if this isn't
     * the main thread or if it isn't its first initialization call.
     * Note! CoInitializeEx and CoUninitialize does it's own reference
     *       counting, so this exercise is entirely for the EventQueue init. */
    bool fRc;
    RTTHREAD hSelf = RTThreadSelf();
    if (hSelf != NIL_RTTHREAD)
        ASMAtomicCmpXchgHandle(&gCOMMainThread, hSelf, NIL_RTTHREAD, fRc);
    else
        fRc = false;

    if (fGui)
        Assert(RTThreadIsMain(hSelf));

    if (!fRc)
    {
        if (   gCOMMainThread == hSelf
            && SUCCEEDED(rc))
            gCOMMainInitCount++;

        AssertComRC(rc);
        return rc;
    }
    Assert(RTThreadIsMain(hSelf));

    /* this is the first main thread initialization */
    Assert(gCOMMainInitCount == 0);
    if (SUCCEEDED(rc))
        gCOMMainInitCount = 1;

#else /* !defined (VBOX_WITH_XPCOM) */

    /* Unused here */
    NOREF(fGui);

    if (ASMAtomicXchgBool(&gIsXPCOMInitialized, true) == true)
    {
        /* XPCOM is already initialized on the main thread, no special
         * initialization is necessary on additional threads. Just increase
         * the init counter if it's a main thread again (to correctly support
         * nested calls to Initialize()/Shutdown() for compatibility with
         * Win32). */

        nsCOMPtr<nsIEventQueue> eventQ;
        rc = NS_GetMainEventQ(getter_AddRefs(eventQ));

        if (NS_SUCCEEDED(rc))
        {
            PRBool isOnMainThread = PR_FALSE;
            rc = eventQ->IsOnCurrentThread(&isOnMainThread);
            if (NS_SUCCEEDED(rc) && isOnMainThread)
                ++gXPCOMInitCount;
        }

        AssertComRC(rc);
        return rc;
    }
    Assert(RTThreadIsMain(RTThreadSelf()));

    /* this is the first initialization */
    gXPCOMInitCount = 1;
    bool const fInitEventQueues = true;

    /* prepare paths for registry files */
    char szCompReg[RTPATH_MAX];
    char szXptiDat[RTPATH_MAX];

    int vrc = GetVBoxUserHomeDirectory(szCompReg, sizeof(szCompReg));
    if (vrc == VERR_ACCESS_DENIED)
        return NS_ERROR_FILE_ACCESS_DENIED;
    AssertRCReturn(vrc, NS_ERROR_FAILURE);
    strcpy(szXptiDat, szCompReg);

    vrc = RTPathAppend(szCompReg, sizeof(szCompReg), "compreg.dat");
    AssertRCReturn(vrc, NS_ERROR_FAILURE);
    vrc = RTPathAppend(szXptiDat, sizeof(szXptiDat), "xpti.dat");
    AssertRCReturn(vrc, NS_ERROR_FAILURE);

    LogFlowFunc(("component registry  : \"%s\"\n", szCompReg));
    LogFlowFunc(("XPTI data file      : \"%s\"\n", szXptiDat));

#if defined (XPCOM_GLUE)
    XPCOMGlueStartup(nsnull);
#endif

    static const char *kAppPathsToProbe[] =
    {
        NULL, /* 0: will use VBOX_APP_HOME */
        NULL, /* 1: will try RTPathAppPrivateArch() */
#ifdef RT_OS_LINUX
        "/usr/lib/virtualbox",
        "/opt/VirtualBox",
#elif RT_OS_SOLARIS
        "/opt/VirtualBox/amd64",
        "/opt/VirtualBox/i386",
#elif RT_OS_DARWIN
        "/Application/VirtualBox.app/Contents/MacOS",
#endif
    };

    /* Find out the directory where VirtualBox binaries are located */
    for (size_t i = 0; i < RT_ELEMENTS(kAppPathsToProbe); ++ i)
    {
        char szAppHomeDir[RTPATH_MAX];

        if (i == 0)
        {
            /* Use VBOX_APP_HOME if present */
            vrc = RTEnvGetEx(RTENV_DEFAULT, "VBOX_APP_HOME", szAppHomeDir, sizeof(szAppHomeDir), NULL);
            if (vrc == VERR_ENV_VAR_NOT_FOUND)
                continue;
            AssertRC(vrc);
        }
        else if (i == 1)
        {
            /* Use RTPathAppPrivateArch() first */
            vrc = RTPathAppPrivateArch(szAppHomeDir, sizeof(szAppHomeDir));
            AssertRC(vrc);
        }
        else
        {
            /* Iterate over all other paths */
            szAppHomeDir[RTPATH_MAX - 1] = '\0';
            strncpy(szAppHomeDir, kAppPathsToProbe[i], RTPATH_MAX - 1);
            vrc = VINF_SUCCESS;
        }
        if (RT_FAILURE(vrc))
        {
            rc = NS_ERROR_FAILURE;
            continue;
        }

        char szCompDir[RTPATH_MAX];
        vrc = RTPathAppend(strcpy(szCompDir, szAppHomeDir), sizeof(szCompDir), "components");
        if (RT_FAILURE(vrc))
        {
            rc = NS_ERROR_FAILURE;
            continue;
        }
        LogFlowFunc(("component directory : \"%s\"\n", szCompDir));

        nsCOMPtr<DirectoryServiceProvider> dsProv;
        dsProv = new DirectoryServiceProvider();
        if (dsProv)
            rc = dsProv->init(szCompReg, szXptiDat, szCompDir, szAppHomeDir);
        else
            rc = NS_ERROR_OUT_OF_MEMORY;
        if (NS_FAILED(rc))
            break;

        /* Setup the application path for NS_InitXPCOM2. Note that we properly
         * answer the NS_XPCOM_CURRENT_PROCESS_DIR query in our directory
         * service provider but it seems to be activated after the directory
         * service is used for the first time (see the source NS_InitXPCOM2). So
         * use the same value here to be on the safe side. */
        nsCOMPtr <nsIFile> appDir;
        {
            char *appDirCP = NULL;
            vrc = RTStrUtf8ToCurrentCP(&appDirCP, szAppHomeDir);
            if (RT_SUCCESS(vrc))
            {
                nsCOMPtr<nsILocalFile> file;
                rc = NS_NewNativeLocalFile(nsEmbedCString(appDirCP),
                                           PR_FALSE, getter_AddRefs(file));
                if (NS_SUCCEEDED(rc))
                    appDir = do_QueryInterface(file, &rc);

                RTStrFree(appDirCP);
            }
            else
                rc = NS_ERROR_FAILURE;
        }
        if (NS_FAILED(rc))
            break;

        /* Set VBOX_XPCOM_HOME to the same app path to make XPCOM sources that
         * still use it instead of the directory service happy */
        vrc = RTEnvSetEx(RTENV_DEFAULT, "VBOX_XPCOM_HOME", szAppHomeDir);
        AssertRC(vrc);

        /* Finally, initialize XPCOM */
        {
            nsCOMPtr<nsIServiceManager> serviceManager;
            rc = NS_InitXPCOM2(getter_AddRefs(serviceManager), appDir, dsProv);
            if (NS_SUCCEEDED(rc))
            {
                nsCOMPtr<nsIComponentRegistrar> registrar =
                    do_QueryInterface(serviceManager, &rc);
                if (NS_SUCCEEDED(rc))
                {
                    rc = registrar->AutoRegister(nsnull);
                    if (NS_SUCCEEDED(rc))
                    {
                        /* We succeeded, stop probing paths */
                        LogFlowFunc(("Succeeded.\n"));
                        break;
                    }
                }
            }
        }

        /* clean up before the new try */
        rc = NS_ShutdownXPCOM(nsnull);

        if (i == 0)
        {
            /* We failed with VBOX_APP_HOME, don't probe other paths */
            break;
        }
    }

#endif /* !defined (VBOX_WITH_XPCOM) */

    // for both COM and XPCOM, we only get here if this is the main thread;
    // only then initialize the autolock system (AutoLock.cpp)
    Assert(RTThreadIsMain(RTThreadSelf()));
    util::InitAutoLockSystem();

    AssertComRC(rc);

    /*
     * Init the main event queue (ASSUMES it cannot fail).
     */
    if (SUCCEEDED(rc))
        EventQueue::init();

    return rc;
}