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;
}
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);
}
Esempio n. 3
0
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;
}
/**
 * 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;
}
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;
}