/* 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; }
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; }
/** * 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; }
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; }