Changeset 86871 in vbox
- Timestamp:
- Nov 12, 2020 10:15:18 AM (4 years ago)
- Location:
- trunk/src/VBox/Additions/x11/VBoxClient
- Files:
-
- 11 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Additions/x11/VBoxClient/Makefile.kmk
r85977 r86871 21 21 # Use header files from our tree for randr and xinerama. and don't link but rather dlopen libXrand 22 22 VBOX_WITH_DISTRO_XRAND_XINERAMA= 23 24 # We don't yet have a seamless mode compilation flag, so define it here unconditionally. 25 VBOX_WITH_SEAMLESS:=1 23 26 24 27 # … … 46 49 VBoxClient_SOURCES = \ 47 50 main.cpp \ 48 display-svga-x11.cpp \ 49 seamless.cpp \ 50 seamless-x11.cpp \ 51 logging.cpp \ 52 hostversion.cpp 51 logging.cpp 53 52 54 53 VBoxDRMClient_TEMPLATE = NewVBoxGuestR3Exe … … 84 83 ifdef VBOX_WITH_DRAG_AND_DROP 85 84 ifdef VBOX_DND_WITH_XTEST 86 VBoxClient_DEFS += VBOX_DND_WITH_XTEST87 VBoxClient_LIBS += \85 VBoxClient_DEFS += VBOX_DND_WITH_XTEST 86 VBoxClient_LIBS += \ 88 87 Xtst 89 88 endif … … 94 93 # how else to do that without recompiling or implementing our own memcpy. 95 94 ifeq ($(KBUILD_TARGET),linux) 96 VBoxClient_LDFLAGS.amd64 += \95 VBoxClient_LDFLAGS.amd64 += \ 97 96 -Wl,--wrap=memcpy 98 97 endif 99 98 100 99 ifdef VBOX_WITH_GUEST_PROPS 101 VBoxClient_DEFS += VBOX_WITH_GUEST_PROPS 100 VBoxClient_DEFS += VBOX_WITH_GUEST_PROPS 101 VBoxClient_SOURCES += \ 102 hostversion.cpp 102 103 endif 103 104 104 105 ifdef VBOX_WITH_DRAG_AND_DROP 105 VBoxClient_DEFS+= \106 VBoxClient_DEFS += \ 106 107 VBOX_WITH_DRAG_AND_DROP \ 107 108 $(if $(VBOX_WITH_DRAG_AND_DROP_GH),VBOX_WITH_DRAG_AND_DROP_GH,) 108 VBoxClient_SOURCES+= \109 VBoxClient_SOURCES += \ 109 110 draganddrop.cpp 110 VBoxClient_LIBS += \111 VBoxClient_LIBS += \ 111 112 $(VBOX_LIB_VBGL_R3) \ 112 113 $(PATH_STAGE_LIB)/additions/VBoxDnDGuestR3Lib$(VBOX_SUFF_LIB) 113 114 endif 114 115 116 ifdef VBOX_WITH_SEAMLESS 117 VBoxClient_DEFS += VBOX_WITH_SEAMLESS 118 VBoxClient_SOURCES += \ 119 seamless.cpp \ 120 seamless-x11.cpp 121 endif 122 123 ifdef VBOX_WITH_VMSVGA 124 VBoxClient_DEFS += VBOX_WITH_VMSVGA 125 VBoxClient_SOURCES += \ 126 display-svga-x11.cpp 127 endif 128 115 129 ifdef VBOX_WITH_SHARED_CLIPBOARD 116 VBoxClient_DEFS += \130 VBoxClient_DEFS += \ 117 131 VBOX_WITH_SHARED_CLIPBOARD \ 118 132 $(if $(VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS),VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS,) 119 VBoxClient_SOURCES += \133 VBoxClient_SOURCES += \ 120 134 $(PATH_ROOT)/src/VBox/GuestHost/SharedClipboard/clipboard-common.cpp \ 121 135 $(PATH_ROOT)/src/VBox/GuestHost/SharedClipboard/clipboard-x11.cpp \ … … 172 186 seamless.cpp \ 173 187 seamless-x11.cpp 188 tstSeamlessX11_DEFS += VBOX_BUILD_TARGET=\"$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)\" 174 189 tstSeamlessX11_LIBPATH = \ 175 190 $(VBOX_LIBPATH_X11) -
trunk/src/VBox/Additions/x11/VBoxClient/VBoxClient.h
r84501 r86871 30 30 void VBClLogError(const char *pszFormat, ...); 31 31 void VBClLogFatalError(const char *pszFormat, ...); 32 void VBClLogVerbose(unsigned iLevel, const char *pszFormat, ...); 33 34 int VBClLogCreate(const char *pszLogFile); 32 35 void VBClLogDestroy(void); 33 int VBClLogCreate(const char *pszLogFile);34 36 35 37 /** Call clean-up for the current service and exit. */ 36 extern void VBCl CleanUp(bool fExit = true);38 extern void VBClShutdown(bool fExit = true); 37 39 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 */ 43 typedef struct 41 44 { 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; 44 49 /** Get the services default path to pidfile, relative to $HOME */ 45 50 /** @todo Should this also have a component relative to the X server number? 46 51 */ 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. 55 67 */ 56 void (*cleanup)(struct VBCLSERVICE **ppInterface); 57 }; 68 DECLCALLBACKMEMBER(int, pfnOption,(const char **ppszShort, int argc, char **argv, int *pi)); 58 69 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)); 65 76 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)); 73 85 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. */ 101 typedef VBCLSERVICE *PVBCLSERVICE; 102 /** Pointer to a const VBCLSERVICE. */ 103 typedef VBCLSERVICE const *PCVBCLSERVICE; 104 105 RT_C_DECLS_BEGIN 106 extern VBCLSERVICE g_SvcClipboard; 107 extern VBCLSERVICE g_SvcDisplayDRM; 108 extern VBCLSERVICE g_SvcDisplaySVGA; 109 extern VBCLSERVICE g_SvcDragAndDrop; 110 extern VBCLSERVICE g_SvcHostVersion; 111 extern VBCLSERVICE g_SvcSeamless; 112 113 extern bool g_fDaemonized; 114 RT_C_DECLS_END 83 115 84 116 #endif /* !GA_INCLUDED_SRC_x11_VBoxClient_VBoxClient_h */ -
trunk/src/VBox/Additions/x11/VBoxClient/clipboard.cpp
r85834 r86871 58 58 59 59 /** 60 * Global clipboard context information.60 * Struct keeping a Shared Clipboard context. 61 61 */ 62 62 struct SHCLCONTEXT … … 75 75 }; 76 76 77 /** Only one c lient is supported. There seems to be no need for more clients. */77 /** Only one context is supported at a time for now. */ 78 78 static SHCLCONTEXT g_Ctx; 79 79 … … 258 258 int vboxClipboardMain(void) 259 259 { 260 LogRel(("Worker loop running\n"));261 262 260 int rc; 263 261 … … 331 329 case VBGLR3CLIPBOARDEVENTTYPE_QUIT: 332 330 { 333 LogRel2(("Host requested termination\n"));331 VBClLogVerbose(2, "Host requested termination\n"); 334 332 fShutdown = true; 335 333 break; … … 368 366 } 369 367 370 LogRel(("Worker loop ended\n"));371 372 368 LogFlowFuncLeaveRC(rc); 373 369 return rc; … … 377 373 static DECLCALLBACK(int) vboxClipoardFUSEThread(RTTHREAD hThreadSelf, void *pvUser) 378 374 { 379 RT_NOREF( hThreadSelf,pvUser);375 RT_NOREF(pvUser); 380 376 381 377 VbglR3Init(); … … 409 405 } 410 406 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 413 static int vboxClipboardFUSEStart(void) 418 414 { 419 415 LogFlowFuncEnter(); … … 430 426 } 431 427 432 static int vboxClipboardFUSEStop( )428 static int vboxClipboardFUSEStop(void) 433 429 { 434 430 LogFlowFuncEnter(); … … 444 440 #endif /* VBOX_WITH_SHARED_CLIPBOARD_FUSE */ 445 441 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 */ 443 static int vbclShClInit(void) 444 { 460 445 int rc; 461 446 … … 470 455 } 471 456 472 static int run(struct VBCLSERVICE **ppInterface, bool fDaemonised) 473 { 474 RT_NOREF(ppInterface, fDaemonised); 457 /** @copydoc VBCLSERVICE::pfnWorker */ 458 static int vbclShClWorker(bool volatile *pfShutdown) 459 { 460 RT_NOREF(pfShutdown); 475 461 476 462 /* Initialise the guest library. */ … … 483 469 { 484 470 #endif 471 /* Let the main thread know that it can continue spawning services. */ 472 RTThreadUserSignal(RTThreadSelf()); 473 485 474 rc = vboxClipboardMain(); 486 475 … … 502 491 } 503 492 504 static void cleanup(struct VBCLSERVICE **ppInterface) 505 { 506 RT_NOREF(ppInterface); 507 493 /** @copydoc VBCLSERVICE::pfnStop */ 494 static 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 */ 503 static int vbclShClTerm(void) 504 { 508 505 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS 509 506 ShClTransferCtxDestroy(&g_Ctx.TransferCtx); 510 507 #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 512 VBCLSERVICE 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 */ 520 524 }; 521 525 522 struct CLIPBOARDSERVICE523 {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 733 733 * it (guest property) is set. 734 734 */ 735 static bool checkDRMClient( )735 static bool checkDRMClient(void) 736 736 { 737 737 uint32_t uGuestPropSvcClientID; … … 745 745 } 746 746 747 static bool startDRMClient( )747 static bool startDRMClient(void) 748 748 { 749 749 char* argv[] = {NULL}; … … 755 755 int rc = execve(szDRMClientPath, argv, env); 756 756 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)); 758 758 /* This is reached only when execve fails. */ 759 759 return false; 760 760 } 761 761 762 static bool init() 763 { 762 /** @copydoc VBCLSERVICE::pfnInit */ 763 static 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 764 772 /* If DRM client is already running don't start this service. */ 765 773 if (checkDRMClient()) 766 774 { 767 775 VBClLogFatalError("DRM resizing is already running. Exiting this service\n"); 768 return false;776 return VERR_NOT_AVAILABLE; 769 777 } 770 778 if (isXwayland()) … … 781 789 } 782 790 783 static void cleanup() 791 /** @copydoc VBCLSERVICE::pfnStop */ 792 static void vbclSVGAStop(void) 784 793 { 785 794 if (mpMonitorPositions) … … 788 797 mpMonitorPositions = NULL; 789 798 } 790 stopX11MonitorThread(); 799 800 stopX11MonitorThread(); /** @todo r=andy We ignore rc!? */ 801 791 802 if (x11Context.pRandLibraryHandle) 792 803 { … … 1331 1342 } 1332 1343 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; 1344 static int vbclSVGAWorker(bool volatile *pfShutdown) 1345 { 1346 RT_NOREF(pfShutdown); 1356 1347 1357 1348 /* Do not acknowledge the first event we query for to pick up old events, … … 1369 1360 if (rc == VERR_RESOURCE_BUSY) /* Someone else has already acquired it. */ 1370 1361 return VERR_RESOURCE_BUSY; 1362 1363 /* Let the main thread know that it can continue spawning services. */ 1364 RTThreadUserSignal(RTThreadSelf()); 1365 1371 1366 for (;;) 1372 1367 { … … 1442 1437 VBClLogFatalError("Failure waiting for event, rc=%Rrc\n", rc); 1443 1438 } 1444 cleanup(); 1445 } 1446 1447 static struct VBCLSERVICE interface = 1448 { 1449 getName,1450 getPidFilePath,1451 VBClServiceDefaultHandler, /* Init*/1452 run,1453 VBClServiceDefaultCleanup1454 }, *pInterface = &interface; 1455 1456 struct VBCLSERVICE **VBClDisplaySVGAX11Service() 1457 { 1458 return &pInterface;1459 } 1439 } 1440 1441 VBCLSERVICE 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 543 543 544 544 int init(uint32_t uScreenID); 545 void uninit(void); 545 int term(void); 546 void stop(void); 546 547 void reset(void); 547 548 … … 666 667 } 667 668 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); 671 673 672 674 private: … … 677 679 /* Private member vars */ 678 680 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; 683 683 /** Critical section for providing serialized access to list 684 684 * event queue's contents. */ 685 685 RTCRITSECT m_eventQueueCS; 686 /** Thread handle for the HGCM message pumping thread. */ 686 687 RTTHREAD m_hHGCMThread; 688 /** Thread handle for the X11 message pumping thread. */ 687 689 RTTHREAD m_hX11Thread; 688 690 /** This service' DnD command context. */ 689 691 VBGLR3GUESTDNDCMDCTX m_dndCtx; 692 /** Event semaphore for new DnD events. */ 690 693 RTSEMEVENT m_hEventSem; 694 /** Pointer to the allocated DnD instance. 695 Currently we only support and handle one instance at a time. */ 691 696 DragInstance *m_pCurDnD; 692 697 /** Stop indicator flag to signal the thread that it should shut down. */ … … 694 699 695 700 friend class DragInstance; 696 } ;701 } g_Svc; 697 702 698 703 /********************************************************************************************************************************* … … 715 720 716 721 /** 717 * Unitializes (destroys) this drag instance. 718 */ 719 void DragInstance::uninit(void) 722 * Stops this drag instance. 723 */ 724 void 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 */ 739 int DragInstance::term(void) 720 740 { 721 741 LogFlowFuncEnter(); … … 724 744 XDestroyWindow(m_pDisplay, m_wndProxy.hWnd); 725 745 726 int rc2 = VbglR3DnDDisconnect(&m_dndCtx); 746 int rc = VbglR3DnDDisconnect(&m_dndCtx); 747 AssertRCReturn(rc, rc); 727 748 728 749 if (m_pvSelReqData) 729 750 RTMemFree(m_pvSelReqData); 730 751 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; 739 763 } 740 764 … … 3067 3091 ********************************************************************************************************************************/ 3068 3092 3069 /** 3070 * Initializes the drag and drop service. 3071 * 3072 * @returns IPRT status code. 3073 */ 3093 /** @copydoc VBCLSERVICE::pfnInit */ 3074 3094 int DragAndDropService::init(void) 3075 3095 { … … 3106 3126 AssertRCBreak(rc); 3107 3127 3108 rc = RTThreadUserWait(m_hHGCMThread, 10 * 1000 /* 10s timeout */);3128 rc = RTThreadUserWait(m_hHGCMThread, RT_MS_30SEC); 3109 3129 AssertRCBreak(rc); 3110 3130 … … 3117 3137 AssertRCBreak(rc); 3118 3138 3119 rc = RTThreadUserWait(m_hX11Thread, 10 * 1000 /* 10s timeout */);3139 rc = RTThreadUserWait(m_hX11Thread, RT_MS_30SEC); 3120 3140 AssertRCBreak(rc); 3121 3141 … … 3135 3155 } 3136 3156 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 */ 3158 int DragAndDropService::worker(bool volatile *pfShutdown) 3159 { 3150 3160 int rc; 3151 3161 do … … 3167 3177 if (RT_FAILURE(rc)) 3168 3178 VBClLogError("Unable to connect to drag and drop service, rc=%Rrc\n", rc); 3169 else if (rc == VINF_PERMISSION_DENIED) 3170 VBClLog Error("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"); 3171 3181 break; 3172 3182 } 3173 3183 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()); 3176 3186 3177 3187 /* Enter the main event processing loop. */ … … 3282 3292 } 3283 3293 #endif 3294 case VBGLR3DNDEVENTTYPE_QUIT: 3295 { 3296 rc = VINF_SUCCESS; 3297 break; 3298 } 3299 3284 3300 default: 3285 3301 { 3286 VBClLogError("Received unsupported message '%RU32'\n", pVbglR3Event->enmType);3302 VBClLogError("Received unsupported message type %RU32\n", pVbglR3Event->enmType); 3287 3303 rc = VERR_NOT_SUPPORTED; 3288 3304 break; … … 3294 3310 { 3295 3311 /* 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); 3297 3313 3298 3314 /* If anything went wrong, do a reset and start over. */ … … 3300 3316 } 3301 3317 3318 const bool fQuit = pVbglR3Event->enmType == VBGLR3DNDEVENTTYPE_QUIT; 3319 3302 3320 VbglR3DnDEventFree(e.hgcm); 3303 3321 e.hgcm = NULL; 3322 3323 if (fQuit) 3324 break; 3304 3325 } 3305 3326 else if (e.enmType == DnDEvent::DnDEventType_X11) … … 3317 3338 XFlush(m_pDisplay); 3318 3339 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)); 3322 3344 3323 3345 } while (0); … … 3333 3355 } 3334 3356 3335 void DragAndDropService::cleanup(void) 3357 /** @copydoc VBCLSERVICE::pfnStop */ 3358 void DragAndDropService::stop(void) 3336 3359 { 3337 3360 LogFlowFuncEnter(); 3338 3339 VBClLogInfo("Terminating ...\n");3340 3361 3341 3362 /* Set stop flag first. */ 3342 3363 ASMAtomicXchgBool(&m_fStop, true); 3343 3364 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. */ 3345 3370 VbglR3DnDDisconnect(&m_dndCtx); 3371 3372 LogFlowFuncLeave(); 3373 } 3374 3375 /** @copydoc VBCLSERVICE::pfnTerm */ 3376 int DragAndDropService::term(void) 3377 { 3378 int rc = VINF_SUCCESS; 3346 3379 3347 3380 /* 3348 3381 * Wait for threads to terminate. 3349 3382 */ 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); 3356 3390 if (RT_SUCCESS(rc2)) 3357 3391 rc2 = rcThread; 3358 3392 3359 3393 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); 3368 3409 if (RT_SUCCESS(rc2)) 3369 3410 rc2 = rcThread; 3370 3411 3371 3412 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 } 3376 3428 3377 3429 xHelpers::destroyInstance(); 3378 3430 3379 VbglR3Term();3431 return rc; 3380 3432 } 3381 3433 … … 3399 3451 AssertRCReturn(rc, rc); 3400 3452 3453 VBClLogVerbose(2, "HGCM thread started\n"); 3454 3401 3455 /* Number of invalid messages skipped in a row. */ 3402 3456 int cMsgSkippedInvalid = 0; … … 3421 3475 else 3422 3476 { 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) 3427 3484 { 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; 3439 3487 } 3440 3488 } 3441 3489 3442 3490 } while (!ASMAtomicReadBool(&pThis->m_fStop)); 3491 3492 VBClLogVerbose(2, "HGCM thread ended\n"); 3443 3493 3444 3494 LogFlowFuncLeaveRC(rc); … … 3465 3515 /* Note: Nothing to initialize here (yet). */ 3466 3516 3467 /* Set stop indicator on failure. */3468 if (RT_FAILURE(rc))3469 ASMAtomicXchgBool(&pThis->m_fStop, true);3470 3471 3517 /* Let the service instance know in any case. */ 3472 3518 int rc2 = RTThreadUserSignal(hThread); 3473 3519 AssertRC(rc2); 3520 3521 VBClLogVerbose(2, "X11 thread started\n"); 3474 3522 3475 3523 DnDEvent e; … … 3503 3551 } while (!ASMAtomicReadBool(&pThis->m_fStop)); 3504 3552 3553 VBClLogVerbose(2, "X11 thread ended\n"); 3554 3505 3555 LogFlowFuncLeaveRC(rc); 3506 3556 return rc; 3507 3557 } 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 */ 3559 static int vbclDnDInit(void) 3560 { 3561 return g_Svc.init(); 3562 } 3563 3564 /** @copydoc VBCLSERVICE::pfnWorker */ 3565 static int vbclDnDWorker(bool volatile *pfShutdown) 3566 { 3567 return g_Svc.worker(pfShutdown); 3568 } 3569 3570 /** @copydoc VBCLSERVICE::pfnStop */ 3571 static void vbclDnDStop(void) 3572 { 3573 g_Svc.stop(); 3574 } 3575 3576 /** @copydoc VBCLSERVICE::pfnTerm */ 3577 static int vbclDnDTerm(void) 3578 { 3579 return g_Svc.term(); 3580 } 3581 3582 VBCLSERVICE 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 */ 3523 3594 }; 3524 3595 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 cleanup3569 };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 1 1 /* $Id$ */ 2 2 /** @file 3 * X11 guest client - host version check.3 * X11 guest client - Host version check. 4 4 */ 5 5 … … 34 34 #include "VBoxClient.h" 35 35 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 46 36 static int showNotify(const char *pszHeader, const char *pszBody) 47 37 { … … 50 40 DBusConnection *conn; 51 41 DBusMessage* msg = NULL; 52 conn = dbus_bus_get 42 conn = dbus_bus_get(DBUS_BUS_SESSION, NULL); 53 43 if (conn == NULL) 54 44 { 55 LogRelFlowFunc(("Could not retrieve D-BUS session bus!\n"));45 VBClLogError("Could not retrieve D-BUS session bus\n"); 56 46 rc = VERR_INVALID_HANDLE; 57 47 } … … 127 117 } 128 118 119 /** @copydoc VBCLSERVICE::pfnWorker */ 129 120 /** @todo Move this part in VbglR3 and just provide a callback for the platform-specific 130 121 notification stuff, since this is very similar to the VBoxTray code. */ 131 static int run(struct VBCLSERVICE **ppInterface, bool fDaemonised)122 static int vbclHostVerWorker(bool volatile *pfShutdown) 132 123 { 124 RT_NOREF(pfShutdown); 125 126 LogFlowFuncEnter(); 127 133 128 int rc; 134 LogFlowFunc(("\n"));135 136 RT_NOREF(ppInterface);137 138 /* Because we need desktop notifications to be displayed, wait139 * some time to make the desktop environment load (as a work around). */140 if (fDaemonised)141 RTThreadSleep(30 * 1000 /* Wait 30 seconds */);142 143 129 # ifdef VBOX_WITH_DBUS 144 130 rc = RTDBusLoadLib(); … … 155 141 rc = VbglR3GuestPropConnect(&uGuestPropSvcClientID); 156 142 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); 158 144 } 159 145 160 146 if (RT_SUCCESS(rc)) 161 147 { 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 162 156 char *pszHostVersion; 163 157 char *pszGuestVersion; 164 bool bUpdate;165 166 rc = VbglR3HostVersionCheckForUpdate(uGuestPropSvcClientID, & bUpdate, &pszHostVersion, &pszGuestVersion);158 bool fUpdate; 159 160 rc = VbglR3HostVersionCheckForUpdate(uGuestPropSvcClientID, &fUpdate, &pszHostVersion, &pszGuestVersion); 167 161 if (RT_SUCCESS(rc)) 168 162 { 169 if ( bUpdate)163 if (fUpdate) 170 164 { 171 165 char szMsg[1024]; … … 198 192 } 199 193 # endif /* VBOX_WITH_GUEST_PROPS */ 200 VbglR3Term(); 201 LogFlowFunc(("returning %Rrc\n", rc)); 194 202 195 return rc; 203 196 } 204 197 205 struct VBCLSERVICE vbclHostVersionInterface=198 VBCLSERVICE g_SvcHostVersion = 206 199 { 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 */ 212 210 }; 213 211 214 struct HOSTVERSIONSERVICE215 {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 83 83 84 84 /** 85 * Logs a verbose message. 86 * 87 * @param pszFormat The message text. 88 * @param va Format arguments. 89 */ 90 static 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 /** 85 100 * Logs a fatal error, notifies the desktop environment via a message and 86 101 * exits the application immediately. … … 97 112 va_end(args); 98 113 99 AssertPtr (psz);100 LogF lowFunc(("%s", psz));101 LogRel((" %s", psz));114 AssertPtrReturnVoid(psz); 115 LogFunc(("Fatal Error: %s", psz)); 116 LogRel(("Fatal Error: %s", psz)); 102 117 103 118 vbclLogNotify(psz); … … 119 134 va_end(args); 120 135 121 AssertPtr (psz);122 LogF lowFunc(("%s", psz));123 LogRel((" %s", psz));136 AssertPtrReturnVoid(psz); 137 LogFunc(("Error: %s", psz)); 138 LogRel(("Error: %s", psz)); 124 139 125 140 RTStrFree(psz); … … 135 150 va_list args; 136 151 va_start(args, pszFormat); 137 char *psz = NULL; 138 RTStrAPrintfV(&psz, pszFormat, args); 152 vbClLogV(pszFormat, args); 139 153 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 */ 164 void 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 } 146 173 } 147 174 … … 265 292 } 266 293 267 void foo()268 {269 } -
trunk/src/VBox/Additions/x11/VBoxClient/main.cpp
r84538 r86871 27 27 #include <iprt/buildconfig.h> 28 28 #include <iprt/critsect.h> 29 #include <iprt/errno.h> 29 30 #include <iprt/getopt.h> 30 31 #include <iprt/initterm.h> … … 34 35 #include <VBox/VBoxGuestLib.h> 35 36 #include <VBox/err.h> 37 #include <VBox/version.h> 36 38 #include "VBoxClient.h" 37 39 … … 51 53 52 54 /********************************************************************************************************************************* 55 * Local structures * 56 *********************************************************************************************************************************/ 57 /** 58 * The global service state. 59 */ 60 typedef 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. */ 76 typedef VBCLSERVICESTATE *PVBCLSERVICESTATE; 77 78 79 /********************************************************************************************************************************* 53 80 * Global Variables * 54 81 *********************************************************************************************************************************/ 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. */ 83 VBCLSERVICESTATE g_Service = { 0 }; 84 85 /** Set by the signal handler when being called. */ 86 static volatile bool g_fSignalHandlerCalled = false; 87 /** Critical section for the signal handler. */ 88 static RTCRITSECT g_csSignalHandler; 89 /** Flag indicating Whether the service starts in daemonized mode or not. */ 90 bool g_fDaemonized = false; 60 91 /** The name of our pidfile. It is global for the benefit of the cleanup 61 92 * routine. */ … … 70 101 static RTCRITSECT g_critSect; 71 102 /** Counter of how often our daemon has been respawned. */ 72 unsigned g_cRespawn = 0;103 unsigned g_cRespawn = 0; 73 104 /** Logging verbosity level. */ 74 unsigned g_cVerbosity = 0; 105 unsigned g_cVerbosity = 0; 106 /** Absolute path to log file, if any. */ 75 107 static char g_szLogFile[RTPATH_MAX + 128] = ""; 76 108 77 78 /** 79 * Clean up if we get a signal or something. 109 /** 110 * Shut down if we get a signal or something. 80 111 * 81 112 * This is extern so that we can call it from other compilation units. 82 113 */ 83 void VBCl CleanUp(bool fExit /*=true*/)114 void VBClShutdown(bool fExit /*=true*/) 84 115 { 85 116 /* We never release this, as we end up with a call to exit(3) which is not … … 89 120 if (RT_FAILURE(rc)) 90 121 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(); 93 125 if (g_szPidFile[0] && g_hPidFile) 94 126 VbglR3ClosePidFile(g_szPidFile, g_hPidFile); … … 98 130 if (fExit) 99 131 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();111 132 } 112 133 … … 130 151 { 131 152 RT_NOREF1(pDisplay); 132 VBClLogError("A fatal guest X Window error occurred. 133 VBCl CleanUp();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(); 134 155 return 0; /* We should never reach this. */ 135 156 } 136 157 137 158 /** 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 */ 161 static 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 */ 196 static int vboxClientSignalHandlerInstall(void) 142 197 { 143 198 struct sigaction sigAction; 144 145 LogRelFlowFuncEnter();146 199 sigAction.sa_handler = vboxClientSignalHandler; 147 200 sigemptyset(&sigAction.sa_mask); … … 155 208 sigaction(SIGUSR1, &sigAction, NULL); 156 209 sigaction(SIGUSR2, &sigAction, NULL); 157 LogRelFlowFuncLeave(); 210 211 return RTCritSectInit(&g_csSignalHandler); 212 } 213 214 /** 215 * Uninstalls a previously installed signal handler. 216 */ 217 static 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); 158 225 } 159 226 … … 163 230 static void vboxClientUsage(const char *pcszFileName) 164 231 { 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 165 238 RTPrintf("Usage: %s " 166 239 #ifdef VBOX_WITH_SHARED_CLIPBOARD … … 170 243 "--draganddrop|" 171 244 #endif 172 # 245 #ifdef VBOX_WITH_GUEST_PROPS 173 246 "--checkhostversion|" 174 247 #endif 248 #ifdef VBOX_WITH_SEAMLESS 175 249 "--seamless|" 250 #endif 251 #ifdef VBOX_WITH_VMSVGA 176 252 "--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"); 179 256 RTPrintf("Options:\n"); 180 257 #ifdef VBOX_WITH_SHARED_CLIPBOARD … … 187 264 RTPrintf(" --checkhostversion starts the host version notifier service\n"); 188 265 #endif 266 #ifdef VBOX_WITH_SEAMLESS 189 267 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 191 272 RTPrintf(" -f, --foreground run in the foreground (no daemonizing)\n"); 192 273 RTPrintf(" -d, --nodaemon continues running as a system service\n"); … … 209 290 210 291 /** 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 */ 298 static 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 /** 211 323 * The main loop for the VBoxClient daemon. 212 * @todo Clean up for readability.213 324 */ 214 325 int main(int argc, char *argv[]) 215 326 { 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. */ 217 330 int rc = RTR3InitExe(argc, &argv, 0); 218 331 if (RT_FAILURE(rc)) … … 222 335 * object should probably never be used from multiple threads anyway. */ 223 336 if (!XInitThreads()) 224 VBClLogFatalError("Failed to initialize X11 threads\n");337 return RTMsgErrorExitFailure("Failed to initialize X11 threads\n"); 225 338 226 339 /* Get our file name for usage info and hints. */ … … 241 354 242 355 /* Services */ 356 #ifdef VBOX_WITH_GUEST_PROPS 243 357 { "--checkhostversion", VBOXCLIENT_OPT_CHECKHOSTVERSION, RTGETOPT_REQ_NOTHING }, 358 #endif 244 359 #ifdef VBOX_WITH_SHARED_CLIPBOARD 245 360 { "--clipboard", VBOXCLIENT_OPT_CLIPBOARD, RTGETOPT_REQ_NOTHING }, … … 248 363 { "--draganddrop", VBOXCLIENT_OPT_DRAGANDDROP, RTGETOPT_REQ_NOTHING }, 249 364 #endif 365 #ifdef VBOX_WITH_SEAMLESS 250 366 { "--seamless", VBOXCLIENT_OPT_SEAMLESS, RTGETOPT_REQ_NOTHING }, 367 #endif 368 #ifdef VBOX_WITH_VMSVGA 251 369 { "--vmsvga", VBOXCLIENT_OPT_VMSVGA, RTGETOPT_REQ_NOTHING }, 370 #endif 252 371 }; 253 372 … … 256 375 RTGETOPTSTATE GetState; 257 376 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 258 380 AssertRC(rc); 259 381 … … 289 411 rc = RTStrCopy(g_szLogFile, sizeof(g_szLogFile), ValueUnion.psz); 290 412 if (RT_FAILURE(rc)) 291 VBClLogFatalError("Unable to createlog file path, rc=%Rrc\n", rc);413 return RTMsgErrorExitFailure("Unable to set log file path, rc=%Rrc\n", rc); 292 414 break; 293 415 } … … 295 417 case 'n': 296 418 { 297 fRespawn 419 fRespawn = false; 298 420 break; 299 421 } … … 312 434 313 435 /* Services */ 314 436 #ifdef VBOX_WITH_GUEST_PROPS 315 437 case VBOXCLIENT_OPT_CHECKHOSTVERSION: 316 438 { 317 if (g_ pService)439 if (g_Service.pDesc) 318 440 return vbclSyntaxOnlyOneService(); 319 g_ pService = VBClGetHostVersionService();320 break; 321 } 322 441 g_Service.pDesc = &g_SvcHostVersion; 442 break; 443 } 444 #endif 323 445 #ifdef VBOX_WITH_SHARED_CLIPBOARD 324 446 case VBOXCLIENT_OPT_CLIPBOARD: 325 447 { 326 if (g_ pService)448 if (g_Service.pDesc) 327 449 return vbclSyntaxOnlyOneService(); 328 g_ pService = VBClGetClipboardService();450 g_Service.pDesc = &g_SvcClipboard; 329 451 break; 330 452 } … … 333 455 case VBOXCLIENT_OPT_DRAGANDDROP: 334 456 { 335 if (g_ pService)457 if (g_Service.pDesc) 336 458 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 341 464 case VBOXCLIENT_OPT_SEAMLESS: 342 465 { 343 if (g_ pService)466 if (g_Service.pDesc) 344 467 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 349 473 case VBOXCLIENT_OPT_VMSVGA: 350 474 { 351 if (g_ pService)475 if (g_Service.pDesc) 352 476 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; 356 483 357 484 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(); 365 486 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 } 367 504 368 505 } /* switch */ 369 506 } /* while RTGetOpt */ 370 507 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!"); 376 510 377 511 /* Initialize VbglR3 before we do anything else with the logger. */ 378 512 rc = VbglR3InitUser(); 379 513 if (RT_FAILURE(rc)) 380 VBClLogFatalError("VbglR3InitUser failed: %Rrc", rc);514 return RTMsgErrorExitFailure("VbglR3InitUser failed: %Rrc", rc); 381 515 382 516 rc = VBClLogCreate(g_szLogFile[0] ? g_szLogFile : NULL); 383 517 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", 385 519 g_szLogFile[0] ? g_szLogFile : "<None>", rc); 386 387 LogRel(("Service: %s\n", (*g_pService)->getName()));388 520 389 521 if (!fDaemonise) … … 399 531 } 400 532 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 401 536 rc = RTCritSectInit(&g_critSect); 402 537 if (RT_FAILURE(rc)) 403 VBClLogFatalError("Initiali sing 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) 405 540 { 406 541 rc = RTPathUserHome(g_szPidFile, sizeof(g_szPidFile)); 407 542 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); 411 545 if (RT_FAILURE(rc)) 412 546 VBClLogFatalError("Creating PID file path failed: %Rrc\n", rc); … … 414 548 rc = VbglR3Daemonize(false /* fNoChDir */, false /* fNoClose */, fRespawn, &g_cRespawn); 415 549 if (RT_FAILURE(rc)) 416 VBClLogFatalError("Daemonizing failed: %Rrc\n", rc);550 VBClLogFatalError("Daemonizing service failed: %Rrc\n", rc); 417 551 if (g_szPidFile[0]) 418 552 rc = VbglR3PidFile(g_szPidFile, &g_hPidFile); … … 422 556 VBClLogFatalError("Creating PID file failed: %Rrc\n", rc); 423 557 } 424 /* Set signal handlers to clean up on exit. */ 425 vboxClientSetSignalHandlers(); 558 426 559 #ifndef VBOXCLIENT_WITHOUT_X11 427 560 /* Set an X11 error handler, so that we don't die when we get unavoidable … … 432 565 XSetIOErrorHandler(vboxClientXLibIOErrorHandler); 433 566 #endif 434 rc = (*g_pService)->init(g_pService); 567 568 bool fSignalHandlerInstalled = false; 435 569 if (RT_SUCCESS(rc)) 436 570 { 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); 438 588 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); 440 652 } 441 653 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. */ 448 666 return RTEXITCODE_SUCCESS; 449 667 } 668 -
trunk/src/VBox/Additions/x11/VBoxClient/seamless.cpp
r82968 r86871 22 22 * Header files * 23 23 *********************************************************************************************************************************/ 24 #include <new> 25 24 26 #include <X11/Xlib.h> 27 28 #include <iprt/asm.h> 29 #include <iprt/errcore.h> 30 #include <iprt/mem.h> 25 31 26 32 #include <VBox/log.h> 27 33 #include <VBox/VBoxGuestLib.h> 28 #include <iprt/errcore.h>29 #include <iprt/mem.h>30 34 31 35 #include "VBoxClient.h" 32 36 #include "seamless.h" 33 37 34 #include <new> 38 39 /********************************************************************************************************************************* 40 * Global Variables * 41 *********************************************************************************************************************************/ 42 43 /** 44 * Struct for keeping a service instance. 45 */ 46 struct SEAMLESSSERVICE 47 { 48 /** Seamless service object. */ 49 SeamlessMain mSeamless; 50 }; 51 52 /** Service instance data. */ 53 static SEAMLESSSERVICE g_Svc; 54 35 55 36 56 SeamlessMain::SeamlessMain(void) 37 57 { 38 LogRelFlowFuncEnter(); 39 mX11MonitorThread = NIL_RTTHREAD; 58 mX11MonitorThread = NIL_RTTHREAD; 40 59 mX11MonitorThreadStopping = false; 41 mMode = VMMDev_Seamless_Disabled; 60 61 mMode = VMMDev_Seamless_Disabled; 42 62 mfPaused = true; 43 63 } … … 45 65 SeamlessMain::~SeamlessMain() 46 66 { 47 LogRelFlowFuncEnter(); 48 stop(); 67 /* Stopping will be done via main.cpp. */ 49 68 } 50 69 … … 54 73 static void sendRegionUpdate(RTRECT *pRects, size_t cRects) 55 74 { 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")); 60 79 return; 61 80 } 62 81 VbglR3SeamlessSendRects(cRects, pRects); 63 LogRelFlowFuncLeave(); 64 } 65 66 /** 67 * initialise the service. 68 */ 82 } 83 84 /** @copydoc VBCLSERVICE::pfnInit */ 69 85 int SeamlessMain::init(void) 70 86 { … … 72 88 const char *pcszStage; 73 89 74 LogRelFlowFuncEnter();75 do{90 do 91 { 76 92 pcszStage = "Connecting to the X server"; 77 93 rc = mX11Monitor.init(sendRegionUpdate); … … 89 105 if (RT_FAILURE(rc)) 90 106 break; 107 91 108 } while(0); 109 92 110 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 */ 117 int SeamlessMain::worker(bool volatile *pfShutdown) 104 118 { 105 119 int rc = VINF_SUCCESS; 106 120 107 LogRelFlowFuncEnter(); 121 /* Let the main thread know that it can continue spawning services. */ 122 RTThreadUserSignal(RTThreadSelf()); 123 108 124 /* 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 115 130 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 */ 150 void SeamlessMain::stop(void) 151 { 129 152 VbglR3SeamlessSetCap(false); 130 153 VbglR3CtlFilterMask(0, VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST); 131 154 stopX11MonitorThread(); 155 } 156 157 /** @copydoc VBCLSERVICE::pfnTerm */ 158 int 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 132 175 mX11Monitor.uninit(); 133 LogRelFlowFuncLeave(); 176 177 return rc; 134 178 } 135 179 … … 137 181 * Waits for a seamless state change events from the host and dispatch it. 138 182 * 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. 140 186 */ 141 187 int SeamlessMain::nextStateChangeEvent(void) … … 143 189 VMMDevSeamlessMode newMode = VMMDev_Seamless_Disabled; 144 190 145 LogRelFlowFuncEnter();146 191 int rc = VbglR3SeamlessWaitEvent(&newMode); 147 192 if (RT_SUCCESS(rc)) … … 151 196 { 152 197 case VMMDev_Seamless_Visible_Region: 153 /* A simplified seamless mode, obtained by making the host VM window154 * 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"); 156 201 break; 157 202 case VMMDev_Seamless_Disabled: 158 LogRelFlowFunc(("\"Disabled\" mode requested (VBoxClient)\n"));203 VBClLogVerbose(2, "\"Disabled\" mode requested\n"); 159 204 break; 160 205 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"); 163 208 return VERR_NOT_SUPPORTED; 164 209 default: 165 LogRelFunc(("Unsupported mode %d requested (VBoxClient)\n", 166 newMode)); 210 VBClLogError("Unsupported mode %d requested\n", newMode); 167 211 return VERR_NOT_SUPPORTED; 168 212 } 169 213 } 170 if (RT_SUCCESS(rc) || rc == VERR_TRY_AGAIN) 214 if ( RT_SUCCESS(rc) 215 || rc == VERR_TRY_AGAIN) 171 216 { 172 217 if (mMode == VMMDev_Seamless_Visible_Region) … … 177 222 } 178 223 else 179 { 180 LogRelFunc(("VbglR3SeamlessWaitEvent returned %Rrc (VBoxClient)\n", rc)); 181 } 182 LogRelFlowFuncLeaveRC(rc); 224 VBClLogError("VbglR3SeamlessWaitEvent returned %Rrc\n", rc); 225 183 226 return rc; 184 227 } … … 189 232 int SeamlessMain::x11MonitorThread(RTTHREAD hThreadSelf, void *pvUser) 190 233 { 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 193 239 int rc = VINF_SUCCESS; 194 240 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) 199 248 { 200 rc = p Host->mX11Monitor.start();249 rc = pThis->mX11Monitor.start(); 201 250 if (RT_FAILURE(rc)) 202 251 VBClLogFatalError("Failed to change the X11 seamless service state, mfPaused=%RTbool, rc=%Rrc\n", 203 p Host->mfPaused, rc);252 pThis->mfPaused, rc); 204 253 } 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 210 266 return rc; 211 267 } … … 216 272 int SeamlessMain::startX11MonitorThread(void) 217 273 { 218 int rc;219 220 274 mX11MonitorThreadStopping = false; 275 221 276 if (isX11MonitorThreadRunning()) 222 277 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 226 285 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. 233 293 */ 234 294 int SeamlessMain::stopX11MonitorThread(void) 235 295 { 236 int rc;237 238 mX11MonitorThreadStopping = true;239 296 if (!isX11MonitorThreadRunning()) 240 297 return VINF_SUCCESS; 298 299 mX11MonitorThreadStopping = true; 241 300 mX11Monitor.interruptEventWait(); 242 rc = RTThreadWait(mX11MonitorThread, RT_INDEFINITE_WAIT, NULL); 301 302 int rcThread; 303 int rc = RTThreadWait(mX11MonitorThread, RT_MS_30SEC, &rcThread); 243 304 if (RT_SUCCESS(rc)) 305 rc = rcThread; 306 307 if (RT_SUCCESS(rc)) 308 { 244 309 mX11MonitorThread = NIL_RTTHREAD; 310 } 245 311 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 */ 318 static int vbclSeamlessInit(void) 319 { 320 return g_Svc.mSeamless.init(); 321 } 322 323 /** @copydoc VBCLSERVICE::pfnWorker */ 324 static int vbclSeamlessWorker(bool volatile *pfShutdown) 325 { 326 return g_Svc.mSeamless.worker(pfShutdown); 327 } 328 329 /** @copydoc VBCLSERVICE::pfnStop */ 330 static void vbclSeamlessStop(void) 331 { 332 return g_Svc.mSeamless.stop(); 333 } 334 335 /** @copydoc VBCLSERVICE::pfnTerm */ 336 static int vbclSeamlessTerm(void) 337 { 338 return g_Svc.mSeamless.term(); 339 } 340 341 VBCLSERVICE 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 */ 267 353 }; 268 354 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 cleanup330 };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 84 84 #endif 85 85 86 /** 87 * Initialise the service. 88 */ 86 /** @copydoc VBCLSERVICE::pfnInit */ 89 87 int init(void); 90 88 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); 96 91 97 /** 98 * Stops the service. 99 */ 100 void stop(); 92 /** @copydoc VBCLSERVICE::pfnStop */ 93 void stop(void); 101 94 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); 114 97 }; 115 98 -
trunk/src/VBox/Additions/x11/VBoxClient/testcase/tstSeamlessX11.cpp
r82968 r86871 58 58 59 59 exit(1); 60 } 61 62 void 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); 60 70 } 61 71 … … 156 166 RTPrintf("Failed to initialise seamless Additions, rc = %Rrc\n", rc); 157 167 } 158 rc = seamless.run(); 168 bool fShutdown = false; 169 rc = seamless.worker(&fShutdown); 159 170 if (rc != VINF_SUCCESS) 160 171 {
Note:
See TracChangeset
for help on using the changeset viewer.