- Timestamp:
- Jun 4, 2010 8:09:58 AM (15 years ago)
- svn:sync-xref-src-repo-rev:
- 62351
- Location:
- trunk/src/VBox
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp
r30013 r30020 388 388 * Some data left to output? 389 389 */ 390 391 390 if ( fWaitForStdOut 392 391 || fWaitForStdErr) 393 392 { 394 CHECK_ERROR_BREAK(guest, GetProcessOutput(uPID, 0 /* aFlags */, 395 u32TimeoutMS, _64K, ComSafeArrayAsOutParam(aOutputData)));396 cbOutputData = aOutputData.size();397 if ( cbOutputData > 0)393 394 rc = guest->GetProcessOutput(uPID, 0 /* aFlags */, 395 u32TimeoutMS, _64K, ComSafeArrayAsOutParam(aOutputData)); 396 if (FAILED(rc)) 398 397 { 399 /* aOutputData has a platform dependent line ending, standardize on 400 * Unix style, as RTStrmWrite does the LF -> CR/LF replacement on 401 * Windows. Otherwise we end up with CR/CR/LF on Windows. */ 402 ULONG cbOutputDataPrint = cbOutputData; 403 for (BYTE *s = aOutputData.raw(), *d = s; 404 s - aOutputData.raw() < (ssize_t)cbOutputData; 405 s++, d++) 398 /* If we got a VBOX_E_IPRT error we handle the error in a more gentle way 399 * because it contains more accurate info about what went wrong. */ 400 ErrorInfo info(guest); 401 if (info.isFullAvailable()) 406 402 { 407 if ( *s == '\r')403 if (rc == VBOX_E_IPRT_ERROR) 408 404 { 409 /* skip over CR, adjust destination */ 410 d--; 411 cbOutputDataPrint--; 405 RTPrintf("%ls.\n", info.getText().raw()); 412 406 } 413 else if (s != d) 414 *d = *s; 407 else 408 { 409 RTPrintf("ERROR: %ls (%Rhrc).\n", info.getText().raw(), info.getResultCode()); 410 } 415 411 } 416 RTStrmWrite(g_pStdOut, aOutputData.raw(), cbOutputDataPrint);412 cbOutputData = 0; 417 413 } 418 } 419 420 if (cbOutputData <= 0) 414 else 415 { 416 cbOutputData = aOutputData.size(); 417 if (cbOutputData > 0) 418 { 419 /* aOutputData has a platform dependent line ending, standardize on 420 * Unix style, as RTStrmWrite does the LF -> CR/LF replacement on 421 * Windows. Otherwise we end up with CR/CR/LF on Windows. */ 422 ULONG cbOutputDataPrint = cbOutputData; 423 for (BYTE *s = aOutputData.raw(), *d = s; 424 s - aOutputData.raw() < (ssize_t)cbOutputData; 425 s++, d++) 426 { 427 if (*s == '\r') 428 { 429 /* skip over CR, adjust destination */ 430 d--; 431 cbOutputDataPrint--; 432 } 433 else if (s != d) 434 *d = *s; 435 } 436 RTStrmWrite(g_pStdOut, aOutputData.raw(), cbOutputDataPrint); 437 } 438 } 439 } 440 441 if (cbOutputData <= 0) /* No more output data left? */ 421 442 { 422 443 if (fCompleted) … … 431 452 } 432 453 433 /* process async cancelation */454 /* Process async cancelation */ 434 455 if (g_fExecCanceled && !fCanceledAlready) 435 456 { … … 441 462 } 442 463 443 /* progress canceled by Main API? */464 /* Progress canceled by Main API? */ 444 465 if ( SUCCEEDED(progress->COMGETTER(Canceled(&fCanceled))) 445 466 && fCanceled) … … 447 468 break; 448 469 } 449 450 progress->WaitForCompletion(100); 451 } 452 453 /* undo signal handling */ 470 } 471 472 /* Undo signal handling */ 454 473 if (fCancelable) 455 474 { … … 465 484 RTPrintf("Process execution canceled!\n"); 466 485 } 467 else if (fCompleted) 486 else if ( fCompleted 487 && SUCCEEDED(rc)) 468 488 { 469 489 LONG iRc = false; … … 474 494 rc = progress->COMGETTER(ErrorInfo)(execError.asOutParam()); 475 495 com::ErrorInfo info (execError); 476 RTPrintf("\n\nProcess error details:\n"); 477 GluePrintErrorInfo(info); 478 RTPrintf("\n"); 479 } 480 if (fVerbose) 496 if (SUCCEEDED(rc) && info.isFullAvailable()) 497 { 498 /* If we got a VBOX_E_IPRT error we handle the error in a more gentle way 499 * because it contains more accurate info about what went wrong. */ 500 if (info.getResultCode() == VBOX_E_IPRT_ERROR) 501 { 502 RTPrintf("%ls.\n", info.getText().raw()); 503 } 504 else 505 { 506 RTPrintf("\n\nProcess error details:\n"); 507 GluePrintErrorInfo(info); 508 RTPrintf("\n"); 509 } 510 } 511 else 512 AssertMsgFailed(("Full error description is missing!\n")); 513 } 514 else if (fVerbose) 481 515 { 482 516 ULONG uRetStatus, uRetExitCode, uRetFlags; 483 CHECK_ERROR_BREAK(guest, GetProcessStatus(uPID, &uRetExitCode, &uRetFlags, &uRetStatus)); 484 RTPrintf("Exit code=%u (Status=%u [%s], Flags=%u)\n", uRetExitCode, uRetStatus, getStatus(uRetStatus), uRetFlags); 485 } 486 } 487 else /* If neither canceled nor completed we got a hard abort (shouldn't happen). */ 517 rc = guest->GetProcessStatus(uPID, &uRetExitCode, &uRetFlags, &uRetStatus); 518 if (SUCCEEDED(rc)) 519 RTPrintf("Exit code=%u (Status=%u [%s], Flags=%u)\n", uRetExitCode, uRetStatus, getStatus(uRetStatus), uRetFlags); 520 } 521 } 522 else 488 523 { 489 524 if (fVerbose) -
trunk/src/VBox/Main/GuestImpl.cpp
r30002 r30020 114 114 115 115 #ifdef VBOX_WITH_GUEST_CONTROL 116 /* 117 * Cleanup must be done *before* AutoUninitSpan to cancel all 118 * all outstanding waits in API functions (which hold AutoCaller 119 * ref counts). 120 */ 121 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 122 123 /* Clean up callback data. */ 124 CallbackListIter it; 125 for (it = mCallbackList.begin(); it != mCallbackList.end(); it++) 126 destroyCtrlCallbackContext(it); 127 128 /* Clear process list. */ 129 mGuestProcessList.clear(); 116 /* Scope write lock as much as possible. */ 117 { 118 /* 119 * Cleanup must be done *before* AutoUninitSpan to cancel all 120 * all outstanding waits in API functions (which hold AutoCaller 121 * ref counts). 122 */ 123 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 124 125 /* Clean up callback data. */ 126 CallbackListIter it; 127 for (it = mCallbackList.begin(); it != mCallbackList.end(); it++) 128 destroyCtrlCallbackContext(it); 129 130 /* Clear process list. */ 131 mGuestProcessList.clear(); 132 } 130 133 #endif 131 134 … … 493 496 * changes to the object state. 494 497 */ 498 #ifdef DEBUG_andy 495 499 LogFlowFunc(("pvExtension = %p, u32Function = %d, pvParms = %p, cbParms = %d\n", 496 500 pvExtension, u32Function, pvParms, cbParms)); 501 #endif 497 502 ComObjPtr<Guest> pGuest = reinterpret_cast<Guest *>(pvExtension); 498 503 … … 540 545 PCALLBACKDATAEXECSTATUS pData) 541 546 { 542 LogFlowFuncEnter();543 547 int rc = VINF_SUCCESS; 544 548 … … 560 564 561 565 /* Was progress canceled before? */ 562 BOOL fCancel led;563 it->pProgress->COMGETTER(Canceled)(&fCancelled);564 565 /* Do progress handling. */ 566 BOOL fCanceled; 567 ComAssert(it->pProgress.isNotNull()); 568 it->pProgress->COMGETTER(Canceled)(&fCanceled); 569 566 570 Utf8Str errMsg; 567 HRESULT rc2 = S_OK; 568 switch (pData->u32Status) 569 { 570 case PROC_STS_STARTED: 571 break; 572 573 case PROC_STS_TEN: /* Terminated normally. */ 574 if ( !it->pProgress->getCompleted() 575 && !fCancelled) 571 if (!fCanceled) 572 { 573 /* Do progress handling. */ 574 switch (pData->u32Status) 575 { 576 case PROC_STS_STARTED: 577 rc = it->pProgress->SetNextOperation(BstrFmt(tr("Waiting for process to exit ...")), 1 /* Weight */); 578 if (FAILED(rc)) 579 errMsg = Utf8StrFmt(Guest::tr("Cannot enter waiting for process exit stage! rc=%u"), 580 rc); 581 break; 582 583 case PROC_STS_TEN: /* Terminated normally. */ 584 it->pProgress->notifyComplete(S_OK); 585 LogFlowFunc(("Proccess (context ID=%u, status=%u) terminated successfully\n", 586 pData->hdr.u32ContextID, pData->u32Status)); 587 break; 588 589 case PROC_STS_TEA: /* Terminated abnormally. */ 590 errMsg = Utf8StrFmt(Guest::tr("Process terminated abnormally with status '%u'"), 591 pCBData->u32Flags); 592 break; 593 594 case PROC_STS_TES: /* Terminated through signal. */ 595 errMsg = Utf8StrFmt(Guest::tr("Process terminated via signal with status '%u'"), 596 pCBData->u32Flags); 597 break; 598 599 case PROC_STS_TOK: 600 errMsg = Utf8StrFmt(Guest::tr("Process timed out and was killed")); 601 break; 602 603 case PROC_STS_TOA: 604 errMsg = Utf8StrFmt(Guest::tr("Process timed out and could not be killed")); 605 break; 606 607 case PROC_STS_DWN: 608 errMsg = Utf8StrFmt(Guest::tr("Process exited because system is shutting down")); 609 break; 610 611 case PROC_STS_ERROR: 612 errMsg = Utf8StrFmt(Guest::tr("Process execution failed with rc=%Rrc"), pCBData->u32Flags); 613 break; 614 615 default: 616 break; 617 } 618 619 /* Handle process list. */ 620 /** @todo What happens on/deal with PID reuse? */ 621 /** @todo How to deal with multiple updates at once? */ 622 if (pCBData->u32PID > 0) 623 { 624 GuestProcessIter it_proc = getProcessByPID(pCBData->u32PID); 625 if (it_proc == mGuestProcessList.end()) 576 626 { 577 it->pProgress->notifyComplete(S_OK); 627 /* Not found, add to list. */ 628 GuestProcess p; 629 p.mPID = pCBData->u32PID; 630 p.mStatus = pCBData->u32Status; 631 p.mExitCode = pCBData->u32Flags; /* Contains exit code. */ 632 p.mFlags = 0; 633 634 mGuestProcessList.push_back(p); 578 635 } 579 break; 580 581 case PROC_STS_TEA: /* Terminated abnormally. */ 582 errMsg = Utf8StrFmt(Guest::tr("Process terminated abnormally with status '%u'"), 583 pCBData->u32Flags); 584 break; 585 586 case PROC_STS_TES: /* Terminated through signal. */ 587 errMsg = Utf8StrFmt(Guest::tr("Process terminated via signal with status '%u'"), 588 pCBData->u32Flags); 589 break; 590 591 case PROC_STS_TOK: 592 errMsg = Utf8StrFmt(Guest::tr("Process timed out and was killed")); 593 break; 594 595 case PROC_STS_TOA: 596 errMsg = Utf8StrFmt(Guest::tr("Process timed out and could not be killed")); 597 break; 598 599 case PROC_STS_DWN: 600 errMsg = Utf8StrFmt(Guest::tr("Process exited because system is shutting down")); 601 break; 602 603 default: 604 break; 605 } 606 607 /* Handle process list. */ 608 /** @todo What happens on/deal with PID reuse? */ 609 /** @todo How to deal with multiple updates at once? */ 610 GuestProcessIter it_proc = getProcessByPID(pCBData->u32PID); 611 if (it_proc == mGuestProcessList.end()) 612 { 613 /* Not found, add to list. */ 614 GuestProcess p; 615 p.mPID = pCBData->u32PID; 616 p.mStatus = pCBData->u32Status; 617 p.mExitCode = pCBData->u32Flags; /* Contains exit code. */ 618 p.mFlags = 0; 619 620 mGuestProcessList.push_back(p); 621 } 622 else /* Update list. */ 623 { 624 it_proc->mStatus = pCBData->u32Status; 625 it_proc->mExitCode = pCBData->u32Flags; /* Contains exit code. */ 626 it_proc->mFlags = 0; 627 } 628 629 if ( !it->pProgress.isNull() 630 && errMsg.length()) 631 { 632 if ( !it->pProgress->getCompleted() 633 && !fCancelled) 636 else /* Update list. */ 637 { 638 it_proc->mStatus = pCBData->u32Status; 639 it_proc->mExitCode = pCBData->u32Flags; /* Contains exit code. */ 640 it_proc->mFlags = 0; 641 } 642 } 643 } 644 else 645 errMsg = Utf8StrFmt(Guest::tr("Process execution canceled")); 646 647 if (!it->pProgress->getCompleted()) 648 { 649 if ( errMsg.length() 650 || fCanceled) /* If cancelled we have to report E_FAIL! */ 634 651 { 635 it->pProgress->notifyComplete( E_FAIL /** @todo Find a better rc! */, COM_IIDOF(IGuest),652 it->pProgress->notifyComplete(VBOX_E_IPRT_ERROR, COM_IIDOF(IGuest), 636 653 (CBSTR)Guest::getComponentName(), errMsg.c_str()); 637 LogFlowFunc((" Callback (context ID=%u, status=%u) progress marked as completed\n",638 pData->hdr.u32ContextID, pData->u32Status ));654 LogFlowFunc(("Process (context ID=%u, status=%u) reported error: %s\n", 655 pData->hdr.u32ContextID, pData->u32Status, errMsg.c_str())); 639 656 } 640 else 641 LogFlowFunc(("Callback (context ID=%u, status=%u) progress already marked as completed\n", 642 pData->hdr.u32ContextID, pData->u32Status)); 643 } 644 ASMAtomicWriteBool(&it->fCalled, true); 657 } 645 658 } 646 659 else 647 660 LogFlowFunc(("Unexpected callback (magic=%u, context ID=%u) arrived\n", pData->hdr.u32Magic, pData->hdr.u32ContextID)); 648 LogFlowFuncLeave();649 661 return rc; 650 662 } … … 654 666 PCALLBACKDATAEXECOUT pData) 655 667 { 656 LogFlowFuncEnter();657 668 int rc = VINF_SUCCESS; 658 669 … … 663 674 if (it != mCallbackList.end()) 664 675 { 665 Assert(!it->fCalled);666 676 PCALLBACKDATAEXECOUT pCBData = (CALLBACKDATAEXECOUT*)it->pvData; 667 677 AssertPtr(pCBData); … … 687 697 pCBData->cbData = 0; 688 698 } 689 ASMAtomicWriteBool(&it->fCalled, true); 699 700 /* Was progress canceled before? */ 701 BOOL fCanceled; 702 ComAssert(it->pProgress.isNotNull()); 703 it->pProgress->COMGETTER(Canceled)(&fCanceled); 704 705 if (!fCanceled) 706 it->pProgress->notifyComplete(S_OK); 707 else 708 it->pProgress->notifyComplete(VBOX_E_IPRT_ERROR, COM_IIDOF(IGuest), 709 (CBSTR)Guest::getComponentName(), Guest::tr("The output operation was cancelled")); 690 710 } 691 711 else 692 712 LogFlowFunc(("Unexpected callback (magic=%u, context ID=%u) arrived\n", pData->hdr.u32Magic, pData->hdr.u32ContextID)); 693 LogFlowFuncLeave();694 713 return rc; 695 714 } … … 698 717 PCALLBACKDATACLIENTDISCONNECTED pData) 699 718 { 700 LogFlowFuncEnter();701 719 int rc = VINF_SUCCESS; 702 720 … … 708 726 { 709 727 if (it->mContextID == pData->hdr.u32ContextID) 728 { 729 LogFlowFunc(("Client with context ID=%u disconnected\n", it->mContextID)); 710 730 destroyCtrlCallbackContext(it); 711 } 712 713 LogFlowFuncLeave(); 731 } 732 } 714 733 return rc; 715 734 } … … 746 765 void Guest::destroyCtrlCallbackContext(Guest::CallbackListIter it) 747 766 { 748 LogFlowFuncEnter();749 767 if (it->pvData) 750 768 { 769 LogFlowFunc(("Destroying callback with context ID=%u ...\n", it->mContextID)); 770 751 771 RTMemFree(it->pvData); 752 772 it->pvData = NULL; … … 755 775 756 776 /* Notify outstanding waits for progress ... */ 757 if (it->pProgress && !it->pProgress.isNull()) 758 { 759 /* Only cancel if not canceled before! */ 760 BOOL fCancelled; 761 if (SUCCEEDED(it->pProgress->COMGETTER(Canceled)(&fCancelled)) && !fCancelled) 762 it->pProgress->Cancel(); 777 if (it->pProgress && it->pProgress.isNotNull()) 778 { 779 LogFlowFunc(("Handling progress of context ID=%u ...\n", it->mContextID)); 780 781 BOOL fCompleted; 782 it->pProgress->COMGETTER(Completed)(&fCompleted); 783 if (!fCompleted) 784 { 785 /* Only cancel if not canceled before! */ 786 BOOL fCanceled; 787 if (SUCCEEDED(it->pProgress->COMGETTER(Canceled)(&fCanceled)) && !fCanceled) 788 it->pProgress->Cancel(); 789 790 /* To get waitForCompletion notified we have to notify it if necessary. */ 791 it->pProgress->notifyComplete(VBOX_E_IPRT_ERROR, COM_IIDOF(IGuest), 792 (CBSTR)Guest::getComponentName(), Guest::tr("The operation was canceled during shutdown")); 793 } 763 794 /* 764 795 * Do *not NULL pProgress here, because waiting function like executeProcess() … … 766 797 */ 767 798 } 768 LogFlowFuncLeave();769 799 } 770 800 … … 774 804 uint32_t Guest::addCtrlCallbackContext(eVBoxGuestCtrlCallbackType enmType, void *pvData, uint32_t cbData, Progress *pProgress) 775 805 { 776 LogFlowFuncEnter();806 AssertPtr(pProgress); 777 807 uint32_t uNewContext = ASMAtomicIncU32(&mNextContextID); 778 808 if (uNewContext == UINT32_MAX) … … 783 813 context.mContextID = uNewContext; 784 814 context.mType = enmType; 785 context.fCalled = false;786 815 context.pvData = pvData; 787 816 context.cbData = cbData; … … 807 836 } 808 837 #endif 809 810 LogFlowFuncLeave();811 838 return uNewContext; 812 839 } … … 844 871 { 845 872 /* 846 * Create progress object. 873 * Create progress object. Note that this is a multi operation 874 * object to perform the following steps: 875 * - Operation 1 (0): Create/start process. 876 * - Operation 2 (1): Wait for process to exit. 877 * If this progress completed successfully (S_OK), the process 878 * started and exited normally. In any other case an error/exception 879 * occured. 847 880 */ 848 881 ComObjPtr <Progress> progress; … … 852 885 rc = progress->init(static_cast<IGuest*>(this), 853 886 BstrFmt(tr("Executing process")), 854 TRUE); 887 TRUE, 888 2, /* Number of operations. */ 889 BstrFmt(tr("Starting process ..."))); /* Description of first stage. */ 855 890 } 856 891 if (FAILED(rc)) return rc; … … 919 954 PCALLBACKDATAEXECSTATUS pData = (PCALLBACKDATAEXECSTATUS)RTMemAlloc(sizeof(CALLBACKDATAEXECSTATUS)); 920 955 AssertReturn(pData, VBOX_E_IPRT_ERROR); 956 RT_ZERO(*pData); 921 957 uContextID = addCtrlCallbackContext(VBOXGUESTCTRLCALLBACKTYPE_EXEC_START, 922 958 pData, sizeof(CALLBACKDATAEXECSTATUS), progress); … … 974 1010 if (it != mCallbackList.end()) 975 1011 { 976 uint64_t u64Started = RTTimeMilliTS(); 977 while (!it->fCalled) 1012 ComAssert(it->pProgress.isNotNull()); 1013 1014 /* 1015 * Wait for the first stage (=0) to complete (that is starting the process). 1016 */ 1017 PCALLBACKDATAEXECSTATUS pData = NULL; 1018 rc = it->pProgress->WaitForOperationCompletion(0, aTimeoutMS); 1019 if (SUCCEEDED(rc)) 978 1020 { 979 /* Check for timeout.*/980 unsigned cMsWait;981 if ( aTimeoutMS == RT_INDEFINITE_WAIT)982 cMsWait = 10; 983 else1021 /* Was the operation canceled by one of the parties? */ 1022 rc = it->pProgress->COMGETTER(Canceled)(&fCanceled); 1023 if (FAILED(rc)) throw rc; 1024 1025 if (!fCanceled) 984 1026 { 985 uint64_t cMsElapsed = RTTimeMilliTS() - u64Started; 986 if (cMsElapsed >= aTimeoutMS) 987 break; /* Timed out. */ 988 cMsWait = RT_MIN(10, aTimeoutMS - (uint32_t)cMsElapsed); 1027 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 1028 1029 pData = (PCALLBACKDATAEXECSTATUS)it->pvData; 1030 Assert(it->cbData == sizeof(CALLBACKDATAEXECSTATUS)); 1031 AssertPtr(pData); 1032 1033 /* Did we get some status? */ 1034 switch (pData->u32Status) 1035 { 1036 case PROC_STS_STARTED: 1037 /* Process is (still) running; get PID. */ 1038 *aPID = pData->u32PID; 1039 break; 1040 1041 /* In any other case the process either already 1042 * terminated or something else went wrong, so no PID ... */ 1043 case PROC_STS_TEN: /* Terminated normally. */ 1044 case PROC_STS_TEA: /* Terminated abnormally. */ 1045 case PROC_STS_TES: /* Terminated through signal. */ 1046 case PROC_STS_TOK: 1047 case PROC_STS_TOA: 1048 case PROC_STS_DWN: 1049 /* 1050 * Process (already) ended, but we want to get the 1051 * PID anyway to retrieve the output in a later call. 1052 */ 1053 *aPID = pData->u32PID; 1054 break; 1055 1056 case PROC_STS_ERROR: 1057 vrc = pData->u32Flags; /* u32Flags member contains IPRT error code. */ 1058 break; 1059 1060 case PROC_STS_UNDEFINED: 1061 vrc = VERR_TIMEOUT; /* Operation did not complete within time. */ 1062 break; 1063 1064 default: 1065 vrc = VERR_INVALID_PARAMETER; /* Unknown status, should never happen! */ 1066 break; 1067 } 989 1068 } 990 991 /* Check for manual stop. */ 992 if (!it->pProgress.isNull()) 993 { 994 rc = it->pProgress->COMGETTER(Canceled)(&fCanceled); 995 if (FAILED(rc)) throw rc; 996 if (fCanceled) 997 break; /* HGCM/guest wants to abort because of status change. */ 998 999 } 1000 /// @todo r=bird: two operation progress object and wait first operation. 1001 /// IProgress::WaitForOperationCompletion. 1002 RTThreadSleep(cMsWait); 1069 else /* Operation was canceled. */ 1070 vrc = VERR_CANCELLED; 1003 1071 } 1004 } 1005 1006 /* Was the whole thing canceled? */ 1007 if (!fCanceled) 1008 { 1009 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 1010 1011 PCALLBACKDATAEXECSTATUS pData = (PCALLBACKDATAEXECSTATUS)it->pvData; 1012 Assert(it->cbData == sizeof(CALLBACKDATAEXECSTATUS)); 1013 AssertPtr(pData); 1014 1015 if (it->fCalled) 1016 { 1017 /* Did we get some status? */ 1018 switch (pData->u32Status) 1019 { 1020 case PROC_STS_STARTED: 1021 /* Process is (still) running; get PID. */ 1022 *aPID = pData->u32PID; 1023 break; 1024 1025 /* In any other case the process either already 1026 * terminated or something else went wrong, so no PID ... */ 1027 case PROC_STS_TEN: /* Terminated normally. */ 1028 case PROC_STS_TEA: /* Terminated abnormally. */ 1029 case PROC_STS_TES: /* Terminated through signal. */ 1030 case PROC_STS_TOK: 1031 case PROC_STS_TOA: 1032 case PROC_STS_DWN: 1033 /* 1034 * Process (already) ended, but we want to get the 1035 * PID anyway to retrieve the output in a later call. 1036 */ 1037 *aPID = pData->u32PID; 1038 break; 1039 1040 case PROC_STS_ERROR: 1041 vrc = pData->u32Flags; /* u32Flags member contains IPRT error code. */ 1042 break; 1043 1044 default: 1045 vrc = VERR_INVALID_PARAMETER; /* Unknown status, should never happen! */ 1046 break; 1047 } 1048 } 1049 else /* If callback not called within time ... well, that's a timeout! */ 1072 else /* Operation did not complete within time. */ 1050 1073 vrc = VERR_TIMEOUT; 1051 1052 1074 1075 /* 1053 1076 * Do *not* remove the callback yet - we might wait with the IProgress object on something 1054 1077 * else (like end of process) ... … … 1081 1104 tr("The guest did not respond within time (%ums)"), aTimeoutMS); 1082 1105 } 1106 else if (vrc == VERR_CANCELLED) 1107 { 1108 rc = setError(VBOX_E_IPRT_ERROR, 1109 tr("The execution operation was canceled")); 1110 } 1083 1111 else if (vrc == VERR_PERMISSION_DENIED) 1084 1112 { … … 1088 1116 else 1089 1117 { 1090 if (pData ->u32Status == PROC_STS_ERROR)1118 if (pData && pData->u32Status == PROC_STS_ERROR) 1091 1119 rc = setError(VBOX_E_IPRT_ERROR, 1092 1120 tr("Process could not be started: %Rrc"), pData->u32Flags); … … 1094 1122 rc = setError(E_UNEXPECTED, 1095 1123 tr("The service call failed with error %Rrc"), vrc); 1096 } 1124 } 1097 1125 } 1098 1126 else /* Execution went fine. */ … … 1102 1130 } 1103 1131 } 1104 else /* Operation was canceled. */ 1105 { 1106 rc = setError(VBOX_E_IPRT_ERROR, 1107 tr("The operation was canceled")); 1108 } 1132 else /* Callback context not found; should never happen! */ 1133 AssertMsg(it != mCallbackList.end(), ("Callback context with ID %u not found!", uContextID)); 1109 1134 } 1110 1135 else /* HGCM related error codes .*/ … … 1163 1188 /* 1164 1189 * Create progress object. 1165 * Note that we need at least a local progress object here in order 1166 * to get notified when someone cancels the operation. 1190 * This progress object, compared to the one in executeProgress() above, 1191 * is only local and is used to determine whether the operation finished 1192 * or got cancelled. 1167 1193 */ 1168 1194 ComObjPtr <Progress> progress; … … 1183 1209 PCALLBACKDATAEXECOUT pData = (CALLBACKDATAEXECOUT*)RTMemAlloc(sizeof(CALLBACKDATAEXECOUT)); 1184 1210 AssertReturn(pData, VBOX_E_IPRT_ERROR); 1211 RT_ZERO(*pData); 1185 1212 uint32_t uContextID = addCtrlCallbackContext(VBOXGUESTCTRLCALLBACKTYPE_EXEC_OUTPUT, 1186 1213 pData, sizeof(CALLBACKDATAEXECOUT), progress); … … 1232 1259 if (it != mCallbackList.end()) 1233 1260 { 1234 uint64_t u64Started = RTTimeMilliTS(); 1235 while (!it->fCalled) 1236 { 1237 /* Check for timeout. */ 1238 unsigned cMsWait; 1239 if (aTimeoutMS == RT_INDEFINITE_WAIT) 1240 cMsWait = 10; 1241 else 1242 { 1243 uint64_t cMsElapsed = RTTimeMilliTS() - u64Started; 1244 if (cMsElapsed >= aTimeoutMS) 1245 break; /* Timed out. */ 1246 cMsWait = RT_MIN(10, aTimeoutMS - (uint32_t)cMsElapsed); 1247 } 1248 1249 /* Check for manual stop. */ 1250 if (!it->pProgress.isNull()) 1251 { 1252 rc = it->pProgress->COMGETTER(Canceled)(&fCanceled); 1253 if (FAILED(rc)) throw rc; 1254 if (fCanceled) 1255 break; /* Client wants to abort. */ 1256 } 1257 RTThreadSleep(cMsWait); 1258 } 1259 1260 /* Was the whole thing canceled? */ 1261 ComAssert(it->pProgress.isNotNull()); 1262 1263 /* Wait until operation completed. */ 1264 rc = it->pProgress->WaitForCompletion(aTimeoutMS); 1265 if (FAILED(rc)) throw rc; 1266 1267 /* Was the operation canceled by one of the parties? */ 1268 rc = it->pProgress->COMGETTER(Canceled)(&fCanceled); 1269 if (FAILED(rc)) throw rc; 1270 1261 1271 if (!fCanceled) 1262 1272 { 1263 if (it->fCalled) 1273 BOOL fCompleted; 1274 if ( SUCCEEDED(it->pProgress->COMGETTER(Completed)(&fCompleted)) 1275 && fCompleted) 1264 1276 { 1265 1277 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); … … 1287 1299 } 1288 1300 else /* Operation was canceled. */ 1301 { 1289 1302 vrc = VERR_CANCELLED; 1303 } 1290 1304 1291 1305 if (RT_FAILURE(vrc)) … … 1294 1308 { 1295 1309 /* This is not an error we want to report to COM. */ 1310 rc = NO_ERROR; 1296 1311 } 1297 1312 else if (vrc == VERR_TIMEOUT) … … 1303 1318 { 1304 1319 rc = setError(VBOX_E_IPRT_ERROR, 1305 tr("The o peration was canceled"));1320 tr("The output operation was canceled")); 1306 1321 } 1307 1322 else … … 1316 1331 destroyCtrlCallbackContext(it); 1317 1332 } 1333 1334 /* Remove callback context (not used anymore). */ 1335 mCallbackList.erase(it); 1318 1336 } 1319 1337 else /* PID lookup failed. */ -
trunk/src/VBox/Main/include/GuestImpl.h
r29785 r30020 122 122 struct CallbackContext 123 123 { 124 /** Associated context ID. */ 124 125 uint32_t mContextID; 125 126 eVBoxGuestCtrlCallbackType mType; 127 /** Pointer to user-supplied data. */ 126 128 void *pvData; 129 /** Size of user-supplied data. */ 127 130 uint32_t cbData; 128 /** Atomic flag whether callback was called. */129 volatile bool fCalled;130 131 /** Pointer to user-supplied IProgress. */ 131 132 ComObjPtr<Progress> pProgress;
Note:
See TracChangeset
for help on using the changeset viewer.