儲存庫 vbox 的更動 35455
- 時間撮記:
- 2011-1-10 下午01:52:26 (14 年 以前)
- 位置:
- trunk/src/VBox/Main
- 檔案:
-
- 修改 2 筆資料
圖例:
- 未更動
- 新增
- 刪除
-
trunk/src/VBox/Main/include/GuestImpl.h
r35374 r35455 179 179 CallbackMapIter getCtrlCallbackContextByID(uint32_t u32ContextID); 180 180 GuestProcessMapIter getProcessByPID(uint32_t u32PID); 181 void notifyCtrlCallbackContext(Guest::CallbackMapIter it, const char *pszText); 181 182 void destroyCtrlCallbackContext(CallbackMapIter it); 182 183 uint32_t addCtrlCallbackContext(eVBoxGuestCtrlCallbackType enmType, void *pvData, uint32_t cbData, Progress* pProgress); 184 HRESULT waitForProcessStatusChange(ULONG uPID, PULONG puRetStatus, PULONG puRetExitCode, ULONG uTimeoutMS); 183 185 # endif 184 186 -
trunk/src/VBox/Main/src-client/GuestCtrlImpl.cpp
r35437 r35455 296 296 size_t cbTransfered = 0; 297 297 size_t cbRead; 298 SafeArray<BYTE> aInputData(_ 1M);298 SafeArray<BYTE> aInputData(_64K); 299 299 while ( SUCCEEDED(execProgress->COMGETTER(Completed(&fCompleted))) 300 300 && !fCompleted) … … 305 305 { 306 306 vrc = RTFileRead(fileSource, (uint8_t*)aInputData.raw(), 307 RT_MIN(cbToRead, _ 1M), &cbRead);307 RT_MIN(cbToRead, _64K), &cbRead); 308 308 /* 309 309 * Some other error occured? There might be a chance that RTFileRead … … 326 326 ULONG uFlags = ProcessInputFlag_None; 327 327 /* Did we reach the end of the content we want to transfer (last chunk)? */ 328 if ( (cbRead < _ 1M)328 if ( (cbRead < _64K) 329 329 /* ... or does the user want to cancel? */ 330 330 || ( SUCCEEDED(aTask->progress->COMGETTER(Canceled(&fCanceled))) … … 358 358 break; 359 359 360 /* Did the user cancel the operation above? */ 361 if (fCanceled) 362 break; 363 360 364 /* Progress canceled by Main API? */ 361 365 if ( SUCCEEDED(execProgress->COMGETTER(Canceled(&fCanceled))) … … 370 374 371 375 if (SUCCEEDED(rc)) 372 aTask->progress->notifyComplete(S_OK); 376 { 377 /* 378 * If we got here this means the started process either was completed, 379 * canceled or we simply got all stuff transferred. 380 */ 381 ULONG uRetStatus, uRetExitCode; 382 rc = pGuest->waitForProcessStatusChange(uPID, &uRetStatus, &uRetExitCode, 10 * 1000 /* 10s timeout. */); 383 if (FAILED(rc)) 384 { 385 rc = TaskGuest::setProgressErrorInfo(rc, aTask->progress, pGuest); 386 } 387 else 388 { 389 if ( uRetExitCode != 0 390 || uRetStatus != PROC_STS_TEN) 391 { 392 rc = TaskGuest::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress, 393 Guest::tr("Guest reported error %u while copying file \"%s\" to \"%s\""), 394 uRetExitCode, aTask->strSource.c_str(), aTask->strDest.c_str()); 395 } 396 } 397 } 398 399 if (SUCCEEDED(rc)) 400 { 401 if (fCanceled) 402 { 403 /* 404 * In order to make the progress object to behave nicely, we also have to 405 * notify the object with a complete event when it's canceled. 406 */ 407 aTask->progress->notifyComplete(VBOX_E_IPRT_ERROR, 408 COM_IIDOF(IGuest), 409 Guest::getStaticComponentName(), 410 Guest::tr("Copying file \"%s\" canceled"), aTask->strSource.c_str()); 411 } 412 else 413 { 414 /* 415 * Even if we succeeded until here make sure to check whether we really transfered 416 * everything. 417 */ 418 if (!cbTransfered) 419 { 420 /* If nothing was transfered this means "vbox_cat" wasn't able to write 421 * to the destination -> access denied. */ 422 rc = TaskGuest::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress, 423 Guest::tr("Access denied when copying file \"%s\" to \"%s\""), 424 aTask->strSource.c_str(), aTask->strDest.c_str()); 425 } 426 else if (cbTransfered < cbSize) 427 { 428 /* If we did not copy all let the user know. */ 429 rc = TaskGuest::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress, 430 Guest::tr("Copying file \"%s\" failed (%u/%u bytes transfered)"), 431 aTask->strSource.c_str(), cbTransfered, cbSize); 432 } 433 else /* Yay, all went fine! */ 434 aTask->progress->notifyComplete(S_OK); 435 } 436 } 373 437 } 374 438 } … … 1080 1144 case VBOXGUESTCTRLCALLBACKTYPE_EXEC_OUTPUT: 1081 1145 { 1082 PCALLBACKDATAEXECOUT pItData = ( CALLBACKDATAEXECOUT*)it2->second.pvData;1146 PCALLBACKDATAEXECOUT pItData = (PCALLBACKDATAEXECOUT)it2->second.pvData; 1083 1147 AssertPtr(pItData); 1084 1148 if (pItData->u32PID == pCBData->u32PID) 1085 destroyCtrlCallbackContext(it2); 1149 notifyCtrlCallbackContext(it2, errMsg.c_str()); 1150 break; 1151 } 1152 1153 /* When waiting for injecting process input while the process is destroyed, 1154 * make sure we also destroy the actual waiting operation (internal progress object) 1155 * in order to not block the caller. */ 1156 case VBOXGUESTCTRLCALLBACKTYPE_EXEC_INPUT_STATUS: 1157 { 1158 PCALLBACKDATAEXECINSTATUS pItData = (PCALLBACKDATAEXECINSTATUS)it2->second.pvData; 1159 AssertPtr(pItData); 1160 if (pItData->u32PID == pCBData->u32PID) 1161 notifyCtrlCallbackContext(it2, errMsg.c_str()); 1086 1162 break; 1087 1163 } … … 1093 1169 } 1094 1170 1095 HRESULT hr2 = it->second.pProgress->notifyComplete(VBOX_E_IPRT_ERROR, 1096 COM_IIDOF(IGuest), 1097 Guest::getStaticComponentName(), 1098 "%s", errMsg.c_str()); 1099 AssertComRC(hr2); 1171 /* Let the caller know what went wrong ... */ 1172 notifyCtrlCallbackContext(it, errMsg.c_str()); 1173 1100 1174 LogFlowFunc(("Process (CID=%u, status=%u) reported error: %s\n", 1101 1175 pData->hdr.u32ContextID, pData->u32Status, errMsg.c_str())); … … 1189 1263 pCBData->cbProcessed = pData->cbProcessed; 1190 1264 1191 /* Was progress canceled before? */ 1192 BOOL fCanceled; 1193 ComAssert(!it->second.pProgress.isNull()); 1194 if (SUCCEEDED(it->second.pProgress->COMGETTER(Canceled)(&fCanceled)) && fCanceled) 1195 { 1196 it->second.pProgress->notifyComplete(VBOX_E_IPRT_ERROR, 1197 COM_IIDOF(IGuest), 1198 Guest::getStaticComponentName(), 1199 Guest::tr("The input operation was canceled")); 1200 } 1201 else 1202 { 1203 BOOL fCompleted; 1204 if ( SUCCEEDED(it->second.pProgress->COMGETTER(Completed)(&fCompleted)) 1205 && !fCompleted) 1206 { 1207 /* If we previously got completed notification, don't trigger again. */ 1208 it->second.pProgress->notifyComplete(S_OK); 1209 } 1265 /* Only trigger completion once. */ 1266 BOOL fCompleted; 1267 if ( SUCCEEDED(it->second.pProgress->COMGETTER(Completed)(&fCompleted)) 1268 && !fCompleted) 1269 { 1270 it->second.pProgress->notifyComplete(S_OK); 1210 1271 } 1211 1272 } … … 1225 1286 { 1226 1287 LogFlowFunc(("Client with CID=%u disconnected\n", it->first)); 1227 destroyCtrlCallbackContext(it);1288 notifyCtrlCallbackContext(it, Guest::tr("Client disconnected")); 1228 1289 } 1229 1290 return rc; … … 1254 1315 } 1255 1316 1317 /* Remove callback context (not used anymore). */ 1318 mCallbackMap.erase(it); 1319 } 1320 1321 /* No locking here; */ 1322 void Guest::notifyCtrlCallbackContext(Guest::CallbackMapIter it, const char *pszText) 1323 { 1324 AssertPtr(pszText); 1325 LogFlowFunc(("Handling callback with CID=%u ...\n", it->first)); 1326 1256 1327 /* Notify outstanding waits for progress ... */ 1257 1328 if ( it->second.pProgress 1258 1329 && !it->second.pProgress.isNull()) 1259 1330 { 1260 LogFlowFunc(("Handling progress for CID=%u ...\n", it->first)); 1331 LogFlowFunc(("Notifying progress for CID=%u (Reason: %s) ...\n", 1332 it->first, pszText)); 1261 1333 1262 1334 /* … … 1268 1340 if (!fCompleted) 1269 1341 { 1270 LogFlowFunc(("Progress of CID=%u *not* completed, cancelling ...\n", it->first));1271 1272 /* Only cancel if not canceled before! */1273 BOOL fCanceled;1274 if (SUCCEEDED(it->second.pProgress->COMGETTER(Canceled)(&fCanceled)) && !fCanceled)1275 it->second.pProgress->Cancel();1276 1277 1342 /* 1278 1343 * To get waitForCompletion completed (unblocked) we have to notify it if necessary (only … … 1285 1350 COM_IIDOF(IGuest), 1286 1351 Guest::getStaticComponentName(), 1287 Guest::tr("The operation was canceled because client is shutting down"));1352 pszText); 1288 1353 } 1289 1354 /* … … 1352 1417 #endif 1353 1418 return uNewContext; 1419 } 1420 1421 HRESULT Guest::waitForProcessStatusChange(ULONG uPID, PULONG puRetStatus, PULONG puRetExitCode, ULONG uTimeoutMS) 1422 { 1423 AssertPtr(puRetStatus); 1424 AssertPtr(puRetExitCode); 1425 1426 if (uTimeoutMS == 0) 1427 uTimeoutMS = UINT32_MAX; 1428 1429 uint64_t u64StartMS = RTTimeMilliTS(); 1430 1431 HRESULT hRC; 1432 ULONG uRetFlagsIgnored; 1433 do 1434 { 1435 /* 1436 * Do some busy waiting within the specified time period (if any). 1437 */ 1438 if ( uTimeoutMS != UINT32_MAX 1439 && RTTimeMilliTS() - u64StartMS > uTimeoutMS) 1440 { 1441 hRC = setError(VBOX_E_IPRT_ERROR, 1442 tr("The process (PID %u) did not change its status within time (%ums)"), 1443 uPID, uTimeoutMS); 1444 break; 1445 } 1446 hRC = GetProcessStatus(uPID, puRetExitCode, &uRetFlagsIgnored, puRetStatus); 1447 if (FAILED(hRC)) 1448 break; 1449 RTThreadSleep(100); 1450 } while(*puRetStatus == PROC_STS_STARTED && SUCCEEDED(hRC)); 1451 return hRC; 1354 1452 } 1355 1453 #endif /* VBOX_WITH_GUEST_CONTROL */ … … 1736 1834 *aBytesWritten = 0; 1737 1835 1738 /* Search for existing PID. */ 1739 GuestProcessMapIterConst itProc = getProcessByPID(aPID); 1740 if (itProc != mGuestProcessMap.end()) 1741 { 1742 /* PID exists; check if process is still running. */ 1743 if (itProc->second.mStatus != PROC_STS_STARTED) 1836 { 1837 /* Take read lock to prevent races. */ 1838 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 1839 1840 /* Search for existing PID. */ 1841 GuestProcessMapIterConst itProc = getProcessByPID(aPID); 1842 if (itProc != mGuestProcessMap.end()) 1744 1843 { 1844 /* PID exists; check if process is still running. */ 1845 if (itProc->second.mStatus != PROC_STS_STARTED) 1846 rc = setError(VBOX_E_IPRT_ERROR, 1847 Guest::tr("Cannot inject input to not running process (PID %u)"), aPID); 1848 } 1849 else 1745 1850 rc = setError(VBOX_E_IPRT_ERROR, 1746 tr("Process (PID %u) does not run anymore! Status: %ld, Flags: %u, Exit Code: %u"), 1747 aPID, itProc->second.mStatus, itProc->second.mFlags, itProc->second.mExitCode); 1748 } 1749 } 1750 else 1751 rc = setError(VBOX_E_IPRT_ERROR, 1752 tr("Process (PID %u) not found!"), aPID); 1851 Guest::tr("Cannot inject input to non-existent process (PID %u)"), aPID); 1852 } 1753 1853 1754 1854 if (SUCCEEDED(rc)) … … 1756 1856 /* 1757 1857 * Create progress object. 1758 * This progress object, compared to the one in executeProgress() above 1759 * is only local and is used to determine whether the operation finished1760 * or got canceled.1858 * This progress object, compared to the one in executeProgress() above, 1859 * is only single-stage local and is used to determine whether the operation 1860 * finished or got canceled. 1761 1861 */ 1762 ComObjPtr <Progress> p rogress;1763 rc = p rogress.createObject();1862 ComObjPtr <Progress> pProgress; 1863 rc = pProgress.createObject(); 1764 1864 if (SUCCEEDED(rc)) 1765 1865 { 1766 rc = p rogress->init(static_cast<IGuest*>(this),1767 Bstr(tr("Setting input for process")).raw(),1768 TRUE /* Cancelable */);1866 rc = pProgress->init(static_cast<IGuest*>(this), 1867 Bstr(tr("Setting input for process")).raw(), 1868 TRUE /* Cancelable */); 1769 1869 } 1770 if (FAILED(rc)) return rc; 1870 if (FAILED(rc)) throw rc; 1871 ComAssert(!pProgress.isNull()); 1771 1872 1772 1873 /* Adjust timeout. */ … … 1775 1876 1776 1877 PCALLBACKDATAEXECINSTATUS pData = (PCALLBACKDATAEXECINSTATUS)RTMemAlloc(sizeof(CALLBACKDATAEXECINSTATUS)); 1878 if (NULL == pData) throw rc; 1777 1879 AssertReturn(pData, VBOX_E_IPRT_ERROR); 1778 1880 RT_ZERO(*pData); 1881 1779 1882 /* Save PID + output flags for later use. */ 1780 1883 pData->u32PID = aPID; 1781 1884 pData->u32Flags = aFlags; 1885 1782 1886 /* Add job to callback contexts. */ 1783 1887 uint32_t uContextID = addCtrlCallbackContext(VBOXGUESTCTRLCALLBACKTYPE_EXEC_INPUT_STATUS, 1784 pData, sizeof(CALLBACKDATAEXECINSTATUS), p rogress);1888 pData, sizeof(CALLBACKDATAEXECINSTATUS), pProgress); 1785 1889 Assert(uContextID > 0); 1786 1890 … … 1838 1942 if (FAILED(rc)) throw rc; 1839 1943 1840 /* Was the operation canceled by one of the parties? */ 1841 rc = it->second.pProgress->COMGETTER(Canceled)(&fCanceled); 1842 if (FAILED(rc)) throw rc; 1843 1844 if (!fCanceled) 1845 { 1846 BOOL fCompleted; 1847 if ( SUCCEEDED(it->second.pProgress->COMGETTER(Completed)(&fCompleted)) 1848 && fCompleted) 1849 { 1850 PCALLBACKDATAEXECINSTATUS pStatusData = (PCALLBACKDATAEXECINSTATUS)it->second.pvData; 1851 Assert(it->second.cbData == sizeof(CALLBACKDATAEXECINSTATUS)); 1852 AssertPtr(pStatusData); 1853 1854 *aBytesWritten = pStatusData->cbProcessed; 1855 } 1856 } 1857 else /* Operation was canceled. */ 1858 vrc = VERR_CANCELLED; 1859 1860 if (RT_FAILURE(vrc)) 1861 { 1862 if (vrc == VERR_CANCELLED) 1863 { 1864 rc = setError(VBOX_E_IPRT_ERROR, 1865 tr("The input operation was canceled")); 1866 } 1867 else 1868 { 1869 rc = setError(E_UNEXPECTED, 1870 tr("The service call failed with error %Rrc"), vrc); 1871 } 1872 } 1944 /* Was the call completed within time? */ 1945 LONG uResult; 1946 if ( SUCCEEDED(it->second.pProgress->COMGETTER(ResultCode)(&uResult)) 1947 && uResult == S_OK) 1948 { 1949 PCALLBACKDATAEXECINSTATUS pStatusData = (PCALLBACKDATAEXECINSTATUS)it->second.pvData; 1950 AssertPtr(pStatusData); 1951 Assert(it->second.cbData == sizeof(CALLBACKDATAEXECINSTATUS)); 1952 1953 *aBytesWritten = pStatusData->cbProcessed; 1954 } 1955 else if ( SUCCEEDED(it->second.pProgress->COMGETTER(Canceled)(&fCanceled)) 1956 && fCanceled) 1957 { 1958 rc = setError(VBOX_E_IPRT_ERROR, 1959 tr("The input operation was canceled by the guest")); 1960 } 1961 else 1962 rc = setError(VBOX_E_IPRT_ERROR, 1963 tr("The input operation was not acknowledged from guest within time (%ums)"), aTimeoutMS); 1873 1964 1874 1965 { 1875 1966 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 1876 /* 1877 * Destroy locally used progress object. 1878 */ 1967 /* Destroy locally used progress object. */ 1879 1968 destroyCtrlCallbackContext(it); 1880 1969 } 1881 1882 /* Remove callback context (not used anymore). */1883 mCallbackMap.erase(it);1884 1970 } 1885 1971 else /* PID lookup failed. */ 1886 1972 rc = setError(VBOX_E_IPRT_ERROR, 1887 tr("Process (PID %u) not found !"), aPID);1973 tr("Process (PID %u) not found"), aPID); 1888 1974 } 1889 1975 else /* HGCM operation failed. */ 1890 1976 rc = setError(E_UNEXPECTED, 1891 tr("The HGCM call failed with error %Rrc"), vrc);1977 tr("The HGCM call failed (%Rrc)"), vrc); 1892 1978 1893 1979 /* Cleanup. */ 1894 progress->uninit(); 1895 progress.setNull(); 1980 if (!pProgress.isNull()) 1981 pProgress->uninit(); 1982 pProgress.setNull(); 1896 1983 } 1897 1984 } … … 1938 2025 rc = progress->init(static_cast<IGuest*>(this), 1939 2026 Bstr(tr("Getting output of process")).raw(), 1940 TRUE );2027 TRUE /* Cancelable */); 1941 2028 } 1942 2029 if (FAILED(rc)) return rc; … … 2072 2159 { 2073 2160 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 2074 /* 2075 * Destroy locally used progress object. 2076 */ 2161 /* Destroy locally used progress object. */ 2077 2162 destroyCtrlCallbackContext(it); 2078 2163 } 2079 2080 /* Remove callback context (not used anymore). */2081 mCallbackMap.erase(it);2082 2164 } 2083 2165 else /* PID lookup failed. */
注意:
瀏覽 TracChangeset
來幫助您使用更動檢視器