/**
 * Resumes all threads not running.
 *
 * This is called by PDMR3Resume() and PDMR3PowerOn() after all the devices
 * and drivers have been notified about the resume / power on .
 *
 * @return VBox status code.
 * @param   pVM         Pointer to the VM.
 */
int pdmR3ThreadResumeAll(PVM pVM)
{
    PUVM pUVM = pVM->pUVM;
    RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
    for (PPDMTHREAD pThread = pUVM->pdm.s.pThreads; pThread; pThread = pThread->Internal.s.pNext)
        switch (pThread->enmState)
        {
            case PDMTHREADSTATE_SUSPENDED:
            {
                int rc = PDMR3ThreadResume(pThread);
                AssertRCReturn(rc, rc);
                break;
            }

            default:
                AssertMsgFailed(("pThread=%p enmState=%d\n", pThread, pThread->enmState));
                break;
        }
    RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
    return VINF_SUCCESS;
}
/**
 * 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;
}