/** * Notify the progress object that we're almost at the point of no return. * * This atomically checks for and disables cancelation. Calls to * IProgress::Cancel() made after a successful call to this method will fail * and the user can be told. While this isn't entirely clean behavior, it * prevents issues with an irreversible actually operation succeeding while the * user believe it was rolled back. * * @returns Success indicator. * @retval true on success. * @retval false if the progress object has already been canceled or is in an * invalid state */ bool Progress::i_notifyPointOfNoReturn(void) { AutoCaller autoCaller(this); AssertComRCReturn(autoCaller.rc(), false); AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); if (mCanceled) { LogThisFunc(("returns false\n")); return false; } mCancelable = FALSE; LogThisFunc(("returns true\n")); return true; }
HRESULT Progress::cancel() { AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); if (!mCancelable) return setError(VBOX_E_INVALID_OBJECT_STATE, tr("Operation cannot be canceled")); if (!mCanceled) { LogThisFunc(("Canceling\n")); mCanceled = TRUE; if (m_pfnCancelCallback) m_pfnCancelCallback(m_pvCancelUserArg); } else LogThisFunc(("Already canceled\n")); return S_OK; }
HRESULT Progress::setTimeout(ULONG aTimeout) { AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); if (!mCancelable) return setError(VBOX_E_INVALID_OBJECT_STATE, tr("Operation cannot be canceled")); LogThisFunc(("%#x => %#x\n", m_cMsTimeout, aTimeout)); m_cMsTimeout = aTimeout; return S_OK; }
STDMETHODIMP Progress::COMSETTER(Timeout)(ULONG aTimeout) { AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); if (!mCancelable) return setError(VBOX_E_INVALID_OBJECT_STATE, tr("Operation cannot be canceled")); LogThisFunc(("%#x => %#x\n", m_cMsTimeout, aTimeout)); m_cMsTimeout = aTimeout; return S_OK; }
/** * Internal worker for ThreadTask::createThread, * ThreadTask::createThreadWithType. * * @note Always consumes @a this! */ HRESULT ThreadTask::createThreadInternal(RTTHREADTYPE enmType) { LogThisFunc(("Created \"%s\"\n", m_strTaskName.c_str())); mAsync = true; int vrc = RTThreadCreate(NULL, taskHandlerThreadProc, (void *)this, 0, enmType, 0, m_strTaskName.c_str()); if (RT_SUCCESS(vrc)) return S_OK; mAsync = false; delete this; return E_FAIL; }
int GuestDnDResponse::onDispatch(uint32_t u32Function, void *pvParms, uint32_t cbParms) { LogFlowFunc(("u32Function=%RU32, pvParms=%p, cbParms=%RU32\n", u32Function, pvParms, cbParms)); int rc = VERR_WRONG_ORDER; /* Play safe. */ bool fTryCallbacks = false; switch (u32Function) { case DragAndDropSvc::GUEST_DND_CONNECT: { LogThisFunc(("Client connected\n")); /* Nothing to do here (yet). */ rc = VINF_SUCCESS; break; } case DragAndDropSvc::GUEST_DND_DISCONNECT: { LogThisFunc(("Client disconnected\n")); rc = setProgress(100, DND_PROGRESS_CANCELLED, VINF_SUCCESS); break; } case DragAndDropSvc::GUEST_DND_HG_ACK_OP: { DragAndDropSvc::PVBOXDNDCBHGACKOPDATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBHGACKOPDATA>(pvParms); AssertPtr(pCBData); AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBHGACKOPDATA) == cbParms, VERR_INVALID_PARAMETER); AssertReturn(DragAndDropSvc::CB_MAGIC_DND_HG_ACK_OP == pCBData->hdr.uMagic, VERR_INVALID_PARAMETER); setDefAction(pCBData->uAction); rc = notifyAboutGuestResponse(); break; } case DragAndDropSvc::GUEST_DND_HG_REQ_DATA: { DragAndDropSvc::PVBOXDNDCBHGREQDATADATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBHGREQDATADATA>(pvParms); AssertPtr(pCBData); AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBHGREQDATADATA) == cbParms, VERR_INVALID_PARAMETER); AssertReturn(DragAndDropSvc::CB_MAGIC_DND_HG_REQ_DATA == pCBData->hdr.uMagic, VERR_INVALID_PARAMETER); if ( pCBData->cbFormat == 0 || pCBData->cbFormat > _64K /** @todo Make this configurable? */ || pCBData->pszFormat == NULL) { rc = VERR_INVALID_PARAMETER; } else if (!RTStrIsValidEncoding(pCBData->pszFormat)) { rc = VERR_INVALID_PARAMETER; } else { setFormats(GuestDnD::toFormatList(pCBData->pszFormat)); rc = VINF_SUCCESS; } int rc2 = notifyAboutGuestResponse(); if (RT_SUCCESS(rc)) rc = rc2; break; } case DragAndDropSvc::GUEST_DND_HG_EVT_PROGRESS: { DragAndDropSvc::PVBOXDNDCBHGEVTPROGRESSDATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBHGEVTPROGRESSDATA>(pvParms); AssertPtr(pCBData); AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBHGEVTPROGRESSDATA) == cbParms, VERR_INVALID_PARAMETER); AssertReturn(DragAndDropSvc::CB_MAGIC_DND_HG_EVT_PROGRESS == pCBData->hdr.uMagic, VERR_INVALID_PARAMETER); rc = setProgress(pCBData->uPercentage, pCBData->uStatus, pCBData->rc); if (RT_SUCCESS(rc)) rc = notifyAboutGuestResponse(); break; } #ifdef VBOX_WITH_DRAG_AND_DROP_GH case DragAndDropSvc::GUEST_DND_GH_ACK_PENDING: { DragAndDropSvc::PVBOXDNDCBGHACKPENDINGDATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBGHACKPENDINGDATA>(pvParms); AssertPtr(pCBData); AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBGHACKPENDINGDATA) == cbParms, VERR_INVALID_PARAMETER); AssertReturn(DragAndDropSvc::CB_MAGIC_DND_GH_ACK_PENDING == pCBData->hdr.uMagic, VERR_INVALID_PARAMETER); if ( pCBData->cbFormat == 0 || pCBData->cbFormat > _64K /** @todo Make the maximum size configurable? */ || pCBData->pszFormat == NULL) { rc = VERR_INVALID_PARAMETER; } else if (!RTStrIsValidEncoding(pCBData->pszFormat)) { rc = VERR_INVALID_PARAMETER; } else { setFormats (GuestDnD::toFormatList(pCBData->pszFormat)); setDefAction (pCBData->uDefAction); setAllActions(pCBData->uAllActions); rc = VINF_SUCCESS; } int rc2 = notifyAboutGuestResponse(); if (RT_SUCCESS(rc)) rc = rc2; break; } #endif /* VBOX_WITH_DRAG_AND_DROP_GH */ default: /* * Try if the event is covered by a registered callback. */ fTryCallbacks = true; break; } /* * Try the host's installed callbacks (if any). */ if (fTryCallbacks) { GuestDnDCallbackMap::const_iterator it = m_mapCallbacks.find(u32Function); if (it != m_mapCallbacks.end()) { AssertPtr(it->second.pfnCallback); rc = it->second.pfnCallback(u32Function, pvParms, cbParms, it->second.pvUser); } else { LogFlowFunc(("No callback for function %RU32 defined (%zu callbacks total)\n", u32Function, m_mapCallbacks.size())); rc = VERR_NOT_SUPPORTED; /* Tell the guest. */ } } LogFlowFunc(("Returning rc=%Rrc\n", rc)); return rc; }
void Guest::i_updateStats(uint64_t iTick) { uint64_t cbFreeTotal = 0; uint64_t cbAllocTotal = 0; uint64_t cbBalloonedTotal = 0; uint64_t cbSharedTotal = 0; uint64_t cbSharedMem = 0; ULONG uNetStatRx = 0; ULONG uNetStatTx = 0; ULONG aGuestStats[GUESTSTATTYPE_MAX]; RT_ZERO(aGuestStats); AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); ULONG validStats = mVmValidStats; /* Check if we have anything to report */ if (validStats) { mVmValidStats = pm::VMSTATMASK_NONE; memcpy(aGuestStats, mCurrentGuestStat, sizeof(aGuestStats)); } alock.release(); /* * Calling SessionMachine may take time as the object resides in VBoxSVC * process. This is why we took a snapshot of currently collected stats * and released the lock. */ Console::SafeVMPtrQuiet ptrVM(mParent); if (ptrVM.isOk()) { int rc; /* * There is no point in collecting VM shared memory if other memory * statistics are not available yet. Or is there? */ if (validStats) { /* Query the missing per-VM memory statistics. */ uint64_t cbTotalMemIgn, cbPrivateMemIgn, cbZeroMemIgn; rc = PGMR3QueryMemoryStats(ptrVM.rawUVM(), &cbTotalMemIgn, &cbPrivateMemIgn, &cbSharedMem, &cbZeroMemIgn); if (rc == VINF_SUCCESS) validStats |= pm::VMSTATMASK_GUEST_MEMSHARED; } if (mCollectVMMStats) { rc = PGMR3QueryGlobalMemoryStats(ptrVM.rawUVM(), &cbAllocTotal, &cbFreeTotal, &cbBalloonedTotal, &cbSharedTotal); AssertRC(rc); if (rc == VINF_SUCCESS) validStats |= pm::VMSTATMASK_VMM_ALLOC | pm::VMSTATMASK_VMM_FREE | pm::VMSTATMASK_VMM_BALOON | pm::VMSTATMASK_VMM_SHARED; } uint64_t uRxPrev = mNetStatRx; uint64_t uTxPrev = mNetStatTx; mNetStatRx = mNetStatTx = 0; rc = STAMR3Enum(ptrVM.rawUVM(), "/Public/Net/*/Bytes*", i_staticEnumStatsCallback, this); AssertRC(rc); uint64_t uTsNow = RTTimeNanoTS(); uint64_t cNsPassed = uTsNow - mNetStatLastTs; if (cNsPassed >= 1000) { mNetStatLastTs = uTsNow; uNetStatRx = (ULONG)((mNetStatRx - uRxPrev) * 1000000 / (cNsPassed / 1000)); /* in bytes per second */ uNetStatTx = (ULONG)((mNetStatTx - uTxPrev) * 1000000 / (cNsPassed / 1000)); /* in bytes per second */ validStats |= pm::VMSTATMASK_NET_RX | pm::VMSTATMASK_NET_TX; LogFlowThisFunc(("Net Rx=%llu Tx=%llu Ts=%llu Delta=%llu\n", mNetStatRx, mNetStatTx, uTsNow, cNsPassed)); } else { /* Can happen on resume or if we're using a non-monotonic clock source for the timer and the time is adjusted. */ mNetStatRx = uRxPrev; mNetStatTx = uTxPrev; LogThisFunc(("Net Ts=%llu cNsPassed=%llu - too small interval\n", uTsNow, cNsPassed)); } } mParent->i_reportVmStatistics(validStats, aGuestStats[GUESTSTATTYPE_CPUUSER], aGuestStats[GUESTSTATTYPE_CPUKERNEL], aGuestStats[GUESTSTATTYPE_CPUIDLE], /* Convert the units for RAM usage stats: page (4K) -> 1KB units */ mCurrentGuestStat[GUESTSTATTYPE_MEMTOTAL] * (_4K/_1K), mCurrentGuestStat[GUESTSTATTYPE_MEMFREE] * (_4K/_1K), mCurrentGuestStat[GUESTSTATTYPE_MEMBALLOON] * (_4K/_1K), (ULONG)(cbSharedMem / _1K), /* bytes -> KB */ mCurrentGuestStat[GUESTSTATTYPE_MEMCACHE] * (_4K/_1K), mCurrentGuestStat[GUESTSTATTYPE_PAGETOTAL] * (_4K/_1K), (ULONG)(cbAllocTotal / _1K), /* bytes -> KB */ (ULONG)(cbFreeTotal / _1K), (ULONG)(cbBalloonedTotal / _1K), (ULONG)(cbSharedTotal / _1K), uNetStatRx, uNetStatTx); }
/** * Creates a TCP server that listens for the source machine and passes control * over to Console::teleporterTrgServeConnection(). * * @returns VBox status code. * @param pUVM The user-mode VM handle * @param pMachine The IMachine for the virtual machine. * @param pErrorMsg Pointer to the error string for VMSetError. * @param fStartPaused Whether to start it in the Paused (true) or * Running (false) state, * @param pProgress Pointer to the progress object. * @param pfPowerOffOnFailure Whether the caller should power off * the VM on failure. * * @remarks The caller expects error information to be set on failure. * @todo Check that all the possible failure paths sets error info... */ HRESULT Console::teleporterTrg(PUVM pUVM, IMachine *pMachine, Utf8Str *pErrorMsg, bool fStartPaused, Progress *pProgress, bool *pfPowerOffOnFailure) { LogThisFunc(("pUVM=%p pMachine=%p fStartPaused=%RTbool pProgress=%p\n", pUVM, pMachine, fStartPaused, pProgress)); *pfPowerOffOnFailure = true; /* * Get the config. */ ULONG uPort; HRESULT hrc = pMachine->COMGETTER(TeleporterPort)(&uPort); if (FAILED(hrc)) return hrc; ULONG const uPortOrg = uPort; Bstr bstrAddress; hrc = pMachine->COMGETTER(TeleporterAddress)(bstrAddress.asOutParam()); if (FAILED(hrc)) return hrc; Utf8Str strAddress(bstrAddress); const char *pszAddress = strAddress.isEmpty() ? NULL : strAddress.c_str(); Bstr bstrPassword; hrc = pMachine->COMGETTER(TeleporterPassword)(bstrPassword.asOutParam()); if (FAILED(hrc)) return hrc; Utf8Str strPassword(bstrPassword); strPassword.append('\n'); /* To simplify password checking. */ /* * Create the TCP server. */ int vrc; PRTTCPSERVER hServer; if (uPort) vrc = RTTcpServerCreateEx(pszAddress, uPort, &hServer); else { for (int cTries = 10240; cTries > 0; cTries--) { uPort = RTRandU32Ex(cTries >= 8192 ? 49152 : 1024, 65534); vrc = RTTcpServerCreateEx(pszAddress, uPort, &hServer); if (vrc != VERR_NET_ADDRESS_IN_USE) break; } if (RT_SUCCESS(vrc)) { hrc = pMachine->COMSETTER(TeleporterPort)(uPort); if (FAILED(hrc)) { RTTcpServerDestroy(hServer); return hrc; } } } if (RT_FAILURE(vrc)) return setError(E_FAIL, tr("RTTcpServerCreateEx failed with status %Rrc"), vrc); /* * Create a one-shot timer for timing out after 5 mins. */ RTTIMERLR hTimerLR; vrc = RTTimerLRCreateEx(&hTimerLR, 0 /*ns*/, RTTIMER_FLAGS_CPU_ANY, teleporterDstTimeout, hServer); if (RT_SUCCESS(vrc)) { vrc = RTTimerLRStart(hTimerLR, 5*60*UINT64_C(1000000000) /*ns*/); if (RT_SUCCESS(vrc)) { /* * Do the job, when it returns we're done. */ TeleporterStateTrg theState(this, pUVM, pProgress, pMachine, mControl, &hTimerLR, fStartPaused); theState.mstrPassword = strPassword; theState.mhServer = hServer; void *pvUser = static_cast<void *>(static_cast<TeleporterState *>(&theState)); if (pProgress->setCancelCallback(teleporterProgressCancelCallback, pvUser)) { LogRel(("Teleporter: Waiting for incoming VM...\n")); hrc = pProgress->SetNextOperation(Bstr(tr("Waiting for incoming VM")).raw(), 1); if (SUCCEEDED(hrc)) { vrc = RTTcpServerListen(hServer, Console::teleporterTrgServeConnection, &theState); pProgress->setCancelCallback(NULL, NULL); if (vrc == VERR_TCP_SERVER_STOP) { vrc = theState.mRc; /* Power off the VM on failure unless the state callback already did that. */ *pfPowerOffOnFailure = false; if (RT_SUCCESS(vrc)) hrc = S_OK; else { VMSTATE enmVMState = VMR3GetStateU(pUVM); if ( enmVMState != VMSTATE_OFF && enmVMState != VMSTATE_POWERING_OFF) *pfPowerOffOnFailure = true; /* Set error. */ if (pErrorMsg->length()) hrc = setError(E_FAIL, "%s", pErrorMsg->c_str()); else hrc = setError(E_FAIL, tr("Teleporation failed (%Rrc)"), vrc); } } else if (vrc == VERR_TCP_SERVER_SHUTDOWN) { BOOL fCanceled = TRUE; hrc = pProgress->COMGETTER(Canceled)(&fCanceled); if (FAILED(hrc) || fCanceled) hrc = setError(E_FAIL, tr("Teleporting canceled")); else hrc = setError(E_FAIL, tr("Teleporter timed out waiting for incoming connection")); LogRel(("Teleporter: RTTcpServerListen aborted - %Rrc\n", vrc)); } else { hrc = setError(E_FAIL, tr("Unexpected RTTcpServerListen status code %Rrc"), vrc); LogRel(("Teleporter: Unexpected RTTcpServerListen rc: %Rrc\n", vrc)); } } else LogThisFunc(("SetNextOperation failed, %Rhrc\n", hrc)); } else { LogThisFunc(("Canceled - check point #1\n")); hrc = setError(E_FAIL, tr("Teleporting canceled")); } } else hrc = setError(E_FAIL, "RTTimerLRStart -> %Rrc", vrc); RTTimerLRDestroy(hTimerLR); } else hrc = setError(E_FAIL, "RTTimerLRCreate -> %Rrc", vrc); RTTcpServerDestroy(hServer); /* * If we change TeleporterPort above, set it back to it's original * value before returning. */ if (uPortOrg != uPort) { ErrorInfoKeeper Eik; pMachine->COMSETTER(TeleporterPort)(uPortOrg); } return hrc; }