VirtualBox

Changeset 45415 in vbox for trunk/src/VBox/Main


Ignore:
Timestamp:
Apr 8, 2013 9:40:42 PM (12 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
84843
Message:

GuestCtrl: Implemented using (public) VirtualBox events instead of own callback mechanisms. Bugfixes for testcases (still work in progress).

Location:
trunk/src/VBox/Main
Files:
2 added
14 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/Makefile.kmk

    r45276 r45415  
    611611        src-client/GuestImpl.cpp \
    612612        src-client/GuestDirectoryImpl.cpp \
     613        src-client/GuestErrorInfoImpl.cpp \
    613614        src-client/GuestFileImpl.cpp \
    614615        src-client/GuestFsObjInfoImpl.cpp \
  • trunk/src/VBox/Main/idl/VirtualBox.xidl

    r45284 r45415  
    94919491      Process execution statuses.
    94929492    </desc>
     9493   
    94939494    <const name="Undefined"             value="0">
    94949495      <desc>Process is in an undefined state.</desc>
     
    95289529    </const>
    95299530  </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 
    95319588  <enum
    95329589    name="FsObjType"
     
    96059662    </const>
    96069663  </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>
    96079683
    96089684  <interface
    96099685    name="IGuestSession" extends="$unknown"
    9610     uuid="56f551a2-f924-43ab-8a69-a954109db878"
     9686    uuid="c8e8607b-5e67-4073-8f14-146515d0c1ff"
    96119687    wsmap="managed"
    96129688    >
     
    96899765      </desc>
    96909766    </attribute>
     9767   
     9768    <attribute name="eventSource" type="IEventSource" readonly="yes">
     9769      <desc>
     9770        Event source for guest session events.
     9771      </desc>
     9772    </attribute>
    96919773
    96929774    <method name="close">
     
    1070610788  <interface
    1070710789    name="IFile" extends="$unknown"
    10708     uuid="b702a560-6139-4a8e-a892-bbf14b97bf97"
     10790    uuid="0b45a95f-6267-499e-a7f2-efa5f8e081f2"
    1070910791    wsmap="managed"
    1071010792    >
     
    1071210794      Abstract parent interface for files handled by VirtualBox.
    1071310795    </desc>
     10796    <attribute name="status" type="FileStatus" readonly="yes">
     10797      <desc>
     10798        TODO
     10799      </desc>
     10800    </attribute>
    1071410801    <attribute name="creationMode" type="unsigned long" readonly="yes">
    1071510802      <desc>
     
    1857318660  <enum
    1857418661    name="VBoxEventType"
    18575     uuid="0d67e79e-b7b1-4919-aab3-b36866075515"
     18662    uuid="83c03e4b-ffe5-421c-a0fb-0b27b2d56753"
    1857618663    >
    1857718664
     
    1887118958      </desc>
    1887218959    </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>
    1887419010    <!-- Last event marker -->
    18875     <const name="Last" value="80">
     19011    <const name="Last" value="90">
    1887619012      <desc>
    1887719013        Must be last event, used for iterations and structures relying on numerical event values.
     
    1974519881  </interface>
    1974619882
    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 
    1974820153  <interface
    1974920154    name="IVRDEServerChangedEvent" extends="IEvent"
  • trunk/src/VBox/Main/include/GuestCtrlImplPrivate.h

    r45109 r45415  
    132132    int Init(CALLBACKTYPE enmType);
    133133
    134     CALLBACKTYPE GetCallbackType(void) { return mType; }
     134    CALLBACKTYPE GetType(void) { return mType; }
    135135
    136136    const void* GetDataRaw(void) const { return pvData; }
     
    568568};
    569569
    570 /**
    571  * Pure virtual class (interface) for guest objects (processes, files, ...) --
     570class GuestBase
     571{
     572
     573public:
     574
     575    GuestBase(void);
     576    virtual ~GuestBase(void);
     577
     578public:
     579
     580    int generateContextID(uint32_t uSessionID, uint32_t uObjectID, uint32_t *puContextID);
     581
     582protected:
     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, ...) --
    572593 * contains all per-object callback management.
    573594 */
    574 class GuestObject
    575 {
    576 
    577 public:
    578 
    579     ULONG getObjectID(void) { return mObject.mObjectID; }
     595class GuestObject : public GuestBase
     596{
     597
     598public:
     599
     600    GuestObject(void);
     601    virtual ~GuestObject(void);
     602
     603public:
     604
     605    ULONG getObjectID(void) { return mObjectID; }
    580606
    581607protected:
     
    587613
    588614    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);
    594615    int sendCommand(uint32_t uFunction, uint32_t uParms, PVBOXHGCMSVCPARM paParms);
    595616
     
    597618
    598619    /**
    599      * Commom structure for all derived objects, when then have
     620     * Commom parameters for all derived objects, when then have
    600621     * an own mData structure to keep their specific data around.
    601622     */
    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};
    818636#endif // ____H_GUESTIMPLPRIVATE
    819637
  • trunk/src/VBox/Main/include/GuestFileImpl.h

    r45109 r45415  
    2121
    2222#include "VirtualBoxBase.h"
     23#include "EventImpl.h"
    2324
    2425#include "GuestFsObjInfoImpl.h"
     
    6364    STDMETHOD(COMGETTER(Offset))(LONG64 *aOffset);
    6465    STDMETHOD(COMGETTER(OpenMode))(ULONG *aOpenMode);
     66    STDMETHOD(COMGETTER(Status))(FileStatus_T *aStatus);
    6567
    6668    STDMETHOD(Close)(void);
     
    8082    int             closeFile(int *pGuestRc);
    8183    static uint32_t getDispositionFromString(const Utf8Str &strDisposition);
     84    EventSource    *getEventSource(void) { return mEventSource; }
    8285    static uint32_t getOpenModeFromString(const Utf8Str &strOpenMode);
    8386    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);
    8689    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);
    9193    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);
    94101    /** @}  */
    95102
    96103private:
    97104
     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
    98114    struct Data
    99115    {
    100         /** The internal console object. */
    101         Console                *mConsole;
    102         /** The associate session this file belongs to. */
    103         GuestSession           *mSession;
    104116        /** All related callbacks to this file. */
    105117        GuestCtrlCallbacks      mCallbacks;
     
    110122        /** The file's internal ID. */
    111123        uint32_t                mID;
     124        /** The current file status. */
     125        FileStatus_T            mStatus;
    112126        /** The file's current offset. */
    113127        uint64_t                mOffCurrent;
  • trunk/src/VBox/Main/include/GuestImpl.h

    r44935 r45415  
    177177        GuestSessions           mGuestSessions;
    178178        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;
    195200    /** General extension callback for guest control. */
    196     HGCMSVCEXTHANDLE  mhExtCtrl;
     201    HGCMSVCEXTHANDLE                mhExtCtrl;
    197202#endif
    198203
  • trunk/src/VBox/Main/include/GuestProcessImpl.h

    r45010 r45415  
    8383    int terminateProcess(int *pGuestRc);
    8484    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);
    8588    int writeData(uint32_t uHandle, uint32_t uFlags, void *pvData, size_t cbData, uint32_t uTimeoutMS, uint32_t *puWritten, int *pGuestRc);
    8689    /** @}  */
     
    9093     * @{ */
    9194    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);
    97100    int prepareExecuteEnv(const char *pszEnv, void **ppvList, ULONG *pcbList, ULONG *pcEnvVars);
    98101    int setProcessStatus(ProcessStatus_T procStatus, int procRc);
    99     int signalWaiters(ProcessWaitResult_T enmWaitResult, int rc = VINF_SUCCESS);
    100102    static DECLCALLBACK(int) startProcessThread(RTTHREAD Thread, void *pvUser);
    101103    /** @}  */
    102104
    103105private:
     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;
    104113
    105114    struct Data
     
    116125         *  returned from the guest side. */
    117126        int                      mRC;
    118         /** How many waiters? At the moment there can only
    119          *  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;
    124127    } mData;
    125128};
  • trunk/src/VBox/Main/include/GuestSessionImpl.h

    r45010 r45415  
    2121
    2222#include "VirtualBoxBase.h"
     23#include "EventImpl.h"
    2324
    2425#include "GuestCtrlImplPrivate.h"
     
    238239class ATL_NO_VTABLE GuestSession :
    239240    public VirtualBoxBase,
     241    public GuestBase,
    240242    VBOX_SCRIPTABLE_IMPL(IGuestSession)
    241243{
     
    271273    STDMETHOD(COMGETTER(Directories))(ComSafeArrayOut(IGuestDirectory *, aDirectories));
    272274    STDMETHOD(COMGETTER(Files))(ComSafeArrayOut(IGuestFile *, aFiles));
     275    STDMETHOD(COMGETTER(EventSource))(IEventSource ** aEventSource);
    273276    /** @}  */
    274277
     
    345348    const GuestCredentials &getCredentials(void);
    346349    const GuestEnvironment &getEnvironment(void);
     350    EventSource            *getEventSource(void) { return mEventSource; }
    347351    Utf8Str                 getName(void);
    348352    ULONG                   getId(void) { return mData.mSession.mID; }
    349353    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);
    351356    int                     startSessionIntenal(int *pGuestRc);
    352357    int                     startSessionAsync(void);
    353358    static DECLCALLBACK(int)
    354359                            startSessionThread(RTTHREAD Thread, void *pvUser);
    355     Guest                  *getParent(void) { return mData.mParent; }
     360    Guest                  *getParent(void) { return mParent; }
    356361    uint32_t                getProtocolVersion(void) { return mData.mProtocolVersion; }
    357362    int                     processRemoveFromList(GuestProcess *pProcess);
     
    361366    int                     sendCommand(uint32_t uFunction, uint32_t uParms, PVBOXHGCMSVCPARM paParms);
    362367    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 */);
    363370    int                     startTaskAsync(const Utf8Str &strTaskDesc, GuestSessionTask *pTask, ComObjPtr<Progress> &pProgress);
    364371    int                     queryInfo(void);
    365372    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);
    366374    /** @}  */
    367375
    368376private:
     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;
    369386
    370387    struct Data
    371388    {
    372         /** Pointer to the parent (Guest). */
    373         Guest                      *mParent;
    374389        /** The session credentials. */
    375390        GuestCredentials            mCredentials;
     
    381396         *  overwritten/extended by ProcessCreate(Ex). */
    382397        GuestEnvironment            mEnvironment;
    383         /** The session callback, needed for communicating
    384          *  with the guest. */
    385         GuestCtrlCallback           mCallback;
    386398        /** Directory objects bound to this session. */
    387399        SessionDirectories          mDirectories;
     
    402414         *  returned from the guest side. */
    403415        int                         mRC;
    404         /** How many waiters? At the moment there can only
    405          *  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;
    410416    } mData;
    411417};
  • trunk/src/VBox/Main/src-client/GuestCtrlImpl.cpp

    r45078 r45415  
    55
    66/*
    7  * Copyright (C) 2006-2012 Oracle Corporation
     7 * Copyright (C) 2006-2013 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    2323#include "ConsoleImpl.h"
    2424#include "ProgressImpl.h"
     25#include "VBoxEvents.h"
    2526#include "VMMDev.h"
    2627
     
    159160        {
    160161            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"),
    162163                              VBOX_GUESTCTRL_MAX_SESSIONS);
    163164                break;
     
    316317    LogFlowFunc(("Closing session (ID=%RU32) ...\n", pSession->getId()));
    317318
    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())
    320321    {
    321322        if (pSession == itSessions->second)
     
    324325                         (GuestSession *)itSessions->second, itSessions->second->getId(), mData.mGuestSessions.size() - 1));
    325326
    326             mData.mGuestSessions.erase(itSessions++);
    327 
     327            mData.mGuestSessions.erase(itSessions);
     328
     329            fireGuestSessionRegisteredEvent(mEventSource, pSession,
     330                                            false /* Unregistered */);
    328331            rc = VINF_SUCCESS;
    329332            break;
    330333        }
     334
     335        itSessions++;
    331336    }
    332337
     
    398403         * Add session object to our session map. This is necessary
    399404         * before calling openSession because the guest calls back
    400          * with the creation result to this session.
     405         * with the creation result of this session.
    401406         */
    402407        mData.mGuestSessions[uNewSessionID] = pGuestSession;
    403408
    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 */);
    407411    }
    408412    catch (int rc2)
     
    459463    }
    460464
    461     int guestRc;
    462465    if (RT_SUCCESS(rc))
    463466    {
    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();
    476470    }
    477471
     
    482476        switch (rc)
    483477        {
    484             case VERR_GSTCTL_GUEST_ERROR:
    485                 hr = GuestSession::setErrorExternal(this, guestRc);
    486                 break;
    487 
    488478            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"),
    490480                              VBOX_GUESTCTRL_MAX_SESSIONS);
    491481                break;
  • trunk/src/VBox/Main/src-client/GuestCtrlPrivate.cpp

    r45367 r45415  
    12581258}
    12591259
     1260GuestBase::GuestBase(void)
     1261    : mConsole(NULL),
     1262      mNextContextID(0)
     1263{
     1264}
     1265
     1266GuestBase::~GuestBase(void)
     1267{
     1268}
     1269
     1270int 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
     1284GuestObject::GuestObject(void)
     1285    : mSession(NULL),
     1286      mObjectID(0)
     1287{
     1288}
     1289
     1290GuestObject::~GuestObject(void)
     1291{
     1292}
     1293
    12601294int GuestObject::bindToSession(Console *pConsole, GuestSession *pSession, uint32_t uObjectID)
    12611295{
     
    12631297    AssertPtrReturn(pSession, VERR_INVALID_POINTER);
    12641298
    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;
    12701302
    12711303    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 means
    1299              * we can use this context ID for our new callback we want
    1300              * 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 includes
    1314          *       the session + process ID), just the context count
    1315          *       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;
    13861304}
    13871305
     
    13921310
    13931311#ifndef VBOX_GUESTCTRL_TEST_CASE
    1394     ComObjPtr<Console> pConsole = mObject.mConsole;
     1312    ComObjPtr<Console> pConsole = mConsole;
    13951313    Assert(!pConsole.isNull());
    13961314
  • trunk/src/VBox/Main/src-client/GuestFileImpl.cpp

    r45109 r45415  
    2121*   Header Files                                                               *
    2222*******************************************************************************/
     23#include "GuestErrorInfoImpl.h"
    2324#include "GuestFileImpl.h"
    2425#include "GuestSessionImpl.h"
     
    2829#include "Global.h"
    2930#include "AutoCaller.h"
    30 
     31#include "VBoxEvents.h"
     32
     33#include <iprt/cpp/utils.h> /* For unconst(). */
    3134#include <iprt/file.h>
    3235#include <VBox/com/array.h>
     
    8891        mData.mID = 0;
    8992        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    {
    91103        /* Confirm a successful initialization when it's the case. */
    92104        autoInitSpan.setSucceeded();
    93         return vrc;
    94     }
    95 
    96     autoInitSpan.setFailed();
     105    }
     106    else
     107        autoInitSpan.setFailed();
     108
     109    LogFlowFuncLeaveRC(vrc);
    97110    return vrc;
    98111}
     
    112125
    113126#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();
    119128#endif
    120129
     
    230239
    231240    *aOpenMode = getOpenModeFromString(mData.mOpenInfo.mOpenMode);
     241
     242    return S_OK;
     243#endif /* VBOX_WITH_GUEST_CONTROL */
     244}
     245
     246STDMETHODIMP 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;
    232259
    233260    return S_OK;
     
    248275    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    249276
    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 when
    252      * doing the actual HGCM sending stuff. */
    253     GuestCtrlCallback *pCallback = NULL;
    254     GuestCtrlCallbacks::const_iterator it
    255         = 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 DEBUG
    261         LogFlowThisFunc(("pCallback=%p, CID=%RU32, Count=%RU32\n",
    262                          pCallback, pCbCtx->uContextID, VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(pCbCtx->uContextID)));
    263 #endif
    264     }
    265 
    266277    int vrc;
    267278    switch (pCbCtx->uFunction)
    268279    {
    269280        case GUEST_DISCONNECTED:
    270             vrc = onGuestDisconnected(pCbCtx, pSvcCb, pCallback); /* Affects all callbacks. */
     281            vrc = onGuestDisconnected(pCbCtx, pSvcCb);
    271282            break;
    272283
    273284        case GUEST_FILE_NOTIFY:
    274             vrc = onFileNotify(pCbCtx, pSvcCb, pCallback);
     285            vrc = onFileNotify(pCbCtx, pSvcCb);
    275286            break;
    276287
     
    291302    LogFlowThisFunc(("strFile=%s\n", mData.mOpenInfo.mFileName.c_str()));
    292303
    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    }
    303319
    304320    LogFlowFuncLeaveRC(vrc);
     
    383399}
    384400
    385 int GuestFile::onFileNotify(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData,
    386                             GuestCtrlCallback *pCallback)
     401int GuestFile::onFileNotify(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
    387402{
    388403    AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
    389404    AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);
    390     /* pCallback is optional. */
    391405
    392406    if (pSvcCbData->mParms < 3)
     
    401415    pSvcCbData->mpaParms[idx++].getUInt32(&dataCb.rc);
    402416
     417    int guestRc = (int)dataCb.rc; /* uint32_t vs. int. */
     418
    403419    switch (dataCb.uType)
    404420    {
    405421        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        }
    408429
    409430        case GUEST_FILE_NOTIFYTYPE_OPEN:
     431        {
    410432            if (pSvcCbData->mParms == 4)
    411433            {
     
    417439                          ("File ID %RU32 does not match context ID %RU32\n", mData.mID,
    418440                           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;
    419446            }
    420447            else
    421448                vrc = VERR_NOT_SUPPORTED;
    422             break;
     449
     450            break;
     451        }
    423452
    424453        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        }
    427460
    428461        case GUEST_FILE_NOTIFYTYPE_READ:
     
    431464                pSvcCbData->mpaParms[idx++].getPointer(&dataCb.u.read.pvData,
    432465                                                       &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                }
    435476            }
    436477            else
     
    444485
    445486                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);
    446491            }
    447492            else
     
    455500
    456501                mData.mOffCurrent = dataCb.u.seek.uOffActual;
     502
     503                if (dataCb.u.seek.uOffActual)
     504                    fireGuestFileOffsetChangedEvent(mEventSource, mSession, this,
     505                                                    mData.mOffCurrent, 0 /* Processed */);
    457506            }
    458507            else
     
    465514                pSvcCbData->mpaParms[idx++].getUInt64(&dataCb.u.tell.uOffActual);
    466515
    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                }
    468523            }
    469524            else
     
    476531    }
    477532
    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
    482536    if (RT_SUCCESS(vrc))
    483537    {
     
    490544    }
    491545
    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 
    503546    LogFlowFuncLeaveRC(vrc);
    504547    return vrc;
    505548}
    506549
    507 int GuestFile::onGuestDisconnected(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData,
    508                                    GuestCtrlCallback *pCallback)
     550int GuestFile::onGuestDisconnected(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
    509551{
    510552    AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
    511553    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);
    523559
    524560    LogFlowFuncLeaveRC(vrc);
     
    534570    /* Prepare HGCM call. */
    535571    VBOXHGCMSVCPARM paParms[8];
    536     int i = 1; /* Context ID will be set in sendFileComannd(). */
     572    int i = 0;
    537573    paParms[i++].setPointer((void*)mData.mOpenInfo.mFileName.c_str(),
    538574                            (ULONG)mData.mOpenInfo.mFileName.length() + 1);
     
    544580    paParms[i++].setUInt64(mData.mOpenInfo.mInitialOffset);
    545581
    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 */);
    548586
    549587    LogFlowFuncLeaveRC(vrc);
     
    551589}
    552590
    553 int GuestFile::readData(uint32_t uSize, uint32_t uTimeoutMS, void *pvData, size_t cbData,
    554                         size_t *pcbRead, int *pGuestRc)
     591int GuestFile::readData(uint32_t uSize, uint32_t uTimeoutMS,
     592                        void* pvData, uint32_t cbData, uint32_t* pcbRead)
    555593{
    556594    LogFlowThisFunc(("uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
    557595                     uSize, uTimeoutMS, pvData, cbData));
    558596
     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
     626int 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
     663int 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
    559669    /* Prepare HGCM call. */
    560670    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;
    658672    paParms[i++].setUInt32(mData.mID /* File handle */);
    659673    paParms[i++].setUInt32(eSeekType /* Seek method */);
    660674    paParms[i++].setUInt64(uOffset /* Offset (in bytes) to start reading */);
    661675
    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);
    721677    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);
    786679
    787680    LogFlowFuncLeaveRC(vrc);
     
    798691}
    799692
    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! */
     694int 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
     728int GuestFile::waitForOffsetChange(uint32_t uTimeoutMS, uint64_t *puOffset)
     729{
     730    return VINF_SUCCESS;
     731}
     732
     733int GuestFile::waitForRead(uint32_t uTimeoutMS, void* pvData, size_t cbData, uint32_t *pcbRead)
     734{
     735    return VINF_SUCCESS;
     736}
     737
     738int 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
     826int GuestFile::waitForWrite(uint32_t uTimeoutMS, uint32_t *pcbWritten)
     827{
     828    return VINF_SUCCESS;
     829}
     830
     831int GuestFile::writeData(uint32_t uTimeoutMS, void *pvData, uint32_t cbData,
     832                         uint32_t *pcbWritten)
    802833{
    803834    AssertPtrReturn(pvData, VERR_INVALID_POINTER);
     
    807838                     uTimeoutMS, pvData, cbData));
    808839
    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);
    820843    if (RT_SUCCESS(vrc))
    821844    {
    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    }
    840866
    841867    LogFlowFuncLeaveRC(vrc);
     
    844870
    845871int 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)
    848873{
    849874    AssertPtrReturn(pvData, VERR_INVALID_POINTER);
     
    853878                     uOffset, uTimeoutMS, pvData, cbData));
    854879
    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);
    867883    if (RT_SUCCESS(vrc))
    868884    {
    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    }
    887910
    888911    LogFlowFuncLeaveRC(vrc);
     
    909932     * work first and then return an error. */
    910933
    911     AssertPtr(mData.mSession);
    912     int rc2 = mData.mSession->fileRemoveFromList(this);
     934    AssertPtr(mSession);
     935    int rc2 = mSession->fileRemoveFromList(this);
    913936    if (RT_SUCCESS(rc))
    914937        rc = rc2;
     
    964987    HRESULT hr = S_OK;
    965988
    966     size_t cbRead; int guestRc;
     989    uint32_t cbRead;
    967990    int vrc = readData(aToRead, aTimeoutMS,
    968                        data.raw(), aToRead, &cbRead, &guestRc);
     991                       data.raw(), aToRead, &cbRead);
    969992    if (RT_SUCCESS(vrc))
    970993    {
     
    9771000        switch (vrc)
    9781001        {
    979             case VERR_GSTCTL_GUEST_ERROR:
    980                 hr = GuestFile::setErrorExternal(this, guestRc);
    981                 break;
    982 
    9831002            default:
    9841003                hr = setError(VBOX_E_IPRT_ERROR,
     
    10131032    HRESULT hr = S_OK;
    10141033
    1015     size_t cbRead; int guestRc;
     1034    size_t cbRead;
    10161035    int vrc = readDataAt(aOffset, aToRead, aTimeoutMS,
    1017                          data.raw(), aToRead, &cbRead, &guestRc);
     1036                         data.raw(), aToRead, &cbRead);
    10181037    if (RT_SUCCESS(vrc))
    10191038    {
     
    10261045        switch (vrc)
    10271046        {
    1028             case VERR_GSTCTL_GUEST_ERROR:
    1029                 hr = GuestFile::setErrorExternal(this, guestRc);
    1030                 break;
    1031 
    10321047            default:
    10331048                hr = setError(VBOX_E_IPRT_ERROR,
     
    10731088    }
    10741089
    1075     int guestRc;
    10761090    int vrc = seekAt(aOffset, eSeekType,
    1077                      30 * 1000 /* 30s timeout */, &guestRc);
     1091                     30 * 1000 /* 30s timeout */, NULL /* puOffset */);
    10781092    if (RT_FAILURE(vrc))
    10791093    {
    10801094        switch (vrc)
    10811095        {
    1082             case VERR_GSTCTL_GUEST_ERROR:
    1083                 hr = GuestFile::setErrorExternal(this, guestRc);
    1084                 break;
    1085 
    10861096            default:
    10871097                hr = setError(VBOX_E_IPRT_ERROR,
     
    11231133    HRESULT hr = S_OK;
    11241134
    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);
    11271138    if (RT_FAILURE(vrc))
    11281139    {
    11291140        switch (vrc)
    11301141        {
    1131             case VERR_GSTCTL_GUEST_ERROR:
    1132                 hr = GuestFile::setErrorExternal(this, guestRc);
    1133                 break;
    1134 
    11351142            default:
    11361143                hr = setError(VBOX_E_IPRT_ERROR,
     
    11621169    HRESULT hr = S_OK;
    11631170
    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);
    11661174    if (RT_FAILURE(vrc))
    11671175    {
    11681176        switch (vrc)
    11691177        {
    1170             case VERR_GSTCTL_GUEST_ERROR:
    1171                 hr = GuestFile::setErrorExternal(this, guestRc);
    1172                 break;
    1173 
    11741178            default:
    11751179                hr = setError(VBOX_E_IPRT_ERROR,
  • trunk/src/VBox/Main/src-client/GuestImpl.cpp

    r44903 r45415  
    8080
    8181    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? */
    8484        mMemoryBalloonSize = aMemoryBalloonSize;
    8585    else
    86         mMemoryBalloonSize = 0;                     /* Default is no ballooning */
     86        mMemoryBalloonSize = 0; /* Default is no ballooning */
    8787
    8888    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? */
    9191        mfPageFusionEnabled = fPageFusionEnabled;
    9292    else
    93         mfPageFusionEnabled = false;                /* Default is no page fusion*/
    94 
    95     mStatUpdateInterval = 0;                    /* Default is not to report guest statistics at all */
     93        mfPageFusionEnabled = false; /* Default is no page fusion*/
     94
     95    mStatUpdateInterval = 0; /* Default is not to report guest statistics at all */
    9696    mCollectVMMStats = false;
    9797
     
    106106    int vrc = RTTimerLRCreate(&mStatTimer, 1000 /* ms */,
    107107                              &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
    109117
    110118    try
     
    117125    catch(std::bad_alloc &)
    118126    {
    119         return E_OUTOFMEMORY;
    120     }
    121 
    122     return S_OK;
     127        hr = E_OUTOFMEMORY;
     128    }
     129
     130    return hr;
    123131}
    124132
     
    167175#endif
    168176
     177#ifdef VBOX_WITH_GUEST_CONTROL
     178    unconst(mEventSource).setNull();
     179#endif
    169180    unconst(mParent) = NULL;
    170181
  • trunk/src/VBox/Main/src-client/GuestProcessImpl.cpp

    r45109 r45415  
    2929*   Header Files                                                               *
    3030*******************************************************************************/
     31#include "GuestErrorInfoImpl.h"
    3132#include "GuestProcessImpl.h"
    3233#include "GuestSessionImpl.h"
    3334#include "GuestCtrlImplPrivate.h"
    3435#include "ConsoleImpl.h"
     36#include "VBoxEvents.h"
    3537
    3638#include "Global.h"
     
    4042
    4143#include <iprt/asm.h>
     44#include <iprt/cpp/utils.h> /* For unconst(). */
    4245#include <iprt/getopt.h>
     46
    4347#include <VBox/com/array.h>
    4448
     
    9296    mData.mStatus = ProcessStatus_Undefined;
    9397
    94     mData.mWaitCount = 0;
    95     mData.mWaitEvent = NULL;
    96 
    97     HRESULT hr = BaseFinalConstruct();
    98     return hr;
     98    return BaseFinalConstruct();
    9999}
    100100
     
    124124
    125125    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
    126135    if (RT_SUCCESS(vrc))
    127136    {
     
    156165
    157166#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();
    172168#endif
    173169
     
    346342    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    347343
    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 when
    350      * doing the actual HGCM sending stuff. */
    351     GuestCtrlCallback *pCallback = NULL;
    352     GuestCtrlCallbacks::const_iterator it
    353         = 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 DEBUG
    359         LogFlowThisFunc(("pCallback=%p, CID=%RU32, Count=%RU32\n",
    360                          pCallback, pCbCtx->uContextID, VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(pCbCtx->uContextID)));
    361 #endif
    362     }
    363 
    364344    int vrc;
    365345    switch (pCbCtx->uFunction)
     
    367347        case GUEST_DISCONNECTED:
    368348        {
    369             vrc = onGuestDisconnected(pCbCtx, pCallback, pSvcCb); /* Affects all callbacks. */
     349            vrc = onGuestDisconnected(pCbCtx, pSvcCb);
    370350            break;
    371351        }
     
    373353        case GUEST_EXEC_STATUS:
    374354        {
    375             vrc = onProcessStatusChange(pCbCtx, pCallback, pSvcCb);
     355            vrc = onProcessStatusChange(pCbCtx, pSvcCb);
    376356            break;
    377357        }
     
    379359        case GUEST_EXEC_OUTPUT:
    380360        {
    381             vrc = onProcessOutput(pCbCtx, pCallback, pSvcCb);
     361            vrc = onProcessOutput(pCbCtx, pSvcCb);
    382362            break;
    383363        }
     
    385365        case GUEST_EXEC_INPUT_STATUS:
    386366        {
    387             vrc = onProcessInputStatus(pCbCtx, pCallback, pSvcCb);
     367            vrc = onProcessInputStatus(pCbCtx, pSvcCb);
    388368            break;
    389369        }
     
    422402
    423403         */
    424         if (mObject.mSession->getProtocolVersion() < 2)
     404        if (mSession->getProtocolVersion() < 2)
    425405        {
    426406            /* Simply ignore the stale requests. */
     
    487467
    488468        case VERR_MAX_PROCS_REACHED:
    489             strError += Utf8StrFmt(tr("Maximum number of parallel guest processes has been reached"));
     469            strError += Utf8StrFmt(tr("Maximum number of concurrent guest processes has been reached"));
    490470            break;
    491471
     
    526506}
    527507
    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);
     508int 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);
    551516
    552517    LogFlowFuncLeaveRC(vrc);
     
    554519}
    555520
    556 int GuestProcess::onProcessInputStatus(PVBOXGUESTCTRLHOSTCBCTX pCbCtx,
    557                                        GuestCtrlCallback *pCallback, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
    558 {
    559     AssertPtrReturn(pCallback, VERR_INVALID_POINTER);
     521int GuestProcess::onProcessInputStatus(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
     522{
     523    AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
    560524    AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);
     525    /* pCallback is optional. */
    561526
    562527    if (pSvcCbData->mParms < 5)
     
    574539    AssertRCReturn(vrc, vrc);
    575540
    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));
    578543
    579544    vrc = checkPID(dataCb.uPID);
    580545    AssertRCReturn(vrc, vrc);
    581546
    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);
    600573    }
    601574
     
    604577}
    605578
    606 int GuestProcess::onProcessNotifyIO(PVBOXGUESTCTRLHOSTCBCTX pCbCtx,
    607                                     GuestCtrlCallback *pCallback, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
    608 {
    609     AssertPtrReturn(pCallback, VERR_INVALID_POINTER);
     579int GuestProcess::onProcessNotifyIO(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
     580{
     581    AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
     582    AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);
    610583
    611584    return VERR_NOT_IMPLEMENTED;
    612585}
    613586
    614 int GuestProcess::onProcessStatusChange(PVBOXGUESTCTRLHOSTCBCTX pCbCtx,
    615                                         GuestCtrlCallback *pCallback, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
     587int GuestProcess::onProcessStatusChange(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
    616588{
    617589    /* pCallback is optional. */
     
    632604    AssertRCReturn(vrc, vrc);
    633605
    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));
    636608
    637609    vrc = checkPID(dataCb.uPID);
     
    641613    int procRc = VINF_SUCCESS;
    642614
    643     bool fSignalWaiters = false;
    644     ProcessWaitResult_T waitRes;
    645 
    646     uint32_t uWaitFlags = mData.mWaitEvent
    647                         ? mData.mWaitEvent->GetWaitFlags() : 0;
    648615    switch (dataCb.uStatus)
    649616    {
    650617        case PROC_STS_STARTED:
    651618        {
    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 
    659619            procStatus = ProcessStatus_Started;
    660620            mData.mPID = dataCb.uPID; /* Set the process PID. */
     
    664624        case PROC_STS_TEN:
    665625        {
    666             fSignalWaiters = true; /* Signal in any case. */
    667             waitRes = ProcessWaitResult_Terminate;
    668 
    669626            procStatus = ProcessStatus_TerminatedNormally;
    670627            mData.mExitCode = dataCb.uFlags; /* Contains the exit code. */
     
    674631        case PROC_STS_TES:
    675632        {
    676             fSignalWaiters = true; /* Signal in any case. */
    677             waitRes = ProcessWaitResult_Terminate;
    678 
    679633            procStatus = ProcessStatus_TerminatedSignal;
    680634            mData.mExitCode = dataCb.uFlags; /* Contains the signal. */
     
    684638        case PROC_STS_TEA:
    685639        {
    686             fSignalWaiters = true; /* Signal in any case. */
    687             waitRes = ProcessWaitResult_Terminate;
    688 
    689640            procStatus = ProcessStatus_TerminatedAbnormally;
    690641            break;
     
    693644        case PROC_STS_TOK:
    694645        {
    695             fSignalWaiters = true; /* Signal in any case. */
    696             waitRes = ProcessWaitResult_Timeout;
    697 
    698646            procStatus = ProcessStatus_TimedOutKilled;
    699647            break;
     
    702650        case PROC_STS_TOA:
    703651        {
    704             fSignalWaiters = true; /* Signal in any case. */
    705             waitRes = ProcessWaitResult_Timeout;
    706 
    707652            procStatus = ProcessStatus_TimedOutAbnormally;
    708653            break;
     
    711656        case PROC_STS_DWN:
    712657        {
    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             else
    718                 waitRes = ProcessWaitResult_Terminate;
    719 
    720658            procStatus = ProcessStatus_Down;
    721659            break;
     
    724662        case PROC_STS_ERROR:
    725663        {
    726             fSignalWaiters = true; /* Signal in any case. */
    727             waitRes = ProcessWaitResult_Error;
    728 
    729664            procRc = dataCb.uFlags; /* mFlags contains the IPRT error sent from the guest. */
    730665            procStatus = ProcessStatus_Error;
     
    736671        {
    737672            /* Silently skip this request. */
    738             fSignalWaiters = true; /* Signal in any case. */
    739             waitRes = ProcessWaitResult_Status;
    740 
    741673            procStatus = ProcessStatus_Undefined;
    742674            break;
     
    744676    }
    745677
    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));
    748680
    749681    /* Set the process status. */
     
    752684        vrc = rc2;
    753685
    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 
    771686    LogFlowFuncLeaveRC(vrc);
    772687    return vrc;
    773688}
    774689
    775 int GuestProcess::onProcessOutput(PVBOXGUESTCTRLHOSTCBCTX pCbCtx,
    776                                   GuestCtrlCallback *pCallback, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
    777 {
    778     AssertPtrReturn(pCallback, VERR_INVALID_POINTER);
     690int GuestProcess::onProcessOutput(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
     691{
    779692    AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);
    780693
     
    793706    AssertRCReturn(vrc, vrc);
    794707
    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));
    797710
    798711    vrc = checkPID(dataCb.uPID);
    799712    AssertRCReturn(vrc, vrc);
    800713
    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));
    842719
    843720    LogFlowFuncLeaveRC(vrc);
     
    855732    /* pcbRead is optional. */
    856733
     734    /** @todo Validate uHandle. */
     735
    857736    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    858737
     
    866745    }
    867746
    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);
    882750    if (RT_SUCCESS(vrc))
    883751    {
    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];
    895753        int i = 0;
    896754        paParms[i++].setUInt32(uContextID);
     
    900758
    901759        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         }
    907760    }
    908761
    909762    if (RT_SUCCESS(vrc))
    910763    {
    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    }
    956769
    957770    LogFlowFuncLeaveRC(vrc);
     
    970783        /* Do not allow overwriting an already set error. If this happens
    971784         * 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));
    973786    }
    974787    else
    975788        AssertMsg(RT_SUCCESS(procRc), ("Guest rc must not be an error (%Rrc)\n", procRc));
    976789
    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    }
    979807
    980808    return VINF_SUCCESS;
     
    988816
    989817    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;
    1004818}
    1005819
     
    1013827    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    1014828
    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);
    1028834    if (RT_SUCCESS(vrc))
    1029835    {
    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;
    1041837        AssertPtr(pSession);
    1042838
     
    1088884        if (RT_SUCCESS(vrc))
    1089885        {
    1090             AssertPtr(mObject.mSession);
    1091             uint32_t uProtocol = mObject.mSession->getProtocolVersion();
     886            AssertPtr(mSession);
     887            uint32_t uProtocol = mSession->getProtocolVersion();
    1092888
    1093889            /* Prepare HGCM call. */
     
    1151947        if (RT_SUCCESS(vrc))
    1152948        {
    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    }
    1183953
    1184954    LogFlowFuncLeaveRC(vrc);
     
    12451015    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    12461016
    1247     if (mObject.mSession->getProtocolVersion() < 2)
     1017    AssertPtr(mSession);
     1018    if (mSession->getProtocolVersion() < 99)
    12481019        return VERR_NOT_SUPPORTED;
    12491020
     
    12511022        return VINF_SUCCESS; /* Nothing to do (anymore). */
    12521023
    1253     int vrc = VINF_SUCCESS;
    1254 
    1255     GuestCtrlCallback *pCallbackTerminate = NULL;
    1256     try
    1257     {
    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. */
    12661024    uint32_t uContextID;
     1025    int vrc = generateContextID(mSession->getId(), mObjectID,
     1026                                &uContextID);
    12671027    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];
    12761030        int i = 0;
    12771031        paParms[i++].setUInt32(uContextID);
    12781032        paParms[i++].setUInt32(mData.mPID);
    12791033
    1280         //vrc = sendCommand(HOST_EXEC_TERMINATE, i, paParms);
     1034        vrc = sendCommand(HOST_EXEC_TERMINATE, i, paParms);
    12811035    }
    12821036
    12831037    if (RT_SUCCESS(vrc))
    12841038    {
    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    }
    13141045
    13151046    LogFlowFuncLeaveRC(vrc);
     
    13231054    AssertReturn(fWaitFlags, VERR_INVALID_PARAMETER);
    13241055
    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));*/
    13271058
    13281059    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     
    14191150
    14201151    /* 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)
    14231157    {
    14241158        if (   waitResult == ProcessWaitResult_None
     
    14471181    }
    14481182
    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);
    14641187    if (RT_SUCCESS(vrc))
    14651188    {
    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
     1224int 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
     1348int 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
     1475int 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;
    14961609
    14971610    LogFlowFuncLeaveRC(vrc);
     
    15171630    }
    15181631
    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);
    15421635    if (RT_SUCCESS(vrc))
    15431636    {
     
    15521645
    15531646        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         }
    15591647    }
    15601648
    15611649    if (RT_SUCCESS(vrc))
    15621650    {
    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    }
    16231665
    16241666    LogFlowFuncLeaveRC(vrc);
     
    17131755    }
    17141756
    1715     AssertPtr(mObject.mSession);
    1716     mObject.mSession->processRemoveFromList(this);
     1757    AssertPtr(mSession);
     1758    mSession->processRemoveFromList(this);
    17171759
    17181760    /*
  • trunk/src/VBox/Main/src-client/GuestSessionImpl.cpp

    r45109 r45415  
    2222*******************************************************************************/
    2323#include "GuestImpl.h"
     24#include "GuestErrorInfoImpl.h"
    2425#include "GuestSessionImpl.h"
    2526#include "GuestCtrlImplPrivate.h"
     
    2829#include "AutoCaller.h"
    2930#include "ProgressImpl.h"
     31#include "VBoxEvents.h"
    3032#include "VMMDev.h"
    3133
    3234#include <memory> /* For auto_ptr. */
    3335
     36#include <iprt/cpp/utils.h> /* For unconst(). */
    3437#include <iprt/env.h>
    3538#include <iprt/file.h> /* For CopyTo/From. */
    3639
    3740#include <VBox/com/array.h>
     41#include <VBox/com/listeners.h>
    3842#include <VBox/version.h>
    3943
     
    9195    mData.mRC = VINF_SUCCESS;
    9296    mData.mStatus = GuestSessionStatus_Undefined;
    93 
    94     mData.mWaitCount = 0;
    95     mData.mWaitEvent = NULL;
    9697
    9798    return BaseFinalConstruct();
     
    128129    AssertReturn(autoInitSpan.isOk(), VERR_OBJECT_DESTROYED);
    129130
    130     mData.mParent = pGuest;
     131    mParent = pGuest;
    131132
    132133    /* Copy over startup info. */
     
    149150    if (RT_SUCCESS(rc))
    150151    {
     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    {
    151161        /* Confirm a successful initialization when it's the case. */
    152162        autoInitSpan.setSucceeded();
     
    174184    int rc = VINF_SUCCESS;
    175185
    176 #ifndef VBOX_WITH_GUEST_CONTROL
     186#ifdef VBOX_WITH_GUEST_CONTROL
    177187    LogFlowThisFunc(("Closing directories (%RU64 total)\n",
    178188                     mData.mDirectories.size()));
     
    180190         itDirs != mData.mDirectories.end(); ++itDirs)
    181191    {
    182 #ifdef DEBUG
     192# ifdef DEBUG
    183193        ULONG cRefs = (*itDirs)->AddRef();
    184         LogFlowThisFunc(("pFile=%p, cRefs=%RU32\n", (*itDirs), cRefs));
     194        LogFlowThisFunc(("pFile=%p, cRefs=%RU32\n", (*itDirs), cRefs - 1));
    185195        (*itDirs)->Release();
    186 #endif
     196# endif
    187197        (*itDirs)->uninit();
    188198    }
     
    194204         itFiles != mData.mFiles.end(); ++itFiles)
    195205    {
    196 #ifdef DEBUG
    197         ULONG cRefs = (*itFiles)->AddRef();
    198         LogFlowThisFunc(("pFile=%p, cRefs=%RU32\n", (*itFiles), cRefs));
    199         (*itFiles)->Release();
    200 #endif
    201         (*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();
    202212    }
    203213    mData.mFiles.clear();
     
    208218         itProcs != mData.mProcesses.end(); ++itProcs)
    209219    {
    210 #ifdef DEBUG
     220# ifdef DEBUG
    211221        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));
    213223        itProcs->second->Release();
    214 #endif
     224# endif
    215225        itProcs->second->uninit();
    216226    }
     
    218228
    219229    LogFlowThisFunc(("mNumObjects=%RU32\n", mData.mNumObjects));
    220 #endif
     230
     231    unconst(mEventSource).setNull();
     232
     233#endif /* VBOX_WITH_GUEST_CONTROL */
    221234    LogFlowFuncLeaveRC(rc);
    222235}
     
    495508}
    496509
     510STDMETHODIMP 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
    497523// private methods
    498524///////////////////////////////////////////////////////////////////////////////
     
    501527{
    502528    LogFlowThisFunc(("uFlags=%x, uTimeoutMS=%RU32\n", uFlags, uTimeoutMS));
     529
     530    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    503531
    504532    /* Legacy Guest Additions don't support opening dedicated
     
    512540    /** @todo uFlags validation. */
    513541
    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);
    523548    if (RT_SUCCESS(vrc))
    524549    {
    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    }
    567571
    568572    LogFlowFuncLeaveRC(vrc);
     
    813817
    814818#ifdef DEBUG
    815     LogFlowThisFunc(("ID=%RU32, uContextID=%RU32, uFunction=%RU32, pSvcCb=%p\n",
     819    LogFlowThisFunc(("sessionID=%RU32, CID=%RU32, uFunction=%RU32, pSvcCb=%p\n",
    816820                     mData.mSession.mID, pCbCtx->uContextID, pCbCtx->uFunction, pSvcCb));
    817821#endif
     
    821825    {
    822826        case GUEST_DISCONNECTED:
    823             /** @todo Handle closing all processes. */
     827            /** @todo Handle closing all guest objects. */
    824828            break;
    825829
    826830        case GUEST_SESSION_NOTIFY:
    827831        {
    828             rc = onSessionStatusChange(pCbCtx,
    829                                        &mData.mCallback, pSvcCb);
     832            rc = onSessionStatusChange(pCbCtx, pSvcCb);
    830833            break;
    831834        }
     
    960963        return VERR_COM_UNEXPECTED;
    961964
    962     Console *pConsole = mData.mParent->getConsole();
     965    Console *pConsole = mParent->getConsole();
    963966    AssertPtr(pConsole);
    964967
     
    11031106
    11041107        case VERR_MAX_PROCS_REACHED:
    1105             strError += Utf8StrFmt(tr("Maximum number of parallel guest processes has been reached"));
     1108            strError += Utf8StrFmt(tr("Maximum number of concurrent guest processes has been reached"));
    11061109            break;
    11071110
     
    11221125}
    11231126
     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 */
     1133HRESULT 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
    11241144/** No locking! */
    1125 int GuestSession::onSessionStatusChange(PVBOXGUESTCTRLHOSTCBCTX pCbCtx,
    1126                                         GuestCtrlCallback *pCallback, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
    1127 {
     1145int GuestSession::onSessionStatusChange(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
     1146{
     1147    AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
    11281148    /* pCallback is optional. */
    11291149    AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);
     
    11371157    pSvcCbData->mpaParms[2].getUInt32(&dataCb.uResult);
    11381158
    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));
    11411161
    11421162    int vrc = VINF_SUCCESS;
     1163
     1164    GuestSessionStatus_T sessionStatus = GuestSessionStatus_Undefined;
    11431165
    11441166    int guestRc = dataCb.uResult; /** @todo uint32_t vs. int. */
     
    11461168    {
    11471169        case GUEST_SESSION_NOTIFYTYPE_ERROR:
    1148             mData.mStatus = GuestSessionStatus_Error;
     1170            sessionStatus = GuestSessionStatus_Error;
    11491171            break;
    11501172
    11511173        case GUEST_SESSION_NOTIFYTYPE_STARTED:
    1152             mData.mStatus = GuestSessionStatus_Started;
     1174            sessionStatus = GuestSessionStatus_Started;
    11531175            break;
    11541176
     
    11561178        case GUEST_SESSION_NOTIFYTYPE_TES:
    11571179        case GUEST_SESSION_NOTIFYTYPE_TEA:
    1158             mData.mStatus = GuestSessionStatus_Terminated;
     1180            sessionStatus = GuestSessionStatus_Terminated;
    11591181            break;
    11601182
    11611183        case GUEST_SESSION_NOTIFYTYPE_TOK:
    1162             mData.mStatus = GuestSessionStatus_TimedOutKilled;
     1184            sessionStatus = GuestSessionStatus_TimedOutKilled;
    11631185            break;
    11641186
    11651187        case GUEST_SESSION_NOTIFYTYPE_TOA:
    1166             mData.mStatus = GuestSessionStatus_TimedOutAbnormally;
     1188            sessionStatus = GuestSessionStatus_TimedOutAbnormally;
    11671189            break;
    11681190
    11691191        case GUEST_SESSION_NOTIFYTYPE_DWN:
    1170             mData.mStatus = GuestSessionStatus_Down;
     1192            sessionStatus = GuestSessionStatus_Down;
    11711193            break;
    11721194
     1195        case GUEST_SESSION_NOTIFYTYPE_UNDEFINED:
    11731196        default:
    11741197            vrc = VERR_NOT_SUPPORTED;
     
    11791202    {
    11801203        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));
    12021216
    12031217    LogFlowFuncLeaveRC(vrc);
     
    12091223    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    12101224
    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));
    12131228
    12141229    /* Legacy Guest Additions don't support opening dedicated
     
    12221237    }
    12231238
     1239    if (mData.mStatus != GuestSessionStatus_Undefined)
     1240        return VINF_SUCCESS;
     1241
    12241242    /** @todo mData.mSession.uFlags validation. */
    12251243
     
    12271245    mData.mStatus = GuestSessionStatus_Starting;
    12281246
    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);
    12361250    if (RT_SUCCESS(vrc))
    12371251    {
    1238         uint32_t uContextID =
    1239             VBOX_GUESTCTRL_CONTEXTID_MAKE(mData.mSession.mID /* Session ID */,
    1240                                           0 /* Object */, 0 /* Count */);
    1241 
    12421252        VBOXHGCMSVCPARM paParms[8];
    12431253
     
    12581268    if (RT_SUCCESS(vrc))
    12591269    {
    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    }
    12861275
    12871276    LogFlowFuncLeaveRC(vrc);
     
    13441333int GuestSession::processRemoveFromList(GuestProcess *pProcess)
    13451334{
    1346     LogFlowThisFuncEnter();
     1335    AssertPtrReturn(pProcess, VERR_INVALID_POINTER);
     1336
     1337    LogFlowThisFunc(("pProcess=%p\n", pProcess));
    13471338
    13481339    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     
    13521343    ULONG uPID;
    13531344    HRESULT hr = pProcess->COMGETTER(PID)(&uPID);
     1345    ComAssertComRC(hr);
    13541346
    13551347    LogFlowFunc(("Closing process (PID=%RU32) ...\n", uPID));
    13561348
    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())
    13591351    {
    13601352        if (pProcess == itProcs->second)
     
    13671359
    13681360            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"));
    13721365            mData.mProcesses.erase(itProcs);
    13731366            mData.mNumObjects--;
    13741367
     1368            LogFlowFunc(("2\n"));
     1369            fireGuestProcessRegisteredEvent(mEventSource, this /* Session */, NULL /* Process */,
     1370                                            uPID, false /* Process unregistered */);
     1371            LogFlowFunc(("3\n"));
    13751372            rc = VINF_SUCCESS;
    13761373            break;
    13771374        }
     1375
     1376        LogFlowFunc(("4\n"));
     1377        itProcs++;
    13781378    }
    13791379
     
    14751475        return VERR_COM_UNEXPECTED;
    14761476
    1477     rc = pProcess->init(mData.mParent->getConsole() /* Console */, this /* Session */,
     1477    rc = pProcess->init(mParent->getConsole() /* Console */, this /* Session */,
    14781478                        uNewProcessID, procInfo);
    14791479    if (RT_FAILURE(rc))
     
    14851485    Assert(mData.mNumObjects <= VBOX_GUESTCTRL_MAX_OBJECTS);
    14861486
     1487    fireGuestProcessRegisteredEvent(mEventSource, this /* Session */, pProcess,
     1488                                    0 /* PID */, true /* Process registered */);
     1489
    14871490    LogFlowFunc(("Added new process (Session: %RU32) with process ID=%RU32 (now total %ld processes, %ld objects)\n",
    14881491                 mData.mSession.mID, uNewProcessID, mData.mProcesses.size(), mData.mNumObjects));
     
    15371540
    15381541#ifndef VBOX_GUESTCTRL_TEST_CASE
    1539     ComObjPtr<Console> pConsole = mData.mParent->getConsole();
     1542    ComObjPtr<Console> pConsole = mParent->getConsole();
    15401543    Assert(!pConsole.isNull());
    15411544
     
    15651568
    15661569    return pInterface->setError(VBOX_E_IPRT_ERROR, GuestSession::guestErrorToString(guestRc).c_str());
     1570}
     1571
     1572/* Does not do locking; caller is responsible for that! */
     1573int 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
     1606int 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;
    15671618}
    15681619
     
    16211672     * This is done using the Guest Additions version
    16221673     */
    1623     ComObjPtr<Guest> pGuest = mData.mParent;
     1674    ComObjPtr<Guest> pGuest = mParent;
    16241675    Assert(!pGuest.isNull());
    16251676
     
    16471698    AssertReturn(fWaitFlags, VERR_INVALID_PARAMETER);
    16481699
    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));*/
    16511702
    16521703    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     
    17371788    }
    17381789
    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);
    17541794    if (RT_SUCCESS(vrc))
    17551795    {
    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
     1829int 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;
    17861956
    17871957    LogFlowFuncLeaveRC(vrc);
     
    18101980
    18111981    /* Remove ourselves from the session list. */
    1812     int rc2 = mData.mParent->sessionRemove(this);
     1982    int rc2 = mParent->sessionRemove(this);
    18131983    if (RT_SUCCESS(rc))
    18141984        rc = rc2;
     
    18281998
    18291999        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);
    18312001    }
    18322002
     
    24662636    if (FAILED(autoCaller.rc())) return autoCaller.rc();
    24672637
     2638    HRESULT hr = isReadyExternal();
     2639    if (FAILED(hr))
     2640        return hr;
     2641
    24682642    /** @todo Validate open mode. */
    24692643    /** @todo Validate disposition mode. */
     
    24712645    /** @todo Validate creation mode. */
    24722646    uint32_t uCreationMode = 0;
    2473 
    2474     HRESULT hr = S_OK;
    24752647
    24762648    GuestFileOpenInfo openInfo;
     
    26602832    AutoCaller autoCaller(this);
    26612833    if (FAILED(autoCaller.rc())) return autoCaller.rc();
     2834
     2835    HRESULT hr = isReadyExternal();
     2836    if (FAILED(hr))
     2837        return hr;
    26622838
    26632839    GuestProcessStartupInfo procInfo;
     
    26882864    }
    26892865
    2690     HRESULT hr = S_OK;
    2691 
    26922866    if (RT_SUCCESS(rc))
    26932867    {
     
    27322906        {
    27332907            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"),
    27352909                                                    VBOX_GUESTCTRL_MAX_OBJECTS);
    27362910                break;
  • trunk/src/VBox/Main/testcase/tstGuestCtrlContextID.cpp

    r44863 r45415  
    3535{
    3636    RTTEST hTest;
    37     int rc = RTTestInitAndCreate("tstMakeup", &hTest);
     37    int rc = RTTestInitAndCreate("tstGuestCtrlContextID", &hTest);
    3838    if (rc)
    3939        return rc;
     
    7676    RTTestIPrintf(RTTESTLVL_DEBUG, "Max context is: %RU32\n", uContextMax);
    7777
    78     /* Do 64 tests 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++)
    8080    {
    8181        /* VBOX_GUESTCTRL_MAX_* includes 0 as an object, so subtract one. */
Note: See TracChangeset for help on using the changeset viewer.

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