int main() { /* How many integer test items should be created. */ static const size_t s_cTestCount = 1000; RTTEST hTest; RTEXITCODE rcExit = RTTestInitAndCreate("tstIprtList", &hTest); if (rcExit) return rcExit; RTTestBanner(hTest); /* * Native types. */ uint8_t au8TestInts[s_cTestCount]; for (size_t i = 0; i < RT_ELEMENTS(au8TestInts); ++i) au8TestInts[i] = (uint8_t)RTRandU32Ex(1, UINT8_MAX); test1<RTCList, uint8_t, uint8_t, uint8_t>("ST: Native type", au8TestInts, RT_ELEMENTS(au8TestInts)); test1<RTCMTList, uint8_t, uint8_t, uint8_t>("MT: Native type", au8TestInts, RT_ELEMENTS(au8TestInts)); uint16_t au16TestInts[s_cTestCount]; for (size_t i = 0; i < RT_ELEMENTS(au16TestInts); ++i) au16TestInts[i] = (uint16_t)RTRandU32Ex(1, UINT16_MAX); test1<RTCList, uint16_t, uint16_t, uint16_t>("ST: Native type", au16TestInts, RT_ELEMENTS(au16TestInts)); test1<RTCMTList, uint16_t, uint16_t, uint16_t>("MT: Native type", au16TestInts, RT_ELEMENTS(au16TestInts)); uint32_t au32TestInts[s_cTestCount]; for (size_t i = 0; i < RT_ELEMENTS(au32TestInts); ++i) au32TestInts[i] = RTRandU32Ex(1, UINT32_MAX); test1<RTCList, uint32_t, uint32_t, uint32_t>("ST: Native type", au32TestInts, RT_ELEMENTS(au32TestInts)); test1<RTCMTList, uint32_t, uint32_t, uint32_t>("MT: Native type", au32TestInts, RT_ELEMENTS(au32TestInts)); /* * Specialized type. */ uint64_t au64TestInts[s_cTestCount]; for (size_t i = 0; i < RT_ELEMENTS(au64TestInts); ++i) au64TestInts[i] = RTRandU64Ex(1, UINT64_MAX); test1<RTCList, uint64_t, uint64_t, uint64_t>("ST: Specialized type", au64TestInts, RT_ELEMENTS(au64TestInts)); test1<RTCMTList, uint64_t, uint64_t, uint64_t>("MT: Specialized type", au64TestInts, RT_ELEMENTS(au64TestInts)); /* * Big size type (translate to internal pointer list). */ test1<RTCList, RTCString, RTCString *, const char *>("ST: Class type", g_apszTestStrings, RT_ELEMENTS(g_apszTestStrings)); test1<RTCMTList, RTCString, RTCString *, const char *>("MT: Class type", g_apszTestStrings, RT_ELEMENTS(g_apszTestStrings)); /* * Multi-threading test. */ test2(); /* * Summary. */ return RTTestSummaryAndDestroy(hTest); }
static void rtCreateTempFillTemplate(char *pszX, unsigned cXes) { static char const s_sz[] = "0123456789abcdefghijklmnopqrstuvwxyz"; unsigned j = cXes; while (j-- > 0) pszX[j] = s_sz[RTRandU32Ex(0, RT_ELEMENTS(s_sz) - 2)]; }
static int testSessionDataReadTestMsg(RTTEST hTest, RTLOCALIPCSESSION hSession, void *pvBuffer, size_t cbBuffer, const char *pszMsg) { AssertPtrReturn(pvBuffer, VERR_INVALID_POINTER); AssertPtrReturn(pszMsg, VERR_INVALID_POINTER); void *pvBufCur = pvBuffer; size_t cbReadTotal = 0; for (;;) { size_t cbRead = RTRandU32Ex(1, sizeof(LOCALIPCTESTMSG) - cbReadTotal); /* Force a bit of fragmentation. */ RTTEST_CHECK_BREAK(hTest, cbRead); RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcSessionRead(hSession, pvBufCur, cbBuffer, &cbRead), VINF_SUCCESS); RTTEST_CHECK_BREAK(hTest, cbRead); pvBufCur = (uint8_t *)pvBufCur + cbRead; /* Advance. */ cbReadTotal += cbRead; RTTEST_CHECK_BREAK(hTest, cbReadTotal <= cbBuffer); if (cbReadTotal >= sizeof(LOCALIPCTESTMSG)) /* Got a complete test message? */ { RTTEST_CHECK_BREAK(hTest, cbReadTotal == sizeof(LOCALIPCTESTMSG)); PLOCALIPCTESTMSG pMsg = (PLOCALIPCTESTMSG)pvBuffer; RTTEST_CHECK_BREAK(hTest, pMsg != NULL); RTTEST_CHECK_BREAK(hTest, !RTStrCmp(pMsg->szOp, pszMsg)); break; } /* Try receiving next part of the message in another round. */ } return !RTTestErrorCount(hTest) ? VINF_SUCCESS : VERR_GENERAL_FAILURE /* Doesn't matter */; }
static int tstPDMACTestFileThread(PVM pVM, PPDMTHREAD pThread) { PPDMACTESTFILE pTestFile = (PPDMACTESTFILE)pThread->pvUser; int iWriteChance = 100; /* Chance to get a write task in percent. */ uint32_t cTasksStarted = 0; int rc = VINF_SUCCESS; if (pThread->enmState == PDMTHREADSTATE_INITIALIZING) return VINF_SUCCESS; while (pTestFile->fRunning) { unsigned iTaskCurr = 0; /* Fill all tasks */ while ( (pTestFile->cTasksActiveCurr < pTestFile->cTasksActiveMax) && (iTaskCurr < pTestFile->cTasksActiveMax)) { PPDMACTESTFILETASK pTask = &pTestFile->paTasks[iTaskCurr]; if (!pTask->fActive) { /* Read or write task? */ bool fWrite = tstPDMACTestIsTrue(iWriteChance); ASMAtomicIncU32(&pTestFile->cTasksActiveCurr); if (fWrite) rc = tstPDMACStressTestFileWrite(pTestFile, pTask); else rc = tstPDMACStressTestFileRead(pTestFile, pTask); if (rc != VINF_AIO_TASK_PENDING) tstPDMACStressTestFileTaskCompleted(pVM, pTask, pTestFile, rc); cTasksStarted++; } iTaskCurr++; } /* * Recalc write chance. The bigger the file the lower the chance to have a write. * The minimum chance is 33 percent. */ iWriteChance = 100 - (int)(((float)100.0 / pTestFile->cbFileMax) * (float)pTestFile->cbFileCurr); iWriteChance = RT_MAX(33, iWriteChance); /* Wait a random amount of time. (1ms - 100ms) */ RTThreadSleep(RTRandU32Ex(1, 100)); } /* Wait for the rest to complete. */ while (pTestFile->cTasksActiveCurr) RTThreadSleep(250); RTPrintf("Thread exiting: processed %u tasks\n", cTasksStarted); return rc; }
static int tstPDMACStressTestFileRead(PPDMACTESTFILE pTestFile, PPDMACTESTFILETASK pTestTask) { int rc = VINF_SUCCESS; Assert(!pTestTask->fActive); pTestTask->fActive = true; pTestTask->fWrite = false; pTestTask->DataSeg.cbSeg = RTRandU32Ex(1, RT_MIN(pTestFile->cbFileCurr, TASK_TRANSFER_SIZE_MAX)); AssertMsg(pTestFile->cbFileCurr >= pTestTask->DataSeg.cbSeg, ("Impossible\n")); pTestTask->off = RTRandU64Ex(0, pTestFile->cbFileCurr - pTestTask->DataSeg.cbSeg); /* Allocate data buffer. */ pTestTask->DataSeg.pvSeg = RTMemAlloc(pTestTask->DataSeg.cbSeg); if (!pTestTask->DataSeg.pvSeg) return VERR_NO_MEMORY; /* Engage */ rc = PDMR3AsyncCompletionEpRead(pTestFile->hEndpoint, pTestTask->off, &pTestTask->DataSeg, 1, pTestTask->DataSeg.cbSeg, pTestTask, &pTestTask->hTask); return rc; }
/** * Thread for erasing items from a shared list. * * @param hSelf The thread handle. * @param pvUser The provided user data. */ DECLCALLBACK(int) mttest6(RTTHREAD hSelf, void *pvUser) { MTTESTLISTTYPE<MTTESTTYPE> *pTestList = (MTTESTLISTTYPE<MTTESTTYPE> *)pvUser; /* Try to delete items from random places. */ for (size_t i = 0; i < MTTESTITEMS; ++i) { /* Make sure there is at least one item in the list. */ while (pTestList->isEmpty()) {}; pTestList->removeAt(RTRandU32Ex(0, (uint32_t)pTestList->size() - 1)); } return VINF_SUCCESS; }
static void doMemWipeThoroughly(RTTEST hTest) { for (uint32_t p = 0; p < RTRandU32Ex(1, 64); p++) { size_t cbAlloc = RTRandS32Ex(1, _1M) * sizeof(uint8_t); RTTestPrintf(hTest, RTTESTLVL_ALWAYS, "Testing wipe #%.02RU32 (%u bytes) ...\n", p + 1, cbAlloc); void *pvBuf = RTMemAlloc(cbAlloc); if (!pvBuf) { RTTestIFailed("No memory for first buffer (%z bytes)\n", cbAlloc); continue; } RTRandBytes(pvBuf, cbAlloc); void *pvWipe = RTMemDup(pvBuf, cbAlloc); if (!pvWipe) { RTMemFree(pvBuf); RTTestIFailed("No memory for second buffer (%z bytes)\n", cbAlloc); continue; } size_t cbWipeRand = RTRandU32Ex(1, cbAlloc); RTMemWipeThoroughly(pvWipe, RT_MIN(cbAlloc, cbWipeRand), p /* Passes */); if (!memcmp(pvWipe, pvBuf, cbAlloc)) RTTestIFailed("Memory blocks must differ (%z bytes, 0x%p vs. 0x%p)!\n", cbAlloc, pvWipe, pvBuf); RTMemFree(pvWipe); RTMemFree(pvBuf); } }
/** * Thread for replacing items in a shared list. * * @param hSelf The thread handle. * @param pvUser The provided user data. */ static DECLCALLBACK(int) MtTest5ThreadProc(RTTHREAD hSelf, void *pvUser) { MTTESTLISTTYPE<MTTESTTYPE> *pTestList = (MTTESTLISTTYPE<MTTESTTYPE> *)pvUser; /* Try to replace C items from random places. */ for (size_t i = 0; i < MTTESTITEMS; ++i) { /* Make sure there is at least one item in the list. */ while (pTestList->isEmpty()) RTThreadYield(); pTestList->replace(RTRandU32Ex(0, (uint32_t)pTestList->size() - 1), 0xFF00FF00); } return VINF_SUCCESS; }
int main() { RTR3InitExeNoArguments(0); RTPrintf("tstRand: TESTING...\n"); /* * Do some smoke tests first? */ /** @todo RTRand smoke testing. */ #if 1 /* * Test distribution. */ #if 1 /* unsigned 32-bit */ static const struct { uint32_t u32First; uint32_t u32Last; } s_aU32Tests[] = { { 0, UINT32_MAX }, { 0, UINT32_MAX / 2 + UINT32_MAX / 4 }, { 0, UINT32_MAX / 2 + UINT32_MAX / 8 }, { 0, UINT32_MAX / 2 + UINT32_MAX / 16 }, { 0, UINT32_MAX / 2 + UINT32_MAX / 64 }, { 0, UINT32_MAX / 2 }, { UINT32_MAX / 4, UINT32_MAX / 4 * 3 }, { 0, TST_RAND_SAMPLE_RANGES - 1 }, { 1234, 1234 + TST_RAND_SAMPLE_RANGES - 1 }, }; for (unsigned iTest = 0; iTest < RT_ELEMENTS(s_aU32Tests); iTest++) { uint32_t acHits[TST_RAND_SAMPLE_RANGES] = {0}; uint32_t const uFirst = s_aU32Tests[iTest].u32First; uint32_t const uLast = s_aU32Tests[iTest].u32Last; uint32_t const uRange = uLast - uFirst; Assert(uLast >= uFirst); uint32_t const uDivisor = uRange / TST_RAND_SAMPLE_RANGES + 1; RTPrintf("tstRand: TESTING RTRandU32Ex(%#RX32, %#RX32) distribution... [div=%#RX32 range=%#RX32]\n", uFirst, uLast, uDivisor, uRange); for (unsigned iSample = 0; iSample < TST_RAND_SAMPLE_RANGES * 10240; iSample++) { uint32_t uRand = RTRandU32Ex(uFirst, uLast); CHECK_EXPR_MSG(uRand >= uFirst, ("%#RX32 %#RX32\n", uRand, uFirst)); CHECK_EXPR_MSG(uRand <= uLast, ("%#RX32 %#RX32\n", uRand, uLast)); uint32_t off = uRand - uFirst; acHits[off / uDivisor]++; } tstRandCheckDist(acHits, iTest); } #endif #if 1 /* unsigned 64-bit */ static const struct { uint64_t u64First; uint64_t u64Last; } s_aU64Tests[] = { { 0, UINT64_MAX }, { 0, UINT64_MAX / 2 + UINT64_MAX / 4 }, { 0, UINT64_MAX / 2 + UINT64_MAX / 8 }, { 0, UINT64_MAX / 2 + UINT64_MAX / 16 }, { 0, UINT64_MAX / 2 + UINT64_MAX / 64 }, { 0, UINT64_MAX / 2 }, { UINT64_MAX / 4, UINT64_MAX / 4 * 3 }, { 0, UINT32_MAX }, { 0, UINT32_MAX / 2 + UINT32_MAX / 4 }, { 0, UINT32_MAX / 2 + UINT32_MAX / 8 }, { 0, UINT32_MAX / 2 + UINT32_MAX / 16 }, { 0, UINT32_MAX / 2 + UINT32_MAX / 64 }, { 0, UINT32_MAX / 2 }, { UINT32_MAX / 4, UINT32_MAX / 4 * 3 }, { 0, TST_RAND_SAMPLE_RANGES - 1 }, { 1234, 1234 + TST_RAND_SAMPLE_RANGES - 1 }, }; for (unsigned iTest = 0; iTest < RT_ELEMENTS(s_aU64Tests); iTest++) { uint32_t acHits[TST_RAND_SAMPLE_RANGES] = {0}; uint64_t const uFirst = s_aU64Tests[iTest].u64First; uint64_t const uLast = s_aU64Tests[iTest].u64Last; uint64_t const uRange = uLast - uFirst; Assert(uLast >= uFirst); uint64_t const uDivisor = uRange / TST_RAND_SAMPLE_RANGES + 1; RTPrintf("tstRand: TESTING RTRandU64Ex(%#RX64, %#RX64) distribution... [div=%#RX64 range=%#RX64]\n", uFirst, uLast, uDivisor, uRange); for (unsigned iSample = 0; iSample < TST_RAND_SAMPLE_RANGES * 10240; iSample++) { uint64_t uRand = RTRandU64Ex(uFirst, uLast); CHECK_EXPR_MSG(uRand >= uFirst, ("%#RX64 %#RX64\n", uRand, uFirst)); CHECK_EXPR_MSG(uRand <= uLast, ("%#RX64 %#RX64\n", uRand, uLast)); uint64_t off = uRand - uFirst; acHits[off / uDivisor]++; } tstRandCheckDist(acHits, iTest); } #endif #if 1 /* signed 32-bit */ static const struct { int32_t i32First; int32_t i32Last; } s_aS32Tests[] = { { -429496729, 429496729 }, { INT32_MIN, INT32_MAX }, { INT32_MIN, INT32_MAX / 2 }, { -0x20000000, INT32_MAX }, { -0x10000000, INT32_MAX }, { -0x08000000, INT32_MAX }, { -0x00800000, INT32_MAX }, { -0x00080000, INT32_MAX }, { -0x00008000, INT32_MAX }, { -0x00000800, INT32_MAX }, { 2, INT32_MAX / 2 }, { 4000000, INT32_MAX / 2 }, { -4000000, INT32_MAX / 2 }, { INT32_MIN / 2, INT32_MAX / 2 }, { INT32_MIN / 3, INT32_MAX / 2 }, { INT32_MIN / 3, INT32_MAX / 3 }, { INT32_MIN / 3, INT32_MAX / 4 }, { INT32_MIN / 4, INT32_MAX / 4 }, { INT32_MIN / 5, INT32_MAX / 5 }, { INT32_MIN / 6, INT32_MAX / 6 }, { INT32_MIN / 7, INT32_MAX / 6 }, { INT32_MIN / 7, INT32_MAX / 7 }, { INT32_MIN / 7, INT32_MAX / 8 }, { INT32_MIN / 8, INT32_MAX / 8 }, { INT32_MIN / 9, INT32_MAX / 9 }, { INT32_MIN / 9, INT32_MAX / 12 }, { INT32_MIN / 12, INT32_MAX / 12 }, { 0, TST_RAND_SAMPLE_RANGES - 1 }, { -TST_RAND_SAMPLE_RANGES / 2, TST_RAND_SAMPLE_RANGES / 2 - 1 }, }; for (unsigned iTest = 0; iTest < RT_ELEMENTS(s_aS32Tests); iTest++) { uint32_t acHits[TST_RAND_SAMPLE_RANGES] = {0}; int32_t const iFirst = s_aS32Tests[iTest].i32First; int32_t const iLast = s_aS32Tests[iTest].i32Last; uint32_t const uRange = iLast - iFirst; AssertMsg(iLast >= iFirst, ("%d\n", iTest)); uint32_t const uDivisor = (uRange ? uRange : UINT32_MAX) / TST_RAND_SAMPLE_RANGES + 1; RTPrintf("tstRand: TESTING RTRandS32Ex(%#RI32, %#RI32) distribution... [div=%#RX32 range=%#RX32]\n", iFirst, iLast, uDivisor, uRange); for (unsigned iSample = 0; iSample < TST_RAND_SAMPLE_RANGES * 10240; iSample++) { int32_t iRand = RTRandS32Ex(iFirst, iLast); CHECK_EXPR_MSG(iRand >= iFirst, ("%#RI32 %#RI32\n", iRand, iFirst)); CHECK_EXPR_MSG(iRand <= iLast, ("%#RI32 %#RI32\n", iRand, iLast)); uint32_t off = iRand - iFirst; acHits[off / uDivisor]++; } tstRandCheckDist(acHits, iTest); } #endif #if 1 /* signed 64-bit */ static const struct { int64_t i64First; int64_t i64Last; } s_aS64Tests[] = { { INT64_MIN, INT64_MAX }, { INT64_MIN, INT64_MAX / 2 }, { INT64_MIN / 2, INT64_MAX / 2 }, { INT64_MIN / 2 + INT64_MIN / 4, INT64_MAX / 2 }, { INT64_MIN / 2 + INT64_MIN / 8, INT64_MAX / 2 }, { INT64_MIN / 2 + INT64_MIN / 16, INT64_MAX / 2 }, { INT64_MIN / 2 + INT64_MIN / 64, INT64_MAX / 2 }, { INT64_MIN / 2 + INT64_MIN / 64, INT64_MAX / 2 + INT64_MAX / 64 }, { INT64_MIN / 2, INT64_MAX / 2 + INT64_MAX / 64 }, { INT64_MIN / 2, INT64_MAX / 2 + INT64_MAX / 8 }, { INT64_MIN / 2, INT64_MAX / 2 - INT64_MAX / 8 }, { INT64_MIN / 2 - INT64_MIN / 4, INT64_MAX / 2 - INT64_MAX / 4 }, { INT64_MIN / 2 - INT64_MIN / 4, INT64_MAX / 2 - INT64_MAX / 8 }, { INT64_MIN / 2 - INT64_MIN / 8, INT64_MAX / 2 - INT64_MAX / 8 }, { INT64_MIN / 2 - INT64_MIN / 16, INT64_MAX / 2 - INT64_MAX / 8 }, { INT64_MIN / 2 - INT64_MIN / 16, INT64_MAX / 2 - INT64_MAX / 16 }, { INT64_MIN / 2 - INT64_MIN / 32, INT64_MAX / 2 - INT64_MAX / 16 }, { INT64_MIN / 2 - INT64_MIN / 32, INT64_MAX / 2 - INT64_MAX / 32 }, { INT64_MIN / 2 - INT64_MIN / 64, INT64_MAX / 2 - INT64_MAX / 64 }, { INT64_MIN / 2 - INT64_MIN / 8, INT64_MAX / 2 }, { INT64_MIN / 4, INT64_MAX / 4 }, { INT64_MIN / 5, INT64_MAX / 5 }, { INT64_MIN / 6, INT64_MAX / 6 }, { INT64_MIN / 7, INT64_MAX / 7 }, { INT64_MIN / 8, INT64_MAX / 8 }, { INT32_MIN, INT32_MAX }, { INT32_MIN, INT32_MAX / 2 }, { -0x20000000, INT32_MAX }, { -0x10000000, INT32_MAX }, { -0x7f000000, INT32_MAX }, { -0x08000000, INT32_MAX }, { -0x00800000, INT32_MAX }, { -0x00080000, INT32_MAX }, { -0x00008000, INT32_MAX }, { 2, INT32_MAX / 2 }, { 4000000, INT32_MAX / 2 }, { -4000000, INT32_MAX / 2 }, { INT32_MIN / 2, INT32_MAX / 2 }, { 0, TST_RAND_SAMPLE_RANGES - 1 }, { -TST_RAND_SAMPLE_RANGES / 2, TST_RAND_SAMPLE_RANGES / 2 - 1 } }; for (unsigned iTest = 0; iTest < RT_ELEMENTS(s_aS64Tests); iTest++) { uint32_t acHits[TST_RAND_SAMPLE_RANGES] = {0}; int64_t const iFirst = s_aS64Tests[iTest].i64First; int64_t const iLast = s_aS64Tests[iTest].i64Last; uint64_t const uRange = iLast - iFirst; AssertMsg(iLast >= iFirst, ("%d\n", iTest)); uint64_t const uDivisor = (uRange ? uRange : UINT64_MAX) / TST_RAND_SAMPLE_RANGES + 1; RTPrintf("tstRand: TESTING RTRandS64Ex(%#RI64, %#RI64) distribution... [div=%#RX64 range=%#016RX64]\n", iFirst, iLast, uDivisor, uRange); for (unsigned iSample = 0; iSample < TST_RAND_SAMPLE_RANGES * 10240; iSample++) { int64_t iRand = RTRandS64Ex(iFirst, iLast); CHECK_EXPR_MSG(iRand >= iFirst, ("%#RI64 %#RI64\n", iRand, iFirst)); CHECK_EXPR_MSG(iRand <= iLast, ("%#RI64 %#RI64\n", iRand, iLast)); uint64_t off = iRand - iFirst; acHits[off / uDivisor]++; } tstRandCheckDist(acHits, iTest); } #endif #endif /* Testing RTRand */ #if 1 /* * Test the various random generators. */ RTPrintf("tstRand: TESTING RTRandAdvCreateParkerMiller\n"); RTRAND hRand; int rc = RTRandAdvCreateParkMiller(&hRand); CHECK_EXPR_MSG(rc == VINF_SUCCESS, ("rc=%Rrc\n", rc)); if (RT_SUCCESS(rc)) if (tstRandAdv(hRand)) return 1; #endif /* Testing RTRandAdv */ /* * Summary. */ if (!g_cErrors) RTPrintf("tstRand: SUCCESS\n"); else RTPrintf("tstRand: FAILED - %d errors\n", g_cErrors); return !!g_cErrors; }
RTDECL(int) RTDirCreateTemp(char *pszTemplate) { /* * Validate input and count X'es. * * The X'es may be trailing, or they may be a cluster of 3 or more inside * the file name. */ AssertPtr(pszTemplate); unsigned cXes = 0; char *pszX = strchr(pszTemplate, '\0'); if ( pszX != pszTemplate && pszX[-1] != 'X') { /* look inside the file name. */ char *pszFilename = RTPathFilename(pszTemplate); if ( pszFilename && (size_t)(pszX - pszFilename) > 3) { char *pszXEnd = pszX - 1; pszFilename += 3; do { if ( pszXEnd[-1] == 'X' && pszXEnd[-2] == 'X' && pszXEnd[-3] == 'X') { pszX = pszXEnd - 3; cXes = 3; break; } } while (pszXEnd-- != pszFilename); } } /* count them */ while ( pszX != pszTemplate && pszX[-1] == 'X') { pszX--; cXes++; } /* fail if none found. */ if (!cXes) { AssertFailed(); *pszTemplate = '\0'; return VERR_INVALID_PARAMETER; } /* * Try ten thousand times. */ int i = 10000; while (i-- > 0) { static char const s_sz[] = "0123456789abcdefghijklmnopqrstuvwxyz"; unsigned j = cXes; while (j-- > 0) pszX[j] = s_sz[RTRandU32Ex(0, RT_ELEMENTS(s_sz) - 2)]; int rc = RTDirCreate(pszTemplate, 0700); if (RT_SUCCESS(rc)) return rc; if (rc != VERR_ALREADY_EXISTS) { *pszTemplate = '\0'; return rc; } } /* we've given up. */ *pszTemplate = '\0'; return VERR_ALREADY_EXISTS; }
/** * 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; }
/** * Returns true with the given chance in percent. * * @returns true or false * @param iPercentage The percentage of the chance to return true. */ static bool tstPDMACTestIsTrue(int iPercentage) { int uRnd = RTRandU32Ex(0, 100); return (uRnd <= iPercentage); /* This should be enough for our purpose */ }
static int tstPDMACStressTestFileWrite(PPDMACTESTFILE pTestFile, PPDMACTESTFILETASK pTestTask) { int rc = VINF_SUCCESS; Assert(!pTestTask->fActive); pTestTask->fActive = true; pTestTask->fWrite = true; pTestTask->DataSeg.cbSeg = RTRandU32Ex(512, TASK_TRANSFER_SIZE_MAX) & ~511; uint64_t offMax; /* Did we reached the maximum file size */ if (pTestFile->cbFileCurr < pTestFile->cbFileMax) { offMax = (pTestFile->cbFileMax - pTestFile->cbFileCurr) < pTestTask->DataSeg.cbSeg ? pTestFile->cbFileMax - pTestTask->DataSeg.cbSeg : pTestFile->cbFileCurr; } else offMax = pTestFile->cbFileMax - pTestTask->DataSeg.cbSeg; uint64_t offMin; /* * If we reached the maximum file size write in the whole file * otherwise we will enforce the range for random offsets to let it grow * more quickly. */ if (pTestFile->cbFileCurr == pTestFile->cbFileMax) offMin = 0; else offMin = RT_MIN(pTestFile->cbFileCurr, offMax); pTestTask->off = RTRandU64Ex(offMin, offMax) & ~511; /* Set new file size of required */ if ((uint64_t)pTestTask->off + pTestTask->DataSeg.cbSeg > pTestFile->cbFileCurr) pTestFile->cbFileCurr = pTestTask->off + pTestTask->DataSeg.cbSeg; AssertMsg(pTestFile->cbFileCurr <= pTestFile->cbFileMax, ("Current file size (%llu) exceeds final size (%llu)\n", pTestFile->cbFileCurr, pTestFile->cbFileMax)); /* Allocate data buffer. */ pTestTask->DataSeg.pvSeg = RTMemAlloc(pTestTask->DataSeg.cbSeg); if (!pTestTask->DataSeg.pvSeg) return VERR_NO_MEMORY; /* Fill data into buffer. */ tstPDMACStressTestFileFillBuffer(pTestFile, pTestTask); /* Engage */ rc = PDMR3AsyncCompletionEpWrite(pTestFile->hEndpoint, pTestTask->off, &pTestTask->DataSeg, 1, pTestTask->DataSeg.cbSeg, pTestTask, &pTestTask->hTask); return rc; }
/** * Creates a TCP server that listens for the source machine and passes control * over to Console::teleporterTrgServeConnection(). * * @returns VBox status code. * @param pUVM The user-mode VM handle * @param pMachine The IMachine for the virtual machine. * @param pErrorMsg Pointer to the error string for VMSetError. * @param fStartPaused Whether to start it in the Paused (true) or * Running (false) state, * @param pProgress Pointer to the progress object. * @param pfPowerOffOnFailure Whether the caller should power off * the VM on failure. * * @remarks The caller expects error information to be set on failure. * @todo Check that all the possible failure paths sets error info... */ HRESULT Console::teleporterTrg(PUVM pUVM, IMachine *pMachine, Utf8Str *pErrorMsg, bool fStartPaused, Progress *pProgress, bool *pfPowerOffOnFailure) { LogThisFunc(("pUVM=%p pMachine=%p fStartPaused=%RTbool pProgress=%p\n", pUVM, pMachine, fStartPaused, pProgress)); *pfPowerOffOnFailure = true; /* * Get the config. */ ULONG uPort; HRESULT hrc = pMachine->COMGETTER(TeleporterPort)(&uPort); if (FAILED(hrc)) return hrc; ULONG const uPortOrg = uPort; Bstr bstrAddress; hrc = pMachine->COMGETTER(TeleporterAddress)(bstrAddress.asOutParam()); if (FAILED(hrc)) return hrc; Utf8Str strAddress(bstrAddress); const char *pszAddress = strAddress.isEmpty() ? NULL : strAddress.c_str(); Bstr bstrPassword; hrc = pMachine->COMGETTER(TeleporterPassword)(bstrPassword.asOutParam()); if (FAILED(hrc)) return hrc; Utf8Str strPassword(bstrPassword); strPassword.append('\n'); /* To simplify password checking. */ /* * Create the TCP server. */ int vrc; PRTTCPSERVER hServer; if (uPort) vrc = RTTcpServerCreateEx(pszAddress, uPort, &hServer); else { for (int cTries = 10240; cTries > 0; cTries--) { uPort = RTRandU32Ex(cTries >= 8192 ? 49152 : 1024, 65534); vrc = RTTcpServerCreateEx(pszAddress, uPort, &hServer); if (vrc != VERR_NET_ADDRESS_IN_USE) break; } if (RT_SUCCESS(vrc)) { hrc = pMachine->COMSETTER(TeleporterPort)(uPort); if (FAILED(hrc)) { RTTcpServerDestroy(hServer); return hrc; } } } if (RT_FAILURE(vrc)) return setError(E_FAIL, tr("RTTcpServerCreateEx failed with status %Rrc"), vrc); /* * Create a one-shot timer for timing out after 5 mins. */ RTTIMERLR hTimerLR; vrc = RTTimerLRCreateEx(&hTimerLR, 0 /*ns*/, RTTIMER_FLAGS_CPU_ANY, teleporterDstTimeout, hServer); if (RT_SUCCESS(vrc)) { vrc = RTTimerLRStart(hTimerLR, 5*60*UINT64_C(1000000000) /*ns*/); if (RT_SUCCESS(vrc)) { /* * Do the job, when it returns we're done. */ TeleporterStateTrg theState(this, pUVM, pProgress, pMachine, mControl, &hTimerLR, fStartPaused); theState.mstrPassword = strPassword; theState.mhServer = hServer; void *pvUser = static_cast<void *>(static_cast<TeleporterState *>(&theState)); if (pProgress->setCancelCallback(teleporterProgressCancelCallback, pvUser)) { LogRel(("Teleporter: Waiting for incoming VM...\n")); hrc = pProgress->SetNextOperation(Bstr(tr("Waiting for incoming VM")).raw(), 1); if (SUCCEEDED(hrc)) { vrc = RTTcpServerListen(hServer, Console::teleporterTrgServeConnection, &theState); pProgress->setCancelCallback(NULL, NULL); if (vrc == VERR_TCP_SERVER_STOP) { vrc = theState.mRc; /* Power off the VM on failure unless the state callback already did that. */ *pfPowerOffOnFailure = false; if (RT_SUCCESS(vrc)) hrc = S_OK; else { VMSTATE enmVMState = VMR3GetStateU(pUVM); if ( enmVMState != VMSTATE_OFF && enmVMState != VMSTATE_POWERING_OFF) *pfPowerOffOnFailure = true; /* Set error. */ if (pErrorMsg->length()) hrc = setError(E_FAIL, "%s", pErrorMsg->c_str()); else hrc = setError(E_FAIL, tr("Teleporation failed (%Rrc)"), vrc); } } else if (vrc == VERR_TCP_SERVER_SHUTDOWN) { BOOL fCanceled = TRUE; hrc = pProgress->COMGETTER(Canceled)(&fCanceled); if (FAILED(hrc) || fCanceled) hrc = setError(E_FAIL, tr("Teleporting canceled")); else hrc = setError(E_FAIL, tr("Teleporter timed out waiting for incoming connection")); LogRel(("Teleporter: RTTcpServerListen aborted - %Rrc\n", vrc)); } else { hrc = setError(E_FAIL, tr("Unexpected RTTcpServerListen status code %Rrc"), vrc); LogRel(("Teleporter: Unexpected RTTcpServerListen rc: %Rrc\n", vrc)); } } else LogThisFunc(("SetNextOperation failed, %Rhrc\n", hrc)); } else { LogThisFunc(("Canceled - check point #1\n")); hrc = setError(E_FAIL, tr("Teleporting canceled")); } } else hrc = setError(E_FAIL, "RTTimerLRStart -> %Rrc", vrc); RTTimerLRDestroy(hTimerLR); } else hrc = setError(E_FAIL, "RTTimerLRCreate -> %Rrc", vrc); RTTcpServerDestroy(hServer); /* * If we change TeleporterPort above, set it back to it's original * value before returning. */ if (uPortOrg != uPort) { ErrorInfoKeeper Eik; pMachine->COMSETTER(TeleporterPort)(uPortOrg); } return hrc; }