VirtualBox

Ignore:
Timestamp:
Nov 12, 2020 10:15:18 AM (4 years ago)
Author:
vboxsync
Message:

Additions/VBoxClient: Big revamp of the internal service handling and termination fixes. A service now runs as part of a worker thread, while the main thread is used for initialization / shutdown and signal handling.

File:
1 edited

Legend:

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

    r82968 r86871  
    2222*   Header files                                                                                                                 *
    2323*********************************************************************************************************************************/
     24#include <new>
     25
    2426#include <X11/Xlib.h>
     27
     28#include <iprt/asm.h>
     29#include <iprt/errcore.h>
     30#include <iprt/mem.h>
    2531
    2632#include <VBox/log.h>
    2733#include <VBox/VBoxGuestLib.h>
    28 #include <iprt/errcore.h>
    29 #include <iprt/mem.h>
    3034
    3135#include "VBoxClient.h"
    3236#include "seamless.h"
    3337
    34 #include <new>
     38
     39/*********************************************************************************************************************************
     40*   Global Variables                                                                                                             *
     41*********************************************************************************************************************************/
     42
     43/**
     44 * Struct for keeping a service instance.
     45 */
     46struct SEAMLESSSERVICE
     47{
     48    /** Seamless service object. */
     49    SeamlessMain mSeamless;
     50};
     51
     52/** Service instance data. */
     53static SEAMLESSSERVICE g_Svc;
     54
    3555
    3656SeamlessMain::SeamlessMain(void)
    3757{
    38     LogRelFlowFuncEnter();
    39     mX11MonitorThread = NIL_RTTHREAD;
     58    mX11MonitorThread         = NIL_RTTHREAD;
    4059    mX11MonitorThreadStopping = false;
    41     mMode = VMMDev_Seamless_Disabled;
     60
     61    mMode    = VMMDev_Seamless_Disabled;
    4262    mfPaused = true;
    4363}
     
    4565SeamlessMain::~SeamlessMain()
    4666{
    47     LogRelFlowFuncEnter();
    48     stop();
     67    /* Stopping will be done via main.cpp. */
    4968}
    5069
     
    5473static void sendRegionUpdate(RTRECT *pRects, size_t cRects)
    5574{
    56     LogRelFlowFuncEnter();
    57     if (cRects && !pRects)  /* Assertion */
    58     {
    59         VBClLogError(("Region update called with NULL pointer!\n"));
     75    if (   cRects
     76        && !pRects)  /* Assertion */
     77    {
     78        VBClLogError(("Region update called with NULL pointer\n"));
    6079        return;
    6180    }
    6281    VbglR3SeamlessSendRects(cRects, pRects);
    63     LogRelFlowFuncLeave();
    64 }
    65 
    66 /**
    67  * initialise the service.
    68  */
     82}
     83
     84/** @copydoc VBCLSERVICE::pfnInit */
    6985int SeamlessMain::init(void)
    7086{
     
    7288    const char *pcszStage;
    7389
    74     LogRelFlowFuncEnter();
    75     do {
     90    do
     91    {
    7692        pcszStage = "Connecting to the X server";
    7793        rc = mX11Monitor.init(sendRegionUpdate);
     
    89105        if (RT_FAILURE(rc))
    90106            break;
     107
    91108    } while(0);
     109
    92110    if (RT_FAILURE(rc))
    93         VBClLogError("Failed to start in stage '%s' -- error: %Rrc\n", pcszStage, rc);
    94     return rc;
    95 }
    96 
    97 /**
    98  * Run the main service thread which listens for host state change
    99  * notifications.
    100  * @returns iprt status value.  Service will be set to the stopped state on
    101  *          failure.
    102  */
    103 int SeamlessMain::run(void)
     111        VBClLogError("Failed to start in stage '%s' -- error %Rrc\n", pcszStage, rc);
     112
     113    return rc;
     114}
     115
     116/** @copydoc VBCLSERVICE::pfnWorker */
     117int SeamlessMain::worker(bool volatile *pfShutdown)
    104118{
    105119    int rc = VINF_SUCCESS;
    106120
    107     LogRelFlowFuncEnter();
     121    /* Let the main thread know that it can continue spawning services. */
     122    RTThreadUserSignal(RTThreadSelf());
     123
    108124    /* This will only exit if something goes wrong. */
    109     while (RT_SUCCESS(rc) || rc == VERR_INTERRUPTED)
    110     {
    111         if (RT_FAILURE(rc))
    112             /* If we are not stopping, sleep for a bit to avoid using up too
    113                 much CPU while retrying. */
    114             RTThreadYield();
     125    for (;;)
     126    {
     127        if (ASMAtomicReadBool(pfShutdown))
     128            break;
     129
    115130        rc = nextStateChangeEvent();
    116     }
    117     if (RT_FAILURE(rc))
    118     {
    119         VBClLogError("Event loop failed with error: %Rrc\n", rc);
    120         stop();
    121     }
    122     return rc;
    123 }
    124 
    125 /** Stops the service. */
    126 void SeamlessMain::stop()
    127 {
    128     LogRelFlowFuncEnter();
     131
     132        if (rc == VERR_TRY_AGAIN)
     133            rc = VINF_SUCCESS;
     134
     135        if (RT_FAILURE(rc))
     136            break;
     137
     138        if (ASMAtomicReadBool(pfShutdown))
     139            break;
     140
     141        /* If we are not stopping, sleep for a bit to avoid using up too
     142           much CPU while retrying. */
     143        RTThreadYield();
     144    }
     145
     146    return rc;
     147}
     148
     149/** @copydoc VBCLSERVICE::pfnStop */
     150void SeamlessMain::stop(void)
     151{
    129152    VbglR3SeamlessSetCap(false);
    130153    VbglR3CtlFilterMask(0, VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST);
    131154    stopX11MonitorThread();
     155}
     156
     157/** @copydoc VBCLSERVICE::pfnTerm */
     158int SeamlessMain::term(void)
     159{
     160    int rc;
     161
     162    if (mX11MonitorThread)
     163    {
     164        rc = RTThreadWait(mX11MonitorThread, RT_MS_30SEC, NULL);
     165        if (RT_SUCCESS(rc))
     166        {
     167            mX11MonitorThread = NIL_RTTHREAD;
     168        }
     169        else
     170            VBClLogError("Failed to stop X11 monitor thread, rc=%Rrc\n", rc);
     171    }
     172    else
     173        rc = VINF_SUCCESS;
     174
    132175    mX11Monitor.uninit();
    133     LogRelFlowFuncLeave();
     176
     177    return rc;
    134178}
    135179
     
    137181 * Waits for a seamless state change events from the host and dispatch it.
    138182 *
    139  * @returns        IRPT return code.
     183 * @returns VBox return code, or
     184 *          VERR_TRY_AGAIN if no new status is available and we have to try it again
     185 *          at some later point in time.
    140186 */
    141187int SeamlessMain::nextStateChangeEvent(void)
     
    143189    VMMDevSeamlessMode newMode = VMMDev_Seamless_Disabled;
    144190
    145     LogRelFlowFuncEnter();
    146191    int rc = VbglR3SeamlessWaitEvent(&newMode);
    147192    if (RT_SUCCESS(rc))
     
    151196        {
    152197            case VMMDev_Seamless_Visible_Region:
    153             /* A simplified seamless mode, obtained by making the host VM window
    154              * borderless and making the guest desktop transparent. */
    155                 LogRelFlowFunc(("\"Visible region\" mode requested (VBoxClient)\n"));
     198                /* A simplified seamless mode, obtained by making the host VM window
     199                 * borderless and making the guest desktop transparent. */
     200                VBClLogVerbose(2, "\"Visible region\" mode requested\n");
    156201                break;
    157202            case VMMDev_Seamless_Disabled:
    158                 LogRelFlowFunc(("\"Disabled\" mode requested (VBoxClient)\n"));
     203                VBClLogVerbose(2, "\"Disabled\" mode requested\n");
    159204                break;
    160205            case VMMDev_Seamless_Host_Window:
    161             /* One host window represents one guest window.  Not yet implemented. */
    162                 LogRelFunc(("Unsupported \"host window\" mode requested (VBoxClient)\n"));
     206                /* One host window represents one guest window.  Not yet implemented. */
     207                VBClLogVerbose(2, "Unsupported \"host window\" mode requested\n");
    163208                return VERR_NOT_SUPPORTED;
    164209            default:
    165                 LogRelFunc(("Unsupported mode %d requested (VBoxClient)\n",
    166                             newMode));
     210                VBClLogError("Unsupported mode %d requested\n", newMode);
    167211                return VERR_NOT_SUPPORTED;
    168212        }
    169213    }
    170     if (RT_SUCCESS(rc) || rc == VERR_TRY_AGAIN)
     214    if (   RT_SUCCESS(rc)
     215        || rc == VERR_TRY_AGAIN)
    171216    {
    172217        if (mMode == VMMDev_Seamless_Visible_Region)
     
    177222    }
    178223    else
    179     {
    180         LogRelFunc(("VbglR3SeamlessWaitEvent returned %Rrc (VBoxClient)\n", rc));
    181     }
    182     LogRelFlowFuncLeaveRC(rc);
     224        VBClLogError("VbglR3SeamlessWaitEvent returned %Rrc\n", rc);
     225
    183226    return rc;
    184227}
     
    189232int SeamlessMain::x11MonitorThread(RTTHREAD hThreadSelf, void *pvUser)
    190233{
    191     RT_NOREF1(hThreadSelf);
    192     SeamlessMain *pHost = (SeamlessMain *)pvUser;
     234    RT_NOREF(hThreadSelf);
     235
     236    SeamlessMain *pThis = (SeamlessMain *)pvUser;
     237    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
     238
    193239    int rc = VINF_SUCCESS;
    194240
    195     LogRelFlowFuncEnter();
    196     while (!pHost->mX11MonitorThreadStopping)
    197     {
    198         if (!pHost->mfPaused)
     241    RTThreadUserSignal(hThreadSelf);
     242
     243    VBClLogVerbose(2, "X11 monitor thread started\n");
     244
     245    while (!pThis->mX11MonitorThreadStopping)
     246    {
     247        if (!pThis->mfPaused)
    199248        {
    200             rc = pHost->mX11Monitor.start();
     249            rc = pThis->mX11Monitor.start();
    201250            if (RT_FAILURE(rc))
    202251                VBClLogFatalError("Failed to change the X11 seamless service state, mfPaused=%RTbool, rc=%Rrc\n",
    203                                   pHost->mfPaused, rc);
     252                                  pThis->mfPaused, rc);
    204253        }
    205         pHost->mX11Monitor.nextConfigurationEvent();
    206         if (pHost->mfPaused || pHost->mX11MonitorThreadStopping)
    207             pHost->mX11Monitor.stop();
    208     }
    209     LogRelFlowFuncLeaveRC(rc);
     254
     255        pThis->mX11Monitor.nextConfigurationEvent();
     256
     257        if (   pThis->mfPaused
     258            || pThis->mX11MonitorThreadStopping)
     259        {
     260            pThis->mX11Monitor.stop();
     261        }
     262    }
     263
     264    VBClLogVerbose(2, "X11 monitor thread ended\n");
     265
    210266    return rc;
    211267}
     
    216272int SeamlessMain::startX11MonitorThread(void)
    217273{
    218     int rc;
    219 
    220274    mX11MonitorThreadStopping = false;
     275
    221276    if (isX11MonitorThreadRunning())
    222277        return VINF_SUCCESS;
    223     rc = RTThreadCreate(&mX11MonitorThread, x11MonitorThread, this, 0,
    224                         RTTHREADTYPE_MSG_PUMP, RTTHREADFLAGS_WAITABLE,
    225                         "X11 events");
     278
     279    int rc = RTThreadCreate(&mX11MonitorThread, x11MonitorThread, this, 0,
     280                            RTTHREADTYPE_MSG_PUMP, RTTHREADFLAGS_WAITABLE,
     281                            "seamless x11");
     282    if (RT_SUCCESS(rc))
     283        rc = RTThreadUserWait(mX11MonitorThread, RT_MS_30SEC);
     284
    226285    if (RT_FAILURE(rc))
    227         LogRelFunc(("Warning: failed to start X11 monitor thread (VBoxClient)\n"));
    228     return rc;
    229 }
    230 
    231 /**
    232  * Send a signal to the thread function that it should exit
     286        VBClLogError("Failed to start X11 monitor thread, rc=%Rrc\n", rc);
     287
     288    return rc;
     289}
     290
     291/**
     292 * Stops the monitor thread.
    233293 */
    234294int SeamlessMain::stopX11MonitorThread(void)
    235295{
    236     int rc;
    237 
    238     mX11MonitorThreadStopping = true;
    239296    if (!isX11MonitorThreadRunning())
    240297        return VINF_SUCCESS;
     298
     299    mX11MonitorThreadStopping = true;
    241300    mX11Monitor.interruptEventWait();
    242     rc = RTThreadWait(mX11MonitorThread, RT_INDEFINITE_WAIT, NULL);
     301
     302    int rcThread;
     303    int rc = RTThreadWait(mX11MonitorThread, RT_MS_30SEC, &rcThread);
    243304    if (RT_SUCCESS(rc))
     305        rc = rcThread;
     306
     307    if (RT_SUCCESS(rc))
     308    {
    244309        mX11MonitorThread = NIL_RTTHREAD;
     310    }
    245311    else
    246         LogRelThisFunc(("Failed to stop X11 monitor thread, rc=%Rrc!\n",
    247                         rc));
    248     return rc;
    249 }
    250 
    251 /** Service magic number, start of a UUID. */
    252 #define SEAMLESSSERVICE_MAGIC 0xd28ba727
    253 
    254 /** VBoxClient service class wrapping the logic for the seamless service while
    255  *  the main VBoxClient code provides the daemon logic needed by all services.
    256  */
    257 struct SEAMLESSSERVICE
    258 {
    259     /** The service interface. */
    260     struct VBCLSERVICE *pInterface;
    261     /** Magic number for sanity checks. */
    262     uint32_t magic;
    263     /** Seamless service object. */
    264     SeamlessMain mSeamless;
    265     /** Are we initialised yet? */
    266     bool mIsInitialised;
     312        VBClLogError("Waiting for X11 monitor thread to stop failed, rc=%Rrc\n", rc);
     313
     314    return rc;
     315}
     316
     317/** @copydoc VBCLSERVICE::pfnInit */
     318static int vbclSeamlessInit(void)
     319{
     320    return g_Svc.mSeamless.init();
     321}
     322
     323/** @copydoc VBCLSERVICE::pfnWorker */
     324static int vbclSeamlessWorker(bool volatile *pfShutdown)
     325{
     326    return g_Svc.mSeamless.worker(pfShutdown);
     327}
     328
     329/** @copydoc VBCLSERVICE::pfnStop */
     330static void vbclSeamlessStop(void)
     331{
     332    return g_Svc.mSeamless.stop();
     333}
     334
     335/** @copydoc VBCLSERVICE::pfnTerm */
     336static int vbclSeamlessTerm(void)
     337{
     338    return g_Svc.mSeamless.term();
     339}
     340
     341VBCLSERVICE g_SvcSeamless =
     342{
     343    "seamless",                 /* szName */
     344    "Seamless Mode Support",    /* pszDescription */
     345    ".vboxclient-seamless.pid", /* pszPidFilePath */
     346    NULL,                       /* pszUsage */
     347    NULL,                       /* pszOptions */
     348    NULL,                       /* pfnOption */
     349    vbclSeamlessInit,           /* pfnInit */
     350    vbclSeamlessWorker,         /* pfnWorker */
     351    vbclSeamlessStop,           /* pfnStop*/
     352    vbclSeamlessTerm            /* pfnTerm */
    267353};
    268354
    269 static const char *getName()
    270 {
    271     return "Seamless";
    272 }
    273 
    274 static const char *getPidFilePath(void)
    275 {
    276     return ".vboxclient-seamless.pid";
    277 }
    278 
    279 static struct SEAMLESSSERVICE *getClassFromInterface(struct VBCLSERVICE **
    280                                                          ppInterface)
    281 {
    282     struct SEAMLESSSERVICE *pSelf = (struct SEAMLESSSERVICE *)ppInterface;
    283     if (pSelf->magic != SEAMLESSSERVICE_MAGIC)
    284         VBClLogFatalError("Bad seamless service object!\n");
    285     return pSelf;
    286 }
    287 
    288 static int init(struct VBCLSERVICE **ppInterface)
    289 {
    290     struct SEAMLESSSERVICE *pSelf = getClassFromInterface(ppInterface);
    291 
    292     if (pSelf->mIsInitialised)
    293         return VERR_INTERNAL_ERROR;
    294 
    295     int rc = pSelf->mSeamless.init();
    296     if (RT_FAILURE(rc))
    297         return rc;
    298     pSelf->mIsInitialised = true;
    299     return VINF_SUCCESS;
    300 }
    301 
    302 static int run(struct VBCLSERVICE **ppInterface, bool fDaemonised)
    303 {
    304     RT_NOREF1(fDaemonised);
    305     struct SEAMLESSSERVICE *pSelf = getClassFromInterface(ppInterface);
    306     int rc;
    307 
    308     if (!pSelf->mIsInitialised)
    309         return VERR_INTERNAL_ERROR;
    310     /* This only exits on error. */
    311     rc = pSelf->mSeamless.run();
    312     pSelf->mIsInitialised = false;
    313     return rc;
    314 }
    315 
    316 static void cleanup(struct VBCLSERVICE **ppInterface)
    317 {
    318     RT_NOREF(ppInterface);
    319     VbglR3SeamlessSetCap(false);
    320     VbglR3Term();
    321 }
    322 
    323 struct VBCLSERVICE vbclSeamlessInterface =
    324 {
    325     getName,
    326     getPidFilePath,
    327     init,
    328     run,
    329     cleanup
    330 };
    331 
    332 struct VBCLSERVICE **VBClGetSeamlessService()
    333 {
    334     struct SEAMLESSSERVICE *pService =
    335         (struct SEAMLESSSERVICE *)RTMemAlloc(sizeof(*pService));
    336 
    337     if (!pService)
    338         VBClLogFatalError("Out of memory\n");
    339     pService->pInterface = &vbclSeamlessInterface;
    340     pService->magic = SEAMLESSSERVICE_MAGIC;
    341     new(&pService->mSeamless) SeamlessMain();
    342     pService->mIsInitialised = false;
    343     return &pService->pInterface;
    344 }
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