VirtualBox

儲存庫 vbox 的更動 35455


忽略:
時間撮記:
2011-1-10 下午01:52:26 (14 年 以前)
作者:
vboxsync
訊息:

Guest Control/Main: Various bugfixes for cancellation handling, use _64K (instead of _1M) transfer chunks again, better control context notification/deletion separation.

位置:
trunk/src/VBox/Main
檔案:
修改 2 筆資料

圖例:

未更動
新增
刪除
  • trunk/src/VBox/Main/include/GuestImpl.h

    r35374 r35455  
    179179    CallbackMapIter getCtrlCallbackContextByID(uint32_t u32ContextID);
    180180    GuestProcessMapIter getProcessByPID(uint32_t u32PID);
     181    void notifyCtrlCallbackContext(Guest::CallbackMapIter it, const char *pszText);
    181182    void destroyCtrlCallbackContext(CallbackMapIter it);
    182183    uint32_t addCtrlCallbackContext(eVBoxGuestCtrlCallbackType enmType, void *pvData, uint32_t cbData, Progress* pProgress);
     184    HRESULT waitForProcessStatusChange(ULONG uPID, PULONG puRetStatus, PULONG puRetExitCode, ULONG uTimeoutMS);
    183185# endif
    184186
  • trunk/src/VBox/Main/src-client/GuestCtrlImpl.cpp

    r35437 r35455  
    296296                        size_t cbTransfered = 0;
    297297                        size_t cbRead;
    298                         SafeArray<BYTE> aInputData(_1M);
     298                        SafeArray<BYTE> aInputData(_64K);
    299299                        while (   SUCCEEDED(execProgress->COMGETTER(Completed(&fCompleted)))
    300300                               && !fCompleted)
     
    305305                            {
    306306                                vrc = RTFileRead(fileSource, (uint8_t*)aInputData.raw(),
    307                                                  RT_MIN(cbToRead, _1M), &cbRead);
     307                                                 RT_MIN(cbToRead, _64K), &cbRead);
    308308                                /*
    309309                                 * Some other error occured? There might be a chance that RTFileRead
     
    326326                            ULONG uFlags = ProcessInputFlag_None;
    327327                            /* Did we reach the end of the content we want to transfer (last chunk)? */
    328                             if (   (cbRead < _1M)
     328                            if (   (cbRead < _64K)
    329329                                /* ... or does the user want to cancel? */
    330330                                || (   SUCCEEDED(aTask->progress->COMGETTER(Canceled(&fCanceled)))
     
    358358                                break;
    359359
     360                            /* Did the user cancel the operation above? */
     361                            if (fCanceled)
     362                                break;
     363
    360364                            /* Progress canceled by Main API? */
    361365                            if (   SUCCEEDED(execProgress->COMGETTER(Canceled(&fCanceled)))
     
    370374
    371375                        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                        }
    373437                    }
    374438                }
     
    10801144                        case VBOXGUESTCTRLCALLBACKTYPE_EXEC_OUTPUT:
    10811145                        {
    1082                             PCALLBACKDATAEXECOUT pItData = (CALLBACKDATAEXECOUT*)it2->second.pvData;
     1146                            PCALLBACKDATAEXECOUT pItData = (PCALLBACKDATAEXECOUT)it2->second.pvData;
    10831147                            AssertPtr(pItData);
    10841148                            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());
    10861162                            break;
    10871163                        }
     
    10931169                }
    10941170
    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
    11001174                LogFlowFunc(("Process (CID=%u, status=%u) reported error: %s\n",
    11011175                             pData->hdr.u32ContextID, pData->u32Status, errMsg.c_str()));
     
    11891263        pCBData->cbProcessed = pData->cbProcessed;
    11901264
    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);
    12101271        }
    12111272    }
     
    12251286    {
    12261287        LogFlowFunc(("Client with CID=%u disconnected\n", it->first));
    1227         destroyCtrlCallbackContext(it);
     1288        notifyCtrlCallbackContext(it, Guest::tr("Client disconnected"));
    12281289    }
    12291290    return rc;
     
    12541315    }
    12551316
     1317    /* Remove callback context (not used anymore). */
     1318    mCallbackMap.erase(it);
     1319}
     1320
     1321/* No locking here; */
     1322void Guest::notifyCtrlCallbackContext(Guest::CallbackMapIter it, const char *pszText)
     1323{
     1324    AssertPtr(pszText);
     1325    LogFlowFunc(("Handling callback with CID=%u ...\n", it->first));
     1326
    12561327    /* Notify outstanding waits for progress ... */
    12571328    if (    it->second.pProgress
    12581329         && !it->second.pProgress.isNull())
    12591330    {
    1260         LogFlowFunc(("Handling progress for CID=%u ...\n", it->first));
     1331        LogFlowFunc(("Notifying progress for CID=%u (Reason: %s) ...\n",
     1332                     it->first, pszText));
    12611333
    12621334        /*
     
    12681340        if (!fCompleted)
    12691341        {
    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 
    12771342            /*
    12781343             * To get waitForCompletion completed (unblocked) we have to notify it if necessary (only
     
    12851350                                                 COM_IIDOF(IGuest),
    12861351                                                 Guest::getStaticComponentName(),
    1287                                                  Guest::tr("The operation was canceled because client is shutting down"));
     1352                                                 pszText);
    12881353        }
    12891354        /*
     
    13521417#endif
    13531418    return uNewContext;
     1419}
     1420
     1421HRESULT 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;
    13541452}
    13551453#endif /* VBOX_WITH_GUEST_CONTROL */
     
    17361834        *aBytesWritten = 0;
    17371835
    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())
    17441843            {
     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
    17451850                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        }
    17531853
    17541854        if (SUCCEEDED(rc))
     
    17561856            /*
    17571857             * 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 finished
    1760              * 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.
    17611861             */
    1762             ComObjPtr <Progress> progress;
    1763             rc = progress.createObject();
     1862            ComObjPtr <Progress> pProgress;
     1863            rc = pProgress.createObject();
    17641864            if (SUCCEEDED(rc))
    17651865            {
    1766                 rc = progress->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 */);
    17691869            }
    1770             if (FAILED(rc)) return rc;
     1870            if (FAILED(rc)) throw rc;
     1871            ComAssert(!pProgress.isNull());
    17711872
    17721873            /* Adjust timeout. */
     
    17751876
    17761877            PCALLBACKDATAEXECINSTATUS pData = (PCALLBACKDATAEXECINSTATUS)RTMemAlloc(sizeof(CALLBACKDATAEXECINSTATUS));
     1878            if (NULL == pData) throw rc;
    17771879            AssertReturn(pData, VBOX_E_IPRT_ERROR);
    17781880            RT_ZERO(*pData);
     1881
    17791882            /* Save PID + output flags for later use. */
    17801883            pData->u32PID = aPID;
    17811884            pData->u32Flags = aFlags;
     1885
    17821886            /* Add job to callback contexts. */
    17831887            uint32_t uContextID = addCtrlCallbackContext(VBOXGUESTCTRLCALLBACKTYPE_EXEC_INPUT_STATUS,
    1784                                                          pData, sizeof(CALLBACKDATAEXECINSTATUS), progress);
     1888                                                         pData, sizeof(CALLBACKDATAEXECINSTATUS), pProgress);
    17851889            Assert(uContextID > 0);
    17861890
     
    18381942                    if (FAILED(rc)) throw rc;
    18391943
    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);
    18731964
    18741965                    {
    18751966                        AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    1876                         /*
    1877                          * Destroy locally used progress object.
    1878                          */
     1967                        /* Destroy locally used progress object. */
    18791968                        destroyCtrlCallbackContext(it);
    18801969                    }
    1881 
    1882                     /* Remove callback context (not used anymore). */
    1883                     mCallbackMap.erase(it);
    18841970                }
    18851971                else /* PID lookup failed. */
    18861972                    rc = setError(VBOX_E_IPRT_ERROR,
    1887                                   tr("Process (PID %u) not found!"), aPID);
     1973                                  tr("Process (PID %u) not found"), aPID);
    18881974            }
    18891975            else /* HGCM operation failed. */
    18901976                rc = setError(E_UNEXPECTED,
    1891                               tr("The HGCM call failed with error %Rrc"), vrc);
     1977                              tr("The HGCM call failed (%Rrc)"), vrc);
    18921978
    18931979            /* Cleanup. */
    1894             progress->uninit();
    1895             progress.setNull();
     1980            if (!pProgress.isNull())
     1981                pProgress->uninit();
     1982            pProgress.setNull();
    18961983        }
    18971984    }
     
    19382025            rc = progress->init(static_cast<IGuest*>(this),
    19392026                                Bstr(tr("Getting output of process")).raw(),
    1940                                 TRUE);
     2027                                TRUE /* Cancelable */);
    19412028        }
    19422029        if (FAILED(rc)) return rc;
     
    20722159                {
    20732160                    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    2074                     /*
    2075                      * Destroy locally used progress object.
    2076                      */
     2161                    /* Destroy locally used progress object. */
    20772162                    destroyCtrlCallbackContext(it);
    20782163                }
    2079 
    2080                 /* Remove callback context (not used anymore). */
    2081                 mCallbackMap.erase(it);
    20822164            }
    20832165            else /* PID lookup failed. */
注意: 瀏覽 TracChangeset 來幫助您使用更動檢視器

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette