VirtualBox

Ignore:
Timestamp:
Feb 18, 2014 2:57:35 PM (11 years ago)
Author:
vboxsync
Message:

Additions/x11/VBoxClient: add VT monitoring to seamless service.

Location:
trunk/src/VBox/Additions/x11/VBoxClient
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Additions/x11/VBoxClient/seamless.cpp

    r50471 r50495  
    3636    mX11MonitorThread = NIL_RTTHREAD;
    3737    mX11MonitorThreadStopping = false;
     38    mMode = VMMDev_Seamless_Disabled;
     39    mfPaused = false;
    3840}
    3941
     
    4547
    4648/**
    47  * Start the main service thread which listens for host state change
     49 * initialise the service.
     50 */
     51int SeamlessMain::init(void)
     52{
     53    int rc;
     54    const char *pcszStage;
     55
     56    LogRelFlowFunc(("\n"));
     57    do {
     58        pcszStage = "Connecting to the X server";
     59        rc = mX11Monitor.init(this);
     60        if (RT_FAILURE(rc))
     61            break;
     62        pcszStage = "Setting guest IRQ filter mask";
     63        rc = VbglR3CtlFilterMask(VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST, 0);
     64        if (RT_FAILURE(rc))
     65            break;
     66        pcszStage = "Reporting support for seamless capability";
     67        rc = VbglR3SeamlessSetCap(true);
     68        if (RT_FAILURE(rc))
     69            break;
     70    } while(0);
     71    if (RT_FAILURE(rc))
     72        LogRel(("VBoxClient (seamless): failed to start.  Stage: \"%s\"  Error: %Rrc\n",
     73                pcszStage, rc));
     74    return rc;
     75}
     76
     77/**
     78 * Run the main service thread which listens for host state change
    4879 * notifications.
    4980 * @returns iprt status value.  Service will be set to the stopped state on
    5081 *          failure.
    5182 */
    52 int SeamlessMain::start(void)
    53 {
    54     int rc;
    55     const char *pszStage;
    56 
    57     LogRelFlowFunc(("\n"));
    58     do {
    59         pszStage = "Testing event loop cancellation";
    60         VbglR3InterruptEventWaits();
    61         if (RT_FAILURE(VbglR3WaitEvent(VMMDEV_EVENT_VALID_EVENT_MASK, 0, NULL)))
    62             break;
    63         if (   VbglR3WaitEvent(VMMDEV_EVENT_VALID_EVENT_MASK, 0, NULL)
    64             != VERR_TIMEOUT)
    65             break;
    66         pszStage = "Connecting to the X server";
    67         rc = mX11Monitor.init(this);
    68         if (RT_FAILURE(rc))
    69             break;
    70         pszStage = "Setting guest IRQ filter mask";
    71         rc = VbglR3CtlFilterMask(VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST, 0);
    72         if (RT_FAILURE(rc))
    73             break;
    74         pszStage = "Reporting support for seamless capability";
    75         rc = VbglR3SeamlessSetCap(true);
    76         if (RT_FAILURE(rc))
    77             break;
    78         pszStage = "Running event loop";
    79         /* This will only exit if something goes wrong. */
    80         /** @todo Add a "stopping" variable.  Actually "pausing" the service
    81          * should be enough. */
    82         while (RT_SUCCESS(rc) || rc == VERR_TRY_AGAIN || rc == VERR_INTERRUPTED)
    83         {
    84             if (RT_FAILURE(rc))
    85                 /* If we are not stopping, sleep for a bit to avoid using up too
    86                     much CPU while retrying. */
    87                 RTThreadYield();
    88             rc = nextStateChangeEvent();
    89         }
    90     } while(0);
    91     if (RT_FAILURE(rc))
    92     {
    93         LogRel(("VBoxClient (seamless): failed to start.  Stage: \"%s\"  Error: %Rrc\n",
    94                 pszStage, rc));
     83int SeamlessMain::run(void)
     84{
     85    int rc = VINF_SUCCESS;
     86
     87    LogRelFlowFunc(("\n"));
     88    /* This will only exit if something goes wrong. */
     89    while (RT_SUCCESS(rc) || rc == VERR_INTERRUPTED)
     90    {
     91        if (RT_FAILURE(rc))
     92            /* If we are not stopping, sleep for a bit to avoid using up too
     93                much CPU while retrying. */
     94            RTThreadYield();
     95        rc = nextStateChangeEvent();
     96    }
     97    if (RT_FAILURE(rc))
     98    {
     99        LogRel(("VBoxClient (seamless): event loop failed with error: %Rrc\n",
     100                rc));
    95101        stop();
    96102    }
    97     LogRelFlowFunc(("returning %Rrc\n", rc));
    98103    return rc;
    99104}
     
    123128    if (RT_SUCCESS(rc))
    124129    {
    125         switch(newMode)
     130        mMode = newMode;
     131        switch (newMode)
    126132        {
    127133            case VMMDev_Seamless_Visible_Region:
    128             /* A simplified seamless mode, obtained by making the host VM window borderless and
    129               making the guest desktop transparent. */
    130                 LogRelFlowFunc(("VMMDev_Seamless_Visible_Region request received (VBoxClient).\n"));
    131                 /** @todo Do something on failure, like bail out. */
    132                 startX11MonitorThread();
     134            /* A simplified seamless mode, obtained by making the host VM window
     135             * borderless and making the guest desktop transparent. */
     136                LogRelFlowFunc(("\"Visible region\" mode requested (VBoxClient).\n"));
     137                break;
     138            case VMMDev_Seamless_Disabled:
     139                LogRelFlowFunc(("\"Disabled\" mode requested (VBoxClient).\n"));
    133140                break;
    134141            case VMMDev_Seamless_Host_Window:
    135142            /* One host window represents one guest window.  Not yet implemented. */
    136                 LogRelFunc(("Warning: VMMDev_Seamless_Host_Window request received (VBoxClient).\n"));
    137                 /* fall through to default */
     143                LogRelFunc(("Unsupported \"host window\" mode requested (VBoxClient).\n"));
     144                return VERR_NOT_SUPPORTED;
    138145            default:
    139                 LogRelFunc(("Warning: unsupported VMMDev_Seamless request %d received (VBoxClient).\n", newMode));
    140                 /* fall through to case VMMDev_Seamless_Disabled */
    141             case VMMDev_Seamless_Disabled:
    142                 LogRelFlowFunc(("VMMDev_Seamless_Disabled set (VBoxClient).\n"));
    143                 stopX11MonitorThread();
     146                LogRelFunc(("Unsupported mode %d requested (VBoxClient).\n",
     147                            newMode));
     148                return VERR_NOT_SUPPORTED;
    144149        }
    145150    }
     151    if (RT_SUCCESS(rc) || rc == VERR_TRY_AGAIN)
     152    {
     153        if (mMode == VMMDev_Seamless_Visible_Region && !mfPaused)
     154            /* This does it's own logging on failure. */
     155            rc = startX11MonitorThread();
     156        else
     157            /* This does it's own logging on failure. */
     158            rc = stopX11MonitorThread();
     159    }
    146160    else
    147161    {
     
    150164    LogRelFlowFunc(("returning %Rrc\n", rc));
    151165    return rc;
     166}
     167
     168int SeamlessMain::cancelEvent(void)
     169{
     170    return VbglR3InterruptEventWaits();
    152171}
    153172
     
    196215
    197216    mX11MonitorThreadStopping = false;
     217    if (isX11MonitorThreadRunning())
     218        return VINF_SUCCESS;
    198219    rc = RTThreadCreate(&mX11MonitorThread, x11MonitorThread, this, 0,
    199220                        RTTHREADTYPE_MSG_PUMP, RTTHREADFLAGS_WAITABLE,
     
    207228 * Send a signal to the thread function that it should exit
    208229 */
    209 void SeamlessMain::stopX11MonitorThread(void)
     230int SeamlessMain::stopX11MonitorThread(void)
    210231{
    211232    int rc;
    212233
    213234    mX11MonitorThreadStopping = true;
    214     if (!mX11MonitorThread)
    215         return;
     235    if (!isX11MonitorThreadRunning())
     236        return VINF_SUCCESS;
    216237    mX11Monitor.interruptEventWait();
    217238    rc = RTThreadWait(mX11MonitorThread, RT_INDEFINITE_WAIT, NULL);
     
    221242        LogRelThisFunc(("Failed to stop X11 monitor thread, rc=%Rrc!\n",
    222243                        rc));
    223 }
    224 
    225 /** @todo Re-arrange the service to support pausing and resuming.  The state
    226  * needs to become more complex: we need to know: whether seamless is currently
    227  * requested by the host; whether we are currently in charge of the guest
    228  * desktop; whether the guest monitoring thead is currently active. */
     244    return rc;
     245}
     246
     247/** Pause the service loop. */
     248int SeamlessMain::pause()
     249{
     250    int rc;
     251    const char *pcszStage;
     252
     253    LogRelFlowFunc(("\n"));
     254    mfPaused = true;
     255    do {
     256        pcszStage = "Reporting end of support for seamless capability";
     257        rc = VbglR3SeamlessSetCap(false);
     258        if (RT_FAILURE(rc))
     259            break;
     260        pcszStage = "Interrupting the event loop";
     261        rc = cancelEvent();
     262        if (RT_FAILURE(rc))
     263            break;
     264    } while (0);
     265    if (RT_FAILURE(rc))
     266        LogRelFunc(("Failure.  Stage: \"%s\"  Error: %Rrc (VBoxClient)\n",
     267                    pcszStage, rc));
     268    return rc;
     269}
     270
     271/** Resume after pausing. */
     272int SeamlessMain::resume()
     273{
     274    int rc;
     275    const char *pcszStage;
     276
     277    LogRelFlowFunc(("\n"));
     278    mfPaused = false;
     279    do {
     280        pcszStage = "Reporting support for seamless capability";
     281        rc = VbglR3SeamlessSetCap(true);
     282        if (RT_FAILURE(rc))
     283            break;
     284        pcszStage = "Interrupting the event loop";
     285        rc = cancelEvent();
     286        if (RT_FAILURE(rc))
     287            break;
     288    } while (0);
     289    if (RT_FAILURE(rc))
     290        LogRelFunc(("Failure.  Stage: \"%s\"  Error: %Rrc (VBoxClient)\n",
     291                    pcszStage, rc));
     292    return rc;
     293}
     294
     295/** @todo Expand this? */
     296int SeamlessMain::selfTest()
     297{
     298    int rc = VERR_INTERNAL_ERROR;
     299    const char *pcszStage;
     300
     301    LogRelFlowFunc(("\n"));
     302    do {
     303        pcszStage = "Testing event loop cancellation";
     304        VbglR3InterruptEventWaits();
     305        if (RT_FAILURE(VbglR3WaitEvent(VMMDEV_EVENT_VALID_EVENT_MASK, 0, NULL)))
     306            break;
     307        if (   VbglR3WaitEvent(VMMDEV_EVENT_VALID_EVENT_MASK, 0, NULL)
     308            != VERR_TIMEOUT)
     309            break;
     310        pcszStage = "Testing pause";  /* Other states are dangerous to test. */
     311        mMode = VMMDev_Seamless_Visible_Region;
     312        pause();
     313        if (RT_FAILURE(nextStateChangeEvent()))
     314            break;
     315        if (isX11MonitorThreadRunning())
     316            break;
     317        mMode = VMMDev_Seamless_Disabled;
     318        mfPaused = false;
     319        rc = VINF_SUCCESS;
     320    } while(0);
     321    if (RT_FAILURE(rc))
     322        LogRel(("VBoxClient (seamless): self test failed.  Stage: \"%s\"\n",
     323                pcszStage));
     324    return rc;
     325}
     326
    229327/** VBoxClient service class wrapping the logic for the seamless service while
    230328 *  the main VBoxClient code provides the daemon logic needed by all services.
     
    240338        return ".vboxclient-seamless.pid";
    241339    }
    242     virtual int run(bool fDaemonised /* = false */)
     340    virtual int init()
    243341    {
    244342        int rc;
     343
    245344        if (mIsInitialised)
    246345            return VERR_INTERNAL_ERROR;
     346        rc = mSeamless.init();
     347        if (RT_FAILURE(rc))
     348            return rc;
     349        rc = mSeamless.selfTest();
     350        if (RT_FAILURE(rc))
     351        {
     352            mSeamless.stop();
     353            return rc;
     354        }
    247355        mIsInitialised = true;
    248         rc = mSeamless.start();
    249         LogRelFunc(("VBoxClient: seamless service failed to start.  Error: %Rrc\n",
    250                     rc));
     356        return VINF_SUCCESS;
     357    }
     358    virtual int run(bool fDaemonised /* = false */)
     359    {
     360        int rc;
     361        if (!mIsInitialised)
     362            return VERR_INTERNAL_ERROR;
     363        /* This only exits on error. */
     364        rc = mSeamless.run();
     365        mIsInitialised = false;
    251366        return rc;
    252367    }
     368    virtual int pause() { return mSeamless.pause(); }
     369    virtual int resume() { return mSeamless.resume(); }
    253370    virtual void cleanup()
    254371    {
  • trunk/src/VBox/Additions/x11/VBoxClient/seamless.h

    r50471 r50495  
    4545    volatile bool mX11MonitorThreadStopping;
    4646
     47    /** The current seamless mode we are in. */
     48    VMMDevSeamlessMode mMode;
     49    /** Is the service currently paused? */
     50    volatile bool mfPaused;
     51
    4752    /**
    4853     * Waits for a seamless state change events from the host and dispatch it.  This is
     
    5459
    5560    /**
    56      * Interrupt an event wait and cause nextStateChangeEvent() to return immediately.
     61     * Interrupt an event wait and cause the current or next
     62     * @a nextStateChangeEvent call to return immediately.
    5763     */
    58     void cancelEvent(void) { VbglR3InterruptEventWaits(); }
     64    int cancelEvent(void);
    5965   
    6066    /** Thread function to monitor X11 window configuration changes. */
     
    6571
    6672    /** Helper to stop the X11 monitor thread again. */
    67     void stopX11MonitorThread(void);
     73    int stopX11MonitorThread(void);
     74   
     75    /** Is the service currently actively monitoring X11 windows? */
     76    bool isX11MonitorThreadRunning()
     77    {
     78        return mX11MonitorThread != NIL_RTTHREAD;
     79    }
    6880
    6981public:
     
    7284
    7385    /**
    74       * Start the service.
     86      * Initialise the service.
     87      */
     88    int init(void);
     89
     90    /**
     91      * Run the service.
    7592      * @returns iprt status value
    7693      */
    77     int start(void);
     94    int run(void);
    7895
    7996    /**
     
    8299    void stop();
    83100
     101    /** Pause the service loop.  This must be safe to call on a different thread
     102     * and potentially before @a run is or after it exits.
     103     * This is called by the VT monitoring thread to allow the service to disable
     104     * itself when the X server is switched out.  If the monitoring functionality
     105     * is available then @a pause or @a resume will be called as soon as it starts
     106     * up. */
     107    int pause();
     108    /** Resume after pausing.  The same applies here as for @a pause. */
     109    int resume();
     110
    84111    /**
    85112     * Update the set of visible rectangles in the host.
    86113     */
    87114    virtual void sendRegionUpdate(RTRECT *pRects, size_t cRects);
     115
     116    /** Run a few tests to be sure everything is working as intended. */
     117    int selfTest();
    88118};
    89119
  • trunk/src/VBox/Additions/x11/VBoxClient/testcase/tstSeamlessX11.cpp

    r50471 r50495  
    120120    SeamlessMain seamless;
    121121    LogRel(("Starting seamless Guest Additions...\n"));
    122     rc = seamless.start();
     122    rc = seamless.init();
    123123    if (rc != VINF_SUCCESS)
    124124    {
    125125        RTPrintf("Failed to initialise seamless Additions, rc = %Rrc\n", rc);
    126126    }
     127    rc = seamless.run();
     128    if (rc != VINF_SUCCESS)
     129    {
     130        RTPrintf("Failed to run seamless Additions, rc = %Rrc\n", rc);
     131    }
    127132    return rc;
    128133}
Note: See TracChangeset for help on using the changeset viewer.

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