/* static */
int getDriveInfoFromSysfs(DriveInfoList *pList, bool isDVD, bool *pfSuccess)
{
    AssertPtrReturn(pList, VERR_INVALID_POINTER);
    AssertPtrNullReturn(pfSuccess, VERR_INVALID_POINTER); /* Valid or Null */
    LogFlowFunc (("pList=%p, isDVD=%u, pfSuccess=%p\n",
                  pList, (unsigned) isDVD, pfSuccess));
    RTDIR hDir;
    int rc;
    bool fSuccess = false;
    unsigned cFound = 0;

    if (!RTPathExists("/sys"))
        return VINF_SUCCESS;
    rc = RTDirOpen(&hDir, "/sys/block");
    /* This might mean that sysfs semantics have changed */
    AssertReturn(rc != VERR_FILE_NOT_FOUND, VINF_SUCCESS);
    fSuccess = true;
    if (RT_SUCCESS(rc))
    {
        for (;;)
        {
            RTDIRENTRY entry;
            rc = RTDirRead(hDir, &entry, NULL);
            Assert(rc != VERR_BUFFER_OVERFLOW);  /* Should never happen... */
            if (RT_FAILURE(rc))  /* Including overflow and no more files */
                break;
            if (entry.szName[0] == '.')
                continue;
            sysfsBlockDev dev(entry.szName, isDVD);
            /* This might mean that sysfs semantics have changed */
            AssertBreakStmt(dev.isConsistent(), fSuccess = false);
            if (!dev.isValid())
                continue;
            try
            {
                pList->push_back(DriveInfo(dev.getNode(), dev.getUdi(), dev.getDesc()));
            }
            catch(std::bad_alloc &e)
            {
                rc = VERR_NO_MEMORY;
                break;
            }
            ++cFound;
        }
        RTDirClose(hDir);
    }
    if (rc == VERR_NO_MORE_FILES)
        rc = VINF_SUCCESS;
    if (RT_FAILURE(rc))
        /* Clean up again */
        for (unsigned i = 0; i < cFound; ++i)
            pList->pop_back();
    if (pfSuccess)
        *pfSuccess = fSuccess;
    LogFlow (("rc=%Rrc, fSuccess=%u\n", rc, (unsigned) fSuccess));
    return rc;
}
static DECLCALLBACK(int) drvHostALSAAudioCaptureIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
                                                   uint32_t *pcSamplesCaptured)
{
    NOREF(pInterface);
    AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);

    PALSAAUDIOSTREAMIN pThisStrmIn = (PALSAAUDIOSTREAMIN)pHstStrmIn;

    snd_pcm_sframes_t cAvail;
    int rc = drvHostALSAAudioGetAvail(pThisStrmIn->phPCM, &cAvail);
    if (RT_FAILURE(rc))
    {
        LogFunc(("Error getting number of captured frames, rc=%Rrc\n", rc));
        return rc;
    }

    if (!cAvail) /* No data yet? */
    {
        snd_pcm_state_t state = snd_pcm_state(pThisStrmIn->phPCM);
        switch (state)
        {
            case SND_PCM_STATE_PREPARED:
                cAvail = AudioMixBufFree(&pHstStrmIn->MixBuf);
                break;

            case SND_PCM_STATE_SUSPENDED:
            {
                rc = drvHostALSAAudioResume(pThisStrmIn->phPCM);
                if (RT_FAILURE(rc))
                    break;

                LogFlow(("Resuming suspended input stream\n"));
                break;
            }

            default:
                LogFlow(("No frames available, state=%d\n", state));
                break;
        }

        if (!cAvail)
        {
            if (pcSamplesCaptured)
                *pcSamplesCaptured = 0;
            return VINF_SUCCESS;
        }
    }

    /*
     * Check how much we can read from the capture device without overflowing
     * the mixer buffer.
     */
    Assert(cAvail);
    size_t cbMixFree = AudioMixBufFreeBytes(&pHstStrmIn->MixBuf);
    size_t cbToRead = RT_MIN((size_t)AUDIOMIXBUF_S2B(&pHstStrmIn->MixBuf, cAvail), cbMixFree);

    LogFlowFunc(("cbToRead=%zu, cAvail=%RI32\n", cbToRead, cAvail));

    uint32_t cWrittenTotal = 0;
    snd_pcm_uframes_t cToRead;
    snd_pcm_sframes_t cRead;

    while (   cbToRead
           && RT_SUCCESS(rc))
    {
        cToRead = RT_MIN(AUDIOMIXBUF_B2S(&pHstStrmIn->MixBuf, cbToRead),
                         AUDIOMIXBUF_B2S(&pHstStrmIn->MixBuf, pThisStrmIn->cbBuf));
        AssertBreakStmt(cToRead, rc = VERR_NO_DATA);
        cRead = snd_pcm_readi(pThisStrmIn->phPCM, pThisStrmIn->pvBuf, cToRead);
        if (cRead <= 0)
        {
            switch (cRead)
            {
                case 0:
                {
                    LogFunc(("No input frames available\n"));
                    rc = VERR_ACCESS_DENIED;
                    break;
                }

                case -EAGAIN:
                    /*
                     * Don't set error here because EAGAIN means there are no further frames
                     * available at the moment, try later. As we might have read some frames
                     * already these need to be processed instead.
                     */
                    cbToRead = 0;
                    break;

                case -EPIPE:
                {
                    rc = drvHostALSAAudioRecover(pThisStrmIn->phPCM);
                    if (RT_FAILURE(rc))
                        break;

                    LogFlowFunc(("Recovered from capturing\n"));
                    continue;
                }

                default:
                    LogFunc(("Failed to read input frames: %s\n", snd_strerror(cRead)));
                    rc = VERR_GENERAL_FAILURE; /** @todo Fudge! */
                    break;
            }
        }
        else
        {
            uint32_t cWritten;
            rc = AudioMixBufWriteCirc(&pHstStrmIn->MixBuf,
                                      pThisStrmIn->pvBuf, AUDIOMIXBUF_S2B(&pHstStrmIn->MixBuf, cRead),
                                      &cWritten);
            if (RT_FAILURE(rc))
                break;

            /*
             * We should not run into a full mixer buffer or we loose samples and
             * run into an endless loop if ALSA keeps producing samples ("null"
             * capture device for example).
             */
            AssertLogRelMsgBreakStmt(cWritten > 0, ("Mixer buffer shouldn't be full at this point!\n"),
                                     rc = VERR_INTERNAL_ERROR);
            uint32_t cbWritten = AUDIOMIXBUF_S2B(&pHstStrmIn->MixBuf, cWritten);

            Assert(cbToRead >= cbWritten);
            cbToRead -= cbWritten;
            cWrittenTotal += cWritten;
        }
    }

    if (RT_SUCCESS(rc))
    {
        uint32_t cProcessed = 0;
        if (cWrittenTotal)
            rc = AudioMixBufMixToParent(&pHstStrmIn->MixBuf, cWrittenTotal,
                                        &cProcessed);

        if (pcSamplesCaptured)
            *pcSamplesCaptured = cWrittenTotal;

        LogFlowFunc(("cWrittenTotal=%RU32 (%RU32 processed), rc=%Rrc\n",
                     cWrittenTotal, cProcessed, rc));
    }

    LogFlowFuncLeaveRC(rc);
    return rc;
}
static DECLCALLBACK(int) drvHostALSAAudioInitIn(PPDMIHOSTAUDIO pInterface,
                                                PPDMAUDIOHSTSTRMIN pHstStrmIn, PPDMAUDIOSTREAMCFG pCfg,
                                                PDMAUDIORECSOURCE enmRecSource,
                                                uint32_t *pcSamples)
{
    NOREF(pInterface);
    AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
    AssertPtrReturn(pCfg, VERR_INVALID_POINTER);

    int rc;

    PALSAAUDIOSTREAMIN pThisStrmIn = (PALSAAUDIOSTREAMIN)pHstStrmIn;
    snd_pcm_t *phPCM = NULL;

    do
    {
        ALSAAUDIOSTREAMCFG req;
        req.fmt         = drvHostALSAAudioFmtToALSA(pCfg->enmFormat);
        req.freq        = pCfg->uHz;
        req.nchannels   = pCfg->cChannels;
        req.period_size = s_ALSAConf.period_size_in;
        req.buffer_size = s_ALSAConf.buffer_size_in;

        ALSAAUDIOSTREAMCFG obt;
        rc = drvHostALSAAudioOpen(true /* fIn */, &req, &obt, &phPCM);
        if (RT_FAILURE(rc))
            break;

        PDMAUDIOFMT enmFormat;
        PDMAUDIOENDIANNESS enmEnd;
        rc = drvHostALSAAudioALSAToFmt(obt.fmt, &enmFormat, &enmEnd);
        if (RT_FAILURE(rc))
            break;

        PDMAUDIOSTREAMCFG streamCfg;
        streamCfg.uHz           = obt.freq;
        streamCfg.cChannels     = obt.nchannels;
        streamCfg.enmFormat     = enmFormat;
        streamCfg.enmEndianness = enmEnd;

        rc = drvAudioStreamCfgToProps(&streamCfg, &pHstStrmIn->Props);
        if (RT_FAILURE(rc))
            break;

        AssertBreakStmt(obt.samples, rc = VERR_INVALID_PARAMETER);
        size_t cbBuf = obt.samples * (1 << pHstStrmIn->Props.cShift);
        AssertBreakStmt(cbBuf, rc = VERR_INVALID_PARAMETER);
        pThisStrmIn->pvBuf = RTMemAlloc(cbBuf);
        if (!pThisStrmIn->pvBuf)
        {
            LogRel(("ALSA: Not enough memory for input ADC buffer (%RU32 samples, each %d bytes)\n",
                    obt.samples, 1 << pHstStrmIn->Props.cShift));
            rc = VERR_NO_MEMORY;
            break;
        }

        pThisStrmIn->cbBuf       = cbBuf;
        pThisStrmIn->phPCM       = phPCM;

        if (pcSamples)
            *pcSamples = obt.samples;
    }
    while (0);

    if (RT_FAILURE(rc))
        drvHostALSAAudioClose(&phPCM);

    LogFlowFuncLeaveRC(rc);
    return rc;
}
Esempio n. 4
0
RTDECL(int) RTLocalIpcSessionWaitForData(RTLOCALIPCSESSION hSession, uint32_t cMillies)
{
    PRTLOCALIPCSESSIONINT pThis = (PRTLOCALIPCSESSIONINT)hSession;
    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
    AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, VERR_INVALID_HANDLE);

    uint64_t const StartMsTS = RTTimeMilliTS();

    int rc = RTCritSectEnter(&pThis->CritSect);
    if (RT_FAILURE(rc))
        return rc;
    for (unsigned iLoop = 0;; iLoop++)
    {
        HANDLE hWait = INVALID_HANDLE_VALUE;

        if (pThis->fIOPending)
            hWait = pThis->OverlappedIO.hEvent;
        else
        {
            /* Peek at the pipe buffer and see how many bytes it contains. */
            DWORD cbAvailable;
            BOOL fRc = PeekNamedPipe(pThis->hNmPipe, NULL, 0, NULL, &cbAvailable, NULL);
            if (   fRc
                && cbAvailable)
            {
                rc = VINF_SUCCESS;
                break;
            }
            else if (!fRc)
            {
                rc = RTErrConvertFromWin32(GetLastError());
                break;
            }

            /* Start a zero byte read operation that we can wait on. */
            if (cMillies == 0)
            {
                rc = VERR_TIMEOUT;
                break;
            }
            AssertBreakStmt(pThis->cRefs == 1, rc = VERR_WRONG_ORDER);
            fRc = ResetEvent(pThis->OverlappedIO.hEvent); Assert(fRc == TRUE);
            DWORD cbRead = 0;
            if (ReadFile(pThis->hNmPipe, pThis->abBuf, 0, &cbRead, &pThis->OverlappedIO))
            {
                rc = VINF_SUCCESS;
                if (iLoop > 10)
                    RTThreadYield();
            }
            else if (GetLastError() == ERROR_IO_PENDING)
            {
                pThis->cRefs++;
                pThis->fIOPending = true;
                pThis->fZeroByteRead = true;
                hWait = pThis->OverlappedIO.hEvent;
            }
            else
                rc = RTErrConvertFromWin32(GetLastError());
        }

        if (RT_FAILURE(rc))
            break;

        /*
         * Check for timeout.
         */
        DWORD cMsMaxWait = INFINITE;
        if (   cMillies != RT_INDEFINITE_WAIT
            && (   hWait != INVALID_HANDLE_VALUE
                || iLoop > 10)
           )
        {
            uint64_t cElapsed = RTTimeMilliTS() - StartMsTS;
            if (cElapsed >= cMillies)
            {
                rc = VERR_TIMEOUT;
                break;
            }
            cMsMaxWait = cMillies - (uint32_t)cElapsed;
        }

        /*
         * Wait.
         */
        if (hWait != INVALID_HANDLE_VALUE)
        {
            RTCritSectLeave(&pThis->CritSect);

            DWORD dwRc = WaitForSingleObject(hWait, cMsMaxWait);
            if (dwRc == WAIT_OBJECT_0)
                rc = VINF_SUCCESS;
            else if (dwRc == WAIT_TIMEOUT)
                rc = VERR_TIMEOUT;
            else if (dwRc == WAIT_ABANDONED)
                rc = VERR_INVALID_HANDLE;
            else
                rc = RTErrConvertFromWin32(GetLastError());

            if (   RT_FAILURE(rc)
                && pThis->u32Magic != RTLOCALIPCSESSION_MAGIC)
                return rc;

            int rc2 = RTCritSectEnter(&pThis->CritSect);
            AssertRC(rc2);
            if (pThis->fZeroByteRead)
            {
                Assert(pThis->cRefs);
                pThis->cRefs--;
                pThis->fIOPending = false;

                if (rc != VINF_SUCCESS)
                {
                    BOOL fRc = CancelIo(pThis->hNmPipe);
                    Assert(fRc == TRUE);
                }

                DWORD cbRead = 0;
                BOOL fRc = GetOverlappedResult(pThis->hNmPipe, &pThis->OverlappedIO, &cbRead, TRUE /*fWait*/);
                if (   !fRc
                    && RT_SUCCESS(rc))
                {
                    DWORD dwRc = GetLastError();
                    if (dwRc == ERROR_OPERATION_ABORTED)
                        rc = VERR_CANCELLED;
                    else
                        rc = RTErrConvertFromWin32(dwRc);
                }
            }

            if (RT_FAILURE(rc))
                break;
        }
    }

    int rc2 = RTCritSectLeave(&pThis->CritSect);
    if (RT_SUCCESS(rc))
        rc = rc2;

    return rc;
}
RTDECL(int) RTEnvQueryUtf8Block(RTENV hEnv, bool fSorted, char **ppszzBlock, size_t *pcbBlock)
{
    RTENV           hClone  = NIL_RTENV;
    PRTENVINTERNAL  pIntEnv;
    int             rc;

    /*
     * Validate / simplify input.
     */
    if (hEnv == RTENV_DEFAULT)
    {
        rc = RTEnvClone(&hClone, RTENV_DEFAULT);
        if (RT_FAILURE(rc))
            return rc;
        pIntEnv = hClone;
    }
    else
    {
        pIntEnv = hEnv;
        AssertPtrReturn(pIntEnv, VERR_INVALID_HANDLE);
        AssertReturn(pIntEnv->u32Magic == RTENV_MAGIC, VERR_INVALID_HANDLE);
        rc = VINF_SUCCESS;
    }

    RTENV_LOCK(pIntEnv);

    /*
     * Sort it, if requested.
     */
    if (fSorted)
        RTSortApvShell((void **)pIntEnv->papszEnv, pIntEnv->cVars, rtEnvSortCompare, pIntEnv);

    /*
     * Calculate the size. We add one extra terminator just to be on the safe side.
     */
    size_t cbBlock = 2;
    for (size_t iVar = 0; iVar < pIntEnv->cVars; iVar++)
        cbBlock += strlen(pIntEnv->papszEnv[iVar]) + 1;

    if (pcbBlock)
        *pcbBlock = cbBlock - 1;

    /*
     * Allocate memory and copy out the variables.
     */
    char *pszzBlock;
    char *pszz = pszzBlock = (char *)RTMemAlloc(cbBlock);
    if (pszz)
    {
        size_t cbLeft = cbBlock;
        for (size_t iVar = 0; iVar < pIntEnv->cVars; iVar++)
        {
            size_t cb = strlen(pIntEnv->papszEnv[iVar]) + 1;
            AssertBreakStmt(cb + 2 <= cbLeft, rc = VERR_INTERNAL_ERROR_3);
            memcpy(pszz, pIntEnv->papszEnv[iVar], cb);
            pszz   += cb;
            cbLeft -= cb;
        }
        if (RT_SUCCESS(rc))
        {
            pszz[0] = '\0';
            pszz[1] = '\0'; /* The extra one. */
        }
        else
        {
            RTMemFree(pszzBlock);
            pszzBlock = NULL;
        }
    }
    else
        rc = VERR_NO_MEMORY;

    RTENV_UNLOCK(pIntEnv);

    if (hClone != NIL_RTENV)
        RTEnvDestroy(hClone);
    if (RT_SUCCESS(rc))
        *ppszzBlock = pszzBlock;
    return rc;
}
RTDECL(int) RTEnvQueryUtf16Block(RTENV hEnv, PRTUTF16 *ppwszzBlock)
{
    RTENV           hClone  = NIL_RTENV;
    PRTENVINTERNAL  pIntEnv;
    int             rc;

    /*
     * Validate / simplify input.
     */
    if (hEnv == RTENV_DEFAULT)
    {
        rc = RTEnvClone(&hClone, RTENV_DEFAULT);
        if (RT_FAILURE(rc))
            return rc;
        pIntEnv = hClone;
    }
    else
    {
        pIntEnv = hEnv;
        AssertPtrReturn(pIntEnv, VERR_INVALID_HANDLE);
        AssertReturn(pIntEnv->u32Magic == RTENV_MAGIC, VERR_INVALID_HANDLE);
        rc = VINF_SUCCESS;
    }

    RTENV_LOCK(pIntEnv);

    /*
     * Sort it first.
     */
    RTSortApvShell((void **)pIntEnv->papszEnv, pIntEnv->cVars, rtEnvSortCompare, pIntEnv);

    /*
     * Calculate the size.
     */
    size_t cwc;
    size_t cwcTotal = 2;
    for (size_t iVar = 0; iVar < pIntEnv->cVars; iVar++)
    {
        rc = RTStrCalcUtf16LenEx(pIntEnv->papszEnv[iVar], RTSTR_MAX, &cwc);
        AssertRCBreak(rc);
        cwcTotal += cwc + 1;
    }

    PRTUTF16 pwszzBlock = NULL;
    if (RT_SUCCESS(rc))
    {
        /*
         * Perform the conversion.
         */
        PRTUTF16 pwszz = pwszzBlock = (PRTUTF16)RTMemAlloc(cwcTotal * sizeof(RTUTF16));
        if (pwszz)
        {
            size_t cwcLeft = cwcTotal;
            for (size_t iVar = 0; iVar < pIntEnv->cVars; iVar++)
            {
                rc = RTStrToUtf16Ex(pIntEnv->papszEnv[iVar], RTSTR_MAX,
                                    &pwszz, cwcTotal - (pwszz - pwszzBlock), &cwc);
                AssertRCBreak(rc);
                pwszz   += cwc + 1;
                cwcLeft -= cwc + 1;
                AssertBreakStmt(cwcLeft >= 2, rc = VERR_INTERNAL_ERROR_3);
            }
            AssertStmt(cwcLeft == 2 || RT_FAILURE(rc), rc = VERR_INTERNAL_ERROR_2);
            if (RT_SUCCESS(rc))
            {
                pwszz[0] = '\0';
                pwszz[1] = '\0';
            }
            else
            {
                RTMemFree(pwszzBlock);
                pwszzBlock = NULL;
            }
        }
        else
            rc = VERR_NO_MEMORY;
    }

    RTENV_UNLOCK(pIntEnv);

    if (hClone != NIL_RTENV)
        RTEnvDestroy(hClone);
    if (RT_SUCCESS(rc))
        *ppwszzBlock = pwszzBlock;
    return rc;
}
Esempio n. 7
0
/**
 *  VirtualBox component constructor.
 *
 *  This constructor is responsible for starting the VirtualBox server
 *  process, connecting to it, and redirecting the constructor request to the
 *  VirtualBox component defined on the server.
 */
