static DECLCALLBACK(void) pdmacR3TimerCallback(PVM pVM, PTMTIMER pTimer, void *pvUser) { uint64_t tsCur = RTTimeProgramMilliTS(); uint64_t cMilliesNext = UINT64_MAX; PPDMASYNCCOMPLETIONEPCLASSFILE pEpClassFile = (PPDMASYNCCOMPLETIONEPCLASSFILE)pvUser; ASMAtomicWriteU64(&pEpClassFile->cMilliesNext, UINT64_MAX); /* Go through all endpoints and check for expired requests. */ PPDMASYNCCOMPLETIONENDPOINTFILE pEpFile = (PPDMASYNCCOMPLETIONENDPOINTFILE)pEpClassFile->Core.pEndpointsHead; while (pEpFile) { /* Check for an expired delay. */ if (pEpFile->pDelayedHead != NULL) { PPDMASYNCCOMPLETIONTASKFILE pTaskFile = ASMAtomicXchgPtrT(&pEpFile->pDelayedHead, NULL, PPDMASYNCCOMPLETIONTASKFILE); while (pTaskFile) { PPDMASYNCCOMPLETIONTASKFILE pTmp = pTaskFile; pTaskFile = pTaskFile->pDelayedNext; if (tsCur >= pTmp->tsDelayEnd) { LogRel(("AIOMgr: Delayed request %#p completed\n", pTmp)); pdmR3AsyncCompletionCompleteTask(&pTmp->Core, pTmp->rc, true); } else { /* Prepend to the delayed list again. */ PPDMASYNCCOMPLETIONTASKFILE pHead = NULL; if (pTmp->tsDelayEnd - tsCur < cMilliesNext) cMilliesNext = pTmp->tsDelayEnd - tsCur; do { pHead = ASMAtomicReadPtrT(&pEpFile->pDelayedHead, PPDMASYNCCOMPLETIONTASKFILE); pTmp->pDelayedNext = pHead; } while (!ASMAtomicCmpXchgPtr(&pEpFile->pDelayedHead, pTmp, pHead)); } } } pEpFile = (PPDMASYNCCOMPLETIONENDPOINTFILE)pEpFile->Core.pNext; } if (cMilliesNext < pEpClassFile->cMilliesNext) { ASMAtomicWriteU64(&pEpClassFile->cMilliesNext, cMilliesNext); TMTimerSetMillies(pEpClassFile->pTimer, cMilliesNext); } }
void pdmacFileEpTaskCompleted(PPDMACTASKFILE pTask, void *pvUser, int rc) { PPDMASYNCCOMPLETIONTASKFILE pTaskFile = (PPDMASYNCCOMPLETIONTASKFILE)pvUser; LogFlowFunc(("pTask=%#p pvUser=%#p rc=%Rrc\n", pTask, pvUser, rc)); if (pTask->enmTransferType == PDMACTASKFILETRANSFER_FLUSH) pdmR3AsyncCompletionCompleteTask(&pTaskFile->Core, rc, true); else { Assert((uint32_t)pTask->DataSeg.cbSeg == pTask->DataSeg.cbSeg && (int32_t)pTask->DataSeg.cbSeg >= 0); uint32_t uOld = ASMAtomicSubS32(&pTaskFile->cbTransferLeft, (int32_t)pTask->DataSeg.cbSeg); /* The first error will be returned. */ if (RT_FAILURE(rc)) ASMAtomicCmpXchgS32(&pTaskFile->rc, rc, VINF_SUCCESS); #ifdef VBOX_WITH_DEBUGGER else { PPDMASYNCCOMPLETIONENDPOINTFILE pEpFile = (PPDMASYNCCOMPLETIONENDPOINTFILE)pTaskFile->Core.pEndpoint; /* Overwrite with injected error code. */ if (pTask->enmTransferType == PDMACTASKFILETRANSFER_READ) rc = ASMAtomicXchgS32(&pEpFile->rcReqRead, VINF_SUCCESS); else rc = ASMAtomicXchgS32(&pEpFile->rcReqWrite, VINF_SUCCESS); if (RT_FAILURE(rc)) ASMAtomicCmpXchgS32(&pTaskFile->rc, rc, VINF_SUCCESS); } #endif if (!(uOld - pTask->DataSeg.cbSeg) && !ASMAtomicXchgBool(&pTaskFile->fCompleted, true)) { #ifdef PDM_ASYNC_COMPLETION_FILE_WITH_DELAY PPDMASYNCCOMPLETIONENDPOINTFILE pEpFile = (PPDMASYNCCOMPLETIONENDPOINTFILE)pTaskFile->Core.pEndpoint; PPDMASYNCCOMPLETIONEPCLASSFILE pEpClassFile = (PPDMASYNCCOMPLETIONEPCLASSFILE)pEpFile->Core.pEpClass; /* Check if we should delay completion of the request. */ if ( ASMAtomicReadU32(&pEpFile->msDelay) > 0 && ASMAtomicReadU32(&pEpFile->cReqsDelay) > 0) { uint64_t tsDelay = pEpFile->msDelay; if (pEpFile->msJitter) tsDelay = (RTRandU32() % 100) > 50 ? pEpFile->msDelay + (RTRandU32() % pEpFile->msJitter) : pEpFile->msDelay - (RTRandU32() % pEpFile->msJitter); ASMAtomicDecU32(&pEpFile->cReqsDelay); /* Arm the delay. */ pTaskFile->tsDelayEnd = RTTimeProgramMilliTS() + tsDelay; /* Append to the list. */ PPDMASYNCCOMPLETIONTASKFILE pHead = NULL; do { pHead = ASMAtomicReadPtrT(&pEpFile->pDelayedHead, PPDMASYNCCOMPLETIONTASKFILE); pTaskFile->pDelayedNext = pHead; } while (!ASMAtomicCmpXchgPtr(&pEpFile->pDelayedHead, pTaskFile, pHead)); if (tsDelay < pEpClassFile->cMilliesNext) { ASMAtomicWriteU64(&pEpClassFile->cMilliesNext, tsDelay); TMTimerSetMillies(pEpClassFile->pTimer, tsDelay); } LogRel(("AIOMgr: Delaying request %#p for %u ms\n", pTaskFile, tsDelay)); } else #endif pdmR3AsyncCompletionCompleteTask(&pTaskFile->Core, pTaskFile->rc, true); } } }
void pdmacFileEpTaskCompleted(PPDMACTASKFILE pTask, void *pvUser, int rc) { PPDMASYNCCOMPLETIONTASKFILE pTaskFile = (PPDMASYNCCOMPLETIONTASKFILE)pvUser; LogFlowFunc(("pTask=%#p pvUser=%#p rc=%Rrc\n", pTask, pvUser, rc)); if (pTask->enmTransferType == PDMACTASKFILETRANSFER_FLUSH) { pdmR3AsyncCompletionCompleteTask(&pTaskFile->Core, rc, true); } else { Assert((uint32_t)pTask->DataSeg.cbSeg == pTask->DataSeg.cbSeg && (int32_t)pTask->DataSeg.cbSeg >= 0); uint32_t uOld = ASMAtomicSubS32(&pTaskFile->cbTransferLeft, (int32_t)pTask->DataSeg.cbSeg); /* The first error will be returned. */ if (RT_FAILURE(rc)) ASMAtomicCmpXchgS32(&pTaskFile->rc, rc, VINF_SUCCESS); #ifdef VBOX_WITH_DEBUGGER else { PPDMASYNCCOMPLETIONENDPOINTFILE pEpFile = (PPDMASYNCCOMPLETIONENDPOINTFILE)pTaskFile->Core.pEndpoint; /* Overwrite with injected error code. */ if (pTask->enmTransferType == PDMACTASKFILETRANSFER_READ) rc = ASMAtomicXchgS32(&pEpFile->rcReqRead, VINF_SUCCESS); else rc = ASMAtomicXchgS32(&pEpFile->rcReqWrite, VINF_SUCCESS); if (RT_FAILURE(rc)) ASMAtomicCmpXchgS32(&pTaskFile->rc, rc, VINF_SUCCESS); } #endif if (!(uOld - pTask->DataSeg.cbSeg) && !ASMAtomicXchgBool(&pTaskFile->fCompleted, true)) { #ifdef PDM_ASYNC_COMPLETION_FILE_WITH_DELAY PPDMASYNCCOMPLETIONENDPOINTFILE pEpFile = (PPDMASYNCCOMPLETIONENDPOINTFILE)pTaskFile->Core.pEndpoint; /* Check if we should delay completion of the request. */ if ( ASMAtomicReadU32(&pEpFile->msDelay) > 0 && ASMAtomicCmpXchgPtr(&pEpFile->pReqDelayed, pTaskFile, NULL)) { /* Arm the delay. */ pEpFile->tsDelayEnd = RTTimeProgramMilliTS() + pEpFile->msDelay; LogRel(("AIOMgr: Delaying request %#p for %u ms\n", pTaskFile, pEpFile->msDelay)); return; } #endif pdmR3AsyncCompletionCompleteTask(&pTaskFile->Core, pTaskFile->rc, true); #if PDM_ASYNC_COMPLETION_FILE_WITH_DELAY /* Check for an expired delay. */ if ( pEpFile->pReqDelayed != NULL && RTTimeProgramMilliTS() >= pEpFile->tsDelayEnd) { pTaskFile = ASMAtomicXchgPtrT(&pEpFile->pReqDelayed, NULL, PPDMASYNCCOMPLETIONTASKFILE); ASMAtomicXchgU32(&pEpFile->msDelay, 0); LogRel(("AIOMgr: Delayed request %#p completed\n", pTaskFile)); pdmR3AsyncCompletionCompleteTask(&pTaskFile->Core, pTaskFile->rc, true); } #endif } } }