/** * 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; }
/** * Entry point. */ extern "C" DECLEXPORT(int) TrustedMain(int argc, char **argv, char **envp) { int rcRet = 0; /* error count */ PPDMASYNCCOMPLETIONENDPOINT pEndpointSrc, pEndpointDst; RTR3InitExe(argc, &argv, RTR3INIT_FLAGS_SUPLIB); if (argc != 3) { RTPrintf(TESTCASE ": Usage is ./tstPDMAsyncCompletion <source> <dest>\n"); return 1; } PVM pVM; PUVM pUVM; int rc = VMR3Create(1, NULL, NULL, NULL, NULL, NULL, &pVM, &pUVM); if (RT_SUCCESS(rc)) { /* * Little hack to avoid the VM_ASSERT_EMT assertion. */ RTTlsSet(pVM->pUVM->vm.s.idxTLS, &pVM->pUVM->aCpus[0]); pVM->pUVM->aCpus[0].pUVM = pVM->pUVM; pVM->pUVM->aCpus[0].vm.s.NativeThreadEMT = RTThreadNativeSelf(); /* * Create the template. */ PPDMASYNCCOMPLETIONTEMPLATE pTemplate; rc = PDMR3AsyncCompletionTemplateCreateInternal(pVM, &pTemplate, AsyncTaskCompleted, NULL, "Test"); if (RT_FAILURE(rc)) { RTPrintf(TESTCASE ": Error while creating the template!! rc=%d\n", rc); return 1; } /* * Create event semaphore. */ rc = RTSemEventCreate(&g_FinishedEventSem); AssertRC(rc); /* * Create the temporary buffers. */ for (unsigned i=0; i < NR_TASKS; i++) { g_AsyncCompletionTasksBuffer[i] = (uint8_t *)RTMemAllocZ(BUFFER_SIZE); if (!g_AsyncCompletionTasksBuffer[i]) { RTPrintf(TESTCASE ": out of memory!\n"); return ++rcRet; } } /* Create the destination as the async completion API can't do this. */ RTFILE FileTmp; rc = RTFileOpen(&FileTmp, argv[2], RTFILE_O_READWRITE | RTFILE_O_OPEN_CREATE | RTFILE_O_DENY_NONE); if (RT_FAILURE(rc)) { RTPrintf(TESTCASE ": Error while creating the destination!! rc=%d\n", rc); return ++rcRet; } RTFileClose(FileTmp); /* Create our file endpoint */ rc = PDMR3AsyncCompletionEpCreateForFile(&pEndpointSrc, argv[1], 0, pTemplate); if (RT_SUCCESS(rc)) { rc = PDMR3AsyncCompletionEpCreateForFile(&pEndpointDst, argv[2], 0, pTemplate); if (RT_SUCCESS(rc)) { PDMR3PowerOn(pVM); /* Wait for all threads to finish initialization. */ RTThreadSleep(100); int fReadPass = true; uint64_t cbSrc; size_t offSrc = 0; size_t offDst = 0; uint32_t cTasksUsed = 0; rc = PDMR3AsyncCompletionEpGetSize(pEndpointSrc, &cbSrc); if (RT_SUCCESS(rc)) { /* Copy the data. */ for (;;) { if (fReadPass) { cTasksUsed = (BUFFER_SIZE * NR_TASKS) <= (cbSrc - offSrc) ? NR_TASKS : ((cbSrc - offSrc) / BUFFER_SIZE) + ((cbSrc - offSrc) % BUFFER_SIZE) > 0 ? 1 : 0; g_cTasksLeft = cTasksUsed; for (uint32_t i = 0; i < cTasksUsed; i++) { size_t cbRead = ((size_t)offSrc + BUFFER_SIZE) <= cbSrc ? BUFFER_SIZE : cbSrc - offSrc; RTSGSEG DataSeg; DataSeg.pvSeg = g_AsyncCompletionTasksBuffer[i]; DataSeg.cbSeg = cbRead; rc = PDMR3AsyncCompletionEpRead(pEndpointSrc, offSrc, &DataSeg, 1, cbRead, NULL, &g_AsyncCompletionTasks[i]); AssertRC(rc); offSrc += cbRead; if (offSrc == cbSrc) break; } } else { g_cTasksLeft = cTasksUsed; for (uint32_t i = 0; i < cTasksUsed; i++) { size_t cbWrite = (offDst + BUFFER_SIZE) <= cbSrc ? BUFFER_SIZE : cbSrc - offDst; RTSGSEG DataSeg; DataSeg.pvSeg = g_AsyncCompletionTasksBuffer[i]; DataSeg.cbSeg = cbWrite; rc = PDMR3AsyncCompletionEpWrite(pEndpointDst, offDst, &DataSeg, 1, cbWrite, NULL, &g_AsyncCompletionTasks[i]); AssertRC(rc); offDst += cbWrite; if (offDst == cbSrc) break; } } rc = RTSemEventWait(g_FinishedEventSem, RT_INDEFINITE_WAIT); AssertRC(rc); if (!fReadPass && (offDst == cbSrc)) break; else if (fReadPass) fReadPass = false; else { cTasksUsed = 0; fReadPass = true; } } } else { RTPrintf(TESTCASE ": Error querying size of the endpoint!! rc=%d\n", rc); rcRet++; } PDMR3PowerOff(pVM); PDMR3AsyncCompletionEpClose(pEndpointDst); } PDMR3AsyncCompletionEpClose(pEndpointSrc); } rc = VMR3Destroy(pUVM); AssertMsg(rc == VINF_SUCCESS, ("%s: Destroying VM failed rc=%Rrc!!\n", __FUNCTION__, rc)); VMR3ReleaseUVM(pUVM); /* * Clean up. */ for (uint32_t i = 0; i < NR_TASKS; i++) { RTMemFree(g_AsyncCompletionTasksBuffer[i]); } } else { RTPrintf(TESTCASE ": failed to create VM!! rc=%Rrc\n", rc); rcRet++; } return rcRet; }