VirtualBox

Changeset 86871 in vbox


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.

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

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Additions/x11/VBoxClient/Makefile.kmk

    r85977 r86871  
    2121# Use header files from our tree for randr and xinerama. and don't link but rather dlopen libXrand
    2222VBOX_WITH_DISTRO_XRAND_XINERAMA=
     23
     24# We don't yet have a seamless mode compilation flag, so define it here unconditionally.
     25VBOX_WITH_SEAMLESS:=1
    2326
    2427#
     
    4649VBoxClient_SOURCES = \
    4750        main.cpp \
    48         display-svga-x11.cpp \
    49         seamless.cpp \
    50         seamless-x11.cpp \
    51         logging.cpp \
    52         hostversion.cpp
     51        logging.cpp
    5352
    5453VBoxDRMClient_TEMPLATE = NewVBoxGuestR3Exe
     
    8483ifdef VBOX_WITH_DRAG_AND_DROP
    8584 ifdef VBOX_DND_WITH_XTEST
    86  VBoxClient_DEFS += VBOX_DND_WITH_XTEST
    87  VBoxClient_LIBS += \
     85  VBoxClient_DEFS += VBOX_DND_WITH_XTEST
     86  VBoxClient_LIBS += \
    8887        Xtst
    8988 endif
     
    9493# how else to do that without recompiling or implementing our own memcpy.
    9594ifeq ($(KBUILD_TARGET),linux)
    96 VBoxClient_LDFLAGS.amd64 += \
     95 VBoxClient_LDFLAGS.amd64 += \
    9796        -Wl,--wrap=memcpy
    9897endif
    9998
    10099ifdef VBOX_WITH_GUEST_PROPS
    101 VBoxClient_DEFS += VBOX_WITH_GUEST_PROPS
     100 VBoxClient_DEFS    += VBOX_WITH_GUEST_PROPS
     101 VBoxClient_SOURCES += \
     102        hostversion.cpp
    102103endif
    103104
    104105ifdef VBOX_WITH_DRAG_AND_DROP
    105 VBoxClient_DEFS += \
     106 VBoxClient_DEFS    += \
    106107        VBOX_WITH_DRAG_AND_DROP \
    107108        $(if $(VBOX_WITH_DRAG_AND_DROP_GH),VBOX_WITH_DRAG_AND_DROP_GH,)
    108 VBoxClient_SOURCES += \
     109 VBoxClient_SOURCES += \
    109110        draganddrop.cpp
    110 VBoxClient_LIBS     += \
     111 VBoxClient_LIBS     += \
    111112        $(VBOX_LIB_VBGL_R3) \
    112113        $(PATH_STAGE_LIB)/additions/VBoxDnDGuestR3Lib$(VBOX_SUFF_LIB)
    113114endif
    114115
     116ifdef VBOX_WITH_SEAMLESS
     117 VBoxClient_DEFS    += VBOX_WITH_SEAMLESS
     118 VBoxClient_SOURCES += \
     119        seamless.cpp \
     120        seamless-x11.cpp
     121endif
     122
     123ifdef VBOX_WITH_VMSVGA
     124 VBoxClient_DEFS    += VBOX_WITH_VMSVGA
     125 VBoxClient_SOURCES += \
     126        display-svga-x11.cpp
     127endif
     128
    115129ifdef VBOX_WITH_SHARED_CLIPBOARD
    116  VBoxClient_DEFS += \
     130 VBoxClient_DEFS     += \
    117131        VBOX_WITH_SHARED_CLIPBOARD \
    118132        $(if $(VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS),VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS,)
    119  VBoxClient_SOURCES += \
     133 VBoxClient_SOURCES  += \
    120134        $(PATH_ROOT)/src/VBox/GuestHost/SharedClipboard/clipboard-common.cpp \
    121135        $(PATH_ROOT)/src/VBox/GuestHost/SharedClipboard/clipboard-x11.cpp \
     
    172186          seamless.cpp \
    173187          seamless-x11.cpp
     188  tstSeamlessX11_DEFS   += VBOX_BUILD_TARGET=\"$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)\"
    174189  tstSeamlessX11_LIBPATH = \
    175190          $(VBOX_LIBPATH_X11)
  • trunk/src/VBox/Additions/x11/VBoxClient/VBoxClient.h

    r84501 r86871  
    3030void VBClLogError(const char *pszFormat, ...);
    3131void VBClLogFatalError(const char *pszFormat, ...);
     32void VBClLogVerbose(unsigned iLevel, const char *pszFormat, ...);
     33
     34int VBClLogCreate(const char *pszLogFile);
    3235void VBClLogDestroy(void);
    33 int VBClLogCreate(const char *pszLogFile);
    3436
    3537/** Call clean-up for the current service and exit. */
    36 extern void VBClCleanUp(bool fExit = true);
     38extern void VBClShutdown(bool fExit = true);
    3739
    38 /** A simple interface describing a service.  VBoxClient will run exactly one
    39  * service per invocation. */
    40 struct VBCLSERVICE
     40/**
     41 * A service descriptor.
     42 */
     43typedef struct
    4144{
    42     /** Returns the (friendly) name of the service. */
    43     const char *(*getName)(void);
     45    /** The short service name. 16 chars maximum (RTTHREAD_NAME_LEN). */
     46    const char *pszName;
     47    /** The longer service name. */
     48    const char *pszDesc;
    4449    /** Get the services default path to pidfile, relative to $HOME */
    4550    /** @todo Should this also have a component relative to the X server number?
    4651     */
    47     const char *(*getPidFilePath)(void);
    48     /** Special initialisation, if needed.  @a pause and @a resume are
    49      * guaranteed not to be called until after this returns. */
    50     int (*init)(struct VBCLSERVICE **ppInterface);
    51     /** Run the service main loop */
    52     int (*run)(struct VBCLSERVICE **ppInterface, bool fDaemonised);
    53     /** Clean up any global resources before we shut down hard.  The last calls
    54      * to @a pause and @a resume are guaranteed to finish before this is called.
     52    const char *pszPidFilePath;
     53    /** The usage options stuff for the --help screen. */
     54    const char *pszUsage;
     55    /** The option descriptions for the --help screen. */
     56    const char *pszOptions;
     57
     58    /**
     59     * Tries to parse the given command line option.
     60     *
     61     * @returns 0 if we parsed, -1 if it didn't and anything else means exit.
     62     * @param   ppszShort   If not NULL it points to the short option iterator. a short argument.
     63     *                      If NULL examine argv[*pi].
     64     * @param   argc        The argument count.
     65     * @param   argv        The argument vector.
     66     * @param   pi          The argument vector index. Update if any value(s) are eaten.
    5567     */
    56     void (*cleanup)(struct VBCLSERVICE **ppInterface);
    57 };
     68    DECLCALLBACKMEMBER(int, pfnOption,(const char **ppszShort, int argc, char **argv, int *pi));
    5869
    59 /** Default handler for various struct VBCLSERVICE member functions. */
    60 DECLINLINE(int) VBClServiceDefaultHandler(struct VBCLSERVICE **pSelf)
    61 {
    62     RT_NOREF1(pSelf);
    63     return VINF_SUCCESS;
    64 }
     70    /**
     71     * Called before parsing arguments.
     72     * @returns VBox status code, or
     73     *          VERR_NOT_AVAILABLE if service is supported on this platform in general but not available at the moment.
     74     *          VERR_NOT_SUPPORTED if service is not supported on this platform. */
     75    DECLCALLBACKMEMBER(int, pfnInit,(void));
    6576
    66 /** Default handler for the struct VBCLSERVICE clean-up member function.
    67  * Usually used because the service is cleaned up automatically when the user
    68  * process/X11 exits. */
    69 DECLINLINE(void) VBClServiceDefaultCleanup(struct VBCLSERVICE **ppInterface)
    70 {
    71     RT_NOREF(ppInterface);
    72 }
     77    /** Called from the worker thread.
     78     *
     79     * @returns VBox status code.
     80     * @retval  VINF_SUCCESS if exitting because *pfShutdown was set.
     81     * @param   pfShutdown      Pointer to a per service termination flag to check
     82     *                          before and after blocking.
     83     */
     84    DECLCALLBACKMEMBER(int, pfnWorker,(bool volatile *pfShutdown));
    7385
    74 extern struct VBCLSERVICE **VBClGetClipboardService();
    75 extern struct VBCLSERVICE **VBClGetSeamlessService();
    76 extern struct VBCLSERVICE **VBClGetHostVersionService();
    77 #ifdef VBOX_WITH_DRAG_AND_DROP
    78 extern struct VBCLSERVICE **VBClGetDragAndDropService();
    79 #endif /* VBOX_WITH_DRAG_AND_DROP */
    80 extern struct VBCLSERVICE **VBClCheck3DService();
    81 extern struct VBCLSERVICE **VBClDisplaySVGAService();
    82 extern struct VBCLSERVICE **VBClDisplaySVGAX11Service();
     86    /**
     87     * Asks the service to stop.
     88     *
     89     * @remarks Will be called from the signal handler.
     90     */
     91    DECLCALLBACKMEMBER(void, pfnStop,(void));
     92
     93    /**
     94     * Does termination cleanups.
     95     *
     96     * @remarks This will be called even if pfnInit hasn't been called or pfnStop failed!
     97     */
     98    DECLCALLBACKMEMBER(int, pfnTerm,(void));
     99} VBCLSERVICE;
     100/** Pointer to a VBCLSERVICE. */
     101typedef VBCLSERVICE *PVBCLSERVICE;
     102/** Pointer to a const VBCLSERVICE. */
     103typedef VBCLSERVICE const *PCVBCLSERVICE;
     104
     105RT_C_DECLS_BEGIN
     106extern VBCLSERVICE g_SvcClipboard;
     107extern VBCLSERVICE g_SvcDisplayDRM;
     108extern VBCLSERVICE g_SvcDisplaySVGA;
     109extern VBCLSERVICE g_SvcDragAndDrop;
     110extern VBCLSERVICE g_SvcHostVersion;
     111extern VBCLSERVICE g_SvcSeamless;
     112
     113extern bool        g_fDaemonized;
     114RT_C_DECLS_END
    83115
    84116#endif /* !GA_INCLUDED_SRC_x11_VBoxClient_VBoxClient_h */
  • trunk/src/VBox/Additions/x11/VBoxClient/clipboard.cpp

    r85834 r86871  
    5858
    5959/**
    60  * Global clipboard context information.
     60 * Struct keeping a Shared Clipboard context.
    6161 */
    6262struct SHCLCONTEXT
     
    7575};
    7676
    77 /** Only one client is supported. There seems to be no need for more clients. */
     77/** Only one context is supported at a time for now. */
    7878static SHCLCONTEXT g_Ctx;
    7979
     
    258258int vboxClipboardMain(void)
    259259{
    260     LogRel(("Worker loop running\n"));
    261 
    262260    int rc;
    263261
     
    331329                case VBGLR3CLIPBOARDEVENTTYPE_QUIT:
    332330                {
    333                     LogRel2(("Host requested termination\n"));
     331                    VBClLogVerbose(2, "Host requested termination\n");
    334332                    fShutdown = true;
    335333                    break;
     
    368366    }
    369367
    370     LogRel(("Worker loop ended\n"));
    371 
    372368    LogFlowFuncLeaveRC(rc);
    373369    return rc;
     
    377373static DECLCALLBACK(int) vboxClipoardFUSEThread(RTTHREAD hThreadSelf, void *pvUser)
    378374{
    379     RT_NOREF(hThreadSelf, pvUser);
     375    RT_NOREF(pvUser);
    380376
    381377    VbglR3Init();
     
    409405    }
    410406    else
    411         LogRel(("Error creating FUSE mount directory, rc=%Rrc\n", rc));
    412 
    413     LogFlowFuncLeaveRC(rc);
    414     return rc;
    415 }
    416 
    417 static int vboxClipboardFUSEStart()
     407        VBClLogError("Error creating FUSE mount directory, rc=%Rrc\n", rc);
     408
     409    LogFlowFuncLeaveRC(rc);
     410    return rc;
     411}
     412
     413static int vboxClipboardFUSEStart(void)
    418414{
    419415    LogFlowFuncEnter();
     
    430426}
    431427
    432 static int vboxClipboardFUSEStop()
     428static int vboxClipboardFUSEStop(void)
    433429{
    434430    LogFlowFuncEnter();
     
    444440#endif /* VBOX_WITH_SHARED_CLIPBOARD_FUSE */
    445441
    446 static const char *getName()
    447 {
    448     return "Shared Clipboard";
    449 }
    450 
    451 static const char *getPidFilePath()
    452 {
    453     return ".vboxclient-clipboard.pid";
    454 }
    455 
    456 static int init(struct VBCLSERVICE **pSelf)
    457 {
    458     RT_NOREF(pSelf);
    459 
     442/** @copydoc VBCLSERVICE::pfnInit */
     443static int vbclShClInit(void)
     444{
    460445    int rc;
    461446
     
    470455}
    471456
    472 static int run(struct VBCLSERVICE **ppInterface, bool fDaemonised)
    473 {
    474     RT_NOREF(ppInterface, fDaemonised);
     457/** @copydoc VBCLSERVICE::pfnWorker */
     458static int vbclShClWorker(bool volatile *pfShutdown)
     459{
     460    RT_NOREF(pfShutdown);
    475461
    476462    /* Initialise the guest library. */
     
    483469        {
    484470#endif
     471            /* Let the main thread know that it can continue spawning services. */
     472            RTThreadUserSignal(RTThreadSelf());
     473
    485474            rc = vboxClipboardMain();
    486475
     
    502491}
    503492
    504 static void cleanup(struct VBCLSERVICE **ppInterface)
    505 {
    506     RT_NOREF(ppInterface);
    507 
     493/** @copydoc VBCLSERVICE::pfnStop */
     494static void vbclShClStop(void)
     495{
     496    /* Disconnect from the host service.
     497     * This will also send a VBOX_SHCL_HOST_MSG_QUIT from the host so that we can break out from our message worker. */
     498    VbglR3ClipboardDisconnect(g_Ctx.CmdCtx.idClient);
     499    g_Ctx.CmdCtx.idClient = 0;
     500}
     501
     502/** @copydoc VBCLSERVICE::pfnTerm */
     503static int vbclShClTerm(void)
     504{
    508505#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
    509506    ShClTransferCtxDestroy(&g_Ctx.TransferCtx);
    510507#endif
    511 }
    512 
    513 struct VBCLSERVICE vbclClipboardInterface =
    514 {
    515     getName,
    516     getPidFilePath,
    517     init,
    518     run,
    519     cleanup
     508
     509    return VINF_SUCCESS;
     510}
     511
     512VBCLSERVICE g_SvcClipboard =
     513{
     514    "shcl",                      /* szName */
     515    "Shared Clipboard",          /* pszDescription */
     516    ".vboxclient-clipboard.pid", /* pszPidFilePath */
     517    NULL,                        /* pszUsage */
     518    NULL,                        /* pszOptions */
     519    NULL,                        /* pfnOption */
     520    vbclShClInit,                /* pfnInit */
     521    vbclShClWorker,              /* pfnWorker */
     522    vbclShClStop,                /* pfnStop*/
     523    vbclShClTerm                 /* pfnTerm */
    520524};
    521525
    522 struct CLIPBOARDSERVICE
    523 {
    524     struct VBCLSERVICE *pInterface;
    525 };
    526 
    527 struct VBCLSERVICE **VBClGetClipboardService(void)
    528 {
    529     struct CLIPBOARDSERVICE *pService =
    530         (struct CLIPBOARDSERVICE *)RTMemAlloc(sizeof(*pService));
    531 
    532     if (!pService)
    533         VBClLogFatalError("Out of memory\n");
    534     pService->pInterface = &vbclClipboardInterface;
    535     return &pService->pInterface;
    536 }
  • trunk/src/VBox/Additions/x11/VBoxClient/display-svga-x11.cpp

    r86469 r86871  
    733733 * it (guest property) is set.
    734734 */
    735 static bool checkDRMClient()
     735static bool checkDRMClient(void)
    736736{
    737737   uint32_t uGuestPropSvcClientID;
     
    745745}
    746746
    747 static bool startDRMClient()
     747static bool startDRMClient(void)
    748748{
    749749    char* argv[] = {NULL};
     
    755755    int rc = execve(szDRMClientPath, argv, env);
    756756    if (rc == -1)
    757         VBClLogFatalError("execve for % returns the following error %d %s\n", szDRMClientPath, errno, strerror(errno));
     757        VBClLogFatalError("execve for '%s' returns the following error %d: %s\n", szDRMClientPath, errno, strerror(errno));
    758758    /* This is reached only when execve fails. */
    759759    return false;
    760760}
    761761
    762 static bool init()
    763 {
     762/** @copydoc VBCLSERVICE::pfnInit */
     763static int vbclSVGAInit(void)
     764{
     765    /* In 32-bit guests GAs build on our release machines causes an xserver hang.
     766     * So for 32-bit GAs we use our DRM client. */
     767#if ARCH_BITS == 32
     768    /* igore rc */ startDRMClient();
     769    return VERR_NOT_AVAILABLE;
     770#endif
     771
    764772    /* If DRM client is already running don't start this service. */
    765773    if (checkDRMClient())
    766774    {
    767775        VBClLogFatalError("DRM resizing is already running. Exiting this service\n");
    768         return false;
     776        return VERR_NOT_AVAILABLE;
    769777    }
    770778    if (isXwayland())
     
    781789}
    782790
    783 static void cleanup()
     791/** @copydoc VBCLSERVICE::pfnStop */
     792static void vbclSVGAStop(void)
    784793{
    785794    if (mpMonitorPositions)
     
    788797        mpMonitorPositions = NULL;
    789798    }
    790     stopX11MonitorThread();
     799
     800    stopX11MonitorThread(); /** @todo r=andy We ignore rc!? */
     801
    791802    if (x11Context.pRandLibraryHandle)
    792803    {
     
    13311342}
    13321343
    1333 static const char *getName()
    1334 {
    1335     return "Display SVGA X11";
    1336 }
    1337 
    1338 static const char *getPidFilePath()
    1339 {
    1340     return ".vboxclient-display-svga-x11.pid";
    1341 }
    1342 
    1343 static int run(struct VBCLSERVICE **ppInterface, bool fDaemonised)
    1344 {
    1345     RT_NOREF(ppInterface, fDaemonised);
    1346 
    1347     /* In 32-bit guests GAs build on our release machines causes an xserver hang.
    1348      * So for 32-bit GAs we use our DRM client. */
    1349 #if ARCH_BITS == 32
    1350     startDRMClient();
    1351     return VERR_NOT_AVAILABLE;
    1352 #endif
    1353 
    1354     if (!init())
    1355         return VERR_NOT_AVAILABLE;
     1344static int vbclSVGAWorker(bool volatile *pfShutdown)
     1345{
     1346    RT_NOREF(pfShutdown);
    13561347
    13571348    /* Do not acknowledge the first event we query for to pick up old events,
     
    13691360    if (rc == VERR_RESOURCE_BUSY)  /* Someone else has already acquired it. */
    13701361        return VERR_RESOURCE_BUSY;
     1362
     1363    /* Let the main thread know that it can continue spawning services. */
     1364    RTThreadUserSignal(RTThreadSelf());
     1365
    13711366    for (;;)
    13721367    {
     
    14421437            VBClLogFatalError("Failure waiting for event, rc=%Rrc\n", rc);
    14431438    }
    1444     cleanup();
    1445 }
    1446 
    1447 static struct VBCLSERVICE interface =
    1448 {
    1449     getName,
    1450     getPidFilePath,
    1451     VBClServiceDefaultHandler, /* Init */
    1452     run,
    1453     VBClServiceDefaultCleanup
    1454 }, *pInterface = &interface;
    1455 
    1456 struct VBCLSERVICE **VBClDisplaySVGAX11Service()
    1457 {
    1458     return &pInterface;
    1459 }
     1439}
     1440
     1441VBCLSERVICE g_SvcDisplaySVGA =
     1442{
     1443    "dp-svga-x11",                      /* szName */
     1444    "SVGA X11 display",                 /* pszDescription */
     1445    ".vboxclient-display-svga-x11.pid", /* pszPidFilePath */
     1446    NULL,                               /* pszUsage */
     1447    NULL,                               /* pszOptions */
     1448    NULL,                               /* pfnOption */
     1449    vbclSVGAInit,                       /* pfnInit */
     1450    vbclSVGAWorker,                     /* pfnWorker */
     1451    vbclSVGAStop,                       /* pfnStop*/
     1452    NULL                                /* pfnTerm */
     1453};
     1454
  • trunk/src/VBox/Additions/x11/VBoxClient/draganddrop.cpp

    r85927 r86871  
    543543
    544544    int  init(uint32_t uScreenID);
    545     void uninit(void);
     545    int  term(void);
     546    void stop(void);
    546547    void reset(void);
    547548
     
    666667    }
    667668
    668     int init(void);
    669     int run(bool fDaemonised = false);
    670     void cleanup(void);
     669    int  init(void);
     670    int  worker(bool volatile *pfShutdown);
     671    void stop(void);
     672    int  term(void);
    671673
    672674private:
     
    677679    /* Private member vars */
    678680    Display             *m_pDisplay;
    679 
    680     /** Our (thread-safe) event queue with
    681      *  mixed events (DnD HGCM / X11). */
    682     RTCMTList<DnDEvent>    m_eventQueue;
     681    /** Our (thread-safe) event queue with mixed events (DnD HGCM / X11). */
     682    RTCMTList<DnDEvent>  m_eventQueue;
    683683    /** Critical section for providing serialized access to list
    684684     *  event queue's contents. */
    685685    RTCRITSECT           m_eventQueueCS;
     686    /** Thread handle for the HGCM message pumping thread. */
    686687    RTTHREAD             m_hHGCMThread;
     688    /** Thread handle for the X11 message pumping thread. */
    687689    RTTHREAD             m_hX11Thread;
    688690    /** This service' DnD command context. */
    689691    VBGLR3GUESTDNDCMDCTX m_dndCtx;
     692    /** Event semaphore for new DnD events. */
    690693    RTSEMEVENT           m_hEventSem;
     694    /** Pointer to the allocated DnD instance.
     695        Currently we only support and handle one instance at a time. */
    691696    DragInstance        *m_pCurDnD;
    692697    /** Stop indicator flag to signal the thread that it should shut down. */
     
    694699
    695700    friend class DragInstance;
    696 };
     701} g_Svc;
    697702
    698703/*********************************************************************************************************************************
     
    715720
    716721/**
    717  * Unitializes (destroys) this drag instance.
    718  */
    719 void DragInstance::uninit(void)
     722 * Stops this drag instance.
     723 */
     724void DragInstance::stop(void)
     725{
     726    LogFlowFuncEnter();
     727
     728    int rc2 = VbglR3DnDDisconnect(&m_dndCtx);
     729    AssertRC(rc2);
     730
     731    LogFlowFuncLeave();
     732}
     733
     734/**
     735 * Terminates (destroys) this drag instance.
     736 *
     737 * @return VBox status code.
     738 */
     739int DragInstance::term(void)
    720740{
    721741    LogFlowFuncEnter();
     
    724744        XDestroyWindow(m_pDisplay, m_wndProxy.hWnd);
    725745
    726     int rc2 = VbglR3DnDDisconnect(&m_dndCtx);
     746    int rc = VbglR3DnDDisconnect(&m_dndCtx);
     747    AssertRCReturn(rc, rc);
    727748
    728749    if (m_pvSelReqData)
    729750        RTMemFree(m_pvSelReqData);
    730751
    731     rc2 = RTSemEventDestroy(m_eventQueueEvent);
    732     AssertRC(rc2);
    733 
    734     rc2 = RTCritSectDelete(&m_eventQueueCS);
    735     AssertRC(rc2);
    736 
    737     rc2 = RTCritSectDelete(&m_dataCS);
    738     AssertRC(rc2);
     752    rc = RTSemEventDestroy(m_eventQueueEvent);
     753    AssertRCReturn(rc, rc);
     754
     755    rc = RTCritSectDelete(&m_eventQueueCS);
     756    AssertRCReturn(rc, rc);
     757
     758    rc = RTCritSectDelete(&m_dataCS);
     759    AssertRCReturn(rc, rc);
     760
     761    LogFlowFuncLeaveRC(rc);
     762    return rc;
    739763}
    740764
     
    30673091 ********************************************************************************************************************************/
    30683092
    3069 /**
    3070  * Initializes the drag and drop service.
    3071  *
    3072  * @returns IPRT status code.
    3073  */
     3093/** @copydoc VBCLSERVICE::pfnInit */
    30743094int DragAndDropService::init(void)
    30753095{
     
    31063126        AssertRCBreak(rc);
    31073127
    3108         rc = RTThreadUserWait(m_hHGCMThread, 10 * 1000 /* 10s timeout */);
     3128        rc = RTThreadUserWait(m_hHGCMThread, RT_MS_30SEC);
    31093129        AssertRCBreak(rc);
    31103130
     
    31173137        AssertRCBreak(rc);
    31183138
    3119         rc = RTThreadUserWait(m_hX11Thread, 10 * 1000 /* 10s timeout */);
     3139        rc = RTThreadUserWait(m_hX11Thread, RT_MS_30SEC);
    31203140        AssertRCBreak(rc);
    31213141
     
    31353155}
    31363156
    3137 /**
    3138  * Main loop for the drag and drop service which does the HGCM message
    3139  * processing and routing to the according drag and drop instance(s).
    3140  *
    3141  * @returns IPRT status code.
    3142  * @param   fDaemonised             Whether to run in daemonized or not. Does not
    3143  *                                  apply for this service.
    3144  */
    3145 int DragAndDropService::run(bool fDaemonised /* = false */)
    3146 {
    3147     RT_NOREF1(fDaemonised);
    3148     LogFlowThisFunc(("fDaemonised=%RTbool\n", fDaemonised));
    3149 
     3157/** @copydoc VBCLSERVICE::pfnWorker */
     3158int DragAndDropService::worker(bool volatile *pfShutdown)
     3159{
    31503160    int rc;
    31513161    do
     
    31673177            if (RT_FAILURE(rc))
    31683178                VBClLogError("Unable to connect to drag and drop service, rc=%Rrc\n", rc);
    3169             else if (rc == VINF_PERMISSION_DENIED)
    3170                 VBClLogError("Not available on host, terminating\n");
     3179            else if (rc == VINF_PERMISSION_DENIED) /* No error, DnD might be just disabled. */
     3180                VBClLogInfo("Not available on host, terminating\n");
    31713181            break;
    31723182        }
    31733183
    3174         VBClLogInfo("Started\n");
    3175         VBClLogInfo("%sr%s\n", RTBldCfgVersion(), RTBldCfgRevisionStr());
     3184        /* Let the main thread know that it can continue spawning services. */
     3185        RTThreadUserSignal(RTThreadSelf());
    31763186
    31773187        /* Enter the main event processing loop. */
     
    32823292                    }
    32833293#endif
     3294                    case VBGLR3DNDEVENTTYPE_QUIT:
     3295                    {
     3296                        rc = VINF_SUCCESS;
     3297                        break;
     3298                    }
     3299
    32843300                    default:
    32853301                    {
    3286                        VBClLogError("Received unsupported message '%RU32'\n", pVbglR3Event->enmType);
     3302                        VBClLogError("Received unsupported message type %RU32\n", pVbglR3Event->enmType);
    32873303                        rc = VERR_NOT_SUPPORTED;
    32883304                        break;
     
    32943310                {
    32953311                    /* Tell the user. */
    3296                    VBClLogError("Processing message %RU32 failed with %Rrc\n", pVbglR3Event->enmType, rc);
     3312                    VBClLogError("Processing message %RU32 failed with %Rrc\n", pVbglR3Event->enmType, rc);
    32973313
    32983314                    /* If anything went wrong, do a reset and start over. */
     
    33003316                }
    33013317
     3318                const bool fQuit = pVbglR3Event->enmType == VBGLR3DNDEVENTTYPE_QUIT;
     3319
    33023320                VbglR3DnDEventFree(e.hgcm);
    33033321                e.hgcm = NULL;
     3322
     3323                if (fQuit)
     3324                    break;
    33043325            }
    33053326            else if (e.enmType == DnDEvent::DnDEventType_X11)
     
    33173338            XFlush(m_pDisplay);
    33183339
    3319         } while (!ASMAtomicReadBool(&m_fStop));
    3320 
    3321         VBClLogInfo("Stopped with rc=%Rrc\n", rc);
     3340            if (m_fStop)
     3341                break;
     3342
     3343        } while (!ASMAtomicReadBool(pfShutdown));
    33223344
    33233345    } while (0);
     
    33333355}
    33343356
    3335 void DragAndDropService::cleanup(void)
     3357/** @copydoc VBCLSERVICE::pfnStop */
     3358void DragAndDropService::stop(void)
    33363359{
    33373360    LogFlowFuncEnter();
    3338 
    3339     VBClLogInfo("Terminating ...\n");
    33403361
    33413362    /* Set stop flag first. */
    33423363    ASMAtomicXchgBool(&m_fStop, true);
    33433364
    3344     /* Disconnect from the HGCM host service, which in turn will make the HGCM thread stop. */
     3365    /* First, disconnect any instances. */
     3366    if (m_pCurDnD)
     3367        m_pCurDnD->stop();
     3368
     3369    /* Second, disconnect the service's DnD connection. */
    33453370    VbglR3DnDDisconnect(&m_dndCtx);
     3371
     3372    LogFlowFuncLeave();
     3373}
     3374
     3375/** @copydoc VBCLSERVICE::pfnTerm */
     3376int DragAndDropService::term(void)
     3377{
     3378    int rc = VINF_SUCCESS;
    33463379
    33473380    /*
    33483381     * Wait for threads to terminate.
    33493382     */
    3350     int rcThread, rc2;
    3351     if (m_hHGCMThread != NIL_RTTHREAD)
    3352     {
    3353         VBClLogInfo("Terminating HGCM thread ...\n");
    3354 
    3355         rc2 = RTThreadWait(m_hHGCMThread, 30 * 1000 /* 30s timeout */, &rcThread);
     3383    int rcThread;
     3384
     3385    if (m_hX11Thread != NIL_RTTHREAD)
     3386    {
     3387        VBClLogVerbose(2, "Terminating X11 thread ...\n");
     3388
     3389        int rc2 = RTThreadWait(m_hX11Thread, RT_MS_30SEC, &rcThread);
    33563390        if (RT_SUCCESS(rc2))
    33573391            rc2 = rcThread;
    33583392
    33593393        if (RT_FAILURE(rc2))
    3360             VBClLogInfo("Error waiting for HGCM thread to terminate: %Rrc\n", rc2);
    3361     }
    3362 
    3363     if (m_hX11Thread != NIL_RTTHREAD)
    3364     {
    3365         VBClLogInfo("Terminating X11 thread ...\n");
    3366 
    3367         rc2 = RTThreadWait(m_hX11Thread, 200 /* 200ms timeout */, &rcThread);
     3394            VBClLogError("Error waiting for X11 thread to terminate: %Rrc\n", rc2);
     3395
     3396        if (RT_SUCCESS(rc))
     3397            rc = rc2;
     3398
     3399        m_hX11Thread = NIL_RTTHREAD;
     3400
     3401        VBClLogVerbose(2, "X11 thread terminated\n");
     3402    }
     3403
     3404    if (m_hHGCMThread != NIL_RTTHREAD)
     3405    {
     3406        VBClLogVerbose(2, "Terminating HGCM thread ...\n");
     3407
     3408        int rc2 = RTThreadWait(m_hHGCMThread, RT_MS_30SEC, &rcThread);
    33683409        if (RT_SUCCESS(rc2))
    33693410            rc2 = rcThread;
    33703411
    33713412        if (RT_FAILURE(rc2))
    3372             VBClLogError("Error waiting for X11 thread to terminate: %Rrc\n", rc2);
    3373     }
    3374 
    3375     VBClLogInfo("Terminating threads done\n");
     3413            VBClLogError("Error waiting for HGCM thread to terminate: %Rrc\n", rc2);
     3414
     3415        if (RT_SUCCESS(rc))
     3416            rc = rc2;
     3417
     3418        m_hHGCMThread = NIL_RTTHREAD;
     3419
     3420        VBClLogVerbose(2, "HGCM thread terminated\n");
     3421    }
     3422
     3423    if (m_pCurDnD)
     3424    {
     3425        delete m_pCurDnD;
     3426        m_pCurDnD = NULL;
     3427    }
    33763428
    33773429    xHelpers::destroyInstance();
    33783430
    3379     VbglR3Term();
     3431    return rc;
    33803432}
    33813433
     
    33993451    AssertRCReturn(rc, rc);
    34003452
     3453    VBClLogVerbose(2, "HGCM thread started\n");
     3454
    34013455    /* Number of invalid messages skipped in a row. */
    34023456    int cMsgSkippedInvalid = 0;
     
    34213475        else
    34223476        {
    3423             if (rc == VERR_INTERRUPTED) /* Can happen due to disconnect, for instance. */
    3424                 rc = VINF_SUCCESS;
    3425 
    3426             if (RT_FAILURE(rc))
     3477            VBClLogError("Processing next message failed with rc=%Rrc\n", rc);
     3478
     3479            /* Old(er) hosts either are broken regarding DnD support or otherwise
     3480             * don't support the stuff we do on the guest side, so make sure we
     3481             * don't process invalid messages forever. */
     3482
     3483            if (cMsgSkippedInvalid++ > 32)
    34273484            {
    3428                 VBClLogError("Processing next message failed with rc=%Rrc\n", rc);
    3429 
    3430                 /* Old(er) hosts either are broken regarding DnD support or otherwise
    3431                  * don't support the stuff we do on the guest side, so make sure we
    3432                  * don't process invalid messages forever. */
    3433 
    3434                 if (cMsgSkippedInvalid++ > 32)
    3435                 {
    3436                     VBClLogError("Too many invalid/skipped messages from host, exiting ...\n");
    3437                     break;
    3438                 }
     3485                VBClLogError("Too many invalid/skipped messages from host, exiting ...\n");
     3486                break;
    34393487            }
    34403488        }
    34413489
    34423490    } while (!ASMAtomicReadBool(&pThis->m_fStop));
     3491
     3492    VBClLogVerbose(2, "HGCM thread ended\n");
    34433493
    34443494    LogFlowFuncLeaveRC(rc);
     
    34653515    /* Note: Nothing to initialize here (yet). */
    34663516
    3467     /* Set stop indicator on failure. */
    3468     if (RT_FAILURE(rc))
    3469         ASMAtomicXchgBool(&pThis->m_fStop, true);
    3470 
    34713517    /* Let the service instance know in any case. */
    34723518    int rc2 = RTThreadUserSignal(hThread);
    34733519    AssertRC(rc2);
     3520
     3521    VBClLogVerbose(2, "X11 thread started\n");
    34743522
    34753523    DnDEvent e;
     
    35033551    } while (!ASMAtomicReadBool(&pThis->m_fStop));
    35043552
     3553    VBClLogVerbose(2, "X11 thread ended\n");
     3554
    35053555    LogFlowFuncLeaveRC(rc);
    35063556    return rc;
    35073557}
    3508 
    3509 /** Drag and drop magic number, start of a UUID. */
    3510 #define DRAGANDDROPSERVICE_MAGIC 0x67c97173
    3511 
    3512 /** VBoxClient service class wrapping the logic for the service while
    3513  *  the main VBoxClient code provides the daemon logic needed by all services.
    3514  */
    3515 struct DRAGANDDROPSERVICE
    3516 {
    3517     /** The service interface. */
    3518     struct VBCLSERVICE *pInterface;
    3519     /** Magic number for sanity checks. */
    3520     uint32_t uMagic;
    3521     /** Service object. */
    3522     DragAndDropService mDragAndDrop;
     3558/** @copydoc VBCLSERVICE::pfnInit */
     3559static int vbclDnDInit(void)
     3560{
     3561    return g_Svc.init();
     3562}
     3563
     3564/** @copydoc VBCLSERVICE::pfnWorker */
     3565static int vbclDnDWorker(bool volatile *pfShutdown)
     3566{
     3567    return g_Svc.worker(pfShutdown);
     3568}
     3569
     3570/** @copydoc VBCLSERVICE::pfnStop */
     3571static void vbclDnDStop(void)
     3572{
     3573    g_Svc.stop();
     3574}
     3575
     3576/** @copydoc VBCLSERVICE::pfnTerm */
     3577static int vbclDnDTerm(void)
     3578{
     3579    return g_Svc.term();
     3580}
     3581
     3582VBCLSERVICE g_SvcDragAndDrop =
     3583{
     3584    "dnd",                         /* szName */
     3585    "Drag'n'Drop",                 /* pszDescription */
     3586    ".vboxclient-draganddrop.pid", /* pszPidFilePath */
     3587    NULL,                          /* pszUsage */
     3588    NULL,                          /* pszOptions */
     3589    NULL,                          /* pfnOption */
     3590    vbclDnDInit,                   /* pfnInit */
     3591    vbclDnDWorker,                 /* pfnWorker */
     3592    vbclDnDStop,                   /* pfnStop*/
     3593    vbclDnDTerm                    /* pfnTerm */
    35233594};
    35243595
    3525 static const char *getName()
    3526 {
    3527     return "Drag and Drop (DnD)";
    3528 }
    3529 
    3530 static const char *getPidFilePath()
    3531 {
    3532     return ".vboxclient-draganddrop.pid";
    3533 }
    3534 
    3535 static int init(struct VBCLSERVICE **ppInterface)
    3536 {
    3537     struct DRAGANDDROPSERVICE *pSelf = (struct DRAGANDDROPSERVICE *)ppInterface;
    3538 
    3539     if (pSelf->uMagic != DRAGANDDROPSERVICE_MAGIC)
    3540         VBClLogFatalError("Bad DnD service object!\n");
    3541     return pSelf->mDragAndDrop.init();
    3542 }
    3543 
    3544 static int run(struct VBCLSERVICE **ppInterface, bool fDaemonised)
    3545 {
    3546     struct DRAGANDDROPSERVICE *pSelf = (struct DRAGANDDROPSERVICE *)ppInterface;
    3547 
    3548     if (pSelf->uMagic != DRAGANDDROPSERVICE_MAGIC)
    3549         VBClLogFatalError("Bad DnD service object!\n");
    3550     return pSelf->mDragAndDrop.run(fDaemonised);
    3551 }
    3552 
    3553 static void cleanup(struct VBCLSERVICE **ppInterface)
    3554 {
    3555    struct DRAGANDDROPSERVICE *pSelf = (struct DRAGANDDROPSERVICE *)ppInterface;
    3556 
    3557     if (pSelf->uMagic != DRAGANDDROPSERVICE_MAGIC)
    3558         VBClLogFatalError("Bad DnD service object!\n");
    3559     return pSelf->mDragAndDrop.cleanup();
    3560 }
    3561 
    3562 struct VBCLSERVICE vbclDragAndDropInterface =
    3563 {
    3564     getName,
    3565     getPidFilePath,
    3566     init,
    3567     run,
    3568     cleanup
    3569 };
    3570 
    3571 /* Static factory. */
    3572 struct VBCLSERVICE **VBClGetDragAndDropService(void)
    3573 {
    3574     struct DRAGANDDROPSERVICE *pService =
    3575         (struct DRAGANDDROPSERVICE *)RTMemAlloc(sizeof(*pService));
    3576 
    3577     if (!pService)
    3578         VBClLogFatalError("Out of memory\n");
    3579     pService->pInterface = &vbclDragAndDropInterface;
    3580     pService->uMagic = DRAGANDDROPSERVICE_MAGIC;
    3581     new(&pService->mDragAndDrop) DragAndDropService();
    3582     return &pService->pInterface;
    3583 }
  • trunk/src/VBox/Additions/x11/VBoxClient/hostversion.cpp

    r82968 r86871  
    11/* $Id$ */
    22/** @file
    3  * X11 guest client - host version check.
     3 * X11 guest client - Host version check.
    44 */
    55
     
    3434#include "VBoxClient.h"
    3535
    36 static const char *getName()
    37 {
    38     return "Host Version Check";
    39 }
    40 
    41 static const char *getPidFilePath()
    42 {
    43     return ".vboxclient-hostversion.pid";
    44 }
    45 
    4636static int showNotify(const char *pszHeader, const char *pszBody)
    4737{
     
    5040    DBusConnection *conn;
    5141    DBusMessage* msg = NULL;
    52     conn = dbus_bus_get (DBUS_BUS_SESSION, NULL);
     42    conn = dbus_bus_get(DBUS_BUS_SESSION, NULL);
    5343    if (conn == NULL)
    5444    {
    55         LogRelFlowFunc(("Could not retrieve D-BUS session bus!\n"));
     45        VBClLogError("Could not retrieve D-BUS session bus\n");
    5646        rc = VERR_INVALID_HANDLE;
    5747    }
     
    127117}
    128118
     119/** @copydoc VBCLSERVICE::pfnWorker */
    129120/** @todo Move this part in VbglR3 and just provide a callback for the platform-specific
    130121          notification stuff, since this is very similar to the VBoxTray code. */
    131 static int run(struct VBCLSERVICE **ppInterface, bool fDaemonised)
     122static int vbclHostVerWorker(bool volatile *pfShutdown)
    132123{
     124    RT_NOREF(pfShutdown);
     125
     126    LogFlowFuncEnter();
     127
    133128    int rc;
    134     LogFlowFunc(("\n"));
    135 
    136     RT_NOREF(ppInterface);
    137 
    138     /* Because we need desktop notifications to be displayed, wait
    139      * some time to make the desktop environment load (as a work around). */
    140     if (fDaemonised)
    141         RTThreadSleep(30 * 1000 /* Wait 30 seconds */);
    142 
    143129# ifdef VBOX_WITH_DBUS
    144130    rc = RTDBusLoadLib();
     
    155141        rc = VbglR3GuestPropConnect(&uGuestPropSvcClientID);
    156142        if (RT_FAILURE(rc))
    157             VBClLogError("Cannot connect to guest property service while chcking for host version! rc = %Rrc\n", rc);
     143            VBClLogError("Cannot connect to guest property service while chcking for host version, rc = %Rrc\n", rc);
    158144    }
    159145
    160146    if (RT_SUCCESS(rc))
    161147    {
     148        /* Let the main thread know that it can continue spawning services. */
     149        RTThreadUserSignal(RTThreadSelf());
     150
     151        /* Because we need desktop notifications to be displayed, wait
     152         * some time to make the desktop environment load (as a work around). */
     153        if (g_fDaemonized)
     154            RTThreadSleep(RT_MS_30SEC);
     155
    162156        char *pszHostVersion;
    163157        char *pszGuestVersion;
    164         bool bUpdate;
    165 
    166         rc = VbglR3HostVersionCheckForUpdate(uGuestPropSvcClientID, &bUpdate, &pszHostVersion, &pszGuestVersion);
     158        bool  fUpdate;
     159
     160        rc = VbglR3HostVersionCheckForUpdate(uGuestPropSvcClientID, &fUpdate, &pszHostVersion, &pszGuestVersion);
    167161        if (RT_SUCCESS(rc))
    168162        {
    169             if (bUpdate)
     163            if (fUpdate)
    170164            {
    171165                char szMsg[1024];
     
    198192    }
    199193# endif /* VBOX_WITH_GUEST_PROPS */
    200     VbglR3Term();
    201     LogFlowFunc(("returning %Rrc\n", rc));
     194
    202195    return rc;
    203196}
    204197
    205 struct VBCLSERVICE vbclHostVersionInterface =
     198VBCLSERVICE g_SvcHostVersion =
    206199{
    207     getName,
    208     getPidFilePath,
    209     VBClServiceDefaultHandler, /* init */
    210     run,
    211     VBClServiceDefaultCleanup
     200    "hostversion",                   /* szName */
     201    "VirtualBox host version check", /* pszDescription */
     202    ".vboxclient-hostversion.pid",   /* pszPidFilePath */
     203    NULL,                            /* pszUsage */
     204    NULL,                            /* pszOptions */
     205    NULL,                            /* pfnOption */
     206    NULL,                            /* pfnInit */
     207    vbclHostVerWorker,               /* pfnWorker */
     208    NULL,                            /* pfnStop*/
     209    NULL                             /* pfnTerm */
    212210};
    213211
    214 struct HOSTVERSIONSERVICE
    215 {
    216     struct VBCLSERVICE *pInterface;
    217 };
    218 
    219 /* Static factory */
    220 struct VBCLSERVICE **VBClGetHostVersionService()
    221 {
    222     struct HOSTVERSIONSERVICE *pService =
    223         (struct HOSTVERSIONSERVICE *)RTMemAlloc(sizeof(*pService));
    224 
    225     if (!pService)
    226         VBClLogFatalError("Out of memory\n");
    227     pService->pInterface = &vbclHostVersionInterface;
    228     return &pService->pInterface;
    229 }
  • trunk/src/VBox/Additions/x11/VBoxClient/logging.cpp

    r84501 r86871  
    8383
    8484/**
     85 * Logs a verbose message.
     86 *
     87 * @param   pszFormat   The message text.
     88 * @param   va          Format arguments.
     89 */
     90static void vbClLogV(const char *pszFormat, va_list va)
     91{
     92    char *psz = NULL;
     93    RTStrAPrintfV(&psz, pszFormat, va);
     94    AssertPtrReturnVoid(psz);
     95    LogRel(("%s", psz));
     96    RTStrFree(psz);
     97}
     98
     99/**
    85100 * Logs a fatal error, notifies the desktop environment via a message and
    86101 * exits the application immediately.
     
    97112    va_end(args);
    98113
    99     AssertPtr(psz);
    100     LogFlowFunc(("%s", psz));
    101     LogRel(("%s", psz));
     114    AssertPtrReturnVoid(psz);
     115    LogFunc(("Fatal Error: %s", psz));
     116    LogRel(("Fatal Error: %s", psz));
    102117
    103118    vbclLogNotify(psz);
     
    119134    va_end(args);
    120135
    121     AssertPtr(psz);
    122     LogFlowFunc(("%s", psz));
    123     LogRel(("%s", psz));
     136    AssertPtrReturnVoid(psz);
     137    LogFunc(("Error: %s", psz));
     138    LogRel(("Error: %s", psz));
    124139
    125140    RTStrFree(psz);
     
    135150    va_list args;
    136151    va_start(args, pszFormat);
    137     char *psz = NULL;
    138     RTStrAPrintfV(&psz, pszFormat, args);
     152    vbClLogV(pszFormat, args);
    139153    va_end(args);
    140 
    141     AssertPtr(psz);
    142     LogFlowFunc(("%s", psz));
    143     LogRel(("%s", psz));
    144 
    145     RTStrFree(psz);
     154}
     155
     156/**
     157 * Displays a verbose message based on the currently
     158 * set global verbosity level.
     159 *
     160 * @param   iLevel      Minimum log level required to display this message.
     161 * @param   pszFormat   The message text.
     162 * @param   ...         Format arguments.
     163 */
     164void VBClLogVerbose(unsigned iLevel, const char *pszFormat, ...)
     165{
     166    if (iLevel <= g_cVerbosity)
     167    {
     168        va_list va;
     169        va_start(va, pszFormat);
     170        vbClLogV(pszFormat, va);
     171        va_end(va);
     172    }
    146173}
    147174
     
    265292}
    266293
    267 void foo()
    268 {
    269 }
  • trunk/src/VBox/Additions/x11/VBoxClient/main.cpp

    r84538 r86871  
    2727#include <iprt/buildconfig.h>
    2828#include <iprt/critsect.h>
     29#include <iprt/errno.h>
    2930#include <iprt/getopt.h>
    3031#include <iprt/initterm.h>
     
    3435#include <VBox/VBoxGuestLib.h>
    3536#include <VBox/err.h>
     37#include <VBox/version.h>
    3638#include "VBoxClient.h"
    3739
     
    5153
    5254/*********************************************************************************************************************************
     55*   Local structures                                                                                                             *
     56*********************************************************************************************************************************/
     57/**
     58 * The global service state.
     59 */
     60typedef struct VBCLSERVICESTATE
     61{
     62    /** Pointer to the service descriptor. */
     63    PVBCLSERVICE    pDesc;
     64    /** The worker thread. NIL_RTTHREAD if it's the main thread. */
     65    RTTHREAD        Thread;
     66    /** Whether Pre-init was called. */
     67    bool            fPreInited;
     68    /** Shutdown indicator. */
     69    bool volatile   fShutdown;
     70    /** Indicator set by the service thread exiting. */
     71    bool volatile   fStopped;
     72    /** Whether the service was started or not. */
     73    bool            fStarted;
     74} VBCLSERVICESTATE;
     75/** Pointer to a service state. */
     76typedef VBCLSERVICESTATE *PVBCLSERVICESTATE;
     77
     78
     79/*********************************************************************************************************************************
    5380*   Global Variables                                                                                                             *
    5481*********************************************************************************************************************************/
    55 /*static int (*gpfnOldIOErrorHandler)(Display *) = NULL; - unused */
    56 
    57 /** Object representing the service we are running.  This has to be global
    58  * so that the cleanup routine can access it. */
    59 struct VBCLSERVICE **g_pService;
     82/** The global service state. */
     83VBCLSERVICESTATE     g_Service = { 0 };
     84
     85/** Set by the signal handler when being called. */
     86static volatile bool g_fSignalHandlerCalled = false;
     87/** Critical section for the signal handler. */
     88static RTCRITSECT    g_csSignalHandler;
     89/** Flag indicating Whether the service starts in daemonized  mode or not. */
     90bool                 g_fDaemonized = false;
    6091/** The name of our pidfile.  It is global for the benefit of the cleanup
    6192 * routine. */
     
    70101static RTCRITSECT    g_critSect;
    71102/** Counter of how often our daemon has been respawned. */
    72 unsigned      g_cRespawn = 0;
     103unsigned             g_cRespawn = 0;
    73104/** Logging verbosity level. */
    74 unsigned      g_cVerbosity = 0;
     105unsigned             g_cVerbosity = 0;
     106/** Absolute path to log file, if any. */
    75107static char          g_szLogFile[RTPATH_MAX + 128] = "";
    76108
    77 
    78 /**
    79  * Clean up if we get a signal or something.
     109/**
     110 * Shut down if we get a signal or something.
    80111 *
    81112 * This is extern so that we can call it from other compilation units.
    82113 */
    83 void VBClCleanUp(bool fExit /*=true*/)
     114void VBClShutdown(bool fExit /*=true*/)
    84115{
    85116    /* We never release this, as we end up with a call to exit(3) which is not
     
    89120    if (RT_FAILURE(rc))
    90121        VBClLogFatalError("Failure while acquiring the global critical section, rc=%Rrc\n", rc);
    91     if (g_pService)
    92         (*g_pService)->cleanup(g_pService);
     122    if (   g_Service.pDesc
     123        && g_Service.pDesc->pfnTerm)
     124        g_Service.pDesc->pfnTerm();
    93125    if (g_szPidFile[0] && g_hPidFile)
    94126        VbglR3ClosePidFile(g_szPidFile, g_hPidFile);
     
    98130    if (fExit)
    99131        exit(RTEXITCODE_SUCCESS);
    100 }
    101 
    102 /**
    103  * A standard signal handler which cleans up and exits.
    104  */
    105 static void vboxClientSignalHandler(int cSignal)
    106 {
    107     VBClLogInfo("Terminated with signal %d\n", cSignal);
    108     /** Disable seamless mode */
    109     VBClLogInfo("Terminating ...\n");
    110     VBClCleanUp();
    111132}
    112133
     
    130151{
    131152    RT_NOREF1(pDisplay);
    132     VBClLogError("A fatal guest X Window error occurred.  This may just mean that the Window system was shut down while the client was still running\n");
    133     VBClCleanUp();
     153    VBClLogError("A fatal guest X Window error occurred. This may just mean that the Window system was shut down while the client was still running\n");
     154    VBClShutdown();
    134155    return 0;  /* We should never reach this. */
    135156}
    136157
    137158/**
    138  * Reset all standard termination signals to call our signal handler, which
    139  * cleans up and exits.
    140  */
    141 static void vboxClientSetSignalHandlers(void)
     159 * A standard signal handler which cleans up and exits.
     160 */
     161static void vboxClientSignalHandler(int iSignal)
     162{
     163    int rc = RTCritSectEnter(&g_csSignalHandler);
     164    if (RT_SUCCESS(rc))
     165    {
     166        if (g_fSignalHandlerCalled)
     167        {
     168            RTCritSectLeave(&g_csSignalHandler);
     169            return;
     170        }
     171
     172        VBClLogVerbose(2, "Received signal %d\n", iSignal);
     173        g_fSignalHandlerCalled = true;
     174
     175        /* Leave critical section before stopping the service. */
     176        RTCritSectLeave(&g_csSignalHandler);
     177
     178        if (   g_Service.pDesc
     179            && g_Service.pDesc->pfnStop)
     180        {
     181            VBClLogVerbose(2, "Notifying service to stop ...\n");
     182
     183            /* Signal the service to stop. */
     184            ASMAtomicWriteBool(&g_Service.fShutdown, true);
     185
     186            g_Service.pDesc->pfnStop();
     187
     188            VBClLogVerbose(2, "Service notified to stop, waiting on worker thread to stop ...\n");
     189        }
     190    }
     191}
     192
     193/**
     194 * Reset all standard termination signals to call our signal handler.
     195 */
     196static int vboxClientSignalHandlerInstall(void)
    142197{
    143198    struct sigaction sigAction;
    144 
    145     LogRelFlowFuncEnter();
    146199    sigAction.sa_handler = vboxClientSignalHandler;
    147200    sigemptyset(&sigAction.sa_mask);
     
    155208    sigaction(SIGUSR1, &sigAction, NULL);
    156209    sigaction(SIGUSR2, &sigAction, NULL);
    157     LogRelFlowFuncLeave();
     210
     211    return RTCritSectInit(&g_csSignalHandler);
     212}
     213
     214/**
     215 * Uninstalls a previously installed signal handler.
     216 */
     217static int vboxClientSignalHandlerUninstall(void)
     218{
     219    signal(SIGTERM,  SIG_DFL);
     220#ifdef SIGBREAK
     221    signal(SIGBREAK, SIG_DFL);
     222#endif
     223
     224    return RTCritSectDelete(&g_csSignalHandler);
    158225}
    159226
     
    163230static void vboxClientUsage(const char *pcszFileName)
    164231{
     232    RTPrintf(VBOX_PRODUCT " VBoxClient "
     233             VBOX_VERSION_STRING "\n"
     234             "(C) 2005-" VBOX_C_YEAR " " VBOX_VENDOR "\n"
     235             "All rights reserved.\n"
     236             "\n");
     237
    165238    RTPrintf("Usage: %s "
    166239#ifdef VBOX_WITH_SHARED_CLIPBOARD
     
    170243             "--draganddrop|"
    171244#endif
    172 # ifdef VBOX_WITH_GUEST_PROPS
     245#ifdef VBOX_WITH_GUEST_PROPS
    173246             "--checkhostversion|"
    174247#endif
     248#ifdef VBOX_WITH_SEAMLESS
    175249             "--seamless|"
     250#endif
     251#ifdef VBOX_WITH_VMSVGA
    176252             "--vmsvga"
    177              "[-d|--nodaemon]\n", pcszFileName);
    178     RTPrintf("Starts the VirtualBox DRM/X Window System guest services.\n\n");
     253#endif
     254             "\n[-d|--nodaemon]\n", pcszFileName);
     255    RTPrintf("\n");
    179256    RTPrintf("Options:\n");
    180257#ifdef VBOX_WITH_SHARED_CLIPBOARD
     
    187264    RTPrintf("  --checkhostversion starts the host version notifier service\n");
    188265#endif
     266#ifdef VBOX_WITH_SEAMLESS
    189267    RTPrintf("  --seamless         starts the seamless windows service\n");
    190     RTPrintf("  --vmsvga           starts VMSVGA dynamic resizing for x11/Wayland guests\n");
     268#endif
     269#ifdef VBOX_WITH_VMSVGA
     270    RTPrintf("  --vmsvga           starts VMSVGA dynamic resizing for X11/Wayland guests\n");
     271#endif
    191272    RTPrintf("  -f, --foreground   run in the foreground (no daemonizing)\n");
    192273    RTPrintf("  -d, --nodaemon     continues running as a system service\n");
     
    209290
    210291/**
     292 * The service thread.
     293 *
     294 * @returns Whatever the worker function returns.
     295 * @param   ThreadSelf      My thread handle.
     296 * @param   pvUser          The service index.
     297 */
     298static DECLCALLBACK(int) vbclThread(RTTHREAD ThreadSelf, void *pvUser)
     299{
     300    PVBCLSERVICESTATE pState = (PVBCLSERVICESTATE)pvUser;
     301    AssertPtrReturn(pState, VERR_INVALID_POINTER);
     302
     303#ifndef RT_OS_WINDOWS
     304    /*
     305     * Block all signals for this thread. Only the main thread will handle signals.
     306     */
     307    sigset_t signalMask;
     308    sigfillset(&signalMask);
     309    pthread_sigmask(SIG_BLOCK, &signalMask, NULL);
     310#endif
     311
     312    AssertPtrReturn(pState->pDesc->pfnWorker, VERR_INVALID_POINTER);
     313    int rc = pState->pDesc->pfnWorker(&pState->fShutdown);
     314
     315    VBClLogVerbose(2, "Worker loop ended with %Rrc\n", rc);
     316
     317    ASMAtomicXchgBool(&pState->fShutdown, true);
     318    RTThreadUserSignal(ThreadSelf);
     319    return rc;
     320}
     321
     322/**
    211323 * The main loop for the VBoxClient daemon.
    212  * @todo Clean up for readability.
    213324 */
    214325int main(int argc, char *argv[])
    215326{
    216     /* Initialise our runtime before all else. */
     327    /* Note: No VBClLogXXX calls before actually creating the log. */
     328
     329    /* Initialize our runtime before all else. */
    217330    int rc = RTR3InitExe(argc, &argv, 0);
    218331    if (RT_FAILURE(rc))
     
    222335     * object should probably never be used from multiple threads anyway. */
    223336    if (!XInitThreads())
    224         VBClLogFatalError("Failed to initialize X11 threads\n");
     337        return RTMsgErrorExitFailure("Failed to initialize X11 threads\n");
    225338
    226339    /* Get our file name for usage info and hints. */
     
    241354
    242355        /* Services */
     356#ifdef VBOX_WITH_GUEST_PROPS
    243357        { "--checkhostversion",             VBOXCLIENT_OPT_CHECKHOSTVERSION,          RTGETOPT_REQ_NOTHING },
     358#endif
    244359#ifdef VBOX_WITH_SHARED_CLIPBOARD
    245360        { "--clipboard",                    VBOXCLIENT_OPT_CLIPBOARD,                 RTGETOPT_REQ_NOTHING },
     
    248363        { "--draganddrop",                  VBOXCLIENT_OPT_DRAGANDDROP,               RTGETOPT_REQ_NOTHING },
    249364#endif
     365#ifdef VBOX_WITH_SEAMLESS
    250366        { "--seamless",                     VBOXCLIENT_OPT_SEAMLESS,                  RTGETOPT_REQ_NOTHING },
     367#endif
     368#ifdef VBOX_WITH_VMSVGA
    251369        { "--vmsvga",                       VBOXCLIENT_OPT_VMSVGA,                    RTGETOPT_REQ_NOTHING },
     370#endif
    252371    };
    253372
     
    256375    RTGETOPTSTATE           GetState;
    257376    rc = RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0, 0 /* fFlags */);
     377    if (RT_FAILURE(rc))
     378        return RTMsgErrorExitFailure("Failed to parse command line options, rc=%Rrc\n", rc);
     379
    258380    AssertRC(rc);
    259381
     
    289411                rc = RTStrCopy(g_szLogFile, sizeof(g_szLogFile), ValueUnion.psz);
    290412                if (RT_FAILURE(rc))
    291                     VBClLogFatalError("Unable to create log file path, rc=%Rrc\n", rc);
     413                    return RTMsgErrorExitFailure("Unable to set log file path, rc=%Rrc\n", rc);
    292414                break;
    293415            }
     
    295417            case 'n':
    296418            {
    297                 fRespawn   = false;
     419                fRespawn = false;
    298420                break;
    299421            }
     
    312434
    313435            /* Services */
    314 
     436#ifdef VBOX_WITH_GUEST_PROPS
    315437            case VBOXCLIENT_OPT_CHECKHOSTVERSION:
    316438            {
    317                 if (g_pService)
     439                if (g_Service.pDesc)
    318440                    return vbclSyntaxOnlyOneService();
    319                 g_pService = VBClGetHostVersionService();
    320                 break;
    321             }
    322 
     441                g_Service.pDesc = &g_SvcHostVersion;
     442                break;
     443            }
     444#endif
    323445#ifdef VBOX_WITH_SHARED_CLIPBOARD
    324446            case VBOXCLIENT_OPT_CLIPBOARD:
    325447            {
    326                 if (g_pService)
     448                if (g_Service.pDesc)
    327449                    return vbclSyntaxOnlyOneService();
    328                 g_pService = VBClGetClipboardService();
     450                g_Service.pDesc = &g_SvcClipboard;
    329451                break;
    330452            }
     
    333455            case VBOXCLIENT_OPT_DRAGANDDROP:
    334456            {
    335                 if (g_pService)
     457                if (g_Service.pDesc)
    336458                    return vbclSyntaxOnlyOneService();
    337                 g_pService = VBClGetDragAndDropService();
    338                 break;
    339             }
    340 #endif
     459                g_Service.pDesc = &g_SvcDragAndDrop;
     460                break;
     461            }
     462#endif
     463#ifdef VBOX_WITH_SEAMLESS
    341464            case VBOXCLIENT_OPT_SEAMLESS:
    342465            {
    343                 if (g_pService)
     466                if (g_Service.pDesc)
    344467                    return vbclSyntaxOnlyOneService();
    345                 g_pService = VBClGetSeamlessService();
    346                 break;
    347             }
    348 
     468                g_Service.pDesc = &g_SvcSeamless;
     469                break;
     470            }
     471#endif
     472#ifdef VBOX_WITH_VMSVGA
    349473            case VBOXCLIENT_OPT_VMSVGA:
    350474            {
    351                 if (g_pService)
     475                if (g_Service.pDesc)
    352476                    return vbclSyntaxOnlyOneService();
    353                 g_pService = VBClDisplaySVGAX11Service();
    354                 break;
    355             }
     477                g_Service.pDesc = &g_SvcDisplaySVGA;
     478                break;
     479            }
     480#endif
     481            case VINF_GETOPT_NOT_OPTION:
     482                break;
    356483
    357484            case VERR_GETOPT_UNKNOWN_OPTION:
    358             {
    359                 RTMsgError("unrecognized option '%s'", ValueUnion.psz);
    360                 RTMsgInfo("Try '%s --help' for more information", pcszFileName);
    361                 return RTEXITCODE_SYNTAX;
    362             }
    363 
    364             case VINF_GETOPT_NOT_OPTION:
     485                RT_FALL_THROUGH();
    365486            default:
    366                 break;
     487            {
     488                if (   g_Service.pDesc
     489                    && g_Service.pDesc->pfnOption)
     490                {
     491                    rc = g_Service.pDesc->pfnOption(NULL, argc, argv, &GetState.iNext);
     492                }
     493                else /* No service specified yet. */
     494                    rc = VERR_NOT_FOUND;
     495
     496                if (RT_FAILURE(rc))
     497                {
     498                    RTMsgError("unrecognized option '%s'", ValueUnion.psz);
     499                    RTMsgInfo("Try '%s --help' for more information", pcszFileName);
     500                    return RTEXITCODE_SYNTAX;
     501                }
     502                break;
     503            }
    367504
    368505        } /* switch */
    369506    } /* while RTGetOpt */
    370507
    371     if (!g_pService)
    372     {
    373         RTMsgError("No service specified. Quitting because nothing to do!");
    374         return RTEXITCODE_SYNTAX;
    375     }
     508    if (!g_Service.pDesc)
     509        return RTMsgErrorExit(RTEXITCODE_SYNTAX, "No service specified. Quitting because nothing to do!");
    376510
    377511    /* Initialize VbglR3 before we do anything else with the logger. */
    378512    rc = VbglR3InitUser();
    379513    if (RT_FAILURE(rc))
    380         VBClLogFatalError("VbglR3InitUser failed: %Rrc", rc);
     514        return RTMsgErrorExitFailure("VbglR3InitUser failed: %Rrc", rc);
    381515
    382516    rc = VBClLogCreate(g_szLogFile[0] ? g_szLogFile : NULL);
    383517    if (RT_FAILURE(rc))
    384         return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to create release log '%s', rc=%Rrc\n",
     518        return RTMsgErrorExitFailure("Failed to create release log '%s', rc=%Rrc\n",
    385519                              g_szLogFile[0] ? g_szLogFile : "<None>", rc);
    386 
    387     LogRel(("Service: %s\n", (*g_pService)->getName()));
    388520
    389521    if (!fDaemonise)
     
    399531    }
    400532
     533    VBClLogInfo("VBoxClient %s r%s started. Verbose level = %d\n", RTBldCfgVersion(), RTBldCfgRevisionStr(), g_cVerbosity);
     534    VBClLogInfo("Service: %s\n", g_Service.pDesc->pszDesc);
     535
    401536    rc = RTCritSectInit(&g_critSect);
    402537    if (RT_FAILURE(rc))
    403         VBClLogFatalError("Initialising critical section failed: %Rrc\n", rc);
    404     if ((*g_pService)->getPidFilePath)
     538        VBClLogFatalError("Initializing critical section failed: %Rrc\n", rc);
     539    if (g_Service.pDesc->pszPidFilePath)
    405540    {
    406541        rc = RTPathUserHome(g_szPidFile, sizeof(g_szPidFile));
    407542        if (RT_FAILURE(rc))
    408             VBClLogFatalError("Getting home directory for PID file failed: %Rrc\n", rc);
    409         rc = RTPathAppend(g_szPidFile, sizeof(g_szPidFile),
    410                           (*g_pService)->getPidFilePath());
     543            VBClLogFatalError("Getting home directory failed: %Rrc\n", rc);
     544        rc = RTPathAppend(g_szPidFile, sizeof(g_szPidFile), g_Service.pDesc->pszPidFilePath);
    411545        if (RT_FAILURE(rc))
    412546            VBClLogFatalError("Creating PID file path failed: %Rrc\n", rc);
     
    414548            rc = VbglR3Daemonize(false /* fNoChDir */, false /* fNoClose */, fRespawn, &g_cRespawn);
    415549        if (RT_FAILURE(rc))
    416             VBClLogFatalError("Daemonizing failed: %Rrc\n", rc);
     550            VBClLogFatalError("Daemonizing service failed: %Rrc\n", rc);
    417551        if (g_szPidFile[0])
    418552            rc = VbglR3PidFile(g_szPidFile, &g_hPidFile);
     
    422556            VBClLogFatalError("Creating PID file failed: %Rrc\n", rc);
    423557    }
    424     /* Set signal handlers to clean up on exit. */
    425     vboxClientSetSignalHandlers();
     558
    426559#ifndef VBOXCLIENT_WITHOUT_X11
    427560    /* Set an X11 error handler, so that we don't die when we get unavoidable
     
    432565    XSetIOErrorHandler(vboxClientXLibIOErrorHandler);
    433566#endif
    434     rc = (*g_pService)->init(g_pService);
     567
     568    bool fSignalHandlerInstalled = false;
    435569    if (RT_SUCCESS(rc))
    436570    {
    437         rc = (*g_pService)->run(g_pService, fDaemonise);
     571        rc = vboxClientSignalHandlerInstall();
     572        if (RT_SUCCESS(rc))
     573            fSignalHandlerInstalled = true;
     574    }
     575
     576    if (   RT_SUCCESS(rc)
     577        && g_Service.pDesc->pfnInit)
     578    {
     579        VBClLogInfo("Initializing service ...\n");
     580        rc = g_Service.pDesc->pfnInit();
     581    }
     582
     583    if (RT_SUCCESS(rc))
     584    {
     585        VBClLogInfo("Creating worker thread ...\n");
     586        rc = RTThreadCreate(&g_Service.Thread, vbclThread, (void *)&g_Service, 0,
     587                            RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, g_Service.pDesc->pszName);
    438588        if (RT_FAILURE(rc))
    439             VBClLogError("Running service failed: %Rrc\n", rc);
     589        {
     590            VBClLogError("Creating worker thread failed, rc=%Rrc\n", rc);
     591        }
     592        else
     593        {
     594            g_Service.fStarted = true;
     595
     596            /* Wait for the thread to initialize. */
     597            /** @todo There is a race between waiting and checking
     598             * the fShutdown flag of a thread here and processing
     599             * the thread's actual worker loop. If the thread decides
     600             * to exit the loop before we skipped the fShutdown check
     601             * below the service will fail to start! */
     602            /** @todo This presumably means either a one-shot service or that
     603             * something has gone wrong.  In the second case treating it as failure
     604             * to start is probably right, so we need a way to signal the first
     605             * rather than leaving the idle thread hanging around.  A flag in the
     606             * service description? */
     607            RTThreadUserWait(g_Service.Thread, RT_MS_1MIN);
     608            if (g_Service.fShutdown)
     609            {
     610                VBClLogError("Service failed to start!\n");
     611                rc = VERR_GENERAL_FAILURE;
     612            }
     613            else
     614            {
     615                VBClLogInfo("Service started\n");
     616
     617                int rcThread;
     618                rc = RTThreadWait(g_Service.Thread, RT_INDEFINITE_WAIT, &rcThread);
     619                if (RT_SUCCESS(rc))
     620                    rc = rcThread;
     621
     622                if (RT_FAILURE(rc))
     623                    VBClLogError("Waiting on worker thread to stop failed, rc=%Rrc\n", rc);
     624
     625                if (g_Service.pDesc->pfnTerm)
     626                {
     627                    VBClLogInfo("Terminating service\n");
     628
     629                    int rc2 = g_Service.pDesc->pfnTerm();
     630                    if (RT_SUCCESS(rc))
     631                        rc = rc2;
     632
     633                    if (RT_SUCCESS(rc))
     634                    {
     635                        VBClLogInfo("Service terminated\n");
     636                    }
     637                    else
     638                        VBClLogError("Service failed to terminate, rc=%Rrc\n", rc);
     639                }
     640            }
     641        }
     642    }
     643
     644    if (RT_FAILURE(rc))
     645    {
     646        if (rc == VERR_NOT_AVAILABLE)
     647            VBClLogInfo("Service is not availabe, skipping\n");
     648        else if (rc == VERR_NOT_SUPPORTED)
     649            VBClLogInfo("Service is not supported on this platform, skipping\n");
     650        else
     651            VBClLogError("Service ended with error %Rrc\n", rc);
    440652    }
    441653    else
    442     {
    443         /** @todo r=andy Should we return an appropriate exit code if the service failed to init?
    444          *               Must be tested carefully with our init scripts first. */
    445         VBClLogError("Initializing service failed: %Rrc\n", rc);
    446     }
    447     VBClCleanUp(false /*fExit*/);
     654        VBClLogVerbose(2, "Service ended\n");
     655
     656    if (fSignalHandlerInstalled)
     657    {
     658        int rc2 = vboxClientSignalHandlerUninstall();
     659        AssertRC(rc2);
     660    }
     661
     662    VBClShutdown(false /*fExit*/);
     663
     664    /** @todo r=andy Should we return an appropriate exit code if the service failed to init?
     665     *               Must be tested carefully with our init scripts first. */
    448666    return RTEXITCODE_SUCCESS;
    449667}
     668
  • 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 }
  • trunk/src/VBox/Additions/x11/VBoxClient/seamless.h

    r82968 r86871  
    8484#endif
    8585
    86     /**
    87       * Initialise the service.
    88       */
     86    /** @copydoc VBCLSERVICE::pfnInit */
    8987    int init(void);
    9088
    91     /**
    92       * Run the service.
    93       * @returns iprt status value
    94       */
    95     int run(void);
     89    /** @copydoc VBCLSERVICE::pfnWorker */
     90    int worker(bool volatile *pfShutdown);
    9691
    97     /**
    98      * Stops the service.
    99      */
    100     void stop();
     92    /** @copydoc VBCLSERVICE::pfnStop */
     93    void stop(void);
    10194
    102     /** Pause the service loop.  This must be safe to call on a different thread
    103      * and potentially before @a run is or after it exits.
    104      * This is called by the VT monitoring thread to allow the service to disable
    105      * itself when the X server is switched out.  If the monitoring functionality
    106      * is available then @a pause or @a resume will be called as soon as it starts
    107      * up. */
    108     int pause();
    109     /** Resume after pausing.  The same applies here as for @a pause. */
    110     int resume();
    111 
    112     /** Run a few tests to be sure everything is working as intended. */
    113     int selfTest();
     95    /** @copydoc VBCLSERVICE::pfnTerm */
     96    int term(void);
    11497};
    11598
  • trunk/src/VBox/Additions/x11/VBoxClient/testcase/tstSeamlessX11.cpp

    r82968 r86871  
    5858
    5959    exit(1);
     60}
     61
     62void VBClLogVerbose(unsigned iLevel, const char *pszFormat, ...)
     63{
     64    RT_NOREF(iLevel);
     65
     66    va_list va;
     67    va_start(va, pszFormat);
     68    RTPrintf("%s", pszFormat);
     69    va_end(va);
    6070}
    6171
     
    156166        RTPrintf("Failed to initialise seamless Additions, rc = %Rrc\n", rc);
    157167    }
    158     rc = seamless.run();
     168    bool fShutdown = false;
     169    rc = seamless.worker(&fShutdown);
    159170    if (rc != VINF_SUCCESS)
    160171    {
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