static NS_IMETHODIMP
VirtualBoxConstructor(nsISupports *aOuter, REFNSIID aIID,
                      void **aResult)
{
    LogFlowFuncEnter();

    nsresult rc = NS_OK;
    int vrc = VINF_SUCCESS;

    do
    {
        *aResult = NULL;
        if (NULL != aOuter)
        {
            rc = NS_ERROR_NO_AGGREGATION;
            break;
        }

        if (!IsVBoxSVCPathSet)
        {
            /* Get the directory containing XPCOM components -- the VBoxSVC
             * executable is expected in the parent directory. */
            nsCOMPtr<nsIProperties> dirServ = do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rc);
            if (NS_SUCCEEDED(rc))
            {
                nsCOMPtr<nsIFile> componentDir;
                rc = dirServ->Get(NS_XPCOM_COMPONENT_DIR,
                                  NS_GET_IID(nsIFile), getter_AddRefs(componentDir));

                if (NS_SUCCEEDED(rc))
                {
                    nsCAutoString path;
                    componentDir->GetNativePath(path);

                    LogFlowFunc(("component directory = \"%s\"\n", path.get()));
                    AssertBreakStmt(path.Length() + strlen(VBoxSVC_exe) < RTPATH_MAX,
                                    rc = NS_ERROR_FAILURE);

#if defined(RT_OS_SOLARIS) && defined(VBOX_WITH_HARDENING)
                    char achKernArch[128];
                    int cbKernArch = sysinfo(SI_ARCHITECTURE_K, achKernArch, sizeof(achKernArch));
                    if (cbKernArch > 0)
                    {
                        sprintf(VBoxSVCPath, "/opt/VirtualBox/%s%s", achKernArch, VBoxSVC_exe);
                        IsVBoxSVCPathSet = true;
                    }
                    else
                        rc = NS_ERROR_UNEXPECTED;
#else
                    strcpy(VBoxSVCPath, path.get());
                    RTPathStripFilename(VBoxSVCPath);
                    strcat(VBoxSVCPath, VBoxSVC_exe);

                    IsVBoxSVCPathSet = true;
#endif
                }
            }
            if (NS_FAILED(rc))
                break;
        }

        nsCOMPtr<ipcIService> ipcServ = do_GetService(IPC_SERVICE_CONTRACTID, &rc);
        if (NS_FAILED(rc))
            break;

        /* connect to the VBoxSVC server process */

        bool startedOnce = false;
        unsigned timeLeft = VBoxSVC_Timeout;

        do
        {
            LogFlowFunc(("Resolving server name \"%s\"...\n", VBOXSVC_IPC_NAME));

            PRUint32 serverID = 0;
            rc = ipcServ->ResolveClientName(VBOXSVC_IPC_NAME, &serverID);
            if (NS_FAILED(rc))
            {
                LogFlowFunc(("Starting server \"%s\"...\n", VBoxSVCPath));

                startedOnce = true;

                rc = vboxsvcSpawnDaemon();
                if (NS_FAILED(rc))
                    break;

                /* wait for the server process to establish a connection */
                do
                {
                    RTThreadSleep(VBoxSVC_WaitSlice);
                    rc = ipcServ->ResolveClientName(VBOXSVC_IPC_NAME, &serverID);
                    if (NS_SUCCEEDED(rc))
                        break;
                    if (timeLeft <= VBoxSVC_WaitSlice)
                    {
                        timeLeft = 0;
                        break;
                    }
                    timeLeft -= VBoxSVC_WaitSlice;
                }
                while (1);

                if (!timeLeft)
                {
                    rc = IPC_ERROR_WOULD_BLOCK;
                    break;
                }
            }

            LogFlowFunc(("Connecting to server (ID=%d)...\n", serverID));

            nsCOMPtr<ipcIDConnectService> dconServ =
                do_GetService(IPC_DCONNECTSERVICE_CONTRACTID, &rc);
            if (NS_FAILED(rc))
                break;

            rc = dconServ->CreateInstance(serverID,
                                          CLSID_VirtualBox,
                                          aIID, aResult);
            if (NS_SUCCEEDED(rc))
                break;

            LogFlowFunc(("Failed to connect (rc=%Rhrc (%#08x))\n", rc, rc));

            /* It's possible that the server gets shut down after we
             * successfully resolve the server name but before it
             * receives our CreateInstance() request. So, check for the
             * name again, and restart the cycle if it fails. */
            if (!startedOnce)
            {
                nsresult rc2 =
                    ipcServ->ResolveClientName(VBOXSVC_IPC_NAME, &serverID);
                if (NS_SUCCEEDED(rc2))
                    break;

                LogFlowFunc(("Server seems to have terminated before receiving our request. Will try again.\n"));
            }
            else
                break;
        }
        while (1);
    }
    while (0);

    LogFlowFunc(("rc=%Rhrc (%#08x), vrc=%Rrc\n", rc, rc, vrc));
    LogFlowFuncLeave();

    return rc;
}
RTDECL(int) RTVfsIoStrmReadAll(RTVFSIOSTREAM hVfsIos, void **ppvBuf, size_t *pcbBuf)
{
    /*
     * Try query the object information and in case the stream has a known
     * size we could use for guidance.
     */
    RTFSOBJINFO ObjInfo;
    int    rc = RTVfsIoStrmQueryInfo(hVfsIos, &ObjInfo, RTFSOBJATTRADD_NOTHING);
    size_t cbAllocated = RT_SUCCESS(rc) && ObjInfo.cbObject > 0 && ObjInfo.cbObject < _1G
                       ? (size_t)ObjInfo.cbObject + 1 : _16K;
    cbAllocated += READ_ALL_HEADER_SIZE;
    void *pvBuf = RTMemAlloc(cbAllocated);
    if (pvBuf)
    {
        memset(pvBuf, 0xfe, READ_ALL_HEADER_SIZE);
        size_t off = 0;
        for (;;)
        {
            /*
             * Handle buffer growing and detecting the end of it all.
             */
            size_t cbToRead = cbAllocated - off - READ_ALL_HEADER_SIZE - 1;
            if (!cbToRead)
            {
                /* The end? */
                uint8_t bIgn;
                size_t cbIgn;
                rc = RTVfsIoStrmRead(hVfsIos, &bIgn, 0, true /*fBlocking*/, &cbIgn);
                if (rc == VINF_EOF)
                    break;

                /* Grow the buffer. */
                cbAllocated -= READ_ALL_HEADER_SIZE - 1;
                cbAllocated  = RT_MAX(RT_MIN(cbAllocated, _32M), _1K);
                cbAllocated  = RT_ALIGN_Z(cbAllocated, _4K);
                cbAllocated += READ_ALL_HEADER_SIZE + 1;

                void *pvNew = RTMemRealloc(pvBuf, cbAllocated);
                AssertBreakStmt(pvNew, rc = VERR_NO_MEMORY);
                pvBuf = pvNew;

                cbToRead = cbAllocated - off - READ_ALL_HEADER_SIZE - 1;
            }
            Assert(cbToRead < cbAllocated);

            /*
             * Read.
             */
            size_t cbActual;
            rc = RTVfsIoStrmRead(hVfsIos, (uint8_t *)pvBuf + READ_ALL_HEADER_SIZE + off, cbToRead,
                                 true /*fBlocking*/, &cbActual);
            if (RT_FAILURE(rc))
                break;
            Assert(cbActual > 0);
            Assert(cbActual <= cbToRead);
            off += cbActual;
            if (rc == VINF_EOF)
                break;
        }
        Assert(rc != VERR_EOF);
        if (RT_SUCCESS(rc))
        {
            ((size_t *)pvBuf)[0] = READ_ALL_HEADER_MAGIC;
            ((size_t *)pvBuf)[1] = off;
            ((uint8_t *)pvBuf)[READ_ALL_HEADER_SIZE + off] = 0;

            *ppvBuf = (uint8_t *)pvBuf + READ_ALL_HEADER_SIZE;
            *pcbBuf = off;
            return VINF_SUCCESS;
        }

        RTMemFree(pvBuf);
    }
    else
        rc = VERR_NO_MEMORY;
    *ppvBuf = NULL;
    *pcbBuf = 0;
    return rc;
}
int main(int argc, char **argv)
{
    RTR3InitExe(argc, &argv, 0);

    /*
     * Parse arguments.
     */
    static const RTGETOPTDEF    s_aOptions[] =
    {
        { "--iterations",     'i', RTGETOPT_REQ_UINT32 },
        { "--num-pages",      'n', RTGETOPT_REQ_UINT32 },
        { "--page-at-a-time", 'c', RTGETOPT_REQ_UINT32 },
        { "--page-file",      'f', RTGETOPT_REQ_STRING },
        { "--offset",         'o', RTGETOPT_REQ_UINT64 },
    };

    const char     *pszPageFile = NULL;
    uint64_t        offPageFile = 0;
    uint32_t        cIterations = 1;
    uint32_t        cPagesAtATime = 1;
    RTGETOPTUNION   Val;
    RTGETOPTSTATE   State;
    int rc = RTGetOptInit(&State, argc, argv, &s_aOptions[0], RT_ELEMENTS(s_aOptions), 1, 0);
    AssertRCReturn(rc, 1);

    while ((rc = RTGetOpt(&State, &Val)))
    {
        switch (rc)
        {
            case 'n':
                g_cPages = Val.u32;
                if (g_cPages * PAGE_SIZE * 4 / (PAGE_SIZE * 4) != g_cPages)
                    return Error("The specified page count is too high: %#x (%#llx bytes)\n", g_cPages, (uint64_t)g_cPages * PAGE_SHIFT);
                if (g_cPages < 1)
                    return Error("The specified page count is too low: %#x\n", g_cPages);
                break;

            case 'i':
                cIterations = Val.u32;
                if (cIterations < 1)
                    return Error("The number of iterations must be 1 or higher\n");
                break;

            case 'c':
                cPagesAtATime = Val.u32;
                if (cPagesAtATime < 1 || cPagesAtATime > 10240)
                    return Error("The specified pages-at-a-time count is out of range: %#x\n", cPagesAtATime);
                break;

            case 'f':
                pszPageFile = Val.psz;
                break;

            case 'o':
                offPageFile = Val.u64;
                break;

            case 'O':
                offPageFile = Val.u64 * PAGE_SIZE;
                break;

            case 'h':
                RTPrintf("syntax: tstCompressionBenchmark [options]\n"
                         "\n"
                         "Options:\n"
                         "  -h, --help\n"
                         "    Show this help page\n"
                         "  -i, --iterations <num>\n"
                         "    The number of iterations.\n"
                         "  -n, --num-pages <pages>\n"
                         "    The number of pages.\n"
                         "  -c, --pages-at-a-time <pages>\n"
                         "    Number of pages at a time.\n"
                         "  -f, --page-file <filename>\n"
                         "    File or device to read the page from. The default\n"
                         "    is to generate some garbage.\n"
                         "  -o, --offset <file-offset>\n"
                         "    Offset into the page file to start reading at.\n");
                return 0;

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

            default:
                return RTGetOptPrintError(rc, &Val);
        }
    }

    g_cbPages = g_cPages * PAGE_SIZE;
    uint64_t cbTotal = (uint64_t)g_cPages * PAGE_SIZE * cIterations;
    uint64_t cbTotalKB = cbTotal / _1K;
    if (cbTotal / cIterations != g_cbPages)
        return Error("cPages * cIterations -> overflow\n");

    /*
     * Gather the test memory.
     */
    if (pszPageFile)
    {
        size_t cbFile;
        rc = RTFileReadAllEx(pszPageFile, offPageFile, g_cbPages, RTFILE_RDALL_O_DENY_NONE, (void **)&g_pabSrc, &cbFile);
        if (RT_FAILURE(rc))
            return Error("Error reading %zu bytes from %s at %llu: %Rrc\n", g_cbPages, pszPageFile, offPageFile, rc);
        if (cbFile != g_cbPages)
            return Error("Error reading %zu bytes from %s at %llu: got %zu bytes\n", g_cbPages, pszPageFile, offPageFile, cbFile);
    }
    else
    {
        g_pabSrc = (uint8_t *)RTMemAlloc(g_cbPages);
        if (g_pabSrc)
        {
            /* Just fill it with something - warn about the low quality of the something. */
            RTPrintf("tstCompressionBenchmark: WARNING! No input file was specified so the source\n"
                     "buffer will be filled with generated data of questionable quality.\n");
#ifdef RT_OS_LINUX
            RTPrintf("To get real RAM on linux: sudo dd if=/dev/mem ... \n");
#endif
            uint8_t *pb    = g_pabSrc;
            uint8_t *pbEnd = &g_pabSrc[g_cbPages];
            for (; pb != pbEnd; pb += 16)
            {
                char szTmp[17];
                RTStrPrintf(szTmp, sizeof(szTmp), "aaaa%08Xzzzz", (uint32_t)(uintptr_t)pb);
                memcpy(pb, szTmp, 16);
            }
        }
    }

    g_pabDecompr = (uint8_t *)RTMemAlloc(g_cbPages);
    g_cbComprAlloc = RT_MAX(g_cbPages * 2, 256 * PAGE_SIZE);
    g_pabCompr   = (uint8_t *)RTMemAlloc(g_cbComprAlloc);
    if (!g_pabSrc || !g_pabDecompr || !g_pabCompr)
        return Error("failed to allocate memory buffers (g_cPages=%#x)\n", g_cPages);

    /*
     * Double loop compressing and uncompressing the data, where the outer does
     * the specified number of iterations while the inner applies the different
     * compression algorithms.
     */
    struct
    {
        /** The time spent decompressing. */
        uint64_t    cNanoDecompr;
        /** The time spent compressing. */
        uint64_t    cNanoCompr;
        /** The size of the compressed data. */
        uint64_t    cbCompr;
        /** First error. */
        int         rc;
        /** The compression style: block or stream. */
        bool        fBlock;
        /** Compression type.  */
        RTZIPTYPE   enmType;
        /** Compression level.  */
        RTZIPLEVEL  enmLevel;
        /** Method name. */
        const char *pszName;
    } aTests[] =
    {
        { 0, 0, 0, VINF_SUCCESS, false, RTZIPTYPE_STORE, RTZIPLEVEL_DEFAULT, "RTZip/Store"      },
        { 0, 0, 0, VINF_SUCCESS, false, RTZIPTYPE_LZF,   RTZIPLEVEL_DEFAULT, "RTZip/LZF"        },
/*      { 0, 0, 0, VINF_SUCCESS, false, RTZIPTYPE_ZLIB,  RTZIPLEVEL_DEFAULT, "RTZip/zlib"       }, - slow plus it randomly hits VERR_GENERAL_FAILURE atm. */
        { 0, 0, 0, VINF_SUCCESS, true,  RTZIPTYPE_STORE, RTZIPLEVEL_DEFAULT, "RTZipBlock/Store" },
        { 0, 0, 0, VINF_SUCCESS, true,  RTZIPTYPE_LZF,   RTZIPLEVEL_DEFAULT, "RTZipBlock/LZF"   },
        { 0, 0, 0, VINF_SUCCESS, true,  RTZIPTYPE_LZJB,  RTZIPLEVEL_DEFAULT, "RTZipBlock/LZJB"  },
        { 0, 0, 0, VINF_SUCCESS, true,  RTZIPTYPE_LZO,   RTZIPLEVEL_DEFAULT, "RTZipBlock/LZO"   },
    };
    RTPrintf("tstCompressionBenchmark: TESTING..");
    for (uint32_t i = 0; i < cIterations; i++)
    {
        for (uint32_t j = 0; j < RT_ELEMENTS(aTests); j++)
        {
            if (RT_FAILURE(aTests[j].rc))
                continue;
            memset(g_pabCompr,   0xaa, g_cbComprAlloc);
            memset(g_pabDecompr, 0xcc, g_cbPages);
            g_cbCompr = 0;
            g_offComprIn = 0;
            RTPrintf("."); RTStrmFlush(g_pStdOut);

            /*
             * Compress it.
             */
            uint64_t NanoTS = RTTimeNanoTS();
            if (aTests[j].fBlock)
            {
                size_t          cbLeft    = g_cbComprAlloc;
                uint8_t const  *pbSrcPage = g_pabSrc;
                uint8_t        *pbDstPage = g_pabCompr;
                for (size_t iPage = 0; iPage < g_cPages; iPage += cPagesAtATime)
                {
                    AssertBreakStmt(cbLeft > PAGE_SIZE * 4, aTests[j].rc = rc = VERR_BUFFER_OVERFLOW);
                    uint32_t *pcb = (uint32_t *)pbDstPage;
                    pbDstPage    += sizeof(uint32_t);
                    cbLeft       -= sizeof(uint32_t);
                    size_t  cbSrc = RT_MIN(g_cPages - iPage, cPagesAtATime) * PAGE_SIZE;
                    size_t  cbDst;
                    rc = RTZipBlockCompress(aTests[j].enmType, aTests[j].enmLevel, 0 /*fFlags*/,
                                            pbSrcPage, cbSrc,
                                            pbDstPage, cbLeft, &cbDst);
                    if (RT_FAILURE(rc))
                    {
                        Error("RTZipBlockCompress failed for '%s' (#%u): %Rrc\n", aTests[j].pszName, j, rc);
                        aTests[j].rc = rc;
                        break;
                    }
                    *pcb       = (uint32_t)cbDst;
                    cbLeft    -= cbDst;
                    pbDstPage += cbDst;
                    pbSrcPage += cbSrc;
                }
                if (RT_FAILURE(rc))
                    continue;
                g_cbCompr = pbDstPage - g_pabCompr;
            }
            else
            {
                PRTZIPCOMP pZipComp;
                rc = RTZipCompCreate(&pZipComp, NULL, ComprOutCallback, aTests[j].enmType, aTests[j].enmLevel);
                if (RT_FAILURE(rc))
                {
                    Error("Failed to create the compressor for '%s' (#%u): %Rrc\n", aTests[j].pszName, j, rc);
                    aTests[j].rc = rc;
                    continue;
                }

                uint8_t const  *pbSrcPage = g_pabSrc;
                for (size_t iPage = 0; iPage < g_cPages; iPage += cPagesAtATime)
                {
                    size_t cb = RT_MIN(g_cPages - iPage, cPagesAtATime) * PAGE_SIZE;
                    rc = RTZipCompress(pZipComp, pbSrcPage, cb);
                    if (RT_FAILURE(rc))
                    {
                        Error("RTZipCompress failed for '%s' (#%u): %Rrc\n", aTests[j].pszName, j, rc);
                        aTests[j].rc = rc;
                        break;
                    }
                    pbSrcPage += cb;
                }
                if (RT_FAILURE(rc))
                    continue;
                rc = RTZipCompFinish(pZipComp);
                if (RT_FAILURE(rc))
                {
                    Error("RTZipCompFinish failed for '%s' (#%u): %Rrc\n", aTests[j].pszName, j, rc);
                    aTests[j].rc = rc;
                    break;
                }
                RTZipCompDestroy(pZipComp);
            }
            NanoTS = RTTimeNanoTS() - NanoTS;
            aTests[j].cbCompr    += g_cbCompr;
            aTests[j].cNanoCompr += NanoTS;

            /*
             * Decompress it.
             */
            NanoTS = RTTimeNanoTS();
            if (aTests[j].fBlock)
            {
                uint8_t const  *pbSrcPage = g_pabCompr;
                size_t          cbLeft    = g_cbCompr;
                uint8_t        *pbDstPage = g_pabDecompr;
                for (size_t iPage = 0; iPage < g_cPages; iPage += cPagesAtATime)
                {
                    size_t   cbDst = RT_MIN(g_cPages - iPage, cPagesAtATime) * PAGE_SIZE;
                    size_t   cbSrc = *(uint32_t *)pbSrcPage;
                    pbSrcPage     += sizeof(uint32_t);
                    cbLeft        -= sizeof(uint32_t);
                    rc = RTZipBlockDecompress(aTests[j].enmType, 0 /*fFlags*/,
                                              pbSrcPage, cbSrc, &cbSrc,
                                              pbDstPage, cbDst, &cbDst);
                    if (RT_FAILURE(rc))
                    {
                        Error("RTZipBlockDecompress failed for '%s' (#%u): %Rrc\n", aTests[j].pszName, j, rc);
                        aTests[j].rc = rc;
                        break;
                    }
                    pbDstPage += cbDst;
                    cbLeft    -= cbSrc;
                    pbSrcPage += cbSrc;
                }
                if (RT_FAILURE(rc))
                    continue;
            }
            else
            {
                PRTZIPDECOMP pZipDecomp;
                rc = RTZipDecompCreate(&pZipDecomp, NULL, DecomprInCallback);
                if (RT_FAILURE(rc))
                {
                    Error("Failed to create the decompressor for '%s' (#%u): %Rrc\n", aTests[j].pszName, j, rc);
                    aTests[j].rc = rc;
                    continue;
                }

                uint8_t *pbDstPage = g_pabDecompr;
                for (size_t iPage = 0; iPage < g_cPages; iPage += cPagesAtATime)
                {
                    size_t cb = RT_MIN(g_cPages - iPage, cPagesAtATime) * PAGE_SIZE;
                    rc = RTZipDecompress(pZipDecomp, pbDstPage, cb, NULL);
                    if (RT_FAILURE(rc))
                    {
                        Error("RTZipDecompress failed for '%s' (#%u): %Rrc\n", aTests[j].pszName, j, rc);
                        aTests[j].rc = rc;
                        break;
                    }
                    pbDstPage += cb;
                }
                RTZipDecompDestroy(pZipDecomp);
                if (RT_FAILURE(rc))
                    continue;
            }
            NanoTS = RTTimeNanoTS() - NanoTS;
            aTests[j].cNanoDecompr += NanoTS;

            if (memcmp(g_pabDecompr, g_pabSrc, g_cbPages))
            {
                Error("The compressed data doesn't match the source for '%s' (%#u)\n", aTests[j].pszName, j);
                aTests[j].rc = VERR_BAD_EXE_FORMAT;
                continue;
            }
        }
    }
    if (RT_SUCCESS(rc))
        RTPrintf("\n");

    /*
     * Report the results.
     */
    rc = 0;
    RTPrintf("tstCompressionBenchmark: BEGIN RESULTS\n");
    RTPrintf("%-20s           Compression                                             Decompression\n", "");
    RTPrintf("%-20s        In             Out      Ratio         Size                In             Out\n", "Method");
    RTPrintf("%.20s-----------------------------------------------------------------------------------------\n", "---------------------------------------------");
    for (uint32_t j = 0; j < RT_ELEMENTS(aTests); j++)
    {
        if (RT_SUCCESS(aTests[j].rc))
        {
            unsigned uComprSpeedIn    = (unsigned)(cbTotalKB         / (long double)aTests[j].cNanoCompr   * 1000000000.0);
            unsigned uComprSpeedOut   = (unsigned)(aTests[j].cbCompr / (long double)aTests[j].cNanoCompr   * 1000000000.0 / 1024);
            unsigned uRatio           = (unsigned)(aTests[j].cbCompr / cIterations * 100 / g_cbPages);
            unsigned uDecomprSpeedIn  = (unsigned)(aTests[j].cbCompr / (long double)aTests[j].cNanoDecompr * 1000000000.0 / 1024);
            unsigned uDecomprSpeedOut = (unsigned)(cbTotalKB         / (long double)aTests[j].cNanoDecompr * 1000000000.0);
            RTPrintf("%-20s %'9u KB/s  %'9u KB/s  %3u%%  %'11llu bytes   %'9u KB/s  %'9u KB/s",
                     aTests[j].pszName,
                     uComprSpeedIn,   uComprSpeedOut, uRatio, aTests[j].cbCompr / cIterations,
                     uDecomprSpeedIn, uDecomprSpeedOut);
#if 0
            RTPrintf("  [%'14llu / %'14llu ns]\n",
                     aTests[j].cNanoCompr / cIterations,
                     aTests[j].cNanoDecompr / cIterations);
#else
            RTPrintf("\n");
#endif
        }
        else
        {
            RTPrintf("%-20s: %Rrc\n", aTests[j].pszName, aTests[j].rc);
            rc = 1;
        }
    }
    if (pszPageFile)
        RTPrintf("Input: %'10zu pages from '%s' starting at offset %'lld (%#llx)\n"
                 "                                                           %'11zu bytes\n",
                 g_cPages, pszPageFile, offPageFile, offPageFile, g_cbPages);
    else
        RTPrintf("Input: %'10zu pages of generated rubbish               %'11zu bytes\n",
                 g_cPages, g_cbPages);

    /*
     * Count zero pages in the data set.
     */
    size_t cZeroPages = 0;
    for (size_t iPage = 0; iPage < g_cPages; iPage++)
    {
        if (!ASMMemIsAllU32(&g_pabSrc[iPage * PAGE_SIZE], PAGE_SIZE, 0))
            cZeroPages++;
    }
    RTPrintf("       %'10zu zero pages (%u %%)\n", cZeroPages, cZeroPages * 100 / g_cPages);

    /*
     * A little extension to the test, benchmark relevant CRCs.
     */
    RTPrintf("\n"
             "tstCompressionBenchmark: Hash/CRC - All In One\n");
    tstBenchmarkCRCsAllInOne(g_pabSrc, g_cbPages);

    RTPrintf("\n"
             "tstCompressionBenchmark: Hash/CRC - Page by Page\n");
    tstBenchmarkCRCsPageByPage(g_pabSrc, g_cbPages);

    RTPrintf("\n"
             "tstCompressionBenchmark: Hash/CRC - Zero Page Digest\n");
    static uint8_t s_abZeroPg[PAGE_SIZE];
    RT_ZERO(s_abZeroPg);
    tstBenchmarkCRCsAllInOne(s_abZeroPg, PAGE_SIZE);

    RTPrintf("\n"
             "tstCompressionBenchmark: Hash/CRC - Zero Half Page Digest\n");
    tstBenchmarkCRCsAllInOne(s_abZeroPg, PAGE_SIZE / 2);

    RTPrintf("tstCompressionBenchmark: END RESULTS\n");

    return rc;
}
Esempio n. 10
0
RTDECL(int) RTPipeSelectOne(RTPIPE hPipe, RTMSINTERVAL cMillies)
{
    RTPIPEINTERNAL *pThis = hPipe;
    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
    AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE);

    uint64_t const StartMsTS = RTTimeMilliTS();

    int rc = RTCritSectEnter(&pThis->CritSect);
    if (RT_FAILURE(rc))
        return rc;
    for (unsigned iLoop = 0;; iLoop++)
    {
        HANDLE  hWait = INVALID_HANDLE_VALUE;
        if (pThis->fRead)
        {
            if (pThis->fIOPending)
                hWait = pThis->Overlapped.hEvent;
            else
            {
                /* Peek at the pipe buffer and see how many bytes it contains. */
                DWORD cbAvailable;
                if (   PeekNamedPipe(pThis->hPipe, NULL, 0, NULL, &cbAvailable, NULL)
                    && cbAvailable > 0)
                {
                    rc = VINF_SUCCESS;
                    break;
                }

                /* Start a zero byte read operation that we can wait on. */
                if (cMillies == 0)
                {
                    rc = VERR_TIMEOUT;
                    break;
                }
                AssertBreakStmt(pThis->cUsers == 0, rc = VERR_INTERNAL_ERROR_5);
                rc = ResetEvent(pThis->Overlapped.hEvent); Assert(rc == TRUE);
                DWORD cbRead = 0;
                if (ReadFile(pThis->hPipe, pThis->abBuf, 0, &cbRead, &pThis->Overlapped))
                {
                    rc = VINF_SUCCESS;
                    if (iLoop > 10)
                        RTThreadYield();
                }
                else if (GetLastError() == ERROR_IO_PENDING)
                {
                    pThis->cUsers++;
                    pThis->fIOPending = true;
                    pThis->fZeroByteRead = true;
                    hWait = pThis->Overlapped.hEvent;
                }
                else
                    rc = RTErrConvertFromWin32(GetLastError());
            }
        }
        else
        {
            if (pThis->fIOPending)
            {
                rc = rtPipeWriteCheckCompletion(pThis);
                if (RT_FAILURE(rc))
                    break;
            }
            if (pThis->fIOPending)
                hWait = pThis->Overlapped.hEvent;
            else
            {
                FILE_PIPE_LOCAL_INFORMATION Info;
                if (rtPipeQueryInfo(pThis, &Info))
                {
                    /* Check for broken pipe. */
                    if (Info.NamedPipeState == FILE_PIPE_CLOSING_STATE)
                    {
                        rc = VERR_BROKEN_PIPE;
                        break;
                    }
                    /* Check for available write buffer space. */
                    else if (Info.WriteQuotaAvailable > 0)
                    {
                        pThis->fPromisedWritable = false;
                        rc = VINF_SUCCESS;
                        break;
                    }
                    /* delayed buffer alloc or timeout: phony promise
                       later: See if we still can associate a semaphore with
                              the pipe, like on OS/2. */
                    else if (   Info.OutboundQuota == 0
                             || cMillies)
                    {
                        pThis->fPromisedWritable = true;
                        rc = VINF_SUCCESS;
                        break;
                    }
                }
                else
                {
                    pThis->fPromisedWritable = true;
                    rc = VINF_SUCCESS;
                    break;
                }
            }
        }
        if (RT_FAILURE(rc))
            break;

        /*
         * Check for timeout.
         */
        DWORD cMsMaxWait = INFINITE;
        if (   cMillies != RT_INDEFINITE_WAIT
            && (   hWait != INVALID_HANDLE_VALUE
                || iLoop > 10)
           )
        {
            uint64_t cElapsed = RTTimeMilliTS() - StartMsTS;
            if (cElapsed >= cMillies)
            {
                rc = VERR_TIMEOUT;
                break;
            }
            cMsMaxWait = cMillies - (uint32_t)cElapsed;
        }

        /*
         * Wait.
         */
        if (hWait != INVALID_HANDLE_VALUE)
        {
            RTCritSectLeave(&pThis->CritSect);

            DWORD dwRc = WaitForSingleObject(hWait, cMsMaxWait);
            if (dwRc == WAIT_OBJECT_0)
                rc = VINF_SUCCESS;
            else if (dwRc == WAIT_TIMEOUT)
                rc = VERR_TIMEOUT;
            else if (dwRc == WAIT_ABANDONED)
                rc = VERR_INVALID_HANDLE;
            else
                rc = RTErrConvertFromWin32(GetLastError());
            if (   RT_FAILURE(rc)
                && pThis->u32Magic != RTPIPE_MAGIC)
                return rc;

            RTCritSectEnter(&pThis->CritSect);
            if (pThis->fZeroByteRead)
            {
                pThis->cUsers--;
                pThis->fIOPending = false;
                if (rc != VINF_SUCCESS)
                    CancelIo(pThis->hPipe);
                DWORD cbRead = 0;
                GetOverlappedResult(pThis->hPipe, &pThis->Overlapped, &cbRead, TRUE /*fWait*/);
            }
            if (RT_FAILURE(rc))
                break;
        }
    }

    if (rc == VERR_BROKEN_PIPE)
        pThis->fBrokenPipe = true;

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