Changeset 45415 in vbox for trunk/src/VBox/Main
- Timestamp:
- Apr 8, 2013 9:40:42 PM (12 years ago)
- svn:sync-xref-src-repo-rev:
- 84843
- Location:
- trunk/src/VBox/Main
- Files:
-
- 2 added
- 14 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/Makefile.kmk
r45276 r45415 611 611 src-client/GuestImpl.cpp \ 612 612 src-client/GuestDirectoryImpl.cpp \ 613 src-client/GuestErrorInfoImpl.cpp \ 613 614 src-client/GuestFileImpl.cpp \ 614 615 src-client/GuestFsObjInfoImpl.cpp \ -
trunk/src/VBox/Main/idl/VirtualBox.xidl
r45284 r45415 9491 9491 Process execution statuses. 9492 9492 </desc> 9493 9493 9494 <const name="Undefined" value="0"> 9494 9495 <desc>Process is in an undefined state.</desc> … … 9528 9529 </const> 9529 9530 </enum> 9530 9531 9532 <enum 9533 name="ProcessInputStatus" 9534 uuid="a4a0ef9c-29cc-4805-9803-c8215ae9da6c" 9535 > 9536 <desc> 9537 Process input statuses. 9538 </desc> 9539 9540 <const name="Undefined" value="0"> 9541 <desc>Undefined state.</desc> 9542 </const> 9543 <const name="Broken" value="1"> 9544 <desc>TODO</desc> 9545 </const> 9546 <const name="Available" value="10"> 9547 <desc>TODO</desc> 9548 </const> 9549 <const name="Written" value="50"> 9550 <desc>TODO</desc> 9551 </const> 9552 <const name="Overflow" value="100"> 9553 <desc>TODO</desc> 9554 </const> 9555 </enum> 9556 9557 <enum 9558 name="FileStatus" 9559 uuid="8c86468b-b97b-4080-8914-e29f5b0abd2c" 9560 > 9561 <desc> 9562 File statuses. 9563 </desc> 9564 9565 <const name="Undefined" value="0"> 9566 <desc>File is in an undefined state.</desc> 9567 </const> 9568 <const name="Opening" value="10"> 9569 <desc>TODO</desc> 9570 </const> 9571 <const name="Open" value="100"> 9572 <desc>TODO</desc> 9573 </const> 9574 <const name="Closing" value="150"> 9575 <desc>TODO</desc> 9576 </const> 9577 <const name="Closed" value="200"> 9578 <desc>TODO</desc> 9579 </const> 9580 <const name="Down" value="600"> 9581 <desc>TODO</desc> 9582 </const> 9583 <const name="Error" value="800"> 9584 <desc>Something went wrong.</desc> 9585 </const> 9586 </enum> 9587 9531 9588 <enum 9532 9589 name="FsObjType" … … 9605 9662 </const> 9606 9663 </enum> 9664 9665 <interface 9666 name="IGuestErrorInfo" extends="$unknown" 9667 uuid="ab576a37-dcfc-4d80-9a73-493d15e293c4" 9668 wsmap="managed" 9669 > 9670 <desc> 9671 TODO 9672 </desc> 9673 9674 <attribute name="result" type="long" readonly="yes"> 9675 <desc>TODO</desc> 9676 </attribute> 9677 9678 <attribute name="text" type="wstring" readonly="yes"> 9679 <desc>TODO</desc> 9680 </attribute> 9681 9682 </interface> 9607 9683 9608 9684 <interface 9609 9685 name="IGuestSession" extends="$unknown" 9610 uuid=" 56f551a2-f924-43ab-8a69-a954109db878"9686 uuid="c8e8607b-5e67-4073-8f14-146515d0c1ff" 9611 9687 wsmap="managed" 9612 9688 > … … 9689 9765 </desc> 9690 9766 </attribute> 9767 9768 <attribute name="eventSource" type="IEventSource" readonly="yes"> 9769 <desc> 9770 Event source for guest session events. 9771 </desc> 9772 </attribute> 9691 9773 9692 9774 <method name="close"> … … 10706 10788 <interface 10707 10789 name="IFile" extends="$unknown" 10708 uuid=" b702a560-6139-4a8e-a892-bbf14b97bf97"10790 uuid="0b45a95f-6267-499e-a7f2-efa5f8e081f2" 10709 10791 wsmap="managed" 10710 10792 > … … 10712 10794 Abstract parent interface for files handled by VirtualBox. 10713 10795 </desc> 10796 <attribute name="status" type="FileStatus" readonly="yes"> 10797 <desc> 10798 TODO 10799 </desc> 10800 </attribute> 10714 10801 <attribute name="creationMode" type="unsigned long" readonly="yes"> 10715 10802 <desc> … … 18573 18660 <enum 18574 18661 name="VBoxEventType" 18575 uuid=" 0d67e79e-b7b1-4919-aab3-b36866075515"18662 uuid="83c03e4b-ffe5-421c-a0fb-0b27b2d56753" 18576 18663 > 18577 18664 … … 18871 18958 </desc> 18872 18959 </const> 18873 18960 <const name="OnGuestSessionStateChanged" value="80"> 18961 <desc> 18962 TODO 18963 </desc> 18964 </const> 18965 <const name="OnGuestSessionRegistered" value="81"> 18966 <desc> 18967 TODO 18968 </desc> 18969 </const> 18970 <const name="OnGuestProcessRegistered" value="82"> 18971 <desc> 18972 TODO 18973 </desc> 18974 </const> 18975 <const name="OnGuestProcessStateChanged" value="83"> 18976 <desc> 18977 TODO 18978 </desc> 18979 </const> 18980 <const name="OnGuestProcessInputNotify" value="84"> 18981 <desc> 18982 TODO 18983 </desc> 18984 </const> 18985 <const name="OnGuestProcessOutput" value="85"> 18986 <desc> 18987 TODO 18988 </desc> 18989 </const> 18990 <const name="OnGuestFileStateChanged" value="86"> 18991 <desc> 18992 TODO 18993 </desc> 18994 </const> 18995 <const name="OnGuestFileOffsetChanged" value="87"> 18996 <desc> 18997 TODO 18998 </desc> 18999 </const> 19000 <const name="OnGuestFileRead" value="88"> 19001 <desc> 19002 For performance reasons ... TODO 19003 </desc> 19004 </const> 19005 <const name="OnGuestFileWrite" value="89"> 19006 <desc> 19007 For performance reasons ... TODO 19008 </desc> 19009 </const> 18874 19010 <!-- Last event marker --> 18875 <const name="Last" value=" 80">19011 <const name="Last" value="90"> 18876 19012 <desc> 18877 19013 Must be last event, used for iterations and structures relying on numerical event values. … … 19745 19881 </interface> 19746 19882 19747 19883 <interface 19884 name="IGuestSessionEvent" extends="IEvent" 19885 uuid="b9acd33f-647d-45ac-8fe9-f49b3183ba37" 19886 wsmap="managed" id="GuestSessionEvent" 19887 > 19888 <desc>Base abstract interface for all guest session events.</desc> 19889 19890 <attribute name="session" type="IGuestSession" readonly="yes"> 19891 <desc>Guest session that is subject to change.</desc> 19892 </attribute> 19893 19894 </interface> 19895 19896 <interface 19897 name="IGuestSessionStateChangedEvent" extends="IGuestSessionEvent" 19898 uuid="9c288479-6564-451d-9574-7e7ac0b7e443" 19899 wsmap="managed" autogen="VBoxEvent" id="OnGuestSessionStateChanged" 19900 > 19901 <desc> 19902 TODO 19903 </desc> 19904 19905 <attribute name="id" type="unsigned long" readonly="yes"> 19906 <desc> 19907 TODO 19908 </desc> 19909 </attribute> 19910 <attribute name="status" type="GuestSessionStatus" readonly="yes"> 19911 <desc> 19912 TODO 19913 </desc> 19914 </attribute> 19915 <attribute name="error" type="IGuestErrorInfo" readonly="yes"> 19916 <desc> 19917 TODO 19918 </desc> 19919 </attribute> 19920 19921 </interface> 19922 19923 <interface 19924 name="IGuestSessionRegisteredEvent" extends="IGuestSessionEvent" 19925 uuid="b79de686-eabd-4fa6-960a-f1756c99ea1c" 19926 wsmap="managed" autogen="VBoxEvent" id="OnGuestSessionRegistered" 19927 > 19928 <desc> 19929 TODO 19930 </desc> 19931 19932 <attribute name="registered" type="boolean" readonly="yes"> 19933 <desc> 19934 TODO 19935 </desc> 19936 </attribute> 19937 19938 </interface> 19939 19940 <interface 19941 name="IGuestProcessEvent" extends="IGuestSessionEvent" 19942 uuid="ee4be6e7-76c5-4517-a623-d4b1957d4ea4" 19943 wsmap="managed" id="GuestProcessEvent" 19944 > 19945 <desc>Base abstract interface for all guest process events.</desc> 19946 19947 <attribute name="process" type="IGuestProcess" readonly="yes"> 19948 <desc> 19949 TODO 19950 </desc> 19951 </attribute> 19952 <attribute name="pid" type="unsigned long" readonly="yes"> 19953 <desc> 19954 TODO 19955 </desc> 19956 </attribute> 19957 19958 </interface> 19959 19960 <interface 19961 name="IGuestProcessRegisteredEvent" extends="IGuestProcessEvent" 19962 uuid="1d89e2b3-c6ea-45b6-9d43-dc6f70cc9f02" 19963 wsmap="managed" autogen="VBoxEvent" id="OnGuestProcessRegistered" 19964 > 19965 <desc> 19966 TODO 19967 </desc> 19968 19969 <attribute name="registered" type="boolean" readonly="yes"> 19970 <desc> 19971 TODO 19972 </desc> 19973 </attribute> 19974 19975 </interface> 19976 19977 <interface 19978 name="IGuestProcessStateChangedEvent" extends="IGuestProcessEvent" 19979 uuid="9360d372-d4d9-4948-8e67-e0a0e603acf9" 19980 wsmap="managed" autogen="VBoxEvent" id="OnGuestProcessStateChanged" 19981 > 19982 <desc> 19983 TODO 19984 </desc> 19985 19986 <attribute name="status" type="ProcessStatus" readonly="yes"> 19987 <desc> 19988 TODO 19989 </desc> 19990 </attribute> 19991 <attribute name="error" type="IGuestErrorInfo" readonly="yes"> 19992 <desc> 19993 TODO 19994 </desc> 19995 </attribute> 19996 19997 </interface> 19998 19999 <interface 20000 name="IGuestProcessInputNotifyEvent" extends="IGuestProcessEvent" 20001 uuid="b3d6bb71-0392-4971-a908-f71c931995fd" 20002 wsmap="managed" autogen="VBoxEvent" id="OnGuestProcessInputNotify" 20003 > 20004 <desc> 20005 TODO 20006 </desc> 20007 20008 <attribute name="status" type="ProcessInputStatus" readonly="yes"> 20009 <desc> 20010 TODO 20011 </desc> 20012 </attribute> 20013 20014 <attribute name="handle" type="unsigned long" readonly="yes"> 20015 <desc> 20016 TODO 20017 </desc> 20018 </attribute> 20019 20020 <attribute name="processed" type="unsigned long" readonly="yes"> 20021 <desc> 20022 TODO 20023 </desc> 20024 </attribute> 20025 20026 </interface> 20027 20028 <interface 20029 name="IGuestProcessOutputEvent" extends="IGuestProcessEvent" 20030 uuid="a13533b9-4aba-4937-836e-81325859c9d8" 20031 wsmap="managed" autogen="VBoxEvent" id="OnGuestProcessOutput" 20032 > 20033 <desc> 20034 TODO 20035 </desc> 20036 20037 <attribute name="handle" type="unsigned long" readonly="yes"> 20038 <desc> 20039 TODO 20040 </desc> 20041 </attribute> 20042 20043 <attribute name="data" type="octet" safearray="yes" readonly="yes"> 20044 <desc> 20045 TODO 20046 </desc> 20047 </attribute> 20048 20049 </interface> 20050 20051 <interface 20052 name="IGuestFileEvent" extends="IGuestSessionEvent" 20053 uuid="912f748f-d2f9-4fea-84d2-d36a017cc5f8" 20054 wsmap="managed" id="GuestFileEvent" 20055 > 20056 <desc>Base abstract interface for all guest file events.</desc> 20057 20058 <attribute name="file" type="IGuestFile" readonly="yes"> 20059 <desc> 20060 TODO 20061 </desc> 20062 </attribute> 20063 20064 </interface> 20065 20066 <interface 20067 name="IGuestFileStateChangedEvent" extends="IGuestFileEvent" 20068 uuid="841951c4-4df3-4ee1-bb99-91e5761c18ff" 20069 wsmap="managed" autogen="VBoxEvent" id="OnGuestFileStateChanged" 20070 > 20071 <desc> 20072 TODO 20073 </desc> 20074 20075 <attribute name="status" type="FileStatus" readonly="yes"> 20076 <desc> 20077 TODO 20078 </desc> 20079 </attribute> 20080 <attribute name="error" type="IGuestErrorInfo" readonly="yes"> 20081 <desc> 20082 TODO 20083 </desc> 20084 </attribute> 20085 <!-- Note: No events for reads/writes for performance reasons. 20086 See dedidcated events IGuestFileReadEvent and 20087 IGuestFileWriteEvent. --> 20088 20089 </interface> 20090 20091 <interface 20092 name="IGuestFileIOEvent" extends="IGuestFileEvent" 20093 uuid="b5191a7c-9536-4ef8-820e-3b0e17e5bbc8" 20094 wsmap="managed" id="OnGuestFileIO" 20095 > 20096 <desc> 20097 TODO 20098 </desc> 20099 20100 <attribute name="offset" type="long long" readonly="yes"> 20101 <desc> 20102 TODO 20103 </desc> 20104 </attribute> 20105 <attribute name="processed" type="unsigned long" readonly="yes"> 20106 <desc> 20107 TODO 20108 </desc> 20109 20110 </attribute> 20111 20112 </interface> 20113 20114 <interface 20115 name="IGuestFileOffsetChangedEvent" extends="IGuestFileIOEvent" 20116 uuid="e8f79a21-1207-4179-94cf-ca250036308f" 20117 wsmap="managed" autogen="VBoxEvent" id="OnGuestFileOffsetChanged" 20118 > 20119 <desc> 20120 TODO 20121 </desc> 20122 20123 </interface> 20124 20125 <interface 20126 name="IGuestFileReadEvent" extends="IGuestFileIOEvent" 20127 uuid="4ee3cbcb-486f-40db-9150-deee3fd24189" 20128 wsmap="managed" autogen="VBoxEvent" id="OnGuestFileRead" 20129 > 20130 <desc> 20131 TODO 20132 </desc> 20133 20134 <attribute name="data" type="octet" safearray="yes" readonly="yes"> 20135 <desc> 20136 TODO 20137 </desc> 20138 </attribute> 20139 20140 </interface> 20141 20142 <interface 20143 name="IGuestFileWriteEvent" extends="IGuestFileIOEvent" 20144 uuid="e062a915-3cf5-4c0a-bc90-9b8d4cc94d89" 20145 wsmap="managed" autogen="VBoxEvent" id="OnGuestFileWrite" 20146 > 20147 <desc> 20148 TODO 20149 </desc> 20150 20151 </interface> 20152 19748 20153 <interface 19749 20154 name="IVRDEServerChangedEvent" extends="IEvent" -
trunk/src/VBox/Main/include/GuestCtrlImplPrivate.h
r45109 r45415 132 132 int Init(CALLBACKTYPE enmType); 133 133 134 CALLBACKTYPE Get CallbackType(void) { return mType; }134 CALLBACKTYPE GetType(void) { return mType; } 135 135 136 136 const void* GetDataRaw(void) const { return pvData; } … … 568 568 }; 569 569 570 /** 571 * Pure virtual class (interface) for guest objects (processes, files, ...) -- 570 class GuestBase 571 { 572 573 public: 574 575 GuestBase(void); 576 virtual ~GuestBase(void); 577 578 public: 579 580 int generateContextID(uint32_t uSessionID, uint32_t uObjectID, uint32_t *puContextID); 581 582 protected: 583 584 /** Pointer to the console object. Needed 585 * for HGCM (VMMDev) communication. */ 586 Console *mConsole; 587 /** The next upcoming context ID for this object. */ 588 uint32_t mNextContextID; 589 }; 590 591 /** 592 * Virtual class (interface) for guest objects (processes, files, ...) -- 572 593 * contains all per-object callback management. 573 594 */ 574 class GuestObject 575 { 576 577 public: 578 579 ULONG getObjectID(void) { return mObject.mObjectID; } 595 class GuestObject : public GuestBase 596 { 597 598 public: 599 600 GuestObject(void); 601 virtual ~GuestObject(void); 602 603 public: 604 605 ULONG getObjectID(void) { return mObjectID; } 580 606 581 607 protected: … … 587 613 588 614 int bindToSession(Console *pConsole, GuestSession *pSession, uint32_t uObjectID); 589 int callbackAdd(GuestCtrlCallback *pCallback, uint32_t *puContextID);590 void callbackDelete(GuestCtrlCallback *pCallback);591 bool callbackExists(uint32_t uContextID);592 int callbackRemove(uint32_t uContextID);593 int callbackRemoveAll(void);594 615 int sendCommand(uint32_t uFunction, uint32_t uParms, PVBOXHGCMSVCPARM paParms); 595 616 … … 597 618 598 619 /** 599 * Commom structurefor all derived objects, when then have620 * Commom parameters for all derived objects, when then have 600 621 * an own mData structure to keep their specific data around. 601 622 */ 602 struct Object 603 { 604 /** Pointer to parent session. Per definition 605 * this objects *always* lives shorter than the 606 * parent. */ 607 GuestSession *mSession; 608 /** Pointer to the console object. Needed 609 * for HGCM (VMMDev) communication. */ 610 Console *mConsole; 611 /** All related callbacks to this object. */ 612 GuestCtrlCallbacks mCallbacks; 613 /** The next upcoming context ID for this object. */ 614 ULONG mNextContextID; 615 /** The object ID -- must be unique for each guest 616 * session and is encoded into the context ID. Must 617 * be set manually when initializing the object. 618 * 619 * For guest processes this is the internal PID, 620 * for guest files this is the internal file ID. */ 621 uint32_t mObjectID; 622 } mObject; 623 }; 624 625 #if 0 626 /* 627 * Guest (HGCM) callbacks. All classes will throw 628 * an exception on misuse. 629 */ 630 631 /** Callback class for guest process status. */ 632 class GuestCbProcessStatus : public GuestCtrlCallback 633 { 634 635 public: 636 637 int Init(uint32_t uProtocol, uint32_t uFunction, 638 PVBOXGUESTCTRLHOSTCALLBACK pSvcCb) 639 { 640 AssertPtrReturn(pSvcCb, VERR_INVALID_POINTER); 641 642 int rc = GuestCtrlCallback::Init(); 643 if (RT_FAILURE(rc)) 644 return rc; 645 646 if ( uFunction != GUEST_EXEC_SEND_STATUS 647 || pSvcCb->mParms < 5) 648 return VERR_INVALID_PARAMETER; 649 650 /* pSvcCb->mpaParms[0] always contains the context ID. */ 651 pSvcCb->mpaParms[1].getUInt32(&mPID); 652 pSvcCb->mpaParms[2].getUInt32(&mStatus); 653 pSvcCb->mpaParms[3].getUInt32(&mFlags); /* Can contain an IPRT error, which is a signed int. */ 654 pSvcCb->mpaParms[4].getPointer(&mData, &mcbData); 655 656 return VINF_SUCCESS; 657 } 658 659 void Destroy(void) { } 660 661 uint32_t mPID; 662 uint32_t mStatus; 663 uint32_t mFlags; 664 void *mData; 665 uint32_t mcbData; 666 }; 667 668 /** Callback class for guest process input. */ 669 class GuestCbProcessInput : public GuestCtrlCallback 670 { 671 672 public: 673 674 int Init(uint32_t uProtocol, uint32_t uFunction, 675 PVBOXGUESTCTRLHOSTCALLBACK pSvcCb) 676 { 677 AssertPtrReturn(pSvcCb, VERR_INVALID_POINTER); 678 679 int rc = GuestCtrlCallback::Init(); 680 if (RT_FAILURE(rc)) 681 return rc; 682 683 if ( uFunction != GUEST_EXEC_SEND_INPUT_STATUS 684 || pSvcCb->mParms < 5) 685 return VERR_INVALID_PARAMETER; 686 687 /* pSvcCb->mpaParms[0] always contains the context ID. */ 688 pSvcCb->mpaParms[1].getUInt32(&mPID); 689 /* Associated file handle. */ 690 pSvcCb->mpaParms[2].getUInt32(&mStatus); 691 pSvcCb->mpaParms[3].getUInt32(&mFlags); 692 pSvcCb->mpaParms[4].getUInt32(&mProcessed); 693 694 return VINF_SUCCESS; 695 } 696 697 void Destroy(void) { } 698 699 GuestCbProcessInput& operator=(const GuestCbProcessInput &that) 700 { 701 mPID = that.mPID; 702 mStatus = that.mStatus; 703 mFlags = that.mFlags; 704 mProcessed = that.mProcessed; 705 return *this; 706 } 707 708 uint32_t mPID; 709 uint32_t mStatus; 710 uint32_t mFlags; 711 uint32_t mProcessed; 712 }; 713 714 /** Callback class for guest process output. */ 715 class GuestCbProcessOutput : public GuestCtrlCallback 716 { 717 718 public: 719 720 int Init(uint32_t uProtocol, uint32_t uFunction, 721 PVBOXGUESTCTRLHOSTCALLBACK pSvcCb) 722 { 723 AssertPtrReturn(pSvcCb, VERR_INVALID_POINTER); 724 725 int rc = GuestCtrlCallback::Init(); 726 if (RT_FAILURE(rc)) 727 return rc; 728 729 if ( uFunction != GUEST_EXEC_SEND_OUTPUT 730 || pSvcCb->mParms < 5) 731 return VERR_INVALID_PARAMETER; 732 733 /* pSvcCb->mpaParms[0] always contains the context ID. */ 734 pSvcCb->mpaParms[1].getUInt32(&mPID); 735 /* Associated file handle. */ 736 pSvcCb->mpaParms[2].getUInt32(&mHandle); 737 pSvcCb->mpaParms[3].getUInt32(&mFlags); 738 739 void *pbData; uint32_t cbData; 740 rc = pSvcCb->mpaParms[4].getPointer(&pbData, &cbData); 741 if (RT_SUCCESS(rc)) 742 { 743 Assert(cbData); 744 mData = RTMemAlloc(cbData); 745 AssertPtrReturn(mData, VERR_NO_MEMORY); 746 memcpy(mData, pbData, cbData); 747 mcbData = cbData; 748 } 749 750 return rc; 751 } 752 753 void Destroy(void) 754 { 755 if (mData) 756 { 757 RTMemFree(mData); 758 mData = NULL; 759 mcbData = 0; 760 } 761 } 762 763 GuestCbProcessOutput& operator=(const GuestCbProcessOutput &that) 764 { 765 mPID = that.mPID; 766 mHandle = that.mHandle; 767 mFlags = that.mFlags; 768 769 Destroy(); 770 if (that.mcbData) 771 { 772 void *pvData = RTMemAlloc(that.mcbData); 773 if (pvData) 774 { 775 AssertPtr(pvData); 776 memcpy(pvData, that.mData, that.mcbData); 777 mData = pvData; 778 mcbData = that.mcbData; 779 } 780 } 781 782 return *this; 783 } 784 785 uint32_t mPID; 786 uint32_t mHandle; 787 uint32_t mFlags; 788 void *mData; 789 size_t mcbData; 790 }; 791 792 /** Callback class for guest process IO notifications. */ 793 class GuestCbProcessIO : public GuestCtrlCallback 794 { 795 796 public: 797 798 int Init(uint32_t uProtocol, uint32_t uFunction, 799 PVBOXGUESTCTRLHOSTCALLBACK pSvcCb) 800 { 801 AssertPtrReturn(pSvcCb, VERR_INVALID_POINTER); 802 803 int rc = GuestCtrlCallback::Init(); 804 if (RT_FAILURE(rc)) 805 return rc; 806 807 return VERR_NOT_IMPLEMENTED; 808 } 809 810 void Destroy(void) { GuestCtrlCallback::Destroy(); } 811 812 GuestCbProcessIO& operator=(const GuestCbProcessIO &that) 813 { 814 return *this; 815 } 816 }; 817 #endif 623 624 /** Pointer to parent session. Per definition 625 * this objects *always* lives shorter than the 626 * parent. */ 627 GuestSession *mSession; 628 /** The object ID -- must be unique for each guest 629 * object and is encoded into the context ID. Must 630 * be set manually when initializing the object. 631 * 632 * For guest processes this is the internal PID, 633 * for guest files this is the internal file ID. */ 634 uint32_t mObjectID; 635 }; 818 636 #endif // ____H_GUESTIMPLPRIVATE 819 637 -
trunk/src/VBox/Main/include/GuestFileImpl.h
r45109 r45415 21 21 22 22 #include "VirtualBoxBase.h" 23 #include "EventImpl.h" 23 24 24 25 #include "GuestFsObjInfoImpl.h" … … 63 64 STDMETHOD(COMGETTER(Offset))(LONG64 *aOffset); 64 65 STDMETHOD(COMGETTER(OpenMode))(ULONG *aOpenMode); 66 STDMETHOD(COMGETTER(Status))(FileStatus_T *aStatus); 65 67 66 68 STDMETHOD(Close)(void); … … 80 82 int closeFile(int *pGuestRc); 81 83 static uint32_t getDispositionFromString(const Utf8Str &strDisposition); 84 EventSource *getEventSource(void) { return mEventSource; } 82 85 static uint32_t getOpenModeFromString(const Utf8Str &strOpenMode); 83 86 static Utf8Str guestErrorToString(int guestRc); 84 int onFileNotify(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData , GuestCtrlCallback *pCallback);85 int onGuestDisconnected(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData , GuestCtrlCallback *pCallback);87 int onFileNotify(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData); 88 int onGuestDisconnected(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData); 86 89 int openFile(int *pGuestRc); 87 int readData(uint32_t uSize, uint32_t uTimeoutMS, void *pvData, size_t cbData, size_t *pcbRead, int *pGuestRc); 88 int readDataAt(uint64_t uOffset, uint32_t uSize, uint32_t uTimeoutMS, void *pvData, size_t cbData, size_t *pcbRead, int *pGuestRc); 89 int seekAt(uint64_t uOffset, GUEST_FILE_SEEKTYPE eSeekType, uint32_t uTimeoutMS, int *pGuestRc); 90 int sendFileCommand(uint32_t uFunction, uint32_t uParms, PVBOXHGCMSVCPARM paParms, uint32_t uTimeoutMS, int *pGuestRc, GuestCtrlCallback **ppCallback); 90 int readData(uint32_t uSize, uint32_t uTimeoutMS, void* pvData, uint32_t cbData, uint32_t* pcbRead); 91 int readDataAt(uint64_t uOffset, uint32_t uSize, uint32_t uTimeoutMS, void* pvData, size_t cbData, size_t* pcbRead); 92 int seekAt(uint64_t uOffset, GUEST_FILE_SEEKTYPE eSeekType, uint32_t uTimeoutMS, uint64_t *puOffset); 91 93 static HRESULT setErrorExternal(VirtualBoxBase *pInterface, int guestRc); 92 int writeData(uint32_t uTimeoutMS, void *pvData, size_t cbData, uint32_t *pcbWritten, int *pGuestRc); 93 int writeDataAt(uint64_t uOffset, uint32_t uTimeoutMS, void *pvData, size_t cbData, uint32_t *pcbWritten, int *pGuestRc); 94 int setFileStatus(FileStatus_T fileStatus, int fileRc); 95 int waitForOffsetChange(uint32_t uTimeoutMS, uint64_t *puOffset); 96 int waitForRead(uint32_t uTimeoutMS, void* pvData, size_t cbData, uint32_t *pcbRead); 97 int waitForStatusChange(uint32_t uTimeoutMS, FileStatus_T *pFileStatus); 98 int waitForWrite(uint32_t uTimeoutMS, uint32_t *pcbWritten); 99 int writeData(uint32_t uTimeoutMS, void *pvData, uint32_t cbData, uint32_t *pcbWritten); 100 int writeDataAt(uint64_t uOffset, uint32_t uTimeoutMS, void *pvData, uint32_t cbData, uint32_t *pcbWritten); 94 101 /** @} */ 95 102 96 103 private: 97 104 105 /** The internal console object. */ 106 Console *mConsole; 107 /** The associate session this file belongs to. */ 108 GuestSession *mSession; 109 /** This can safely be used without holding any locks. 110 * An AutoCaller suffices to prevent it being destroy while in use and 111 * internally there is a lock providing the necessary serialization. */ 112 const ComObjPtr<EventSource> mEventSource; 113 98 114 struct Data 99 115 { 100 /** The internal console object. */101 Console *mConsole;102 /** The associate session this file belongs to. */103 GuestSession *mSession;104 116 /** All related callbacks to this file. */ 105 117 GuestCtrlCallbacks mCallbacks; … … 110 122 /** The file's internal ID. */ 111 123 uint32_t mID; 124 /** The current file status. */ 125 FileStatus_T mStatus; 112 126 /** The file's current offset. */ 113 127 uint64_t mOffCurrent; -
trunk/src/VBox/Main/include/GuestImpl.h
r44935 r45415 177 177 GuestSessions mGuestSessions; 178 178 uint32_t mNextSessionID; 179 }; 180 181 ULONG mMemoryBalloonSize; 182 ULONG mStatUpdateInterval; 183 uint64_t mNetStatRx; 184 uint64_t mNetStatTx; 185 uint64_t mNetStatLastTs; 186 ULONG mCurrentGuestStat[GUESTSTATTYPE_MAX]; 187 ULONG mVmValidStats; 188 BOOL mCollectVMMStats; 189 BOOL mfPageFusionEnabled; 190 191 Console *mParent; 192 Data mData; 193 194 #ifdef VBOX_WITH_GUEST_CONTROL 179 } mData; 180 181 ULONG mMemoryBalloonSize; 182 ULONG mStatUpdateInterval; 183 uint64_t mNetStatRx; 184 uint64_t mNetStatTx; 185 uint64_t mNetStatLastTs; 186 ULONG mCurrentGuestStat[GUESTSTATTYPE_MAX]; 187 ULONG mVmValidStats; 188 BOOL mCollectVMMStats; 189 BOOL mfPageFusionEnabled; 190 191 Console *mParent; 192 193 #ifdef VBOX_WITH_GUEST_CONTROL 194 /** 195 * This can safely be used without holding any locks. 196 * An AutoCaller suffices to prevent it being destroy while in use and 197 * internally there is a lock providing the necessary serialization. 198 */ 199 const ComObjPtr<EventSource> mEventSource; 195 200 /** General extension callback for guest control. */ 196 HGCMSVCEXTHANDLE mhExtCtrl;201 HGCMSVCEXTHANDLE mhExtCtrl; 197 202 #endif 198 203 -
trunk/src/VBox/Main/include/GuestProcessImpl.h
r45010 r45415 83 83 int terminateProcess(int *pGuestRc); 84 84 int waitFor(uint32_t fWaitFlags, ULONG uTimeoutMS, ProcessWaitResult_T &waitResult, int *pGuestRc); 85 int waitForInputNotify(uint32_t uHandle, uint32_t uTimeoutMS, ProcessInputStatus_T *pInputStatus, size_t *pcbProcessed); 86 int waitForOutput(uint32_t uHandle, uint32_t uTimeoutMS, void* pvData, size_t cbData, size_t* pcbRead); 87 int waitForStatusChange(uint32_t fWaitFlags, uint32_t uTimeoutMS, ProcessStatus_T *pProcessStatus, int *pGuestRc); 85 88 int writeData(uint32_t uHandle, uint32_t uFlags, void *pvData, size_t cbData, uint32_t uTimeoutMS, uint32_t *puWritten, int *pGuestRc); 86 89 /** @} */ … … 90 93 * @{ */ 91 94 inline bool isAlive(void); 92 int onGuestDisconnected(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, GuestCtrlCallback *pCallback,PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData);93 int onProcessInputStatus(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, GuestCtrlCallback *pCallback,PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData);94 int onProcessNotifyIO(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, GuestCtrlCallback * pCallback,PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData);95 int onProcessStatusChange(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, GuestCtrlCallback *pCallback,PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData);96 int onProcessOutput(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, GuestCtrlCallback *pCallback,PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData);95 int onGuestDisconnected(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData); 96 int onProcessInputStatus(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData); 97 int onProcessNotifyIO(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData); 98 int onProcessStatusChange(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData); 99 int onProcessOutput(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData); 97 100 int prepareExecuteEnv(const char *pszEnv, void **ppvList, ULONG *pcbList, ULONG *pcEnvVars); 98 101 int setProcessStatus(ProcessStatus_T procStatus, int procRc); 99 int signalWaiters(ProcessWaitResult_T enmWaitResult, int rc = VINF_SUCCESS);100 102 static DECLCALLBACK(int) startProcessThread(RTTHREAD Thread, void *pvUser); 101 103 /** @} */ 102 104 103 105 private: 106 107 /** 108 * This can safely be used without holding any locks. 109 * An AutoCaller suffices to prevent it being destroy while in use and 110 * internally there is a lock providing the necessary serialization. 111 */ 112 const ComObjPtr<EventSource> mEventSource; 104 113 105 114 struct Data … … 116 125 * returned from the guest side. */ 117 126 int mRC; 118 /** How many waiters? At the moment there can only119 * be one. */120 uint32_t mWaitCount;121 /** The actual process event for doing the waits.122 * At the moment we only support one wait a time. */123 GuestProcessWaitEvent *mWaitEvent;124 127 } mData; 125 128 }; -
trunk/src/VBox/Main/include/GuestSessionImpl.h
r45010 r45415 21 21 22 22 #include "VirtualBoxBase.h" 23 #include "EventImpl.h" 23 24 24 25 #include "GuestCtrlImplPrivate.h" … … 238 239 class ATL_NO_VTABLE GuestSession : 239 240 public VirtualBoxBase, 241 public GuestBase, 240 242 VBOX_SCRIPTABLE_IMPL(IGuestSession) 241 243 { … … 271 273 STDMETHOD(COMGETTER(Directories))(ComSafeArrayOut(IGuestDirectory *, aDirectories)); 272 274 STDMETHOD(COMGETTER(Files))(ComSafeArrayOut(IGuestFile *, aFiles)); 275 STDMETHOD(COMGETTER(EventSource))(IEventSource ** aEventSource); 273 276 /** @} */ 274 277 … … 345 348 const GuestCredentials &getCredentials(void); 346 349 const GuestEnvironment &getEnvironment(void); 350 EventSource *getEventSource(void) { return mEventSource; } 347 351 Utf8Str getName(void); 348 352 ULONG getId(void) { return mData.mSession.mID; } 349 353 static Utf8Str guestErrorToString(int guestRc); 350 int onSessionStatusChange(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, GuestCtrlCallback *pCallback, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData); 354 HRESULT isReadyExternal(void); 355 int onSessionStatusChange(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData); 351 356 int startSessionIntenal(int *pGuestRc); 352 357 int startSessionAsync(void); 353 358 static DECLCALLBACK(int) 354 359 startSessionThread(RTTHREAD Thread, void *pvUser); 355 Guest *getParent(void) { return m Data.mParent; }360 Guest *getParent(void) { return mParent; } 356 361 uint32_t getProtocolVersion(void) { return mData.mProtocolVersion; } 357 362 int processRemoveFromList(GuestProcess *pProcess); … … 361 366 int sendCommand(uint32_t uFunction, uint32_t uParms, PVBOXHGCMSVCPARM paParms); 362 367 static HRESULT setErrorExternal(VirtualBoxBase *pInterface, int guestRc); 368 int setSessionStatus(GuestSessionStatus_T sessionStatus, int sessionRc); 369 int signalWaiters(GuestSessionWaitResult_T enmWaitResult, int rc /*= VINF_SUCCESS */); 363 370 int startTaskAsync(const Utf8Str &strTaskDesc, GuestSessionTask *pTask, ComObjPtr<Progress> &pProgress); 364 371 int queryInfo(void); 365 372 int waitFor(uint32_t fWaitFlags, ULONG uTimeoutMS, GuestSessionWaitResult_T &waitResult, int *pGuestRc); 373 int waitForStateChange(uint32_t fWaitFlags, uint32_t uTimeoutMS, GuestSessionStatus_T *pSessionStatus, int *pGuestRc); 366 374 /** @} */ 367 375 368 376 private: 377 378 /** Pointer to the parent (Guest). */ 379 Guest *mParent; 380 /** 381 * This can safely be used without holding any locks. 382 * An AutoCaller suffices to prevent it being destroy while in use and 383 * internally there is a lock providing the necessary serialization. 384 */ 385 const ComObjPtr<EventSource> mEventSource; 369 386 370 387 struct Data 371 388 { 372 /** Pointer to the parent (Guest). */373 Guest *mParent;374 389 /** The session credentials. */ 375 390 GuestCredentials mCredentials; … … 381 396 * overwritten/extended by ProcessCreate(Ex). */ 382 397 GuestEnvironment mEnvironment; 383 /** The session callback, needed for communicating384 * with the guest. */385 GuestCtrlCallback mCallback;386 398 /** Directory objects bound to this session. */ 387 399 SessionDirectories mDirectories; … … 402 414 * returned from the guest side. */ 403 415 int mRC; 404 /** How many waiters? At the moment there can only405 * be one. */406 uint32_t mWaitCount;407 /** The actual session event for doing the waits.408 * At the moment we only support one wait a time. */409 GuestSessionWaitEvent *mWaitEvent;410 416 } mData; 411 417 }; -
trunk/src/VBox/Main/src-client/GuestCtrlImpl.cpp
r45078 r45415 5 5 6 6 /* 7 * Copyright (C) 2006-201 2Oracle Corporation7 * Copyright (C) 2006-2013 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 23 23 #include "ConsoleImpl.h" 24 24 #include "ProgressImpl.h" 25 #include "VBoxEvents.h" 25 26 #include "VMMDev.h" 26 27 … … 159 160 { 160 161 case VERR_MAX_PROCS_REACHED: 161 hr = setError(VBOX_E_IPRT_ERROR, tr("Maximum number of guest sessions (%ld) reached"),162 hr = setError(VBOX_E_IPRT_ERROR, tr("Maximum number of concurrent guest sessions (%ld) reached"), 162 163 VBOX_GUESTCTRL_MAX_SESSIONS); 163 164 break; … … 316 317 LogFlowFunc(("Closing session (ID=%RU32) ...\n", pSession->getId())); 317 318 318 for (GuestSessions::iterator itSessions = mData.mGuestSessions.begin();319 itSessions != mData.mGuestSessions.end(); ++itSessions)319 GuestSessions::iterator itSessions = mData.mGuestSessions.begin(); 320 while (itSessions != mData.mGuestSessions.end()) 320 321 { 321 322 if (pSession == itSessions->second) … … 324 325 (GuestSession *)itSessions->second, itSessions->second->getId(), mData.mGuestSessions.size() - 1)); 325 326 326 mData.mGuestSessions.erase(itSessions++); 327 327 mData.mGuestSessions.erase(itSessions); 328 329 fireGuestSessionRegisteredEvent(mEventSource, pSession, 330 false /* Unregistered */); 328 331 rc = VINF_SUCCESS; 329 332 break; 330 333 } 334 335 itSessions++; 331 336 } 332 337 … … 398 403 * Add session object to our session map. This is necessary 399 404 * before calling openSession because the guest calls back 400 * with the creation result tothis session.405 * with the creation result of this session. 401 406 */ 402 407 mData.mGuestSessions[uNewSessionID] = pGuestSession; 403 408 404 /* Drop write lock before opening session, because this will 405 * involve the main dispatcher to run. */ 406 alock.release(); 409 fireGuestSessionRegisteredEvent(mEventSource, pGuestSession, 410 true /* Registered */); 407 411 } 408 412 catch (int rc2) … … 459 463 } 460 464 461 int guestRc;462 465 if (RT_SUCCESS(rc)) 463 466 { 464 /** @todo Do we need to use openSessioAsync() here? Otherwise 465 * there might be a problem on webservice calls (= timeouts) 466 * if opening the guest session takes too long -> Use 467 * the new session.getStatus() API call! */ 468 469 /* Start (fork) the session on the guest. */ 470 rc = pSession->startSessionIntenal(&guestRc); 471 if (RT_SUCCESS(rc)) 472 { 473 LogFlowFunc(("Created new guest session (pSession=%p), now %zu sessions total\n", 474 (GuestSession *)pSession, mData.mGuestSessions.size())); 475 } 467 /* Start (fork) the session asynchronously 468 * on the guest. */ 469 rc = pSession->startSessionAsync(); 476 470 } 477 471 … … 482 476 switch (rc) 483 477 { 484 case VERR_GSTCTL_GUEST_ERROR:485 hr = GuestSession::setErrorExternal(this, guestRc);486 break;487 488 478 case VERR_MAX_PROCS_REACHED: 489 hr = setError(VBOX_E_IPRT_ERROR, tr("Maximum number of guest sessions (%ld) reached"),479 hr = setError(VBOX_E_IPRT_ERROR, tr("Maximum number of concurrent guest sessions (%ld) reached"), 490 480 VBOX_GUESTCTRL_MAX_SESSIONS); 491 481 break; -
trunk/src/VBox/Main/src-client/GuestCtrlPrivate.cpp
r45367 r45415 1258 1258 } 1259 1259 1260 GuestBase::GuestBase(void) 1261 : mConsole(NULL), 1262 mNextContextID(0) 1263 { 1264 } 1265 1266 GuestBase::~GuestBase(void) 1267 { 1268 } 1269 1270 int GuestBase::generateContextID(uint32_t uSessionID, uint32_t uObjectID, uint32_t *puContextID) 1271 { 1272 AssertPtrReturn(puContextID, VERR_INVALID_POINTER); 1273 1274 uint32_t uCount = mNextContextID++; 1275 if (uCount == VBOX_GUESTCTRL_MAX_CONTEXTS) 1276 uCount = 0; 1277 1278 uint32_t uNewContextID = 1279 VBOX_GUESTCTRL_CONTEXTID_MAKE(uSessionID, uObjectID, uCount); 1280 1281 *puContextID = uNewContextID; 1282 } 1283 1284 GuestObject::GuestObject(void) 1285 : mSession(NULL), 1286 mObjectID(0) 1287 { 1288 } 1289 1290 GuestObject::~GuestObject(void) 1291 { 1292 } 1293 1260 1294 int GuestObject::bindToSession(Console *pConsole, GuestSession *pSession, uint32_t uObjectID) 1261 1295 { … … 1263 1297 AssertPtrReturn(pSession, VERR_INVALID_POINTER); 1264 1298 1265 mObject.mConsole = pConsole; 1266 mObject.mSession = pSession; 1267 1268 mObject.mNextContextID = 0; 1269 mObject.mObjectID = uObjectID; 1299 mConsole = pConsole; 1300 mSession = pSession; 1301 mObjectID = uObjectID; 1270 1302 1271 1303 return VINF_SUCCESS; 1272 }1273 1274 int GuestObject::callbackAdd(GuestCtrlCallback *pCallback, uint32_t *puContextID)1275 {1276 const ComObjPtr<GuestSession> pSession(mObject.mSession);1277 Assert(!pSession.isNull());1278 ULONG uSessionID = 0;1279 pSession->COMGETTER(Id)(&uSessionID);1280 1281 /* Create a new context ID and assign it. */1282 int vrc = VERR_NOT_FOUND;1283 1284 ULONG uCount = mObject.mNextContextID++;1285 ULONG uNewContextID = 0;1286 ULONG uTries = 0;1287 for (;;)1288 {1289 if (uCount == VBOX_GUESTCTRL_MAX_CONTEXTS)1290 uCount = 0;1291 1292 /* Create a new context ID ... */1293 uNewContextID = VBOX_GUESTCTRL_CONTEXTID_MAKE(uSessionID, mObject.mObjectID, uCount);1294 1295 /* Is the context ID already used? Try next ID ... */1296 if (!callbackExists(uCount))1297 {1298 /* Callback with context ID was not found. This means1299 * we can use this context ID for our new callback we want1300 * to add below. */1301 vrc = VINF_SUCCESS;1302 break;1303 }1304 1305 uCount++;1306 if (++uTries == UINT32_MAX)1307 break; /* Don't try too hard. */1308 }1309 1310 if (RT_SUCCESS(vrc))1311 {1312 /* Add callback with new context ID to our callback map.1313 * Note: This is *not* uNewContextID (which also includes1314 * the session + process ID), just the context count1315 * will be used here. */1316 mObject.mCallbacks[uCount] = pCallback;1317 Assert(mObject.mCallbacks.size());1318 1319 /* Report back new context ID. */1320 if (puContextID)1321 *puContextID = uNewContextID;1322 1323 LogFlowThisFunc(("Added new callback (Session: %RU32, Object: %RU32, Count: %RU32) CID=%RU32\n",1324 uSessionID, mObject.mObjectID, uCount, uNewContextID));1325 }1326 1327 return vrc;1328 }1329 1330 void GuestObject::callbackDelete(GuestCtrlCallback *pCallback)1331 {1332 if (pCallback)1333 {1334 delete pCallback;1335 pCallback = NULL;1336 }1337 }1338 1339 bool GuestObject::callbackExists(uint32_t uContextID)1340 {1341 GuestCtrlCallbacks::const_iterator it =1342 mObject.mCallbacks.find(VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(uContextID));1343 return (it == mObject.mCallbacks.end()) ? false : true;1344 }1345 1346 int GuestObject::callbackRemove(uint32_t uContextID)1347 {1348 LogFlowThisFunc(("Removing callback (Session=%RU32, Object=%RU32, Count=%RU32) CID=%RU32\n",1349 VBOX_GUESTCTRL_CONTEXTID_GET_SESSION(uContextID),1350 VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(uContextID),1351 VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(uContextID),1352 uContextID));1353 1354 GuestCtrlCallbacks::iterator it =1355 mObject.mCallbacks.find(VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(uContextID));1356 if (it != mObject.mCallbacks.end())1357 {1358 mObject.mCallbacks.erase(it);1359 1360 return VINF_SUCCESS;1361 }1362 1363 return VERR_NOT_FOUND;1364 }1365 1366 int GuestObject::callbackRemoveAll(void)1367 {1368 int vrc = VINF_SUCCESS;1369 1370 /*1371 * Cancel all callbacks + waiters.1372 * Note: Deleting them is the job of the caller!1373 */1374 for (GuestCtrlCallbacks::iterator itCallbacks = mObject.mCallbacks.begin();1375 itCallbacks != mObject.mCallbacks.end(); ++itCallbacks)1376 {1377 GuestCtrlCallback *pCallback = itCallbacks->second;1378 AssertPtr(pCallback);1379 int rc2 = pCallback->Cancel();1380 if (RT_SUCCESS(vrc))1381 vrc = rc2;1382 }1383 mObject.mCallbacks.clear();1384 1385 return vrc;1386 1304 } 1387 1305 … … 1392 1310 1393 1311 #ifndef VBOX_GUESTCTRL_TEST_CASE 1394 ComObjPtr<Console> pConsole = m Object.mConsole;1312 ComObjPtr<Console> pConsole = mConsole; 1395 1313 Assert(!pConsole.isNull()); 1396 1314 -
trunk/src/VBox/Main/src-client/GuestFileImpl.cpp
r45109 r45415 21 21 * Header Files * 22 22 *******************************************************************************/ 23 #include "GuestErrorInfoImpl.h" 23 24 #include "GuestFileImpl.h" 24 25 #include "GuestSessionImpl.h" … … 28 29 #include "Global.h" 29 30 #include "AutoCaller.h" 30 31 #include "VBoxEvents.h" 32 33 #include <iprt/cpp/utils.h> /* For unconst(). */ 31 34 #include <iprt/file.h> 32 35 #include <VBox/com/array.h> … … 88 91 mData.mID = 0; 89 92 mData.mInitialSize = 0; 90 93 mData.mStatus = FileStatus_Undefined; 94 95 unconst(mEventSource).createObject(); 96 HRESULT hr = mEventSource->init(static_cast<IGuestFile*>(this)); 97 if (FAILED(hr)) 98 vrc = VERR_COM_UNEXPECTED; 99 } 100 101 if (RT_SUCCESS(vrc)) 102 { 91 103 /* Confirm a successful initialization when it's the case. */ 92 104 autoInitSpan.setSucceeded(); 93 return vrc; 94 } 95 96 autoInitSpan.setFailed(); 105 } 106 else 107 autoInitSpan.setFailed(); 108 109 LogFlowFuncLeaveRC(vrc); 97 110 return vrc; 98 111 } … … 112 125 113 126 #ifdef VBOX_WITH_GUEST_CONTROL 114 /* 115 * Cancel + remove all callbacks + waiters. 116 * Note: Deleting them is the job of the caller! 117 */ 118 callbackRemoveAll(); 127 unconst(mEventSource).setNull(); 119 128 #endif 120 129 … … 230 239 231 240 *aOpenMode = getOpenModeFromString(mData.mOpenInfo.mOpenMode); 241 242 return S_OK; 243 #endif /* VBOX_WITH_GUEST_CONTROL */ 244 } 245 246 STDMETHODIMP GuestFile::COMGETTER(Status)(FileStatus_T *aStatus) 247 { 248 #ifndef VBOX_WITH_GUEST_CONTROL 249 ReturnComNotImplemented(); 250 #else 251 LogFlowThisFuncEnter(); 252 253 AutoCaller autoCaller(this); 254 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 255 256 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 257 258 *aStatus = mData.mStatus; 232 259 233 260 return S_OK; … … 248 275 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 249 276 250 /* Get the optional callback associated to this context ID.251 * The callback may not be around anymore if just kept locally by the caller when252 * doing the actual HGCM sending stuff. */253 GuestCtrlCallback *pCallback = NULL;254 GuestCtrlCallbacks::const_iterator it255 = mData.mCallbacks.find(VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(pCbCtx->uContextID));256 if (it != mData.mCallbacks.end())257 {258 pCallback = it->second;259 AssertPtr(pCallback);260 #ifdef DEBUG261 LogFlowThisFunc(("pCallback=%p, CID=%RU32, Count=%RU32\n",262 pCallback, pCbCtx->uContextID, VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(pCbCtx->uContextID)));263 #endif264 }265 266 277 int vrc; 267 278 switch (pCbCtx->uFunction) 268 279 { 269 280 case GUEST_DISCONNECTED: 270 vrc = onGuestDisconnected(pCbCtx, pSvcCb , pCallback); /* Affects all callbacks. */281 vrc = onGuestDisconnected(pCbCtx, pSvcCb); 271 282 break; 272 283 273 284 case GUEST_FILE_NOTIFY: 274 vrc = onFileNotify(pCbCtx, pSvcCb , pCallback);285 vrc = onFileNotify(pCbCtx, pSvcCb); 275 286 break; 276 287 … … 291 302 LogFlowThisFunc(("strFile=%s\n", mData.mOpenInfo.mFileName.c_str())); 292 303 293 /* Prepare HGCM call. */ 294 VBOXHGCMSVCPARM paParms[4]; 295 int i = 1; /* Context ID will be set in sendFileComannd(). */ 296 paParms[i++].setUInt32(mData.mID /* Guest file ID */); 297 298 int guestRc; 299 int vrc = sendFileCommand(HOST_FILE_CLOSE, i, paParms, 30 * 1000 /* 30s timeout */, 300 &guestRc, NULL /* ppCallback */); 301 if (pGuestRc) 302 *pGuestRc = guestRc; 304 uint32_t uContextID; 305 int vrc = generateContextID(mSession->getId(), mObjectID, 306 &uContextID); 307 if (RT_SUCCESS(vrc)) 308 { 309 /* Prepare HGCM call. */ 310 VBOXHGCMSVCPARM paParms[4]; 311 int i = 0; 312 paParms[i++].setUInt32(mData.mID /* Guest file ID */); 313 314 vrc = sendCommand(HOST_FILE_CLOSE, i, paParms); 315 if (RT_SUCCESS(vrc)) 316 vrc = waitForStatusChange(30 * 1000 /* Timeout in ms */, 317 NULL /* FileStatus */); 318 } 303 319 304 320 LogFlowFuncLeaveRC(vrc); … … 383 399 } 384 400 385 int GuestFile::onFileNotify(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData, 386 GuestCtrlCallback *pCallback) 401 int GuestFile::onFileNotify(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData) 387 402 { 388 403 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER); 389 404 AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER); 390 /* pCallback is optional. */391 405 392 406 if (pSvcCbData->mParms < 3) … … 401 415 pSvcCbData->mpaParms[idx++].getUInt32(&dataCb.rc); 402 416 417 int guestRc = (int)dataCb.rc; /* uint32_t vs. int. */ 418 403 419 switch (dataCb.uType) 404 420 { 405 421 case GUEST_FILE_NOTIFYTYPE_ERROR: 406 /* No extra data. */ 407 break; 422 { 423 AssertMsg(mData.mStatus != FileStatus_Error, ("File status already set to error\n")); 424 425 int rc2 = setFileStatus(FileStatus_Error, guestRc); 426 AssertRC(rc2); 427 break; 428 } 408 429 409 430 case GUEST_FILE_NOTIFYTYPE_OPEN: 431 { 410 432 if (pSvcCbData->mParms == 4) 411 433 { … … 417 439 ("File ID %RU32 does not match context ID %RU32\n", mData.mID, 418 440 VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pCbCtx->uContextID))); 441 442 /* Set the process status. */ 443 int rc2 = setFileStatus(FileStatus_Open, guestRc); 444 if (RT_SUCCESS(vrc)) 445 vrc = rc2; 419 446 } 420 447 else 421 448 vrc = VERR_NOT_SUPPORTED; 422 break; 449 450 break; 451 } 423 452 424 453 case GUEST_FILE_NOTIFYTYPE_CLOSE: 425 /* No extra data. */ 426 break; 454 { 455 int rc2 = setFileStatus(FileStatus_Closed, guestRc); 456 AssertRC(rc2); 457 458 break; 459 } 427 460 428 461 case GUEST_FILE_NOTIFYTYPE_READ: … … 431 464 pSvcCbData->mpaParms[idx++].getPointer(&dataCb.u.read.pvData, 432 465 &dataCb.u.read.cbData); 433 434 mData.mOffCurrent += dataCb.u.read.cbData; 466 uint32_t cbRead = dataCb.u.read.cbData; 467 if (cbRead) 468 { 469 mData.mOffCurrent += cbRead; 470 471 com::SafeArray<BYTE> data((size_t)cbRead); 472 data.initFrom((BYTE*)dataCb.u.read.pvData, cbRead); 473 fireGuestFileReadEvent(mEventSource, mSession, this, mData.mOffCurrent, 474 cbRead, ComSafeArrayAsInParam(data)); 475 } 435 476 } 436 477 else … … 444 485 445 486 mData.mOffCurrent += dataCb.u.write.cbWritten; 487 488 if (dataCb.u.write.cbWritten) 489 fireGuestFileWriteEvent(mEventSource, mSession, this, mData.mOffCurrent, 490 dataCb.u.write.cbWritten); 446 491 } 447 492 else … … 455 500 456 501 mData.mOffCurrent = dataCb.u.seek.uOffActual; 502 503 if (dataCb.u.seek.uOffActual) 504 fireGuestFileOffsetChangedEvent(mEventSource, mSession, this, 505 mData.mOffCurrent, 0 /* Processed */); 457 506 } 458 507 else … … 465 514 pSvcCbData->mpaParms[idx++].getUInt64(&dataCb.u.tell.uOffActual); 466 515 467 mData.mOffCurrent = dataCb.u.tell.uOffActual; 516 if (mData.mOffCurrent != dataCb.u.tell.uOffActual) 517 { 518 mData.mOffCurrent = dataCb.u.tell.uOffActual; 519 520 fireGuestFileOffsetChangedEvent(mEventSource, mSession, this, 521 mData.mOffCurrent, 0 /* Processed */); 522 } 468 523 } 469 524 else … … 476 531 } 477 532 478 LogFlowThisFunc(("strName=%s, uType=%RU32, rc=%Rrc, pCallback=%p\n", 479 mData.mOpenInfo.mFileName.c_str(), dataCb.uType, dataCb.rc, pCallback)); 480 481 int guestRc = (int)dataCb.rc; /* uint32_t vs. int. */ 533 LogFlowThisFunc(("strName=%s, uType=%RU32, guestRc=%Rrc\n", 534 mData.mOpenInfo.mFileName.c_str(), dataCb.uType, dataCb.rc)); 535 482 536 if (RT_SUCCESS(vrc)) 483 537 { … … 490 544 } 491 545 492 /* Signal callback in every case (if available). */493 if (pCallback)494 {495 int rc2 = pCallback->SetData(&dataCb, sizeof(dataCb));496 if (RT_SUCCESS(vrc))497 vrc = rc2;498 rc2 = pCallback->Signal(guestRc);499 if (RT_SUCCESS(vrc))500 vrc = rc2;501 }502 503 546 LogFlowFuncLeaveRC(vrc); 504 547 return vrc; 505 548 } 506 549 507 int GuestFile::onGuestDisconnected(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData, 508 GuestCtrlCallback *pCallback) 550 int GuestFile::onGuestDisconnected(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData) 509 551 { 510 552 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER); 511 553 AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER); 512 /* pCallback is optional. */ 513 514 LogFlowThisFunc(("strFile=%s, pCallback=%p\n", 515 mData.mOpenInfo.mFileName.c_str(), pCallback)); 516 517 /* First, signal callback in every case. */ 518 if (pCallback) 519 pCallback->Signal(); 520 521 /** @todo More on onGuestDisconnected? */ 522 int vrc = VINF_SUCCESS; 554 555 LogFlowThisFunc(("strFile=%s\n", 556 mData.mOpenInfo.mFileName.c_str())); 557 558 int vrc = setFileStatus(FileStatus_Down, VINF_SUCCESS); 523 559 524 560 LogFlowFuncLeaveRC(vrc); … … 534 570 /* Prepare HGCM call. */ 535 571 VBOXHGCMSVCPARM paParms[8]; 536 int i = 1; /* Context ID will be set in sendFileComannd(). */572 int i = 0; 537 573 paParms[i++].setPointer((void*)mData.mOpenInfo.mFileName.c_str(), 538 574 (ULONG)mData.mOpenInfo.mFileName.length() + 1); … … 544 580 paParms[i++].setUInt64(mData.mOpenInfo.mInitialOffset); 545 581 546 int vrc = sendFileCommand(HOST_FILE_OPEN, i, paParms, 30 * 1000 /* 30s timeout */, 547 pGuestRc, NULL /* ppCallback */); 582 int vrc = sendCommand(HOST_FILE_OPEN, i, paParms); 583 if (RT_SUCCESS(vrc)) 584 vrc = waitForStatusChange(30 * 1000 /* Timeout in ms */, 585 NULL /* FileStatus */); 548 586 549 587 LogFlowFuncLeaveRC(vrc); … … 551 589 } 552 590 553 int GuestFile::readData(uint32_t uSize, uint32_t uTimeoutMS, void *pvData, size_t cbData,554 size_t *pcbRead, int *pGuestRc)591 int GuestFile::readData(uint32_t uSize, uint32_t uTimeoutMS, 592 void* pvData, uint32_t cbData, uint32_t* pcbRead) 555 593 { 556 594 LogFlowThisFunc(("uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n", 557 595 uSize, uTimeoutMS, pvData, cbData)); 558 596 597 uint32_t uContextID; 598 int vrc = generateContextID(mSession->getId(), mObjectID, 599 &uContextID); 600 if (RT_SUCCESS(vrc)) 601 { 602 /* Prepare HGCM call. */ 603 VBOXHGCMSVCPARM paParms[4]; 604 int i = 0; 605 paParms[i++].setUInt32(mData.mID /* File handle */); 606 paParms[i++].setUInt32(uSize /* Size (in bytes) to read */); 607 608 uint32_t cbRead; 609 vrc = sendCommand(HOST_FILE_READ, i, paParms); 610 if (RT_SUCCESS(vrc)) 611 vrc = waitForRead(uTimeoutMS, pvData, cbData, &cbRead); 612 613 if (RT_SUCCESS(vrc)) 614 { 615 LogFlowThisFunc(("cbRead=%RU32\n", cbRead)); 616 617 if (pcbRead) 618 *pcbRead = cbRead; 619 } 620 } 621 622 LogFlowFuncLeaveRC(vrc); 623 return vrc; 624 } 625 626 int GuestFile::readDataAt(uint64_t uOffset, uint32_t uSize, uint32_t uTimeoutMS, 627 void* pvData, size_t cbData, size_t* pcbRead) 628 { 629 LogFlowThisFunc(("uOffset=%RU64, uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n", 630 uOffset, uSize, uTimeoutMS, pvData, cbData)); 631 632 uint32_t uContextID; 633 int vrc = generateContextID(mSession->getId(), mObjectID, 634 &uContextID); 635 if (RT_SUCCESS(vrc)) 636 { 637 638 /* Prepare HGCM call. */ 639 VBOXHGCMSVCPARM paParms[4]; 640 int i = 0; 641 paParms[i++].setUInt32(mData.mID /* File handle */); 642 paParms[i++].setUInt64(uOffset /* Offset (in bytes) to start reading */); 643 paParms[i++].setUInt32(uSize /* Size (in bytes) to read */); 644 645 uint32_t cbRead; 646 int vrc = sendCommand(HOST_FILE_READ_AT, i, paParms); 647 if (RT_SUCCESS(vrc)) 648 vrc = waitForRead(uTimeoutMS, pvData, cbData, &cbRead); 649 650 if (RT_SUCCESS(vrc)) 651 { 652 LogFlowThisFunc(("cbRead=%RU32\n", cbRead)); 653 654 if (pcbRead) 655 *pcbRead = cbRead; 656 } 657 } 658 659 LogFlowFuncLeaveRC(vrc); 660 return vrc; 661 } 662 663 int GuestFile::seekAt(uint64_t uOffset, GUEST_FILE_SEEKTYPE eSeekType, 664 uint32_t uTimeoutMS, uint64_t *puOffset) 665 { 666 LogFlowThisFunc(("uOffset=%RU64, uTimeoutMS=%RU32\n", 667 uOffset, uTimeoutMS)); 668 559 669 /* Prepare HGCM call. */ 560 670 VBOXHGCMSVCPARM paParms[4]; 561 int i = 1; /* Context ID will be set in sendFileComannd(). */ 562 paParms[i++].setUInt32(mData.mID /* File handle */); 563 paParms[i++].setUInt32(uSize /* Size (in bytes) to read */); 564 565 GuestCtrlCallback *pCallback = NULL; int guestRc; 566 int vrc = sendFileCommand(HOST_FILE_READ, i, paParms, uTimeoutMS, 567 &guestRc, &pCallback); 568 569 if (RT_SUCCESS(vrc)) 570 { 571 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 572 573 Assert(pCallback->GetDataSize() == sizeof(CALLBACKDATA_FILE_NOTIFY)); 574 PCALLBACKDATA_FILE_NOTIFY pData = (PCALLBACKDATA_FILE_NOTIFY)pCallback->GetDataRaw(); 575 AssertPtr(pData); 576 Assert(pData->uType == GUEST_FILE_NOTIFYTYPE_READ); 577 578 size_t cbRead = pData->u.read.cbData; 579 if (cbRead) 580 { 581 Assert(cbData >= cbRead); 582 memcpy(pvData, pData->u.read.pvData, cbRead); 583 } 584 585 LogFlowThisFunc(("cbRead=%RU32\n", cbRead)); 586 587 if (pcbRead) 588 *pcbRead = cbRead; 589 } 590 591 callbackDelete(pCallback); 592 593 if (pGuestRc) 594 *pGuestRc = guestRc; 595 596 LogFlowFuncLeaveRC(vrc); 597 return vrc; 598 } 599 600 int GuestFile::readDataAt(uint64_t uOffset, uint32_t uSize, uint32_t uTimeoutMS, 601 void *pvData, size_t cbData, 602 size_t *pcbRead, int *pGuestRc) 603 { 604 LogFlowThisFunc(("uOffset=%RU64, uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n", 605 uOffset, uSize, uTimeoutMS, pvData, cbData)); 606 607 /* Prepare HGCM call. */ 608 VBOXHGCMSVCPARM paParms[4]; 609 int i = 1; /* Context ID will be set in sendFileComannd(). */ 610 paParms[i++].setUInt32(mData.mID /* File handle */); 611 paParms[i++].setUInt64(uOffset /* Offset (in bytes) to start reading */); 612 paParms[i++].setUInt32(uSize /* Size (in bytes) to read */); 613 614 GuestCtrlCallback *pCallback = NULL; int guestRc; 615 int vrc = sendFileCommand(HOST_FILE_READ_AT, i, paParms, uTimeoutMS, 616 &guestRc, &pCallback); 617 618 if (RT_SUCCESS(vrc)) 619 { 620 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 621 622 Assert(pCallback->GetDataSize() == sizeof(CALLBACKDATA_FILE_NOTIFY)); 623 PCALLBACKDATA_FILE_NOTIFY pData = (PCALLBACKDATA_FILE_NOTIFY)pCallback->GetDataRaw(); 624 AssertPtr(pData); 625 Assert(pData->uType == GUEST_FILE_NOTIFYTYPE_READ); 626 627 size_t cbRead = pData->u.read.cbData; 628 if (cbRead) 629 { 630 Assert(cbData >= cbRead); 631 memcpy(pvData, pData->u.read.pvData, cbRead); 632 } 633 634 LogFlowThisFunc(("cbRead=%RU32\n", cbRead)); 635 636 if (pcbRead) 637 *pcbRead = cbRead; 638 } 639 640 callbackDelete(pCallback); 641 642 if (pGuestRc) 643 *pGuestRc = guestRc; 644 645 LogFlowFuncLeaveRC(vrc); 646 return vrc; 647 } 648 649 int GuestFile::seekAt(uint64_t uOffset, GUEST_FILE_SEEKTYPE eSeekType, 650 uint32_t uTimeoutMS, int *pGuestRc) 651 { 652 LogFlowThisFunc(("uOffset=%RU64, uTimeoutMS=%RU32\n", 653 uOffset, uTimeoutMS)); 654 655 /* Prepare HGCM call. */ 656 VBOXHGCMSVCPARM paParms[4]; 657 int i = 1; /* Context ID will be set in sendFileComannd(). */ 671 int i = 0; 658 672 paParms[i++].setUInt32(mData.mID /* File handle */); 659 673 paParms[i++].setUInt32(eSeekType /* Seek method */); 660 674 paParms[i++].setUInt64(uOffset /* Offset (in bytes) to start reading */); 661 675 662 int guestRc; 663 int vrc = sendFileCommand(HOST_FILE_SEEK, i, paParms, uTimeoutMS, 664 &guestRc, NULL /* ppCallback */); 665 if (pGuestRc) 666 *pGuestRc = guestRc; 667 668 LogFlowFuncLeaveRC(vrc); 669 return vrc; 670 } 671 672 /** 673 * Handles the common parts of sending a file command to the guest. 674 * If ppCallback is returned it must be removed via callbackRemove() 675 * by the caller in any case. 676 * 677 * @return IPRT status code. 678 * @param uFunction HGCM function of command to send. 679 * @param uParms Number of HGCM parameters to send. 680 * At least one parameter must be present. 681 * @param paParms Array of HGCM parameters to send. 682 * Index [0] must not be used and will be 683 * filled out by the function. 684 * @param uTimeoutMS Timeout (in ms). 685 * @param pGuestRc Guest result. Optional. 686 * @param ppCallback Pointer which will receive the callback for 687 * further processing by the caller. Must 688 * be deleted with callbackDelete() when done. Optional. 689 */ 690 int GuestFile::sendFileCommand(uint32_t uFunction, uint32_t uParms, PVBOXHGCMSVCPARM paParms, 691 uint32_t uTimeoutMS, int *pGuestRc, GuestCtrlCallback **ppCallback) 692 { 693 AssertReturn(uParms, VERR_INVALID_PARAMETER); 694 AssertPtrReturn(paParms, VERR_INVALID_POINTER); 695 /** pGuestRc is optional. */ 696 /** ppCallback is optional. */ 697 698 LogFlowThisFunc(("strFile=%s, uFunction=%RU32, uParms=%RU32\n", 699 mData.mOpenInfo.mFileName.c_str(), uFunction, uParms)); 700 701 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 702 703 AssertPtr(mData.mSession); 704 uint32_t uProtocol = mData.mSession->getProtocolVersion(); 705 if (uProtocol < 2) 706 return VERR_NOT_SUPPORTED; 707 708 int vrc = VINF_SUCCESS; 709 uint32_t uContextID = 0; 710 711 GuestCtrlCallback *pCallback; 712 try 713 { 714 pCallback = new GuestCtrlCallback(); 715 } 716 catch(std::bad_alloc &) 717 { 718 vrc = VERR_NO_MEMORY; 719 } 720 676 int vrc = sendCommand(HOST_FILE_SEEK, i, paParms); 721 677 if (RT_SUCCESS(vrc)) 722 { 723 /* Create callback and add it to the map. */ 724 vrc = pCallback->Init(CALLBACKTYPE_FILE_NOTIFY); 725 if (RT_SUCCESS(vrc)) 726 vrc = callbackAdd(pCallback, &uContextID); 727 } 728 729 if (RT_SUCCESS(vrc)) 730 { 731 /* Assign context ID. */ 732 paParms[0].setUInt32(uContextID); 733 734 GuestSession *pSession = mData.mSession; 735 AssertPtr(pSession); 736 737 alock.release(); /* Drop the write lock again. */ 738 739 /* Note: Don't hold the write lock in here. */ 740 vrc = sendCommand(uFunction, uParms, paParms); 741 742 if (RT_SUCCESS(vrc)) 743 { 744 /* 745 * Let's wait for the process being started. 746 * Note: Be sure not keeping a AutoRead/WriteLock here. 747 */ 748 LogFlowThisFunc(("Waiting for callback (%RU32ms) ...\n", 749 uTimeoutMS)); 750 vrc = pCallback->Wait(uTimeoutMS); 751 if (RT_SUCCESS(vrc)) /* Wait was successful, check for supplied information. */ 752 { 753 int guestRc = pCallback->GetResultCode(); 754 if (RT_SUCCESS(guestRc)) 755 { 756 /* Nothing to do here yet. */ 757 } 758 else 759 vrc = VERR_GSTCTL_GUEST_ERROR; 760 761 if (pGuestRc) 762 *pGuestRc = guestRc; 763 LogFlowThisFunc(("Callback returned rc=%Rrc\n", guestRc)); 764 } 765 } 766 767 alock.acquire(); /* Get write lock again. */ 768 769 AssertPtr(pCallback); 770 int rc2 = callbackRemove(uContextID); 771 if (RT_SUCCESS(vrc)) 772 vrc = rc2; 773 774 if (ppCallback) 775 { 776 /* Return callback to the caller which then will be 777 * responsible for removing it. Don't forget to lock write 778 * access before using this callback then! */ 779 *ppCallback = pCallback; 780 } 781 else 782 { 783 delete pCallback; 784 } 785 } 678 vrc = waitForOffsetChange(uTimeoutMS, puOffset); 786 679 787 680 LogFlowFuncLeaveRC(vrc); … … 798 691 } 799 692 800 int GuestFile::writeData(uint32_t uTimeoutMS, void *pvData, size_t cbData, 801 uint32_t *pcbWritten, int *pGuestRc) 693 /* Does not do locking; caller is responsible for that! */ 694 int GuestFile::setFileStatus(FileStatus_T fileStatus, int fileRc) 695 { 696 LogFlowThisFunc(("oldStatus=%ld, newStatus=%ld, fileRc=%Rrc\n", 697 mData.mStatus, fileStatus, fileRc)); 698 699 #ifdef VBOX_STRICT 700 if (fileStatus == FileStatus_Error) 701 { 702 AssertMsg(RT_FAILURE(fileRc), ("Guest rc must be an error (%Rrc)\n", fileRc)); 703 } 704 else 705 AssertMsg(RT_SUCCESS(fileRc), ("Guest rc must not be an error (%Rrc)\n", fileRc)); 706 #endif 707 708 if (mData.mStatus != fileStatus) 709 { 710 mData.mStatus = fileStatus; 711 712 ComObjPtr<GuestErrorInfo> errorInfo; 713 HRESULT hr = errorInfo.createObject(); 714 ComAssertComRC(hr); 715 if (RT_FAILURE(fileRc)) 716 { 717 int rc2 = errorInfo->init(fileRc, guestErrorToString(fileRc)); 718 AssertRC(rc2); 719 } 720 721 fireGuestFileStateChangedEvent(mEventSource, mSession, 722 this, mData.mStatus, errorInfo); 723 } 724 725 return VINF_SUCCESS; 726 } 727 728 int GuestFile::waitForOffsetChange(uint32_t uTimeoutMS, uint64_t *puOffset) 729 { 730 return VINF_SUCCESS; 731 } 732 733 int GuestFile::waitForRead(uint32_t uTimeoutMS, void* pvData, size_t cbData, uint32_t *pcbRead) 734 { 735 return VINF_SUCCESS; 736 } 737 738 int GuestFile::waitForStatusChange(uint32_t uTimeoutMS, FileStatus_T *pFileStatus) 739 { 740 int vrc; 741 742 /** @todo Parameter validation. */ 743 744 ComPtr<IEventListener> pListener; 745 HRESULT hr = mEventSource->CreateListener(pListener.asOutParam()); 746 if (SUCCEEDED(hr)) 747 { 748 com::SafeArray <VBoxEventType_T> eventTypes(1); 749 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged); 750 hr = mEventSource->RegisterListener(pListener, ComSafeArrayAsInParam(eventTypes), false); 751 } 752 else 753 vrc = VERR_COM_UNEXPECTED; 754 755 if (SUCCEEDED(hr)) 756 { 757 LogFlowThisFunc(("Waiting for guest file status change event (timeout=%RU32ms) ...\n", 758 uTimeoutMS)); 759 760 vrc = VINF_SUCCESS; 761 762 uint64_t u64Started = RTTimeMilliTS(); 763 bool fSignalled = false; 764 do 765 { 766 unsigned cMsWait; 767 if (uTimeoutMS == RT_INDEFINITE_WAIT) 768 cMsWait = 1000; 769 else 770 { 771 uint64_t cMsElapsed = RTTimeMilliTS() - u64Started; 772 if (cMsElapsed >= uTimeoutMS) 773 break; /* timed out */ 774 cMsWait = RT_MIN(1000, uTimeoutMS - (uint32_t)cMsElapsed); 775 } 776 777 ComPtr<IEvent> pEvent; 778 hr = mEventSource->GetEvent(pListener, cMsWait, pEvent.asOutParam()); 779 if ( SUCCEEDED(hr) 780 && !pEvent.isNull()) 781 { 782 VBoxEventType_T aType; 783 hr = pEvent->COMGETTER(Type)(&aType); 784 ComAssertComRC(hr); 785 switch (aType) 786 { 787 case VBoxEventType_OnGuestFileStateChanged: 788 { 789 ComPtr<IGuestFileStateChangedEvent> pChangedEvent = pEvent; 790 Assert(!pChangedEvent.isNull()); 791 792 ComPtr<IGuestFile> pFile; 793 pChangedEvent->COMGETTER(File)(pFile.asOutParam()); 794 Assert(!pFile.isNull()); 795 796 if (pFile != this) 797 continue; 798 } 799 800 default: 801 AssertMsgFailed(("Unhandled event type %ld\n", aType)); 802 break; 803 } 804 805 fSignalled = true; 806 break; 807 } 808 809 } while (!fSignalled); 810 811 if ( RT_SUCCESS(vrc) 812 && !fSignalled) 813 { 814 vrc = VERR_TIMEOUT; 815 } 816 817 mEventSource->UnregisterListener(pListener); 818 } 819 else 820 vrc = VERR_COM_UNEXPECTED; 821 822 LogFlowFuncLeaveRC(vrc); 823 return vrc; 824 } 825 826 int GuestFile::waitForWrite(uint32_t uTimeoutMS, uint32_t *pcbWritten) 827 { 828 return VINF_SUCCESS; 829 } 830 831 int GuestFile::writeData(uint32_t uTimeoutMS, void *pvData, uint32_t cbData, 832 uint32_t *pcbWritten) 802 833 { 803 834 AssertPtrReturn(pvData, VERR_INVALID_POINTER); … … 807 838 uTimeoutMS, pvData, cbData)); 808 839 809 /* Prepare HGCM call. */ 810 VBOXHGCMSVCPARM paParms[4]; 811 int i = 1; /* Context ID will be set in sendFileComannd(). */ 812 paParms[i++].setUInt32(mData.mID /* File handle */); 813 paParms[i++].setUInt32(cbData /* Size (in bytes) to write */); 814 paParms[i++].setPointer(pvData, cbData); 815 816 GuestCtrlCallback *pCallback = NULL; int guestRc; 817 int vrc = sendFileCommand(HOST_FILE_WRITE, i, paParms, uTimeoutMS, 818 &guestRc, &pCallback); 819 840 uint32_t uContextID; 841 int vrc = generateContextID(mSession->getId(), mObjectID, 842 &uContextID); 820 843 if (RT_SUCCESS(vrc)) 821 844 { 822 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 823 824 Assert(pCallback->GetDataSize() == sizeof(CALLBACKDATA_FILE_NOTIFY)); 825 PCALLBACKDATA_FILE_NOTIFY pData = (PCALLBACKDATA_FILE_NOTIFY)pCallback->GetDataRaw(); 826 AssertPtr(pData); 827 Assert(pData->uType == GUEST_FILE_NOTIFYTYPE_WRITE); 828 829 size_t cbWritten = pData->u.write.cbWritten; 830 LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten)); 831 832 if (pcbWritten) 833 *pcbWritten = cbWritten; 834 } 835 836 callbackDelete(pCallback); 837 838 if (pGuestRc) 839 *pGuestRc = guestRc; 845 /* Prepare HGCM call. */ 846 VBOXHGCMSVCPARM paParms[8]; 847 int i = 0; 848 paParms[i++].setUInt32(uContextID); 849 paParms[i++].setUInt32(mData.mID /* File handle */); 850 paParms[i++].setUInt32(cbData /* Size (in bytes) to write */); 851 paParms[i++].setPointer(pvData, cbData); 852 853 uint32_t cbWritten; 854 vrc = sendCommand(HOST_FILE_WRITE, i, paParms); 855 if (RT_SUCCESS(vrc)) 856 vrc = waitForWrite(uTimeoutMS, &cbWritten); 857 858 if (RT_SUCCESS(vrc)) 859 { 860 LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten)); 861 862 if (cbWritten) 863 *pcbWritten = cbWritten; 864 } 865 } 840 866 841 867 LogFlowFuncLeaveRC(vrc); … … 844 870 845 871 int GuestFile::writeDataAt(uint64_t uOffset, uint32_t uTimeoutMS, 846 void *pvData, size_t cbData, 847 uint32_t *pcbWritten, int *pGuestRc) 872 void *pvData, uint32_t cbData, uint32_t *pcbWritten) 848 873 { 849 874 AssertPtrReturn(pvData, VERR_INVALID_POINTER); … … 853 878 uOffset, uTimeoutMS, pvData, cbData)); 854 879 855 /* Prepare HGCM call. */ 856 VBOXHGCMSVCPARM paParms[4]; 857 int i = 1; /* Context ID will be set in sendFileComannd(). */ 858 paParms[i++].setUInt32(mData.mID /* File handle */); 859 paParms[i++].setUInt64(uOffset /* Offset where to starting writing */); 860 paParms[i++].setUInt32(cbData /* Size (in bytes) to write */); 861 paParms[i++].setPointer(pvData, cbData); 862 863 GuestCtrlCallback *pCallback = NULL; int guestRc; 864 int vrc = sendFileCommand(HOST_FILE_WRITE_AT, i, paParms, uTimeoutMS, 865 &guestRc, &pCallback); 866 880 uint32_t uContextID; 881 int vrc = generateContextID(mSession->getId(), mObjectID, 882 &uContextID); 867 883 if (RT_SUCCESS(vrc)) 868 884 { 869 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 870 871 Assert(pCallback->GetDataSize() == sizeof(CALLBACKDATA_FILE_NOTIFY)); 872 PCALLBACKDATA_FILE_NOTIFY pData = (PCALLBACKDATA_FILE_NOTIFY)pCallback->GetDataRaw(); 873 AssertPtr(pData); 874 Assert(pData->uType == GUEST_FILE_NOTIFYTYPE_WRITE); 875 876 size_t cbWritten = pData->u.write.cbWritten; 877 LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten)); 878 879 if (pcbWritten) 880 *pcbWritten = cbWritten; 881 } 882 883 callbackDelete(pCallback); 884 885 if (pGuestRc) 886 *pGuestRc = guestRc; 885 /* Prepare HGCM call. */ 886 VBOXHGCMSVCPARM paParms[8]; 887 int i = 0; 888 paParms[i++].setUInt32(mData.mID /* File handle */); 889 paParms[i++].setUInt64(uOffset /* Offset where to starting writing */); 890 paParms[i++].setUInt32(cbData /* Size (in bytes) to write */); 891 paParms[i++].setPointer(pvData, cbData); 892 893 vrc = sendCommand(HOST_FILE_WRITE_AT, i, paParms); 894 if (RT_SUCCESS(vrc)) 895 { 896 uint32_t cbWritten; 897 vrc = sendCommand(HOST_FILE_WRITE, i, paParms); 898 if (RT_SUCCESS(vrc)) 899 vrc = waitForWrite(uTimeoutMS, &cbWritten); 900 901 if (RT_SUCCESS(vrc)) 902 { 903 LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten)); 904 905 if (cbWritten) 906 *pcbWritten = cbWritten; 907 } 908 } 909 } 887 910 888 911 LogFlowFuncLeaveRC(vrc); … … 909 932 * work first and then return an error. */ 910 933 911 AssertPtr(m Data.mSession);912 int rc2 = m Data.mSession->fileRemoveFromList(this);934 AssertPtr(mSession); 935 int rc2 = mSession->fileRemoveFromList(this); 913 936 if (RT_SUCCESS(rc)) 914 937 rc = rc2; … … 964 987 HRESULT hr = S_OK; 965 988 966 size_t cbRead; int guestRc;989 uint32_t cbRead; 967 990 int vrc = readData(aToRead, aTimeoutMS, 968 data.raw(), aToRead, &cbRead , &guestRc);991 data.raw(), aToRead, &cbRead); 969 992 if (RT_SUCCESS(vrc)) 970 993 { … … 977 1000 switch (vrc) 978 1001 { 979 case VERR_GSTCTL_GUEST_ERROR:980 hr = GuestFile::setErrorExternal(this, guestRc);981 break;982 983 1002 default: 984 1003 hr = setError(VBOX_E_IPRT_ERROR, … … 1013 1032 HRESULT hr = S_OK; 1014 1033 1015 size_t cbRead; int guestRc;1034 size_t cbRead; 1016 1035 int vrc = readDataAt(aOffset, aToRead, aTimeoutMS, 1017 data.raw(), aToRead, &cbRead , &guestRc);1036 data.raw(), aToRead, &cbRead); 1018 1037 if (RT_SUCCESS(vrc)) 1019 1038 { … … 1026 1045 switch (vrc) 1027 1046 { 1028 case VERR_GSTCTL_GUEST_ERROR:1029 hr = GuestFile::setErrorExternal(this, guestRc);1030 break;1031 1032 1047 default: 1033 1048 hr = setError(VBOX_E_IPRT_ERROR, … … 1073 1088 } 1074 1089 1075 int guestRc;1076 1090 int vrc = seekAt(aOffset, eSeekType, 1077 30 * 1000 /* 30s timeout */, &guestRc);1091 30 * 1000 /* 30s timeout */, NULL /* puOffset */); 1078 1092 if (RT_FAILURE(vrc)) 1079 1093 { 1080 1094 switch (vrc) 1081 1095 { 1082 case VERR_GSTCTL_GUEST_ERROR:1083 hr = GuestFile::setErrorExternal(this, guestRc);1084 break;1085 1086 1096 default: 1087 1097 hr = setError(VBOX_E_IPRT_ERROR, … … 1123 1133 HRESULT hr = S_OK; 1124 1134 1125 com::SafeArray<BYTE> data(ComSafeArrayInArg(aData)); int guestRc; 1126 int vrc = writeData(aTimeoutMS, data.raw(), data.size(), (uint32_t*)aWritten, &guestRc); 1135 com::SafeArray<BYTE> data(ComSafeArrayInArg(aData)); 1136 int vrc = writeData(aTimeoutMS, data.raw(), (uint32_t)data.size(), 1137 (uint32_t*)aWritten); 1127 1138 if (RT_FAILURE(vrc)) 1128 1139 { 1129 1140 switch (vrc) 1130 1141 { 1131 case VERR_GSTCTL_GUEST_ERROR:1132 hr = GuestFile::setErrorExternal(this, guestRc);1133 break;1134 1135 1142 default: 1136 1143 hr = setError(VBOX_E_IPRT_ERROR, … … 1162 1169 HRESULT hr = S_OK; 1163 1170 1164 com::SafeArray<BYTE> data(ComSafeArrayInArg(aData)); int guestRc; 1165 int vrc = writeData(aTimeoutMS, data.raw(), data.size(), (uint32_t*)aWritten, &guestRc); 1171 com::SafeArray<BYTE> data(ComSafeArrayInArg(aData)); 1172 int vrc = writeData(aTimeoutMS, data.raw(), (uint32_t)data.size(), 1173 (uint32_t*)aWritten); 1166 1174 if (RT_FAILURE(vrc)) 1167 1175 { 1168 1176 switch (vrc) 1169 1177 { 1170 case VERR_GSTCTL_GUEST_ERROR:1171 hr = GuestFile::setErrorExternal(this, guestRc);1172 break;1173 1174 1178 default: 1175 1179 hr = setError(VBOX_E_IPRT_ERROR, -
trunk/src/VBox/Main/src-client/GuestImpl.cpp
r44903 r45415 80 80 81 81 ULONG aMemoryBalloonSize; 82 HRESULT ret= mParent->machine()->COMGETTER(MemoryBalloonSize)(&aMemoryBalloonSize);83 if ( ret == S_OK)82 HRESULT hr = mParent->machine()->COMGETTER(MemoryBalloonSize)(&aMemoryBalloonSize); 83 if (hr == S_OK) /** @todo r=andy SUCCEEDED? */ 84 84 mMemoryBalloonSize = aMemoryBalloonSize; 85 85 else 86 mMemoryBalloonSize = 0; 86 mMemoryBalloonSize = 0; /* Default is no ballooning */ 87 87 88 88 BOOL fPageFusionEnabled; 89 ret= mParent->machine()->COMGETTER(PageFusionEnabled)(&fPageFusionEnabled);90 if ( ret == S_OK)89 hr = mParent->machine()->COMGETTER(PageFusionEnabled)(&fPageFusionEnabled); 90 if (hr == S_OK) /** @todo r=andy SUCCEEDED? */ 91 91 mfPageFusionEnabled = fPageFusionEnabled; 92 92 else 93 mfPageFusionEnabled = false; 94 95 mStatUpdateInterval = 0; 93 mfPageFusionEnabled = false; /* Default is no page fusion*/ 94 95 mStatUpdateInterval = 0; /* Default is not to report guest statistics at all */ 96 96 mCollectVMMStats = false; 97 97 … … 106 106 int vrc = RTTimerLRCreate(&mStatTimer, 1000 /* ms */, 107 107 &Guest::staticUpdateStats, this); 108 AssertMsgRC(vrc, ("Failed to create guest statistics update timer(%Rra)\n", vrc)); 108 AssertMsgRC(vrc, ("Failed to create guest statistics update timer (%Rrc)\n", vrc)); 109 110 #ifdef VBOX_WITH_GUEST_CONTROL 111 unconst(mEventSource).createObject(); 112 Assert(!mEventSource.isNull()); 113 hr = mEventSource->init(static_cast<IGuest*>(this)); 114 #else 115 hr = S_OK; 116 #endif 109 117 110 118 try … … 117 125 catch(std::bad_alloc &) 118 126 { 119 returnE_OUTOFMEMORY;120 } 121 122 return S_OK;127 hr = E_OUTOFMEMORY; 128 } 129 130 return hr; 123 131 } 124 132 … … 167 175 #endif 168 176 177 #ifdef VBOX_WITH_GUEST_CONTROL 178 unconst(mEventSource).setNull(); 179 #endif 169 180 unconst(mParent) = NULL; 170 181 -
trunk/src/VBox/Main/src-client/GuestProcessImpl.cpp
r45109 r45415 29 29 * Header Files * 30 30 *******************************************************************************/ 31 #include "GuestErrorInfoImpl.h" 31 32 #include "GuestProcessImpl.h" 32 33 #include "GuestSessionImpl.h" 33 34 #include "GuestCtrlImplPrivate.h" 34 35 #include "ConsoleImpl.h" 36 #include "VBoxEvents.h" 35 37 36 38 #include "Global.h" … … 40 42 41 43 #include <iprt/asm.h> 44 #include <iprt/cpp/utils.h> /* For unconst(). */ 42 45 #include <iprt/getopt.h> 46 43 47 #include <VBox/com/array.h> 44 48 … … 92 96 mData.mStatus = ProcessStatus_Undefined; 93 97 94 mData.mWaitCount = 0; 95 mData.mWaitEvent = NULL; 96 97 HRESULT hr = BaseFinalConstruct(); 98 return hr; 98 return BaseFinalConstruct(); 99 99 } 100 100 … … 124 124 125 125 int vrc = bindToSession(aConsole, aSession, aProcessID /* Object ID */); 126 if (RT_SUCCESS(vrc)) 127 { 128 unconst(mEventSource).createObject(); 129 Assert(!mEventSource.isNull()); 130 HRESULT hr = mEventSource->init(static_cast<IGuestProcess*>(this)); 131 if (FAILED(hr)) 132 vrc = VERR_COM_UNEXPECTED; 133 } 134 126 135 if (RT_SUCCESS(vrc)) 127 136 { … … 156 165 157 166 #ifdef VBOX_WITH_GUEST_CONTROL 158 /* 159 * Cancel + remove all callbacks + waiters. 160 * Note: Deleting them is the job of the caller! 161 */ 162 callbackRemoveAll(); 163 164 if (mData.mWaitEvent) 165 { 166 int rc2 = mData.mWaitEvent->Cancel(); 167 if (RT_SUCCESS(vrc)) 168 vrc = rc2; 169 } 170 171 mData.mStatus = ProcessStatus_Down; /** @todo Correct? */ 167 unconst(mEventSource).setNull(); 172 168 #endif 173 169 … … 346 342 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 347 343 348 /* Get the optional callback associated to this context ID.349 * The callback may not be around anymore if just kept locally by the caller when350 * doing the actual HGCM sending stuff. */351 GuestCtrlCallback *pCallback = NULL;352 GuestCtrlCallbacks::const_iterator it353 = mObject.mCallbacks.find(VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(pCbCtx->uContextID));354 if (it != mObject.mCallbacks.end())355 {356 pCallback = it->second;357 AssertPtr(pCallback);358 #ifdef DEBUG359 LogFlowThisFunc(("pCallback=%p, CID=%RU32, Count=%RU32\n",360 pCallback, pCbCtx->uContextID, VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(pCbCtx->uContextID)));361 #endif362 }363 364 344 int vrc; 365 345 switch (pCbCtx->uFunction) … … 367 347 case GUEST_DISCONNECTED: 368 348 { 369 vrc = onGuestDisconnected(pCbCtx, p Callback, pSvcCb); /* Affects all callbacks. */349 vrc = onGuestDisconnected(pCbCtx, pSvcCb); 370 350 break; 371 351 } … … 373 353 case GUEST_EXEC_STATUS: 374 354 { 375 vrc = onProcessStatusChange(pCbCtx, p Callback, pSvcCb);355 vrc = onProcessStatusChange(pCbCtx, pSvcCb); 376 356 break; 377 357 } … … 379 359 case GUEST_EXEC_OUTPUT: 380 360 { 381 vrc = onProcessOutput(pCbCtx, p Callback, pSvcCb);361 vrc = onProcessOutput(pCbCtx, pSvcCb); 382 362 break; 383 363 } … … 385 365 case GUEST_EXEC_INPUT_STATUS: 386 366 { 387 vrc = onProcessInputStatus(pCbCtx, p Callback, pSvcCb);367 vrc = onProcessInputStatus(pCbCtx, pSvcCb); 388 368 break; 389 369 } … … 422 402 423 403 */ 424 if (m Object.mSession->getProtocolVersion() < 2)404 if (mSession->getProtocolVersion() < 2) 425 405 { 426 406 /* Simply ignore the stale requests. */ … … 487 467 488 468 case VERR_MAX_PROCS_REACHED: 489 strError += Utf8StrFmt(tr("Maximum number of parallelguest processes has been reached"));469 strError += Utf8StrFmt(tr("Maximum number of concurrent guest processes has been reached")); 490 470 break; 491 471 … … 526 506 } 527 507 528 int GuestProcess::onGuestDisconnected(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, 529 GuestCtrlCallback *pCallback, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData) 530 { 531 AssertPtrReturn(pCallback, VERR_INVALID_POINTER); 532 533 LogFlowThisFunc(("uPID=%RU32, pCallback=%p\n", mData.mPID, pCallback)); 534 535 mData.mStatus = ProcessStatus_Down; 536 537 /* First, signal callback in every case. */ 538 if (pCallback) 539 pCallback->Signal(); 540 541 /* Do we need to report a termination? */ 542 ProcessWaitResult_T waitRes; 543 if (mData.mProcess.mFlags & ProcessCreateFlag_IgnoreOrphanedProcesses) 544 waitRes = ProcessWaitResult_Status; /* No, just report a status. */ 545 else 546 waitRes = ProcessWaitResult_Terminate; 547 548 /* Signal in any case. */ 549 int vrc = signalWaiters(waitRes); 550 AssertRC(vrc); 508 int GuestProcess::onGuestDisconnected(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData) 509 { 510 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER); 511 AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER); 512 513 LogFlowThisFunc(("uPID=%RU32\n", mData.mPID)); 514 515 int vrc = setProcessStatus(ProcessStatus_Down, VINF_SUCCESS); 551 516 552 517 LogFlowFuncLeaveRC(vrc); … … 554 519 } 555 520 556 int GuestProcess::onProcessInputStatus(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, 557 GuestCtrlCallback *pCallback, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData) 558 { 559 AssertPtrReturn(pCallback, VERR_INVALID_POINTER); 521 int GuestProcess::onProcessInputStatus(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData) 522 { 523 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER); 560 524 AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER); 525 /* pCallback is optional. */ 561 526 562 527 if (pSvcCbData->mParms < 5) … … 574 539 AssertRCReturn(vrc, vrc); 575 540 576 LogFlowThisFunc(("uPID=%RU32, uStatus=%RU32, uFlags=%RI32, cbProcessed=%RU32 , pCallback=%p\n",577 dataCb.uPID, dataCb.uStatus, dataCb.uFlags, dataCb.uProcessed , pCallback));541 LogFlowThisFunc(("uPID=%RU32, uStatus=%RU32, uFlags=%RI32, cbProcessed=%RU32\n", 542 dataCb.uPID, dataCb.uStatus, dataCb.uFlags, dataCb.uProcessed)); 578 543 579 544 vrc = checkPID(dataCb.uPID); 580 545 AssertRCReturn(vrc, vrc); 581 546 582 /* First, signal callback in every case (if available). */ 583 if (pCallback) 584 { 585 vrc = pCallback->SetData(&dataCb, sizeof(dataCb)); 586 587 int rc2 = pCallback->Signal(); 588 if (RT_SUCCESS(vrc)) 589 vrc = rc2; 590 } 591 592 /* Then do the WaitFor signalling stuff. */ 593 uint32_t uWaitFlags = mData.mWaitEvent 594 ? mData.mWaitEvent->GetWaitFlags() : 0; 595 if (uWaitFlags & ProcessWaitForFlag_StdIn) 596 { 597 int rc2 = signalWaiters(ProcessWaitResult_StdIn); 598 if (RT_SUCCESS(vrc)) 599 vrc = rc2; 547 ProcessInputStatus_T inputStatus = ProcessInputStatus_Undefined; 548 switch (dataCb.uStatus) 549 { 550 case INPUT_STS_WRITTEN: 551 inputStatus = ProcessInputStatus_Written; 552 break; 553 case INPUT_STS_ERROR: 554 inputStatus = ProcessInputStatus_Broken; 555 break; 556 case INPUT_STS_TERMINATED: 557 inputStatus = ProcessInputStatus_Broken; 558 break; 559 case INPUT_STS_OVERFLOW: 560 inputStatus = ProcessInputStatus_Overflow; 561 break; 562 case INPUT_STS_UNDEFINED: 563 /* Fall through is intentional. */ 564 default: 565 AssertMsg(!dataCb.uProcessed, ("Processed data is not 0 in undefined input state\n")); 566 break; 567 } 568 569 if (inputStatus != ProcessInputStatus_Undefined) 570 { 571 fireGuestProcessInputNotifyEvent(mEventSource, mSession, this, 572 mData.mPID, inputStatus, 0 /* StdIn */, dataCb.uProcessed); 600 573 } 601 574 … … 604 577 } 605 578 606 int GuestProcess::onProcessNotifyIO(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, 607 GuestCtrlCallback *pCallback, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData) 608 { 609 AssertPtrReturn(p Callback, VERR_INVALID_POINTER);579 int GuestProcess::onProcessNotifyIO(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData) 580 { 581 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER); 582 AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER); 610 583 611 584 return VERR_NOT_IMPLEMENTED; 612 585 } 613 586 614 int GuestProcess::onProcessStatusChange(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, 615 GuestCtrlCallback *pCallback, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData) 587 int GuestProcess::onProcessStatusChange(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData) 616 588 { 617 589 /* pCallback is optional. */ … … 632 604 AssertRCReturn(vrc, vrc); 633 605 634 LogFlowThisFunc(("uPID=%RU32, uStatus=%RU32, uFlags=%RU32 , pCallback=%p, pSvcCbData=%p\n",635 dataCb.uPID, dataCb.uStatus, dataCb.uFlags , pCallback, pSvcCbData));606 LogFlowThisFunc(("uPID=%RU32, uStatus=%RU32, uFlags=%RU32\n", 607 dataCb.uPID, dataCb.uStatus, dataCb.uFlags)); 636 608 637 609 vrc = checkPID(dataCb.uPID); … … 641 613 int procRc = VINF_SUCCESS; 642 614 643 bool fSignalWaiters = false;644 ProcessWaitResult_T waitRes;645 646 uint32_t uWaitFlags = mData.mWaitEvent647 ? mData.mWaitEvent->GetWaitFlags() : 0;648 615 switch (dataCb.uStatus) 649 616 { 650 617 case PROC_STS_STARTED: 651 618 { 652 fSignalWaiters = (uWaitFlags & ProcessWaitForFlag_Start);653 /* If the caller only wants to wait until the process has been started,654 * notify in any case. */655 if (mData.mProcess.mFlags & ProcessCreateFlag_WaitForProcessStartOnly)656 fSignalWaiters = true;657 waitRes = ProcessWaitResult_Start;658 659 619 procStatus = ProcessStatus_Started; 660 620 mData.mPID = dataCb.uPID; /* Set the process PID. */ … … 664 624 case PROC_STS_TEN: 665 625 { 666 fSignalWaiters = true; /* Signal in any case. */667 waitRes = ProcessWaitResult_Terminate;668 669 626 procStatus = ProcessStatus_TerminatedNormally; 670 627 mData.mExitCode = dataCb.uFlags; /* Contains the exit code. */ … … 674 631 case PROC_STS_TES: 675 632 { 676 fSignalWaiters = true; /* Signal in any case. */677 waitRes = ProcessWaitResult_Terminate;678 679 633 procStatus = ProcessStatus_TerminatedSignal; 680 634 mData.mExitCode = dataCb.uFlags; /* Contains the signal. */ … … 684 638 case PROC_STS_TEA: 685 639 { 686 fSignalWaiters = true; /* Signal in any case. */687 waitRes = ProcessWaitResult_Terminate;688 689 640 procStatus = ProcessStatus_TerminatedAbnormally; 690 641 break; … … 693 644 case PROC_STS_TOK: 694 645 { 695 fSignalWaiters = true; /* Signal in any case. */696 waitRes = ProcessWaitResult_Timeout;697 698 646 procStatus = ProcessStatus_TimedOutKilled; 699 647 break; … … 702 650 case PROC_STS_TOA: 703 651 { 704 fSignalWaiters = true; /* Signal in any case. */705 waitRes = ProcessWaitResult_Timeout;706 707 652 procStatus = ProcessStatus_TimedOutAbnormally; 708 653 break; … … 711 656 case PROC_STS_DWN: 712 657 { 713 fSignalWaiters = true; /* Signal in any case. */714 /* Do we need to report termination? */715 if (mData.mProcess.mFlags & ProcessCreateFlag_IgnoreOrphanedProcesses)716 waitRes = ProcessWaitResult_Status;717 else718 waitRes = ProcessWaitResult_Terminate;719 720 658 procStatus = ProcessStatus_Down; 721 659 break; … … 724 662 case PROC_STS_ERROR: 725 663 { 726 fSignalWaiters = true; /* Signal in any case. */727 waitRes = ProcessWaitResult_Error;728 729 664 procRc = dataCb.uFlags; /* mFlags contains the IPRT error sent from the guest. */ 730 665 procStatus = ProcessStatus_Error; … … 736 671 { 737 672 /* Silently skip this request. */ 738 fSignalWaiters = true; /* Signal in any case. */739 waitRes = ProcessWaitResult_Status;740 741 673 procStatus = ProcessStatus_Undefined; 742 674 break; … … 744 676 } 745 677 746 LogFlowThisFunc(("Got rc=%Rrc, waitRes=%d, procSts=%ld, procRc=%Rrc, fSignalWaiters=%RTbool\n",747 vrc, waitRes, procStatus, procRc, fSignalWaiters));678 LogFlowThisFunc(("Got rc=%Rrc, procSts=%ld, procRc=%Rrc\n", 679 vrc, procStatus, procRc)); 748 680 749 681 /* Set the process status. */ … … 752 684 vrc = rc2; 753 685 754 /*755 * Now do the signalling stuff.756 */757 if (pCallback)758 {759 rc2 = pCallback->Signal(procRc);760 if (RT_SUCCESS(vrc))761 vrc = rc2;762 }763 764 if (fSignalWaiters)765 {766 rc2 = signalWaiters(waitRes, procRc);767 if (RT_SUCCESS(vrc))768 vrc = rc2;769 }770 771 686 LogFlowFuncLeaveRC(vrc); 772 687 return vrc; 773 688 } 774 689 775 int GuestProcess::onProcessOutput(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, 776 GuestCtrlCallback *pCallback, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData) 777 { 778 AssertPtrReturn(pCallback, VERR_INVALID_POINTER); 690 int GuestProcess::onProcessOutput(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData) 691 { 779 692 AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER); 780 693 … … 793 706 AssertRCReturn(vrc, vrc); 794 707 795 LogFlowThisFunc(("uPID=%RU32, uHandle=%RU32, uFlags=%RI32, pvData=%p, cbData=%RU32 , pCallback=%p\n",796 dataCb.uPID, dataCb.uHandle, dataCb.uFlags, dataCb.pvData, dataCb.cbData , pCallback));708 LogFlowThisFunc(("uPID=%RU32, uHandle=%RU32, uFlags=%RI32, pvData=%p, cbData=%RU32\n", 709 dataCb.uPID, dataCb.uHandle, dataCb.uFlags, dataCb.pvData, dataCb.cbData)); 797 710 798 711 vrc = checkPID(dataCb.uPID); 799 712 AssertRCReturn(vrc, vrc); 800 713 801 /* First, signal callback in every case (if available). */ 802 if (pCallback) 803 { 804 vrc = pCallback->SetData(&dataCb, sizeof(dataCb)); 805 806 int rc2 = pCallback->Signal(); 807 if (RT_SUCCESS(vrc)) 808 vrc = rc2; 809 } 810 811 /* Then do the WaitFor signalling stuff. */ 812 BOOL fSignal = FALSE; 813 uint32_t uWaitFlags = mData.mWaitEvent 814 ? mData.mWaitEvent->GetWaitFlags() : 0; 815 816 if ( (uWaitFlags & ProcessWaitForFlag_StdOut) 817 || (uWaitFlags & ProcessWaitForFlag_StdErr)) 818 { 819 fSignal = TRUE; 820 } 821 else if ( (uWaitFlags & ProcessWaitForFlag_StdOut) 822 && (dataCb.uHandle == OUTPUT_HANDLE_ID_STDOUT)) 823 { 824 fSignal = TRUE; 825 } 826 else if ( (uWaitFlags & ProcessWaitForFlag_StdErr) 827 && (dataCb.uHandle == OUTPUT_HANDLE_ID_STDERR)) 828 { 829 fSignal = TRUE; 830 } 831 832 if (fSignal) 833 { 834 int rc2 = VINF_SUCCESS; 835 if (dataCb.uHandle == OUTPUT_HANDLE_ID_STDOUT) 836 rc2 = signalWaiters(ProcessWaitResult_StdOut); 837 else if (dataCb.uHandle == OUTPUT_HANDLE_ID_STDERR) 838 rc2 = signalWaiters(ProcessWaitResult_StdErr); 839 if (RT_SUCCESS(vrc)) 840 vrc = rc2; 841 } 714 com::SafeArray<BYTE> data((size_t)dataCb.cbData); 715 data.initFrom((BYTE*)dataCb.pvData, dataCb.cbData); 716 717 fireGuestProcessOutputEvent(mEventSource, mSession, this, 718 mData.mPID, dataCb.uHandle, ComSafeArrayAsInParam(data)); 842 719 843 720 LogFlowFuncLeaveRC(vrc); … … 855 732 /* pcbRead is optional. */ 856 733 734 /** @todo Validate uHandle. */ 735 857 736 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 858 737 … … 866 745 } 867 746 868 int vrc = VINF_SUCCESS; 869 870 GuestCtrlCallback *pCallbackRead = NULL; 871 try 872 { 873 pCallbackRead = new GuestCtrlCallback(); 874 } 875 catch(std::bad_alloc &) 876 { 877 vrc = VERR_NO_MEMORY; 878 } 879 880 /* Create callback and add it to the map. */ 881 uint32_t uContextID = 0; 747 uint32_t uContextID; 748 int vrc = generateContextID(mSession->getId(), mObjectID, 749 &uContextID); 882 750 if (RT_SUCCESS(vrc)) 883 751 { 884 vrc = pCallbackRead->Init(CALLBACKTYPE_PROC_OUTPUT); 885 if (RT_SUCCESS(vrc)) 886 vrc = callbackAdd(pCallbackRead, &uContextID); 887 } 888 889 alock.release(); /* Drop the write lock again. */ 890 891 if (RT_SUCCESS(vrc)) 892 { 893 VBOXHGCMSVCPARM paParms[5]; 894 752 VBOXHGCMSVCPARM paParms[8]; 895 753 int i = 0; 896 754 paParms[i++].setUInt32(uContextID); … … 900 758 901 759 vrc = sendCommand(HOST_EXEC_GET_OUTPUT, i, paParms); 902 if (RT_FAILURE(vrc))903 {904 int rc2 = setProcessStatus(ProcessStatus_Error, vrc);905 AssertRC(rc2);906 }907 760 } 908 761 909 762 if (RT_SUCCESS(vrc)) 910 763 { 911 /* 912 * Let's wait for the process being started. 913 * Note: Be sure not keeping a AutoRead/WriteLock here. 914 */ 915 LogFlowThisFunc(("Waiting for callback (%RU32ms) ...\n", uTimeoutMS)); 916 vrc = pCallbackRead->Wait(uTimeoutMS); 917 if (RT_SUCCESS(vrc)) /* Wait was successful, check for supplied information. */ 918 { 919 int guestRc = pCallbackRead->GetResultCode(); 920 LogFlowThisFunc(("Callback returned rc=%Rrc, cbData=%RU32\n", guestRc, pCallbackRead->GetDataSize())); 921 922 if (RT_SUCCESS(guestRc)) 923 { 924 Assert(pCallbackRead->GetDataSize() == sizeof(CALLBACKDATA_PROC_OUTPUT)); 925 PCALLBACKDATA_PROC_OUTPUT pData = (PCALLBACKDATA_PROC_OUTPUT)pCallbackRead->GetDataRaw(); 926 AssertPtr(pData); 927 928 size_t cbRead = pData->cbData; 929 if (cbRead) 930 { 931 Assert(cbData >= cbRead); 932 memcpy(pvData, pData->pvData, cbRead); 933 } 934 935 LogFlowThisFunc(("cbRead=%RU32\n", cbRead)); 936 937 if (pcbRead) 938 *pcbRead = cbRead; 939 } 940 else 941 vrc = VERR_GSTCTL_GUEST_ERROR; 942 943 if (pGuestRc) 944 *pGuestRc = guestRc; 945 LogFlowThisFunc(("Callback returned rc=%Rrc\n", guestRc)); 946 } 947 } 948 949 alock.acquire(); 950 951 int rc2 = callbackRemove(uContextID); 952 if (RT_SUCCESS(vrc)) 953 vrc = rc2; 954 955 callbackDelete(pCallbackRead); 764 alock.release(); /* Drop the write lock before waiting. */ 765 766 vrc = waitForOutput(uHandle, uTimeoutMS, 767 pvData, cbData, pcbRead); 768 } 956 769 957 770 LogFlowFuncLeaveRC(vrc); … … 970 783 /* Do not allow overwriting an already set error. If this happens 971 784 * this means we forgot some error checking/locking somewhere. */ 972 AssertMsg(RT_SUCCESS(mData.mRC), ("Guest rc already set (to %Rrc)\n", mData.mRC));785 //AssertMsg(RT_SUCCESS(mData.mRC), ("Guest rc already set (to %Rrc)\n", mData.mRC)); 973 786 } 974 787 else 975 788 AssertMsg(RT_SUCCESS(procRc), ("Guest rc must not be an error (%Rrc)\n", procRc)); 976 789 977 mData.mStatus = procStatus; 978 mData.mRC = procRc; 790 if (mData.mStatus != procStatus) 791 { 792 mData.mStatus = procStatus; 793 mData.mRC = procRc; 794 795 ComObjPtr<GuestErrorInfo> errorInfo; 796 HRESULT hr = errorInfo.createObject(); 797 ComAssertComRC(hr); 798 if (RT_FAILURE(mData.mRC)) 799 { 800 int rc2 = errorInfo->init(mData.mRC, guestErrorToString(mData.mRC)); 801 AssertRC(rc2); 802 } 803 804 fireGuestProcessStateChangedEvent(mEventSource, mSession, this, 805 mData.mPID, mData.mStatus, errorInfo); 806 } 979 807 980 808 return VINF_SUCCESS; … … 988 816 989 817 return pInterface->setError(VBOX_E_IPRT_ERROR, GuestProcess::guestErrorToString(guestRc).c_str()); 990 }991 992 int GuestProcess::signalWaiters(ProcessWaitResult_T enmWaitResult, int rc /*= VINF_SUCCESS */)993 {994 LogFlowThisFunc(("enmWaitResult=%d, rc=%Rrc, mWaitCount=%RU32, mWaitEvent=%p\n",995 enmWaitResult, rc, mData.mWaitCount, mData.mWaitEvent));996 997 /* Note: No write locking here -- already done in the caller. */998 999 int vrc = VINF_SUCCESS;1000 if (mData.mWaitEvent)1001 vrc = mData.mWaitEvent->Signal(enmWaitResult, rc);1002 LogFlowFuncLeaveRC(vrc);1003 return vrc;1004 818 } 1005 819 … … 1013 827 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 1014 828 1015 int vrc = VINF_SUCCESS; 1016 uint32_t uContextID = 0; 1017 1018 GuestCtrlCallback *pCallbackStart = NULL; 1019 try 1020 { 1021 pCallbackStart = new GuestCtrlCallback(); 1022 } 1023 catch(std::bad_alloc &) 1024 { 1025 vrc = VERR_NO_MEMORY; 1026 } 1027 829 mData.mStatus = ProcessStatus_Starting; 830 831 uint32_t uContextID; 832 int vrc = generateContextID(mSession->getId(), mObjectID, 833 &uContextID); 1028 834 if (RT_SUCCESS(vrc)) 1029 835 { 1030 mData.mStatus = ProcessStatus_Starting; 1031 1032 /* Create callback and add it to the map. */ 1033 vrc = pCallbackStart->Init(CALLBACKTYPE_PROC_STATUS); 1034 if (RT_SUCCESS(vrc)) 1035 vrc = callbackAdd(pCallbackStart, &uContextID); 1036 } 1037 1038 if (RT_SUCCESS(vrc)) 1039 { 1040 GuestSession *pSession = mObject.mSession; 836 GuestSession *pSession = mSession; 1041 837 AssertPtr(pSession); 1042 838 … … 1088 884 if (RT_SUCCESS(vrc)) 1089 885 { 1090 AssertPtr(m Object.mSession);1091 uint32_t uProtocol = m Object.mSession->getProtocolVersion();886 AssertPtr(mSession); 887 uint32_t uProtocol = mSession->getProtocolVersion(); 1092 888 1093 889 /* Prepare HGCM call. */ … … 1151 947 if (RT_SUCCESS(vrc)) 1152 948 { 1153 /* 1154 * Let's wait for the process being started. 1155 * Note: Be sure not keeping a AutoRead/WriteLock here. 1156 */ 1157 LogFlowThisFunc(("Waiting for callback (%RU32ms) ...\n", uTimeoutMS)); 1158 vrc = pCallbackStart->Wait(uTimeoutMS); 1159 if (RT_SUCCESS(vrc)) /* Wait was successful, check for supplied information. */ 1160 { 1161 int guestRc = pCallbackStart->GetResultCode(); 1162 if (RT_SUCCESS(guestRc)) 1163 { 1164 /* Nothing to do here right now. */ 1165 } 1166 else 1167 vrc = VERR_GSTCTL_GUEST_ERROR; 1168 1169 if (pGuestRc) 1170 *pGuestRc = guestRc; 1171 LogFlowThisFunc(("Callback returned rc=%Rrc\n", guestRc)); 1172 } 1173 } 1174 1175 AutoWriteLock awlock(this COMMA_LOCKVAL_SRC_POS); 1176 1177 int rc2 = callbackRemove(uContextID); 1178 if (RT_SUCCESS(vrc)) 1179 vrc = rc2; 1180 } 1181 1182 callbackDelete(pCallbackStart); 949 vrc = waitForStatusChange(ProcessWaitForFlag_Start, 30 * 1000 /* Timeout */, 950 NULL /* Process status */, pGuestRc); 951 } 952 } 1183 953 1184 954 LogFlowFuncLeaveRC(vrc); … … 1245 1015 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 1246 1016 1247 if (mObject.mSession->getProtocolVersion() < 2) 1017 AssertPtr(mSession); 1018 if (mSession->getProtocolVersion() < 99) 1248 1019 return VERR_NOT_SUPPORTED; 1249 1020 … … 1251 1022 return VINF_SUCCESS; /* Nothing to do (anymore). */ 1252 1023 1253 int vrc = VINF_SUCCESS;1254 1255 GuestCtrlCallback *pCallbackTerminate = NULL;1256 try1257 {1258 pCallbackTerminate = new GuestCtrlCallback();1259 }1260 catch(std::bad_alloc &)1261 {1262 vrc = VERR_NO_MEMORY;1263 }1264 1265 /* Create callback and add it to the map. */1266 1024 uint32_t uContextID; 1025 int vrc = generateContextID(mSession->getId(), mObjectID, 1026 &uContextID); 1267 1027 if (RT_SUCCESS(vrc)) 1268 vrc = callbackAdd(pCallbackTerminate, &uContextID); 1269 1270 alock.release(); /* Drop the write lock again. */ 1271 1272 if (RT_SUCCESS(vrc)) 1273 { 1274 VBOXHGCMSVCPARM paParms[5]; 1275 1028 { 1029 VBOXHGCMSVCPARM paParms[4]; 1276 1030 int i = 0; 1277 1031 paParms[i++].setUInt32(uContextID); 1278 1032 paParms[i++].setUInt32(mData.mPID); 1279 1033 1280 //vrc = sendCommand(HOST_EXEC_TERMINATE, i, paParms);1034 vrc = sendCommand(HOST_EXEC_TERMINATE, i, paParms); 1281 1035 } 1282 1036 1283 1037 if (RT_SUCCESS(vrc)) 1284 1038 { 1285 /* 1286 * Let's wait for the process being terminated. 1287 * Note: Be sure not keeping a AutoRead/WriteLock here. 1288 */ 1289 LogFlowThisFunc(("Waiting for callback (30s) ...\n")); 1290 vrc = pCallbackTerminate->Wait(30 * 1000); 1291 if (RT_SUCCESS(vrc)) /* Wait was successful, check for supplied information. */ 1292 { 1293 int guestRc = pCallbackTerminate->GetResultCode(); 1294 if (RT_SUCCESS(guestRc)) 1295 { 1296 /* Nothing to do here right now. */ 1297 } 1298 else 1299 vrc = VERR_GSTCTL_GUEST_ERROR; 1300 1301 if (pGuestRc) 1302 *pGuestRc = guestRc; 1303 LogFlowThisFunc(("Callback returned rc=%Rrc\n", guestRc)); 1304 } 1305 } 1306 1307 alock.acquire(); 1308 1309 int rc2 = callbackRemove(uContextID); 1310 if (RT_SUCCESS(vrc)) 1311 vrc = rc2; 1312 1313 callbackDelete(pCallbackTerminate); 1039 alock.release(); /* Drop the write lock before waiting. */ 1040 1041 vrc = waitForStatusChange(ProcessWaitForFlag_Terminate, 1042 30 * 1000 /* 30s timeout */, 1043 NULL /* ProcessStatus */, pGuestRc); 1044 } 1314 1045 1315 1046 LogFlowFuncLeaveRC(vrc); … … 1323 1054 AssertReturn(fWaitFlags, VERR_INVALID_PARAMETER); 1324 1055 1325 LogFlowThisFunc(("fWaitFlags=0x%x, uTimeoutMS=%RU32, mStatus=%RU32, mWaitCount=%RU32, mWaitEvent=%p, pGuestRc=%p\n",1326 fWaitFlags, uTimeoutMS, mData.mStatus, mData.mWaitCount, mData.mWaitEvent, pGuestRc)); 1056 /*LogFlowThisFunc(("fWaitFlags=0x%x, uTimeoutMS=%RU32, mStatus=%RU32, mWaitCount=%RU32, mWaitEvent=%p, pGuestRc=%p\n", 1057 fWaitFlags, uTimeoutMS, mData.mStatus, mData.mWaitCount, mData.mWaitEvent, pGuestRc));*/ 1327 1058 1328 1059 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); … … 1419 1150 1420 1151 /* Filter out waits which are *not* supported using 1421 * older guest control Guest Additions. */ 1422 if (mObject.mSession->getProtocolVersion() < 2) 1152 * older guest control Guest Additions. 1153 * 1154 ** @todo ProcessWaitForFlag_Std* flags are not implemented yet. 1155 */ 1156 if (mSession->getProtocolVersion() < 99) 1423 1157 { 1424 1158 if ( waitResult == ProcessWaitResult_None … … 1447 1181 } 1448 1182 1449 if (mData.mWaitCount > 0) /* We only support one waiting caller a time at the moment. */ 1450 return VERR_ALREADY_EXISTS; 1451 mData.mWaitCount++; 1452 1453 int vrc = VINF_SUCCESS; 1454 try 1455 { 1456 Assert(mData.mWaitEvent == NULL); 1457 mData.mWaitEvent = new GuestProcessWaitEvent(fWaitFlags); 1458 } 1459 catch(std::bad_alloc &) 1460 { 1461 vrc = VERR_NO_MEMORY; 1462 } 1463 1183 alock.release(); /* Release lock before waiting. */ 1184 1185 ProcessStatus_T processStatus; 1186 int vrc = waitForStatusChange(fWaitFlags, uTimeoutMS, &processStatus, pGuestRc); 1464 1187 if (RT_SUCCESS(vrc)) 1465 1188 { 1466 GuestProcessWaitEvent *pEvent = mData.mWaitEvent; 1467 AssertPtr(pEvent); 1468 1469 alock.release(); /* Release lock before waiting. */ 1470 1471 vrc = pEvent->Wait(uTimeoutMS); 1472 LogFlowThisFunc(("Waiting completed with rc=%Rrc\n", vrc)); 1473 if (RT_SUCCESS(vrc)) 1474 { 1475 waitResult = pEvent->GetWaitResult(); 1476 int guestRc = pEvent->GetWaitRc(); 1477 if (RT_FAILURE(guestRc)) 1478 vrc = VERR_GSTCTL_GUEST_ERROR; 1479 1480 LogFlowThisFunc(("Waiting event returned rc=%Rrc\n", guestRc)); 1481 1482 if (pGuestRc) 1483 *pGuestRc = guestRc; 1484 } 1485 1486 alock.acquire(); /* Get the lock again. */ 1487 1488 /* Note: The caller always is responsible of deleting the 1489 * stuff it created before. See close() for more information. */ 1490 delete mData.mWaitEvent; 1491 mData.mWaitEvent = NULL; 1492 } 1493 1494 Assert(mData.mWaitCount); 1495 mData.mWaitCount--; 1189 switch (processStatus) 1190 { 1191 case ProcessStatus_Started: 1192 waitResult = ProcessWaitResult_Start; 1193 break; 1194 1195 case ProcessStatus_TerminatedNormally: 1196 case ProcessStatus_TerminatedAbnormally: 1197 case ProcessStatus_TerminatedSignal: 1198 waitResult = ProcessWaitResult_Terminate; 1199 break; 1200 1201 case ProcessStatus_TimedOutKilled: 1202 case ProcessStatus_TimedOutAbnormally: 1203 waitResult = ProcessWaitResult_Timeout; 1204 break; 1205 1206 case ProcessStatus_Down: 1207 waitResult = ProcessWaitResult_Terminate; 1208 break; 1209 1210 case ProcessStatus_Error: 1211 waitResult = ProcessWaitResult_Error; 1212 break; 1213 1214 default: 1215 waitResult = ProcessWaitResult_Status; 1216 break; 1217 } 1218 } 1219 1220 LogFlowFuncLeaveRC(vrc); 1221 return vrc; 1222 } 1223 1224 int GuestProcess::waitForInputNotify(uint32_t uHandle, uint32_t uTimeoutMS, 1225 ProcessInputStatus_T *pInputStatus, size_t *pcbProcessed) 1226 { 1227 int vrc; 1228 1229 /** @todo Parameter validation. */ 1230 1231 ComPtr<IEventListener> pListener; 1232 HRESULT hr = mEventSource->CreateListener(pListener.asOutParam()); 1233 if (SUCCEEDED(hr)) 1234 { 1235 com::SafeArray <VBoxEventType_T> eventTypes(1); 1236 eventTypes.push_back(VBoxEventType_OnGuestProcessInputNotify); 1237 hr = mEventSource->RegisterListener(pListener, ComSafeArrayAsInParam(eventTypes), false); 1238 } 1239 else 1240 vrc = VERR_COM_UNEXPECTED; 1241 1242 if (SUCCEEDED(hr)) 1243 { 1244 LogFlowThisFunc(("Waiting for guest process input notify event (timeout=%RU32ms, handle=%RU32) ...\n", 1245 uTimeoutMS, uHandle)); 1246 1247 vrc = VINF_SUCCESS; 1248 1249 uint64_t u64Started = RTTimeMilliTS(); 1250 bool fSignalled = false; 1251 do 1252 { 1253 unsigned cMsWait; 1254 if (uTimeoutMS == RT_INDEFINITE_WAIT) 1255 cMsWait = 1000; 1256 else 1257 { 1258 uint64_t cMsElapsed = RTTimeMilliTS() - u64Started; 1259 if (cMsElapsed >= uTimeoutMS) 1260 break; /* timed out */ 1261 cMsWait = RT_MIN(1000, uTimeoutMS - (uint32_t)cMsElapsed); 1262 } 1263 1264 ComPtr<IEvent> pEvent; 1265 hr = mEventSource->GetEvent(pListener, cMsWait, pEvent.asOutParam()); 1266 if ( SUCCEEDED(hr) 1267 && !pEvent.isNull()) 1268 { 1269 VBoxEventType_T aType; 1270 hr = pEvent->COMGETTER(Type)(&aType); 1271 ComAssertComRC(hr); 1272 switch (aType) 1273 { 1274 case VBoxEventType_OnGuestProcessInputNotify: 1275 { 1276 ComPtr<IGuestProcessInputNotifyEvent> pOutputEvent = pEvent; 1277 Assert(!pOutputEvent.isNull()); 1278 1279 ComPtr<IGuestSession> pSession; 1280 pOutputEvent->COMGETTER(Session)(pSession.asOutParam()); 1281 Assert(!pSession.isNull()); 1282 ULONG uSessionID; 1283 hr = pSession->COMGETTER(Id)(&uSessionID); 1284 ComAssertComRC(hr); 1285 if (uSessionID != mSession->getId()) 1286 continue; /* Only the session this process runs in is of interest. */ 1287 1288 ULONG uPID; 1289 hr = pOutputEvent->COMGETTER(Pid)(&uPID); 1290 ComAssertComRC(hr); 1291 if (uPID != mData.mPID) 1292 continue; /* Only the this process is of interest. */ 1293 1294 ULONG uHandleEvent; 1295 hr = pOutputEvent->COMGETTER(Handle)(&uHandleEvent); 1296 ComAssertComRC(hr); 1297 1298 LogFlowThisFunc(("Got output event for process PID=%RU32, handle=%RU32 (session ID=%RU32)\n", 1299 mData.mPID, uHandleEvent, mSession->getId())); 1300 1301 bool fSignal = uHandleEvent == uHandle; 1302 if (!fSignal) 1303 continue; 1304 1305 ProcessInputStatus_T inputStatus; 1306 hr = pOutputEvent->COMGETTER(Status)(&inputStatus); 1307 ComAssertComRC(hr); 1308 1309 ULONG uProcessed; 1310 hr = pOutputEvent->COMGETTER(Processed)(&uProcessed); 1311 ComAssertComRC(hr); 1312 1313 if (pInputStatus) 1314 *pInputStatus = inputStatus; 1315 if (pcbProcessed) 1316 *pcbProcessed = uProcessed; 1317 1318 LogFlowThisFunc(("Input notify event for process PID=%RU32 (session ID=%RU32): %zubytes read\n", 1319 uPID, mSession->getId(), uProcessed)); 1320 1321 fSignalled = true; 1322 break; 1323 } 1324 1325 default: 1326 AssertMsgFailed(("Unhandled event type %ld\n", aType)); 1327 break; 1328 } 1329 } 1330 1331 } while (!fSignalled); 1332 1333 if ( RT_SUCCESS(vrc) 1334 && !fSignalled) 1335 { 1336 vrc = VERR_TIMEOUT; 1337 } 1338 1339 mEventSource->UnregisterListener(pListener); 1340 } 1341 else 1342 vrc = VERR_COM_UNEXPECTED; 1343 1344 LogFlowFuncLeaveRC(vrc); 1345 return vrc; 1346 } 1347 1348 int GuestProcess::waitForOutput(uint32_t uHandle, uint32_t uTimeoutMS, 1349 void *pvData, size_t cbData, size_t *pcbRead) 1350 { 1351 int vrc; 1352 1353 /** @todo Parameter validation. */ 1354 1355 ComPtr<IEventListener> pListener; 1356 HRESULT hr = mEventSource->CreateListener(pListener.asOutParam()); 1357 if (SUCCEEDED(hr)) 1358 { 1359 com::SafeArray <VBoxEventType_T> eventTypes(1); 1360 eventTypes.push_back(VBoxEventType_OnGuestProcessOutput); 1361 hr = mEventSource->RegisterListener(pListener, ComSafeArrayAsInParam(eventTypes), false); 1362 } 1363 else 1364 vrc = VERR_COM_UNEXPECTED; 1365 1366 if (SUCCEEDED(hr)) 1367 { 1368 LogFlowThisFunc(("Waiting for guest process output event (timeout=%RU32ms, handle=%RU32) ...\n", 1369 uTimeoutMS, uHandle)); 1370 1371 vrc = VINF_SUCCESS; 1372 1373 uint64_t u64Started = RTTimeMilliTS(); 1374 bool fSignalled = false; 1375 do 1376 { 1377 unsigned cMsWait; 1378 if (uTimeoutMS == RT_INDEFINITE_WAIT) 1379 cMsWait = 1000; 1380 else 1381 { 1382 uint64_t cMsElapsed = RTTimeMilliTS() - u64Started; 1383 if (cMsElapsed >= uTimeoutMS) 1384 break; /* timed out */ 1385 cMsWait = RT_MIN(1000, uTimeoutMS - (uint32_t)cMsElapsed); 1386 } 1387 1388 ComPtr<IEvent> pEvent; 1389 hr = mEventSource->GetEvent(pListener, cMsWait, pEvent.asOutParam()); 1390 if ( SUCCEEDED(hr) 1391 && !pEvent.isNull()) 1392 { 1393 VBoxEventType_T aType; 1394 hr = pEvent->COMGETTER(Type)(&aType); 1395 ComAssertComRC(hr); 1396 switch (aType) 1397 { 1398 case VBoxEventType_OnGuestProcessOutput: 1399 { 1400 ComPtr<IGuestProcessOutputEvent> pOutputEvent = pEvent; 1401 Assert(!pOutputEvent.isNull()); 1402 1403 ComPtr<IGuestSession> pSession; 1404 pOutputEvent->COMGETTER(Session)(pSession.asOutParam()); 1405 Assert(!pSession.isNull()); 1406 ULONG uSessionID; 1407 hr = pSession->COMGETTER(Id)(&uSessionID); 1408 ComAssertComRC(hr); 1409 if (uSessionID != mSession->getId()) 1410 continue; /* Only the session this process runs in is of interest. */ 1411 1412 ULONG uPID; 1413 hr = pOutputEvent->COMGETTER(Pid)(&uPID); 1414 ComAssertComRC(hr); 1415 if (uPID != mData.mPID) 1416 continue; /* Only the this process is of interest. */ 1417 1418 ULONG uHandleEvent; 1419 hr = pOutputEvent->COMGETTER(Handle)(&uHandleEvent); 1420 ComAssertComRC(hr); 1421 1422 LogFlowThisFunc(("Got output event for process PID=%RU32, handle=%RU32 (session ID=%RU32): %ld\n", 1423 mData.mPID, uHandleEvent, mSession->getId())); 1424 1425 bool fSignal = uHandleEvent == uHandle; 1426 if (!fSignal) 1427 continue; 1428 1429 com::SafeArray <BYTE> data; 1430 hr = pOutputEvent->COMGETTER(Data)(ComSafeArrayAsOutParam(data)); 1431 ComAssertComRC(hr); 1432 1433 size_t cbRead = data.size(); 1434 1435 if (pvData) 1436 { 1437 if (cbRead < cbData) 1438 cbData = cbRead; 1439 memcpy(pvData, data.raw(), cbData); 1440 } 1441 1442 if (pcbRead) 1443 *pcbRead = cbRead; 1444 1445 LogFlowThisFunc(("Output event for process PID=%RU32 (session ID=%RU32): %zubytes read\n", 1446 uPID, mSession->getId(), cbRead)); 1447 1448 fSignalled = true; 1449 break; 1450 } 1451 1452 default: 1453 AssertMsgFailed(("Unhandled event type %ld\n", aType)); 1454 break; 1455 } 1456 } 1457 1458 } while (!fSignalled); 1459 1460 if ( RT_SUCCESS(vrc) 1461 && !fSignalled) 1462 { 1463 vrc = VERR_TIMEOUT; 1464 } 1465 1466 mEventSource->UnregisterListener(pListener); 1467 } 1468 else 1469 vrc = VERR_COM_UNEXPECTED; 1470 1471 LogFlowFuncLeaveRC(vrc); 1472 return vrc; 1473 } 1474 1475 int GuestProcess::waitForStatusChange(uint32_t fWaitFlags, uint32_t uTimeoutMS, 1476 ProcessStatus_T *pProcessStatus, int *pGuestRc) 1477 { 1478 int vrc; 1479 1480 ComPtr<IEventListener> pListener; 1481 HRESULT hr = mEventSource->CreateListener(pListener.asOutParam()); 1482 if (SUCCEEDED(hr)) 1483 { 1484 com::SafeArray <VBoxEventType_T> eventTypes(1); 1485 eventTypes.push_back(VBoxEventType_OnGuestProcessStateChanged); 1486 hr = mEventSource->RegisterListener(pListener, ComSafeArrayAsInParam(eventTypes), false); 1487 } 1488 else 1489 vrc = VERR_COM_UNEXPECTED; 1490 1491 if (SUCCEEDED(hr)) 1492 { 1493 LogFlowThisFunc(("Waiting for guest process state changed event (timeout=%RU32ms, flags=%x) ...\n", 1494 uTimeoutMS, fWaitFlags)); 1495 1496 vrc = VINF_SUCCESS; 1497 1498 uint64_t u64Started = RTTimeMilliTS(); 1499 bool fSignalled = false; 1500 do 1501 { 1502 unsigned cMsWait; 1503 if (uTimeoutMS == RT_INDEFINITE_WAIT) 1504 cMsWait = 1000; 1505 else 1506 { 1507 uint64_t cMsElapsed = RTTimeMilliTS() - u64Started; 1508 if (cMsElapsed >= uTimeoutMS) 1509 break; /* timed out */ 1510 cMsWait = RT_MIN(1000, uTimeoutMS - (uint32_t)cMsElapsed); 1511 } 1512 1513 ComPtr<IEvent> pEvent; 1514 hr = mEventSource->GetEvent(pListener, cMsWait, pEvent.asOutParam()); 1515 if ( SUCCEEDED(hr) 1516 && !pEvent.isNull()) 1517 { 1518 VBoxEventType_T aType; 1519 hr = pEvent->COMGETTER(Type)(&aType); 1520 ComAssertComRC(hr); 1521 switch (aType) 1522 { 1523 case VBoxEventType_OnGuestProcessStateChanged: 1524 { 1525 ComPtr<IGuestProcessStateChangedEvent> pChangedEvent = pEvent; 1526 Assert(!pChangedEvent.isNull()); 1527 1528 ComPtr<IGuestSession> pSession; 1529 pChangedEvent->COMGETTER(Session)(pSession.asOutParam()); 1530 Assert(!pSession.isNull()); 1531 ULONG uSessionID; 1532 hr = pSession->COMGETTER(Id)(&uSessionID); 1533 ComAssertComRC(hr); 1534 if (uSessionID != mSession->getId()) 1535 continue; /* Only the session this process runs in is of interest. */ 1536 1537 ULONG uPID; 1538 hr = pChangedEvent->COMGETTER(Pid)(&uPID); 1539 ComAssertComRC(hr); 1540 if (uPID != mData.mPID) 1541 continue; /* Only the this process is of interest. */ 1542 1543 ProcessStatus_T processStatus; 1544 pChangedEvent->COMGETTER(Status)(&processStatus); 1545 if (pProcessStatus) 1546 *pProcessStatus = processStatus; 1547 1548 LogFlowThisFunc(("Got status changed event for process PID=%RU32 (session ID=%RU32): %ld\n", 1549 mData.mPID, mSession->getId(), processStatus)); 1550 1551 bool fSignal = false; 1552 if (fWaitFlags) 1553 { 1554 switch (processStatus) 1555 { 1556 case ProcessStatus_Started: 1557 fSignal = (fWaitFlags & ProcessWaitForFlag_Start); 1558 break; 1559 1560 default: 1561 fSignal = true; 1562 break; 1563 } 1564 } 1565 else 1566 fSignal = true; 1567 1568 if (!fSignal) 1569 continue; 1570 1571 ComPtr<IGuestErrorInfo> errorInfo; 1572 hr = pChangedEvent->COMGETTER(Error)(errorInfo.asOutParam()); 1573 ComAssertComRC(hr); 1574 1575 LONG lGuestRc; 1576 hr = errorInfo->COMGETTER(Result)(&lGuestRc); 1577 ComAssertComRC(hr); 1578 if (RT_FAILURE((int)lGuestRc)) 1579 vrc = VERR_GSTCTL_GUEST_ERROR; 1580 if (pGuestRc) 1581 *pGuestRc = (int)lGuestRc; 1582 1583 LogFlowThisFunc(("Status changed event for process PID=%RU32 (session ID=%RU32): %ld (%Rrc)\n", 1584 uPID, mSession->getId(), processStatus, 1585 RT_SUCCESS((int)lGuestRc) ? VINF_SUCCESS : (int)lGuestRc)); 1586 1587 fSignalled = true; 1588 break; 1589 } 1590 1591 default: 1592 AssertMsgFailed(("Unhandled event type %ld\n", aType)); 1593 break; 1594 } 1595 } 1596 1597 } while (!fSignalled); 1598 1599 if ( RT_SUCCESS(vrc) 1600 && !fSignalled) 1601 { 1602 vrc = VERR_TIMEOUT; 1603 } 1604 1605 mEventSource->UnregisterListener(pListener); 1606 } 1607 else 1608 vrc = VERR_COM_UNEXPECTED; 1496 1609 1497 1610 LogFlowFuncLeaveRC(vrc); … … 1517 1630 } 1518 1631 1519 int vrc = VINF_SUCCESS; 1520 1521 GuestCtrlCallback *pCallbackWrite = NULL; 1522 try 1523 { 1524 pCallbackWrite = new GuestCtrlCallback(); 1525 } 1526 catch(std::bad_alloc &) 1527 { 1528 vrc = VERR_NO_MEMORY; 1529 } 1530 1531 /* Create callback and add it to the map. */ 1532 uint32_t uContextID = 0; 1533 if (RT_SUCCESS(vrc)) 1534 { 1535 vrc = pCallbackWrite->Init(CALLBACKTYPE_PROC_INPUT); 1536 if (RT_SUCCESS(vrc)) 1537 vrc = callbackAdd(pCallbackWrite, &uContextID); 1538 } 1539 1540 alock.release(); /* Drop the write lock again. */ 1541 1632 uint32_t uContextID; 1633 int vrc = generateContextID(mSession->getId(), mObjectID, 1634 &uContextID); 1542 1635 if (RT_SUCCESS(vrc)) 1543 1636 { … … 1552 1645 1553 1646 vrc = sendCommand(HOST_EXEC_SET_INPUT, i, paParms); 1554 if (RT_FAILURE(vrc))1555 {1556 int rc2 = setProcessStatus(ProcessStatus_Error, vrc);1557 AssertRC(rc2);1558 }1559 1647 } 1560 1648 1561 1649 if (RT_SUCCESS(vrc)) 1562 1650 { 1563 /* 1564 * Let's wait for the process being started. 1565 * Note: Be sure not keeping a AutoRead/WriteLock here. 1566 */ 1567 LogFlowThisFunc(("Waiting for callback (%RU32ms) ...\n", uTimeoutMS)); 1568 vrc = pCallbackWrite->Wait(uTimeoutMS); 1569 if (RT_SUCCESS(vrc)) /* Wait was successful, check for supplied information. */ 1570 { 1571 int guestRc = pCallbackWrite->GetResultCode(); 1572 if (RT_SUCCESS(guestRc)) 1573 { 1574 Assert(pCallbackWrite->GetDataSize() == sizeof(CALLBACKDATA_PROC_INPUT)); 1575 PCALLBACKDATA_PROC_INPUT pData = (PCALLBACKDATA_PROC_INPUT)pCallbackWrite->GetDataRaw(); 1576 AssertPtr(pData); 1577 1578 uint32_t cbWritten = 0; 1579 switch (pData->uStatus) 1580 { 1581 case INPUT_STS_WRITTEN: 1582 cbWritten = pData->uProcessed; 1583 break; 1584 1585 case INPUT_STS_ERROR: 1586 vrc = pData->uFlags; /** @todo Fix int vs. uint32_t! */ 1587 break; 1588 1589 case INPUT_STS_TERMINATED: 1590 vrc = VERR_CANCELLED; 1591 break; 1592 1593 case INPUT_STS_OVERFLOW: 1594 vrc = VERR_BUFFER_OVERFLOW; 1595 break; 1596 1597 default: 1598 /* Silently skip unknown errors. */ 1599 break; 1600 } 1601 1602 LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten)); 1603 1604 if (puWritten) 1605 *puWritten = cbWritten; 1606 } 1607 else 1608 vrc = VERR_GSTCTL_GUEST_ERROR; 1609 1610 if (pGuestRc) 1611 *pGuestRc = guestRc; 1612 LogFlowThisFunc(("Callback returned rc=%Rrc\n", guestRc)); 1613 } 1614 } 1615 1616 alock.acquire(); 1617 1618 int rc2 = callbackRemove(uContextID); 1619 if (RT_SUCCESS(vrc)) 1620 vrc = rc2; 1621 1622 callbackDelete(pCallbackWrite); 1651 alock.release(); /* Drop the write lock before waiting. */ 1652 1653 ProcessInputStatus_T inputStatus; 1654 size_t cbProcessed; 1655 vrc = waitForInputNotify(uHandle, uTimeoutMS, &inputStatus, &cbProcessed); 1656 if (RT_SUCCESS(vrc)) 1657 { 1658 /** @todo Set guestRc. */ 1659 1660 if (puWritten) 1661 *puWritten = cbProcessed; 1662 } 1663 /** @todo Error handling. */ 1664 } 1623 1665 1624 1666 LogFlowFuncLeaveRC(vrc); … … 1713 1755 } 1714 1756 1715 AssertPtr(m Object.mSession);1716 m Object.mSession->processRemoveFromList(this);1757 AssertPtr(mSession); 1758 mSession->processRemoveFromList(this); 1717 1759 1718 1760 /* -
trunk/src/VBox/Main/src-client/GuestSessionImpl.cpp
r45109 r45415 22 22 *******************************************************************************/ 23 23 #include "GuestImpl.h" 24 #include "GuestErrorInfoImpl.h" 24 25 #include "GuestSessionImpl.h" 25 26 #include "GuestCtrlImplPrivate.h" … … 28 29 #include "AutoCaller.h" 29 30 #include "ProgressImpl.h" 31 #include "VBoxEvents.h" 30 32 #include "VMMDev.h" 31 33 32 34 #include <memory> /* For auto_ptr. */ 33 35 36 #include <iprt/cpp/utils.h> /* For unconst(). */ 34 37 #include <iprt/env.h> 35 38 #include <iprt/file.h> /* For CopyTo/From. */ 36 39 37 40 #include <VBox/com/array.h> 41 #include <VBox/com/listeners.h> 38 42 #include <VBox/version.h> 39 43 … … 91 95 mData.mRC = VINF_SUCCESS; 92 96 mData.mStatus = GuestSessionStatus_Undefined; 93 94 mData.mWaitCount = 0;95 mData.mWaitEvent = NULL;96 97 97 98 return BaseFinalConstruct(); … … 128 129 AssertReturn(autoInitSpan.isOk(), VERR_OBJECT_DESTROYED); 129 130 130 m Data.mParent = pGuest;131 mParent = pGuest; 131 132 132 133 /* Copy over startup info. */ … … 149 150 if (RT_SUCCESS(rc)) 150 151 { 152 unconst(mEventSource).createObject(); 153 Assert(!mEventSource.isNull()); 154 HRESULT hr = mEventSource->init(static_cast<IGuestSession*>(this)); 155 if (FAILED(hr)) 156 rc = VERR_COM_UNEXPECTED; 157 } 158 159 if (RT_SUCCESS(rc)) 160 { 151 161 /* Confirm a successful initialization when it's the case. */ 152 162 autoInitSpan.setSucceeded(); … … 174 184 int rc = VINF_SUCCESS; 175 185 176 #if ndef VBOX_WITH_GUEST_CONTROL186 #ifdef VBOX_WITH_GUEST_CONTROL 177 187 LogFlowThisFunc(("Closing directories (%RU64 total)\n", 178 188 mData.mDirectories.size())); … … 180 190 itDirs != mData.mDirectories.end(); ++itDirs) 181 191 { 182 # ifdef DEBUG192 # ifdef DEBUG 183 193 ULONG cRefs = (*itDirs)->AddRef(); 184 LogFlowThisFunc(("pFile=%p, cRefs=%RU32\n", (*itDirs), cRefs ));194 LogFlowThisFunc(("pFile=%p, cRefs=%RU32\n", (*itDirs), cRefs - 1)); 185 195 (*itDirs)->Release(); 186 # endif196 # endif 187 197 (*itDirs)->uninit(); 188 198 } … … 194 204 itFiles != mData.mFiles.end(); ++itFiles) 195 205 { 196 # ifdef DEBUG197 ULONG cRefs = (*itFiles)->AddRef();198 LogFlowThisFunc(("pFile=%p, cRefs=%RU32\n", (*itFiles), cRefs ));199 (*itFiles)->Release();200 # endif201 (*itFiles)->uninit();206 # ifdef DEBUG 207 ULONG cRefs = itFiles->second->AddRef(); 208 LogFlowThisFunc(("pFile=%p, cRefs=%RU32\n", (*itFiles), cRefs - 1)); 209 itFiles->second->Release(); 210 # endif 211 itFiles->second->uninit(); 202 212 } 203 213 mData.mFiles.clear(); … … 208 218 itProcs != mData.mProcesses.end(); ++itProcs) 209 219 { 210 # ifdef DEBUG220 # ifdef DEBUG 211 221 ULONG cRefs = itProcs->second->AddRef(); 212 LogFlowThisFunc(("pProcess=%p, cRefs=%RU32\n", itProcs->second, cRefs ));222 LogFlowThisFunc(("pProcess=%p, cRefs=%RU32\n", itProcs->second, cRefs - 1)); 213 223 itProcs->second->Release(); 214 # endif224 # endif 215 225 itProcs->second->uninit(); 216 226 } … … 218 228 219 229 LogFlowThisFunc(("mNumObjects=%RU32\n", mData.mNumObjects)); 220 #endif 230 231 unconst(mEventSource).setNull(); 232 233 #endif /* VBOX_WITH_GUEST_CONTROL */ 221 234 LogFlowFuncLeaveRC(rc); 222 235 } … … 495 508 } 496 509 510 STDMETHODIMP GuestSession::COMGETTER(EventSource)(IEventSource ** aEventSource) 511 { 512 CheckComArgOutPointerValid(aEventSource); 513 514 AutoCaller autoCaller(this); 515 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 516 517 // no need to lock - lifetime constant 518 mEventSource.queryInterfaceTo(aEventSource); 519 520 return S_OK; 521 } 522 497 523 // private methods 498 524 /////////////////////////////////////////////////////////////////////////////// … … 501 527 { 502 528 LogFlowThisFunc(("uFlags=%x, uTimeoutMS=%RU32\n", uFlags, uTimeoutMS)); 529 530 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 503 531 504 532 /* Legacy Guest Additions don't support opening dedicated … … 512 540 /** @todo uFlags validation. */ 513 541 514 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 515 516 /* Destroy a pending callback request. */ 517 mData.mCallback.Destroy(); 518 519 int vrc = mData.mCallback.Init(CALLBACKTYPE_SESSION_NOTIFY); 520 521 alock.release(); /* Drop the write lock again. */ 522 542 if (mData.mStatus != GuestSessionStatus_Started) 543 return VINF_SUCCESS; 544 545 uint32_t uContextID; 546 int vrc = generateContextID(mData.mSession.mID, 0 /* Object ID */, 547 &uContextID); 523 548 if (RT_SUCCESS(vrc)) 524 549 { 525 /* The context ID only contains this session's ID; all other 526 * parameters like object and the count itself are not needed 527 * and therefore 0. */ 528 uint32_t uContextID = VBOX_GUESTCTRL_CONTEXTID_MAKE(mData.mSession.mID /* Session ID */, 529 0 /* Object */, 0 /* Count */); 530 531 VBOXHGCMSVCPARM paParms[4]; 532 533 int i = 0; 534 paParms[i++].setUInt32(uContextID); 535 paParms[i++].setUInt32(uFlags); 536 537 vrc = sendCommand(HOST_SESSION_CLOSE, i, paParms); 538 } 539 540 if (RT_SUCCESS(vrc)) 541 { 542 /* 543 * Let's wait for the process being started. 544 * Note: Be sure not keeping a AutoRead/WriteLock here. 545 */ 546 LogFlowThisFunc(("Waiting for callback (%RU32ms) ...\n", uTimeoutMS)); 547 vrc = mData.mCallback.Wait(uTimeoutMS); 548 if (RT_SUCCESS(vrc)) /* Wait was successful, check for supplied information. */ 549 { 550 int guestRc = mData.mCallback.GetResultCode(); 551 if (RT_SUCCESS(guestRc)) 552 { 553 /* Nothing to do here right now. */ 554 } 555 else 556 vrc = VERR_GSTCTL_GUEST_ERROR; 557 558 if (pGuestRc) 559 *pGuestRc = guestRc; 560 LogFlowThisFunc(("Callback returned rc=%Rrc\n", guestRc)); 561 } 562 } 563 564 AutoWriteLock awlock(this COMMA_LOCKVAL_SRC_POS); 565 566 mData.mCallback.Destroy(); 550 if (RT_SUCCESS(vrc)) 551 { 552 LogFlowThisFunc(("Sending closing request to guest session ID=%RU32, uFlags=%x\n", 553 mData.mSession.mID, uFlags)); 554 555 VBOXHGCMSVCPARM paParms[4]; 556 int i = 0; 557 paParms[i++].setUInt32(uContextID); 558 paParms[i++].setUInt32(uFlags); 559 560 vrc = sendCommand(HOST_SESSION_CLOSE, i, paParms); 561 } 562 563 if (RT_SUCCESS(vrc)) 564 { 565 alock.release(); /* Drop the write lock before waiting. */ 566 567 vrc = waitForStateChange(GuestSessionWaitForFlag_Terminate, uTimeoutMS, 568 NULL /* Session status */, pGuestRc); 569 } 570 } 567 571 568 572 LogFlowFuncLeaveRC(vrc); … … 813 817 814 818 #ifdef DEBUG 815 LogFlowThisFunc((" ID=%RU32, uContextID=%RU32, uFunction=%RU32, pSvcCb=%p\n",819 LogFlowThisFunc(("sessionID=%RU32, CID=%RU32, uFunction=%RU32, pSvcCb=%p\n", 816 820 mData.mSession.mID, pCbCtx->uContextID, pCbCtx->uFunction, pSvcCb)); 817 821 #endif … … 821 825 { 822 826 case GUEST_DISCONNECTED: 823 /** @todo Handle closing all processes. */827 /** @todo Handle closing all guest objects. */ 824 828 break; 825 829 826 830 case GUEST_SESSION_NOTIFY: 827 831 { 828 rc = onSessionStatusChange(pCbCtx, 829 &mData.mCallback, pSvcCb); 832 rc = onSessionStatusChange(pCbCtx, pSvcCb); 830 833 break; 831 834 } … … 960 963 return VERR_COM_UNEXPECTED; 961 964 962 Console *pConsole = m Data.mParent->getConsole();965 Console *pConsole = mParent->getConsole(); 963 966 AssertPtr(pConsole); 964 967 … … 1103 1106 1104 1107 case VERR_MAX_PROCS_REACHED: 1105 strError += Utf8StrFmt(tr("Maximum number of parallelguest processes has been reached"));1108 strError += Utf8StrFmt(tr("Maximum number of concurrent guest processes has been reached")); 1106 1109 break; 1107 1110 … … 1122 1125 } 1123 1126 1127 /** 1128 * Checks if this session is ready state where it can handle 1129 * all session-bound actions (like guest processes, guest files). 1130 * Only used by official API methods. Will set an external 1131 * error when not ready. 1132 */ 1133 HRESULT GuestSession::isReadyExternal(void) 1134 { 1135 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 1136 1137 /** @todo Be a bit more informative. */ 1138 if (mData.mStatus != GuestSessionStatus_Started) 1139 return setError(E_UNEXPECTED, tr("Session is not in started state")); 1140 1141 return S_OK; 1142 } 1143 1124 1144 /** No locking! */ 1125 int GuestSession::onSessionStatusChange(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, 1126 GuestCtrlCallback *pCallback, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData) 1127 { 1145 int GuestSession::onSessionStatusChange(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData) 1146 { 1147 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER); 1128 1148 /* pCallback is optional. */ 1129 1149 AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER); … … 1137 1157 pSvcCbData->mpaParms[2].getUInt32(&dataCb.uResult); 1138 1158 1139 LogFlowThisFunc(("ID=%RU32, uType=%RU32, rc=%Rrc, pCallback=%p, pData=%p\n",1140 mData.mSession.mID, dataCb.uType, dataCb.uResult , pCallback, pSvcCbData));1159 LogFlowThisFunc(("ID=%RU32, uType=%RU32, guestRc=%Rrc\n", 1160 mData.mSession.mID, dataCb.uType, dataCb.uResult)); 1141 1161 1142 1162 int vrc = VINF_SUCCESS; 1163 1164 GuestSessionStatus_T sessionStatus = GuestSessionStatus_Undefined; 1143 1165 1144 1166 int guestRc = dataCb.uResult; /** @todo uint32_t vs. int. */ … … 1146 1168 { 1147 1169 case GUEST_SESSION_NOTIFYTYPE_ERROR: 1148 mData.mStatus = GuestSessionStatus_Error;1170 sessionStatus = GuestSessionStatus_Error; 1149 1171 break; 1150 1172 1151 1173 case GUEST_SESSION_NOTIFYTYPE_STARTED: 1152 mData.mStatus = GuestSessionStatus_Started;1174 sessionStatus = GuestSessionStatus_Started; 1153 1175 break; 1154 1176 … … 1156 1178 case GUEST_SESSION_NOTIFYTYPE_TES: 1157 1179 case GUEST_SESSION_NOTIFYTYPE_TEA: 1158 mData.mStatus = GuestSessionStatus_Terminated;1180 sessionStatus = GuestSessionStatus_Terminated; 1159 1181 break; 1160 1182 1161 1183 case GUEST_SESSION_NOTIFYTYPE_TOK: 1162 mData.mStatus = GuestSessionStatus_TimedOutKilled;1184 sessionStatus = GuestSessionStatus_TimedOutKilled; 1163 1185 break; 1164 1186 1165 1187 case GUEST_SESSION_NOTIFYTYPE_TOA: 1166 mData.mStatus = GuestSessionStatus_TimedOutAbnormally;1188 sessionStatus = GuestSessionStatus_TimedOutAbnormally; 1167 1189 break; 1168 1190 1169 1191 case GUEST_SESSION_NOTIFYTYPE_DWN: 1170 mData.mStatus = GuestSessionStatus_Down;1192 sessionStatus = GuestSessionStatus_Down; 1171 1193 break; 1172 1194 1195 case GUEST_SESSION_NOTIFYTYPE_UNDEFINED: 1173 1196 default: 1174 1197 vrc = VERR_NOT_SUPPORTED; … … 1179 1202 { 1180 1203 if (RT_FAILURE(guestRc)) 1181 mData.mStatus = GuestSessionStatus_Error; 1182 } 1183 else if (vrc == VERR_NOT_SUPPORTED) 1184 { 1185 /* Also let the callback know. */ 1186 guestRc = VERR_NOT_SUPPORTED; 1187 } 1188 1189 /* 1190 * Now do the signalling stuff. 1191 */ 1192 if (pCallback) 1193 { 1194 int rc2 = pCallback->SetData(&dataCb, sizeof(dataCb)); 1195 AssertRC(rc2); 1196 rc2 = pCallback->Signal(guestRc); 1197 AssertRC(rc2); 1198 } 1199 1200 LogFlowThisFunc(("ID=%RU32, guestRc=%Rrc\n", 1201 mData.mSession.mID, guestRc)); 1204 sessionStatus = GuestSessionStatus_Error; 1205 } 1206 1207 /* Set the session status. */ 1208 if (sessionStatus != GuestSessionStatus_Undefined) 1209 { 1210 int rc2 = setSessionStatus(sessionStatus, guestRc); 1211 if (RT_SUCCESS(vrc)) 1212 vrc = rc2; 1213 } 1214 1215 LogFlowThisFunc(("ID=%RU32, guestRc=%Rrc\n", mData.mSession.mID, guestRc)); 1202 1216 1203 1217 LogFlowFuncLeaveRC(vrc); … … 1209 1223 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 1210 1224 1211 LogFlowThisFunc(("uProtocolVersion=%RU32, openFlags=%x, openTimeoutMS=%RU32\n", 1212 mData.mProtocolVersion, mData.mSession.mOpenFlags, mData.mSession.mOpenTimeoutMS)); 1225 LogFlowThisFunc(("mID=%RU32, mName=%s, uProtocolVersion=%RU32, openFlags=%x, openTimeoutMS=%RU32\n", 1226 mData.mSession.mID, mData.mSession.mName.c_str(), mData.mProtocolVersion, 1227 mData.mSession.mOpenFlags, mData.mSession.mOpenTimeoutMS)); 1213 1228 1214 1229 /* Legacy Guest Additions don't support opening dedicated … … 1222 1237 } 1223 1238 1239 if (mData.mStatus != GuestSessionStatus_Undefined) 1240 return VINF_SUCCESS; 1241 1224 1242 /** @todo mData.mSession.uFlags validation. */ 1225 1243 … … 1227 1245 mData.mStatus = GuestSessionStatus_Starting; 1228 1246 1229 /* Destroy a pending callback request. */ 1230 mData.mCallback.Destroy(); 1231 1232 int vrc = mData.mCallback.Init(CALLBACKTYPE_SESSION_NOTIFY); 1233 1234 alock.release(); /* Drop the write lock again. */ 1235 1247 uint32_t uContextID; 1248 int vrc = generateContextID(mData.mSession.mID, 0 /* Object ID */, 1249 &uContextID); 1236 1250 if (RT_SUCCESS(vrc)) 1237 1251 { 1238 uint32_t uContextID =1239 VBOX_GUESTCTRL_CONTEXTID_MAKE(mData.mSession.mID /* Session ID */,1240 0 /* Object */, 0 /* Count */);1241 1242 1252 VBOXHGCMSVCPARM paParms[8]; 1243 1253 … … 1258 1268 if (RT_SUCCESS(vrc)) 1259 1269 { 1260 /* 1261 * Let's wait for the process being started. 1262 * Note: Be sure not keeping a AutoRead/WriteLock here. 1263 */ 1264 LogFlowThisFunc(("Waiting for callback (%RU32ms) ...\n", mData.mSession.mOpenTimeoutMS)); 1265 vrc = mData.mCallback.Wait(mData.mSession.mOpenTimeoutMS); 1266 if (RT_SUCCESS(vrc)) /* Wait was successful, check for supplied information. */ 1267 { 1268 int guestRc = mData.mCallback.GetResultCode(); 1269 if (RT_SUCCESS(guestRc)) 1270 { 1271 /* Nothing to do here right now. */ 1272 } 1273 else 1274 vrc = VERR_GSTCTL_GUEST_ERROR; 1275 1276 if (pGuestRc) 1277 *pGuestRc = guestRc; 1278 LogFlowThisFunc(("Callback returned rc=%Rrc\n", guestRc)); 1279 } 1280 } 1281 1282 alock.acquire(); 1283 1284 /* Destroy callback. */ 1285 mData.mCallback.Destroy(); 1270 alock.release(); /* Drop write lock before waiting. */ 1271 1272 vrc = waitForStateChange(GuestSessionWaitForFlag_Start, 30 * 1000 /* 30s timeout */, 1273 NULL /* Session status */, pGuestRc); 1274 } 1286 1275 1287 1276 LogFlowFuncLeaveRC(vrc); … … 1344 1333 int GuestSession::processRemoveFromList(GuestProcess *pProcess) 1345 1334 { 1346 LogFlowThisFuncEnter(); 1335 AssertPtrReturn(pProcess, VERR_INVALID_POINTER); 1336 1337 LogFlowThisFunc(("pProcess=%p\n", pProcess)); 1347 1338 1348 1339 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); … … 1352 1343 ULONG uPID; 1353 1344 HRESULT hr = pProcess->COMGETTER(PID)(&uPID); 1345 ComAssertComRC(hr); 1354 1346 1355 1347 LogFlowFunc(("Closing process (PID=%RU32) ...\n", uPID)); 1356 1348 1357 for (SessionProcesses::iterator itProcs = mData.mProcesses.begin();1358 itProcs != mData.mProcesses.end(); ++itProcs)1349 SessionProcesses::iterator itProcs = mData.mProcesses.begin(); 1350 while (itProcs != mData.mProcesses.end()) 1359 1351 { 1360 1352 if (pProcess == itProcs->second) … … 1367 1359 1368 1360 Assert(mData.mNumObjects); 1369 LogFlowFunc(("Removing process (Session: %RU32) with process ID=%RU32, guest PID=%RU32 (now total %ld processes, %ld objects)\n", 1370 mData.mSession.mID, pCurProc->getObjectID(), uPID, mData.mProcesses.size() - 1, mData.mNumObjects - 1)); 1371 1361 LogFlowFunc(("Removing process ID=%RU32 (Session: %RU32), guest PID=%RU32 (now total %ld processes, %ld objects)\n", 1362 pCurProc->getObjectID(), mData.mSession.mID, uPID, mData.mProcesses.size() - 1, mData.mNumObjects - 1)); 1363 1364 LogFlowFunc(("1\n")); 1372 1365 mData.mProcesses.erase(itProcs); 1373 1366 mData.mNumObjects--; 1374 1367 1368 LogFlowFunc(("2\n")); 1369 fireGuestProcessRegisteredEvent(mEventSource, this /* Session */, NULL /* Process */, 1370 uPID, false /* Process unregistered */); 1371 LogFlowFunc(("3\n")); 1375 1372 rc = VINF_SUCCESS; 1376 1373 break; 1377 1374 } 1375 1376 LogFlowFunc(("4\n")); 1377 itProcs++; 1378 1378 } 1379 1379 … … 1475 1475 return VERR_COM_UNEXPECTED; 1476 1476 1477 rc = pProcess->init(m Data.mParent->getConsole() /* Console */, this /* Session */,1477 rc = pProcess->init(mParent->getConsole() /* Console */, this /* Session */, 1478 1478 uNewProcessID, procInfo); 1479 1479 if (RT_FAILURE(rc)) … … 1485 1485 Assert(mData.mNumObjects <= VBOX_GUESTCTRL_MAX_OBJECTS); 1486 1486 1487 fireGuestProcessRegisteredEvent(mEventSource, this /* Session */, pProcess, 1488 0 /* PID */, true /* Process registered */); 1489 1487 1490 LogFlowFunc(("Added new process (Session: %RU32) with process ID=%RU32 (now total %ld processes, %ld objects)\n", 1488 1491 mData.mSession.mID, uNewProcessID, mData.mProcesses.size(), mData.mNumObjects)); … … 1537 1540 1538 1541 #ifndef VBOX_GUESTCTRL_TEST_CASE 1539 ComObjPtr<Console> pConsole = m Data.mParent->getConsole();1542 ComObjPtr<Console> pConsole = mParent->getConsole(); 1540 1543 Assert(!pConsole.isNull()); 1541 1544 … … 1565 1568 1566 1569 return pInterface->setError(VBOX_E_IPRT_ERROR, GuestSession::guestErrorToString(guestRc).c_str()); 1570 } 1571 1572 /* Does not do locking; caller is responsible for that! */ 1573 int GuestSession::setSessionStatus(GuestSessionStatus_T sessionStatus, int sessionRc) 1574 { 1575 LogFlowThisFunc(("oldStatus=%ld, newStatus=%ld, sessionRc=%Rrc\n", 1576 mData.mStatus, sessionStatus, sessionRc)); 1577 1578 if (sessionStatus == GuestSessionStatus_Error) 1579 { 1580 AssertMsg(RT_FAILURE(sessionRc), ("Guest rc must be an error (%Rrc)\n", sessionRc)); 1581 /* Do not allow overwriting an already set error. If this happens 1582 * this means we forgot some error checking/locking somewhere. */ 1583 AssertMsg(RT_SUCCESS(mData.mRC), ("Guest rc already set (to %Rrc)\n", mData.mRC)); 1584 } 1585 else 1586 AssertMsg(RT_SUCCESS(sessionRc), ("Guest rc must not be an error (%Rrc)\n", sessionRc)); 1587 1588 if (mData.mStatus != sessionStatus) 1589 { 1590 mData.mStatus = sessionStatus; 1591 mData.mRC = sessionRc; 1592 1593 ComObjPtr<GuestErrorInfo> errorInfo; 1594 HRESULT hr = errorInfo.createObject(); 1595 ComAssertComRC(hr); 1596 int rc2 = errorInfo->init(sessionRc, guestErrorToString(sessionRc)); 1597 AssertRC(rc2); 1598 1599 fireGuestSessionStateChangedEvent(mEventSource, this, 1600 mData.mSession.mID, sessionStatus, errorInfo); 1601 } 1602 1603 return VINF_SUCCESS; 1604 } 1605 1606 int GuestSession::signalWaiters(GuestSessionWaitResult_T enmWaitResult, int rc /*= VINF_SUCCESS */) 1607 { 1608 /*LogFlowThisFunc(("enmWaitResult=%d, rc=%Rrc, mWaitCount=%RU32, mWaitEvent=%p\n", 1609 enmWaitResult, rc, mData.mWaitCount, mData.mWaitEvent));*/ 1610 1611 /* Note: No write locking here -- already done in the caller. */ 1612 1613 int vrc = VINF_SUCCESS; 1614 /*if (mData.mWaitEvent) 1615 vrc = mData.mWaitEvent->Signal(enmWaitResult, rc);*/ 1616 LogFlowFuncLeaveRC(vrc); 1617 return vrc; 1567 1618 } 1568 1619 … … 1621 1672 * This is done using the Guest Additions version 1622 1673 */ 1623 ComObjPtr<Guest> pGuest = m Data.mParent;1674 ComObjPtr<Guest> pGuest = mParent; 1624 1675 Assert(!pGuest.isNull()); 1625 1676 … … 1647 1698 AssertReturn(fWaitFlags, VERR_INVALID_PARAMETER); 1648 1699 1649 LogFlowThisFunc(("fWaitFlags=0x%x, uTimeoutMS=%RU32, mStatus=%RU32, mWaitCount=%RU32, mWaitEvent=%p, pGuestRc=%p\n",1650 fWaitFlags, uTimeoutMS, mData.mStatus, mData.mWaitCount, mData.mWaitEvent, pGuestRc)); 1700 /*LogFlowThisFunc(("fWaitFlags=0x%x, uTimeoutMS=%RU32, mStatus=%RU32, mWaitCount=%RU32, mWaitEvent=%p, pGuestRc=%p\n", 1701 fWaitFlags, uTimeoutMS, mData.mStatus, mData.mWaitCount, mData.mWaitEvent, pGuestRc));*/ 1651 1702 1652 1703 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); … … 1737 1788 } 1738 1789 1739 if (mData.mWaitCount > 0) /* We only support one waiting caller a time at the moment. */ 1740 return VERR_ALREADY_EXISTS; 1741 mData.mWaitCount++; 1742 1743 int vrc = VINF_SUCCESS; 1744 try 1745 { 1746 Assert(mData.mWaitEvent == NULL); 1747 mData.mWaitEvent = new GuestSessionWaitEvent(fWaitFlags); 1748 } 1749 catch(std::bad_alloc &) 1750 { 1751 vrc = VERR_NO_MEMORY; 1752 } 1753 1790 alock.release(); /* Release lock before waiting. */ 1791 1792 GuestSessionStatus_T sessionStatus; 1793 int vrc = waitForStateChange(fWaitFlags, uTimeoutMS, &sessionStatus, pGuestRc); 1754 1794 if (RT_SUCCESS(vrc)) 1755 1795 { 1756 GuestSessionWaitEvent *pEvent = mData.mWaitEvent; 1757 AssertPtr(pEvent); 1758 1759 alock.release(); /* Release lock before waiting. */ 1760 1761 vrc = pEvent->Wait(uTimeoutMS); 1762 LogFlowThisFunc(("Waiting completed with rc=%Rrc\n", vrc)); 1763 if (RT_SUCCESS(vrc)) 1764 { 1765 waitResult = pEvent->GetWaitResult(); 1766 int guestRc = pEvent->GetWaitRc(); 1767 if (RT_FAILURE(guestRc)) 1768 vrc = VERR_GSTCTL_GUEST_ERROR; 1769 1770 LogFlowThisFunc(("Waiting event returned rc=%Rrc\n", guestRc)); 1771 1772 if (pGuestRc) 1773 *pGuestRc = guestRc; 1774 } 1775 1776 alock.acquire(); /* Get the lock again. */ 1777 1778 /* Note: The caller always is responsible of deleting the 1779 * stuff it created before. See close() for more information. */ 1780 delete mData.mWaitEvent; 1781 mData.mWaitEvent = NULL; 1782 } 1783 1784 Assert(mData.mWaitCount); 1785 mData.mWaitCount--; 1796 switch (sessionStatus) 1797 { 1798 case GuestSessionStatus_Started: 1799 waitResult = GuestSessionWaitResult_Start; 1800 break; 1801 1802 case GuestSessionStatus_Terminated: 1803 waitResult = GuestSessionWaitResult_Terminate; 1804 break; 1805 1806 case GuestSessionStatus_TimedOutKilled: 1807 case GuestSessionStatus_TimedOutAbnormally: 1808 waitResult = GuestSessionWaitResult_Timeout; 1809 break; 1810 1811 case GuestSessionStatus_Down: 1812 waitResult = GuestSessionWaitResult_Terminate; 1813 break; 1814 1815 case GuestSessionStatus_Error: 1816 waitResult = GuestSessionWaitResult_Error; 1817 break; 1818 1819 default: 1820 waitResult = GuestSessionWaitResult_Status; 1821 break; 1822 } 1823 } 1824 1825 LogFlowFuncLeaveRC(vrc); 1826 return vrc; 1827 } 1828 1829 int GuestSession::waitForStateChange(uint32_t fWaitFlags, uint32_t uTimeoutMS, 1830 GuestSessionStatus_T *pSessionStatus, int *pGuestRc) 1831 { 1832 /** @todo Param validation. */ 1833 1834 int vrc; 1835 1836 ComPtr<IEventListener> pListener; 1837 HRESULT hr = mEventSource->CreateListener(pListener.asOutParam()); 1838 if (SUCCEEDED(hr)) 1839 { 1840 com::SafeArray <VBoxEventType_T> eventTypes(1); 1841 eventTypes.push_back(VBoxEventType_OnGuestSessionStateChanged); 1842 hr = mEventSource->RegisterListener(pListener, ComSafeArrayAsInParam(eventTypes), false); 1843 } 1844 else 1845 vrc = VERR_COM_UNEXPECTED; 1846 1847 if (SUCCEEDED(hr)) 1848 { 1849 LogFlowThisFunc(("Waiting for guest session state changed event (timeout=%RU32ms, flags=%x) ...\n", 1850 uTimeoutMS, fWaitFlags)); 1851 1852 vrc = VINF_SUCCESS; 1853 1854 uint64_t u64Started = RTTimeMilliTS(); 1855 bool fSignalled = false; 1856 do 1857 { 1858 unsigned cMsWait; 1859 if (uTimeoutMS == RT_INDEFINITE_WAIT) 1860 cMsWait = 1000; 1861 else 1862 { 1863 uint64_t cMsElapsed = RTTimeMilliTS() - u64Started; 1864 if (cMsElapsed >= uTimeoutMS) 1865 break; /* timed out */ 1866 cMsWait = RT_MIN(1000, uTimeoutMS - (uint32_t)cMsElapsed); 1867 } 1868 1869 ComPtr<IEvent> pEvent; 1870 hr = mEventSource->GetEvent(pListener, cMsWait, pEvent.asOutParam()); 1871 if ( SUCCEEDED(hr) 1872 && !pEvent.isNull()) 1873 { 1874 VBoxEventType_T aType; 1875 hr = pEvent->COMGETTER(Type)(&aType); 1876 ComAssertComRC(hr); 1877 switch (aType) 1878 { 1879 case VBoxEventType_OnGuestSessionStateChanged: 1880 { 1881 ComPtr<IGuestSessionStateChangedEvent> pChangedEvent = pEvent; 1882 Assert(!pChangedEvent.isNull()); 1883 1884 ULONG uSessionID; 1885 pChangedEvent->COMGETTER(Id)(&uSessionID); 1886 if (uSessionID != mData.mSession.mID) 1887 continue; /* Only our own session is of interest. */ 1888 1889 GuestSessionStatus_T sessionStatus; 1890 pChangedEvent->COMGETTER(Status)(&sessionStatus); 1891 if (pSessionStatus) 1892 *pSessionStatus = sessionStatus; 1893 1894 LogFlowThisFunc(("Got status changed event for session ID=%RU32: %ld\n", 1895 mData.mSession.mID, sessionStatus)); 1896 1897 bool fSignal = false; 1898 if (fWaitFlags) 1899 { 1900 switch (sessionStatus) 1901 { 1902 case GuestSessionStatus_Started: 1903 fSignal = ( fWaitFlags & GuestSessionWaitForFlag_Start 1904 || fWaitFlags & GuestSessionWaitForFlag_Status); 1905 break; 1906 1907 default: 1908 fSignal = true; 1909 break; 1910 } 1911 } 1912 else 1913 fSignal = true; 1914 1915 if (!fSignal) 1916 continue; 1917 1918 ComPtr<IGuestErrorInfo> errorInfo; 1919 hr = pChangedEvent->COMGETTER(Error)(errorInfo.asOutParam()); 1920 ComAssertComRC(hr); 1921 1922 LONG lGuestRc; 1923 hr = errorInfo->COMGETTER(Result)(&lGuestRc); 1924 ComAssertComRC(hr); 1925 if (RT_FAILURE((int)lGuestRc)) 1926 vrc = VERR_GSTCTL_GUEST_ERROR; 1927 if (pGuestRc) 1928 *pGuestRc = (int)lGuestRc; 1929 1930 LogFlowThisFunc(("Status changed event for session ID=%RU32: %ld (%Rrc)\n", 1931 mData.mSession.mID, sessionStatus, 1932 RT_SUCCESS((int)lGuestRc) ? VINF_SUCCESS : (int)lGuestRc)); 1933 1934 fSignalled = true; 1935 break; 1936 } 1937 1938 default: 1939 AssertMsgFailed(("Unhandled event type %ld\n", aType)); 1940 break; 1941 } 1942 } 1943 1944 } while (!fSignalled); 1945 1946 if ( RT_SUCCESS(vrc) 1947 && !fSignalled) 1948 { 1949 vrc = VERR_TIMEOUT; 1950 } 1951 1952 mEventSource->UnregisterListener(pListener); 1953 } 1954 else 1955 vrc = VERR_COM_UNEXPECTED; 1786 1956 1787 1957 LogFlowFuncLeaveRC(vrc); … … 1810 1980 1811 1981 /* Remove ourselves from the session list. */ 1812 int rc2 = m Data.mParent->sessionRemove(this);1982 int rc2 = mParent->sessionRemove(this); 1813 1983 if (RT_SUCCESS(rc)) 1814 1984 rc = rc2; … … 1828 1998 1829 1999 return setError(VBOX_E_IPRT_ERROR, 1830 tr("Closing guest session failed with %Rrc \n"), rc);2000 tr("Closing guest session failed with %Rrc"), rc); 1831 2001 } 1832 2002 … … 2466 2636 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 2467 2637 2638 HRESULT hr = isReadyExternal(); 2639 if (FAILED(hr)) 2640 return hr; 2641 2468 2642 /** @todo Validate open mode. */ 2469 2643 /** @todo Validate disposition mode. */ … … 2471 2645 /** @todo Validate creation mode. */ 2472 2646 uint32_t uCreationMode = 0; 2473 2474 HRESULT hr = S_OK;2475 2647 2476 2648 GuestFileOpenInfo openInfo; … … 2660 2832 AutoCaller autoCaller(this); 2661 2833 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 2834 2835 HRESULT hr = isReadyExternal(); 2836 if (FAILED(hr)) 2837 return hr; 2662 2838 2663 2839 GuestProcessStartupInfo procInfo; … … 2688 2864 } 2689 2865 2690 HRESULT hr = S_OK;2691 2692 2866 if (RT_SUCCESS(rc)) 2693 2867 { … … 2732 2906 { 2733 2907 case VERR_MAX_PROCS_REACHED: 2734 hr = setError(VBOX_E_IPRT_ERROR, tr("Maximum number of guest objects per session (%ld) reached"),2908 hr = setError(VBOX_E_IPRT_ERROR, tr("Maximum number of concurrent guest processes per session (%ld) reached"), 2735 2909 VBOX_GUESTCTRL_MAX_OBJECTS); 2736 2910 break; -
trunk/src/VBox/Main/testcase/tstGuestCtrlContextID.cpp
r44863 r45415 35 35 { 36 36 RTTEST hTest; 37 int rc = RTTestInitAndCreate("tst Makeup", &hTest);37 int rc = RTTestInitAndCreate("tstGuestCtrlContextID", &hTest); 38 38 if (rc) 39 39 return rc; … … 76 76 RTTestIPrintf(RTTESTLVL_DEBUG, "Max context is: %RU32\n", uContextMax); 77 77 78 /* Do 64tests total. */79 for (int t = 0; t < 64&& !RTTestErrorCount(hTest); t++)78 /* Do 4048 tests total. */ 79 for (int t = 0; t < 4048 && !RTTestErrorCount(hTest); t++) 80 80 { 81 81 /* VBOX_GUESTCTRL_MAX_* includes 0 as an object, so subtract one. */
Note:
See TracChangeset
for help on using the changeset viewer.