VirtualBox

source: vbox/trunk/src/VBox/Additions/x11/VBoxClient/seamless.cpp@ 90055

Last change on this file since 90055 was 90055, checked in by vboxsync, 3 years ago

Additions: X11: seamless: prevent hang on shutdown, bugref:10032.

This commit adds return code check when notifying X11 monitor thread
to shutdown. At some circumstances (when X11 is no longer running) this
operation might fail and service will hang or crash on shutdown.
In such situation, simply skip problematic de-init path and proceed to
service termination.

Also in this commit, do not try to wait for X11 monitor thread termination
second time, in pfnTerm(), since it was already done/attempted in pfnStop().

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 9.4 KB
Line 
1/* $Id: seamless.cpp 90055 2021-07-06 10:58:38Z vboxsync $ */
2/** @file
3 * X11 Guest client - seamless mode: main logic, communication with the host and
4 * wrapper interface for the main code of the VBoxClient deamon. The
5 * X11-specific parts are split out into their own file for ease of testing.
6 */
7
8/*
9 * Copyright (C) 2006-2020 Oracle Corporation
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 */
19
20
21/*********************************************************************************************************************************
22* Header files *
23*********************************************************************************************************************************/
24#include <new>
25
26#include <X11/Xlib.h>
27
28#include <iprt/asm.h>
29#include <iprt/errcore.h>
30#include <iprt/mem.h>
31
32#include <VBox/log.h>
33#include <VBox/VBoxGuestLib.h>
34
35#include "VBoxClient.h"
36#include "seamless.h"
37
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
55
56SeamlessMain::SeamlessMain(void)
57{
58 mX11MonitorThread = NIL_RTTHREAD;
59 mX11MonitorThreadStopping = false;
60
61 mMode = VMMDev_Seamless_Disabled;
62 mfPaused = true;
63}
64
65SeamlessMain::~SeamlessMain()
66{
67 /* Stopping will be done via main.cpp. */
68}
69
70/**
71 * Update the set of visible rectangles in the host.
72 */
73static void sendRegionUpdate(RTRECT *pRects, size_t cRects)
74{
75 if ( cRects
76 && !pRects) /* Assertion */
77 {
78 VBClLogError(("Region update called with NULL pointer\n"));
79 return;
80 }
81 VbglR3SeamlessSendRects(cRects, pRects);
82}
83
84/** @copydoc VBCLSERVICE::pfnInit */
85int SeamlessMain::init(void)
86{
87 int rc;
88 const char *pcszStage;
89
90 do
91 {
92 pcszStage = "Connecting to the X server";
93 rc = mX11Monitor.init(sendRegionUpdate);
94 if (RT_FAILURE(rc))
95 break;
96 pcszStage = "Setting guest IRQ filter mask";
97 rc = VbglR3CtlFilterMask(VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST, 0);
98 if (RT_FAILURE(rc))
99 break;
100 pcszStage = "Reporting support for seamless capability";
101 rc = VbglR3SeamlessSetCap(true);
102 if (RT_FAILURE(rc))
103 break;
104 rc = startX11MonitorThread();
105 if (RT_FAILURE(rc))
106 break;
107
108 } while(0);
109
110 if (RT_FAILURE(rc))
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)
118{
119 int rc = VINF_SUCCESS;
120
121 /* Let the main thread know that it can continue spawning services. */
122 RTThreadUserSignal(RTThreadSelf());
123
124 /* This will only exit if something goes wrong. */
125 for (;;)
126 {
127 if (ASMAtomicReadBool(pfShutdown))
128 break;
129
130 rc = nextStateChangeEvent();
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{
152 VbglR3SeamlessSetCap(false);
153 VbglR3CtlFilterMask(0, VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST);
154 stopX11MonitorThread();
155}
156
157/** @copydoc VBCLSERVICE::pfnTerm */
158int SeamlessMain::term(void)
159{
160 mX11Monitor.uninit();
161 return VINF_SUCCESS;
162}
163
164/**
165 * Waits for a seamless state change events from the host and dispatch it.
166 *
167 * @returns VBox return code, or
168 * VERR_TRY_AGAIN if no new status is available and we have to try it again
169 * at some later point in time.
170 */
171int SeamlessMain::nextStateChangeEvent(void)
172{
173 VMMDevSeamlessMode newMode = VMMDev_Seamless_Disabled;
174
175 int rc = VbglR3SeamlessWaitEvent(&newMode);
176 if (RT_SUCCESS(rc))
177 {
178 mMode = newMode;
179 switch (newMode)
180 {
181 case VMMDev_Seamless_Visible_Region:
182 /* A simplified seamless mode, obtained by making the host VM window
183 * borderless and making the guest desktop transparent. */
184 VBClLogVerbose(2, "\"Visible region\" mode requested\n");
185 break;
186 case VMMDev_Seamless_Disabled:
187 VBClLogVerbose(2, "\"Disabled\" mode requested\n");
188 break;
189 case VMMDev_Seamless_Host_Window:
190 /* One host window represents one guest window. Not yet implemented. */
191 VBClLogVerbose(2, "Unsupported \"host window\" mode requested\n");
192 return VERR_NOT_SUPPORTED;
193 default:
194 VBClLogError("Unsupported mode %d requested\n", newMode);
195 return VERR_NOT_SUPPORTED;
196 }
197 }
198 if ( RT_SUCCESS(rc)
199 || rc == VERR_TRY_AGAIN)
200 {
201 if (mMode == VMMDev_Seamless_Visible_Region)
202 mfPaused = false;
203 else
204 mfPaused = true;
205 mX11Monitor.interruptEventWait();
206 }
207 else
208 VBClLogError("VbglR3SeamlessWaitEvent returned %Rrc\n", rc);
209
210 return rc;
211}
212
213/**
214 * The actual X11 window configuration change monitor thread function.
215 */
216int SeamlessMain::x11MonitorThread(RTTHREAD hThreadSelf, void *pvUser)
217{
218 RT_NOREF(hThreadSelf);
219
220 SeamlessMain *pThis = (SeamlessMain *)pvUser;
221 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
222
223 int rc = VINF_SUCCESS;
224
225 RTThreadUserSignal(hThreadSelf);
226
227 VBClLogVerbose(2, "X11 monitor thread started\n");
228
229 while (!pThis->mX11MonitorThreadStopping)
230 {
231 if (!pThis->mfPaused)
232 {
233 rc = pThis->mX11Monitor.start();
234 if (RT_FAILURE(rc))
235 VBClLogFatalError("Failed to change the X11 seamless service state, mfPaused=%RTbool, rc=%Rrc\n",
236 pThis->mfPaused, rc);
237 }
238
239 pThis->mX11Monitor.nextConfigurationEvent();
240
241 if ( pThis->mfPaused
242 || pThis->mX11MonitorThreadStopping)
243 {
244 pThis->mX11Monitor.stop();
245 }
246 }
247
248 VBClLogVerbose(2, "X11 monitor thread ended\n");
249
250 return rc;
251}
252
253/**
254 * Start the X11 window configuration change monitor thread.
255 */
256int SeamlessMain::startX11MonitorThread(void)
257{
258 mX11MonitorThreadStopping = false;
259
260 if (isX11MonitorThreadRunning())
261 return VINF_SUCCESS;
262
263 int rc = RTThreadCreate(&mX11MonitorThread, x11MonitorThread, this, 0,
264 RTTHREADTYPE_MSG_PUMP, RTTHREADFLAGS_WAITABLE,
265 "seamless x11");
266 if (RT_SUCCESS(rc))
267 rc = RTThreadUserWait(mX11MonitorThread, RT_MS_30SEC);
268
269 if (RT_FAILURE(rc))
270 VBClLogError("Failed to start X11 monitor thread, rc=%Rrc\n", rc);
271
272 return rc;
273}
274
275/**
276 * Stops the monitor thread.
277 */
278int SeamlessMain::stopX11MonitorThread(void)
279{
280 if (!isX11MonitorThreadRunning())
281 return VINF_SUCCESS;
282
283 mX11MonitorThreadStopping = true;
284 if (!mX11Monitor.interruptEventWait())
285 {
286 VBClLogError("Unable to notify X11 monitor thread\n");
287 return VERR_INVALID_STATE;
288 }
289
290 int rcThread;
291 int rc = RTThreadWait(mX11MonitorThread, RT_MS_30SEC, &rcThread);
292 if (RT_SUCCESS(rc))
293 rc = rcThread;
294
295 if (RT_SUCCESS(rc))
296 {
297 mX11MonitorThread = NIL_RTTHREAD;
298 }
299 else
300 VBClLogError("Waiting for X11 monitor thread to stop failed, rc=%Rrc\n", rc);
301
302 return rc;
303}
304
305/**
306 * @interface_method_impl{VBCLSERVICE,pfnInit}
307 */
308static DECLCALLBACK(int) vbclSeamlessInit(void)
309{
310 return g_Svc.mSeamless.init();
311}
312
313/**
314 * @interface_method_impl{VBCLSERVICE,pfnWorker}
315 */
316static DECLCALLBACK(int) vbclSeamlessWorker(bool volatile *pfShutdown)
317{
318 return g_Svc.mSeamless.worker(pfShutdown);
319}
320
321/**
322 * @interface_method_impl{VBCLSERVICE,pfnStop}
323 */
324static DECLCALLBACK(void) vbclSeamlessStop(void)
325{
326 return g_Svc.mSeamless.stop();
327}
328
329/**
330 * @interface_method_impl{VBCLSERVICE,pfnTerm}
331 */
332static DECLCALLBACK(int) vbclSeamlessTerm(void)
333{
334 return g_Svc.mSeamless.term();
335}
336
337VBCLSERVICE g_SvcSeamless =
338{
339 "seamless", /* szName */
340 "Seamless Mode Support", /* pszDescription */
341 ".vboxclient-seamless.pid", /* pszPidFilePath */
342 NULL, /* pszUsage */
343 NULL, /* pszOptions */
344 NULL, /* pfnOption */
345 vbclSeamlessInit, /* pfnInit */
346 vbclSeamlessWorker, /* pfnWorker */
347 vbclSeamlessStop, /* pfnStop*/
348 vbclSeamlessTerm /* pfnTerm */
349};
350
Note: See TracBrowser for help on using the repository browser.

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