/** * Suspends the thread. * * This can be called at the power off / suspend notifications to suspend the * PDM thread a bit early. The thread will be automatically suspend upon * completion of the device/driver notification cycle. * * The caller is responsible for serializing the control operations on the * thread. That basically means, always do these calls from the EMT. * * @returns VBox status code. * @param pThread The PDM thread. */ VMMR3DECL(int) PDMR3ThreadSuspend(PPDMTHREAD pThread) { /* * Assert sanity. */ AssertPtrReturn(pThread, VERR_INVALID_POINTER); AssertReturn(pThread->u32Version == PDMTHREAD_VERSION, VERR_INVALID_MAGIC); Assert(pThread->Thread != RTThreadSelf()); /* * This is a noop if the thread is already suspended. */ if (pThread->enmState == PDMTHREADSTATE_SUSPENDED) return VINF_SUCCESS; /* * Change the state to resuming and kick the thread. */ int rc = RTSemEventMultiReset(pThread->Internal.s.BlockEvent); if (RT_SUCCESS(rc)) { rc = RTThreadUserReset(pThread->Thread); if (RT_SUCCESS(rc)) { rc = VERR_WRONG_ORDER; if (pdmR3AtomicCmpXchgState(pThread, PDMTHREADSTATE_SUSPENDING, PDMTHREADSTATE_RUNNING)) { rc = pdmR3ThreadWakeUp(pThread); if (RT_SUCCESS(rc)) { /* * Wait for the thread to reach the suspended state. */ if (pThread->enmState != PDMTHREADSTATE_SUSPENDED) rc = RTThreadUserWait(pThread->Thread, 60*1000); if ( RT_SUCCESS(rc) && pThread->enmState != PDMTHREADSTATE_SUSPENDED) rc = VERR_PDM_THREAD_IPE_2; if (RT_SUCCESS(rc)) return rc; } } } } /* * Something failed, initialize termination. */ AssertMsgFailed(("PDMR3ThreadSuspend -> rc=%Rrc enmState=%d suspending '%s'\n", rc, pThread->enmState, RTThreadGetName(pThread->Thread))); pdmR3ThreadBailOut(pThread); return rc; }
/** * Creates a new async I/O manager. * * @returns VBox status code. * @param pEpClass Pointer to the endpoint class data. * @param ppAioMgr Where to store the pointer to the new async I/O manager on success. * @param enmMgrType Wanted manager type - can be overwritten by the global override. */ int pdmacFileAioMgrCreate(PPDMASYNCCOMPLETIONEPCLASSFILE pEpClass, PPPDMACEPFILEMGR ppAioMgr, PDMACEPFILEMGRTYPE enmMgrType) { LogFlowFunc((": Entered\n")); PPDMACEPFILEMGR pAioMgrNew; int rc = MMR3HeapAllocZEx(pEpClass->Core.pVM, MM_TAG_PDM_ASYNC_COMPLETION, sizeof(PDMACEPFILEMGR), (void **)&pAioMgrNew); if (RT_SUCCESS(rc)) { if (enmMgrType < pEpClass->enmMgrTypeOverride) pAioMgrNew->enmMgrType = enmMgrType; else pAioMgrNew->enmMgrType = pEpClass->enmMgrTypeOverride; pAioMgrNew->msBwLimitExpired = RT_INDEFINITE_WAIT; rc = RTSemEventCreate(&pAioMgrNew->EventSem); if (RT_SUCCESS(rc)) { rc = RTSemEventCreate(&pAioMgrNew->EventSemBlock); if (RT_SUCCESS(rc)) { rc = RTCritSectInit(&pAioMgrNew->CritSectBlockingEvent); if (RT_SUCCESS(rc)) { /* Init the rest of the manager. */ if (pAioMgrNew->enmMgrType != PDMACEPFILEMGRTYPE_SIMPLE) rc = pdmacFileAioMgrNormalInit(pAioMgrNew); if (RT_SUCCESS(rc)) { pAioMgrNew->enmState = PDMACEPFILEMGRSTATE_RUNNING; rc = RTThreadCreateF(&pAioMgrNew->Thread, pAioMgrNew->enmMgrType == PDMACEPFILEMGRTYPE_SIMPLE ? pdmacFileAioMgrFailsafe : pdmacFileAioMgrNormal, pAioMgrNew, 0, RTTHREADTYPE_IO, 0, "AioMgr%d-%s", pEpClass->cAioMgrs, pAioMgrNew->enmMgrType == PDMACEPFILEMGRTYPE_SIMPLE ? "F" : "N"); if (RT_SUCCESS(rc)) { /* Link it into the list. */ RTCritSectEnter(&pEpClass->CritSect); pAioMgrNew->pNext = pEpClass->pAioMgrHead; if (pEpClass->pAioMgrHead) pEpClass->pAioMgrHead->pPrev = pAioMgrNew; pEpClass->pAioMgrHead = pAioMgrNew; pEpClass->cAioMgrs++; RTCritSectLeave(&pEpClass->CritSect); *ppAioMgr = pAioMgrNew; Log(("PDMAC: Successfully created new file AIO Mgr {%s}\n", RTThreadGetName(pAioMgrNew->Thread))); return VINF_SUCCESS; } pdmacFileAioMgrNormalDestroy(pAioMgrNew); } RTCritSectDelete(&pAioMgrNew->CritSectBlockingEvent); } RTSemEventDestroy(pAioMgrNew->EventSem); } RTSemEventDestroy(pAioMgrNew->EventSemBlock); } MMR3HeapFree(pAioMgrNew); } LogFlowFunc((": Leave rc=%Rrc\n", rc)); return rc; }
/** * The PDM thread function. * * @returns return from pfnThread. * * @param Thread The thread handle. * @param pvUser Pointer to the PDMTHREAD structure. */ static DECLCALLBACK(int) pdmR3ThreadMain(RTTHREAD Thread, void *pvUser) { PPDMTHREAD pThread = (PPDMTHREAD)pvUser; Log(("PDMThread: Initializing thread %RTthrd / %p / '%s'...\n", Thread, pThread, RTThreadGetName(Thread))); pThread->Thread = Thread; PUVM pUVM = pThread->Internal.s.pVM->pUVM; if ( pUVM->pVmm2UserMethods && pUVM->pVmm2UserMethods->pfnNotifyPdmtInit) pUVM->pVmm2UserMethods->pfnNotifyPdmtInit(pUVM->pVmm2UserMethods, pUVM); /* * The run loop. * * It handles simple thread functions which returns when they see a suspending * request and leaves the PDMR3ThreadIAmSuspending and PDMR3ThreadIAmRunning * parts to us. */ int rc; for (;;) { switch (pThread->Internal.s.enmType) { case PDMTHREADTYPE_DEVICE: rc = pThread->u.Dev.pfnThread(pThread->u.Dev.pDevIns, pThread); break; case PDMTHREADTYPE_USB: rc = pThread->u.Usb.pfnThread(pThread->u.Usb.pUsbIns, pThread); break; case PDMTHREADTYPE_DRIVER: rc = pThread->u.Drv.pfnThread(pThread->u.Drv.pDrvIns, pThread); break; case PDMTHREADTYPE_INTERNAL: rc = pThread->u.Int.pfnThread(pThread->Internal.s.pVM, pThread); break; case PDMTHREADTYPE_EXTERNAL: rc = pThread->u.Ext.pfnThread(pThread); break; default: AssertMsgFailed(("%d\n", pThread->Internal.s.enmType)); rc = VERR_PDM_THREAD_IPE_1; break; } if (RT_FAILURE(rc)) break; /* * If this is a simple thread function, the state will be suspending * or initializing now. If it isn't we're supposed to terminate. */ if ( pThread->enmState != PDMTHREADSTATE_SUSPENDING && pThread->enmState != PDMTHREADSTATE_INITIALIZING) { Assert(pThread->enmState == PDMTHREADSTATE_TERMINATING); break; } rc = PDMR3ThreadIAmSuspending(pThread); if (RT_FAILURE(rc)) break; if (pThread->enmState != PDMTHREADSTATE_RESUMING) { Assert(pThread->enmState == PDMTHREADSTATE_TERMINATING); break; } rc = PDMR3ThreadIAmRunning(pThread); if (RT_FAILURE(rc)) break; } if (RT_FAILURE(rc)) LogRel(("PDMThread: Thread '%s' (%RTthrd) quit unexpectedly with rc=%Rrc.\n", RTThreadGetName(Thread), Thread, rc)); /* * Advance the state to terminating and then on to terminated. */ for (;;) { PDMTHREADSTATE enmState = pThread->enmState; if ( enmState == PDMTHREADSTATE_TERMINATING || pdmR3AtomicCmpXchgState(pThread, PDMTHREADSTATE_TERMINATING, enmState)) break; } ASMAtomicXchgSize(&pThread->enmState, PDMTHREADSTATE_TERMINATED); int rc2 = RTThreadUserSignal(Thread); AssertRC(rc2); if ( pUVM->pVmm2UserMethods && pUVM->pVmm2UserMethods->pfnNotifyPdmtTerm) pUVM->pVmm2UserMethods->pfnNotifyPdmtTerm(pUVM->pVmm2UserMethods, pUVM); Log(("PDMThread: Terminating thread %RTthrd / %p / '%s': %Rrc\n", Thread, pThread, RTThreadGetName(Thread), rc)); return rc; }