VirtualBox

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

Last change on this file since 98475 was 98474, checked in by vboxsync, 23 months ago

Additions: X11: Add possibility restart VBoxClient processes during Guest Additions update, bugref:10359.

This commit makes VBoxClient processes to temporary release reference to vboxguest kernel module and then
restart itself. So module can be reloaded and newly started VBoxClient instance will utilize updated module.

When VBoxClient starts in demonized mode, it forks a child process which represents actual service. Parent
process continues to run and its main function is to restart child when it crashes or terminates with exit
status != 0. This commit makes child process to catch SIGUSR1 and terminate with exit
status VBGLR3EXITCODERELOAD (currently equal to 2). Parent process will detect this and in turn will release
its reference to vboxguest kernel module, allowing to reload it. The parent process will then wait for SIGUSR1
itself. Once received, it will restart itself (loading new, updated VBoxClient process image). This is a part
of the procedure to install and reload/restart Guest Additions kernel modules and user services without
requiring guest reboot.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 9.7 KB
Line 
1/* $Id: seamless.cpp 98474 2023-02-03 19:20:53Z 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-2023 Oracle and/or its affiliates.
10 *
11 * This file is part of VirtualBox base platform packages, as
12 * available from https://www.virtualbox.org.
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation, in version 3 of the
17 * License.
18 *
19 * This program is distributed in the hope that it will be useful, but
20 * WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, see <https://www.gnu.org/licenses>.
26 *
27 * SPDX-License-Identifier: GPL-3.0-only
28 */
29
30
31/*********************************************************************************************************************************
32* Header files *
33*********************************************************************************************************************************/
34#include <new>
35
36#include <X11/Xlib.h>
37
38#include <iprt/asm.h>
39#include <iprt/errcore.h>
40#include <iprt/mem.h>
41
42#include <VBox/log.h>
43#include <VBox/VBoxGuestLib.h>
44
45#include "VBoxClient.h"
46#include "seamless.h"
47
48
49/*********************************************************************************************************************************
50* Global Variables *
51*********************************************************************************************************************************/
52
53/**
54 * Struct for keeping a service instance.
55 */
56struct SEAMLESSSERVICE
57{
58 /** Seamless service object. */
59 SeamlessMain mSeamless;
60};
61
62/** Service instance data. */
63static SEAMLESSSERVICE g_Svc;
64
65
66SeamlessMain::SeamlessMain(void)
67{
68 mX11MonitorThread = NIL_RTTHREAD;
69 mX11MonitorThreadStopping = false;
70
71 mMode = VMMDev_Seamless_Disabled;
72 mfPaused = true;
73}
74
75SeamlessMain::~SeamlessMain()
76{
77 /* Stopping will be done via main.cpp. */
78}
79
80/**
81 * Update the set of visible rectangles in the host.
82 */
83static void sendRegionUpdate(RTRECT *pRects, size_t cRects)
84{
85 if ( cRects
86 && !pRects) /* Assertion */
87 {
88 VBClLogError(("Region update called with NULL pointer\n"));
89 return;
90 }
91 VbglR3SeamlessSendRects(cRects, pRects);
92}
93
94/** @copydoc VBCLSERVICE::pfnInit */
95int SeamlessMain::init(void)
96{
97 int rc;
98 const char *pcszStage;
99
100 do
101 {
102 pcszStage = "Connecting to the X server";
103 rc = mX11Monitor.init(sendRegionUpdate);
104 if (RT_FAILURE(rc))
105 break;
106 pcszStage = "Setting guest IRQ filter mask";
107 rc = VbglR3CtlFilterMask(VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST, 0);
108 if (RT_FAILURE(rc))
109 break;
110 pcszStage = "Reporting support for seamless capability";
111 rc = VbglR3SeamlessSetCap(true);
112 if (RT_FAILURE(rc))
113 break;
114 rc = startX11MonitorThread();
115 if (RT_FAILURE(rc))
116 break;
117
118 } while(0);
119
120 if (RT_FAILURE(rc))
121 VBClLogError("Failed to start in stage '%s' -- error %Rrc\n", pcszStage, rc);
122
123 return rc;
124}
125
126/** @copydoc VBCLSERVICE::pfnWorker */
127int SeamlessMain::worker(bool volatile *pfShutdown)
128{
129 int rc = VINF_SUCCESS;
130
131 /* Let the main thread know that it can continue spawning services. */
132 RTThreadUserSignal(RTThreadSelf());
133
134 /* This will only exit if something goes wrong. */
135 for (;;)
136 {
137 if (ASMAtomicReadBool(pfShutdown))
138 break;
139
140 rc = nextStateChangeEvent();
141
142 if (rc == VERR_TRY_AGAIN)
143 rc = VINF_SUCCESS;
144
145 if (RT_FAILURE(rc))
146 break;
147
148 if (ASMAtomicReadBool(pfShutdown))
149 break;
150
151 /* If we are not stopping, sleep for a bit to avoid using up too
152 much CPU while retrying. */
153 RTThreadYield();
154 }
155
156 return rc;
157}
158
159/** @copydoc VBCLSERVICE::pfnStop */
160void SeamlessMain::stop(void)
161{
162 VbglR3SeamlessSetCap(false);
163 VbglR3CtlFilterMask(0, VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST);
164 stopX11MonitorThread();
165}
166
167/** @copydoc VBCLSERVICE::pfnTerm */
168int SeamlessMain::term(void)
169{
170 mX11Monitor.uninit();
171 return VINF_SUCCESS;
172}
173
174/**
175 * Waits for a seamless state change events from the host and dispatch it.
176 *
177 * @returns VBox return code, or
178 * VERR_TRY_AGAIN if no new status is available and we have to try it again
179 * at some later point in time.
180 */
181int SeamlessMain::nextStateChangeEvent(void)
182{
183 VMMDevSeamlessMode newMode = VMMDev_Seamless_Disabled;
184
185 int rc = VbglR3SeamlessWaitEvent(&newMode);
186 if (RT_SUCCESS(rc))
187 {
188 mMode = newMode;
189 switch (newMode)
190 {
191 case VMMDev_Seamless_Visible_Region:
192 /* A simplified seamless mode, obtained by making the host VM window
193 * borderless and making the guest desktop transparent. */
194 VBClLogVerbose(2, "\"Visible region\" mode requested\n");
195 break;
196 case VMMDev_Seamless_Disabled:
197 VBClLogVerbose(2, "\"Disabled\" mode requested\n");
198 break;
199 case VMMDev_Seamless_Host_Window:
200 /* One host window represents one guest window. Not yet implemented. */
201 VBClLogVerbose(2, "Unsupported \"host window\" mode requested\n");
202 return VERR_NOT_SUPPORTED;
203 default:
204 VBClLogError("Unsupported mode %d requested\n", newMode);
205 return VERR_NOT_SUPPORTED;
206 }
207 }
208 if ( RT_SUCCESS(rc)
209 || rc == VERR_TRY_AGAIN)
210 {
211 if (mMode == VMMDev_Seamless_Visible_Region)
212 mfPaused = false;
213 else
214 mfPaused = true;
215 mX11Monitor.interruptEventWait();
216 }
217 else
218 VBClLogError("VbglR3SeamlessWaitEvent returned %Rrc\n", rc);
219
220 return rc;
221}
222
223/**
224 * The actual X11 window configuration change monitor thread function.
225 */
226int SeamlessMain::x11MonitorThread(RTTHREAD hThreadSelf, void *pvUser)
227{
228 RT_NOREF(hThreadSelf);
229
230 SeamlessMain *pThis = (SeamlessMain *)pvUser;
231 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
232
233 int rc = VINF_SUCCESS;
234
235 RTThreadUserSignal(hThreadSelf);
236
237 VBClLogVerbose(2, "X11 monitor thread started\n");
238
239 while (!pThis->mX11MonitorThreadStopping)
240 {
241 if (!pThis->mfPaused)
242 {
243 rc = pThis->mX11Monitor.start();
244 if (RT_FAILURE(rc))
245 VBClLogFatalError("Failed to change the X11 seamless service state, mfPaused=%RTbool, rc=%Rrc\n",
246 pThis->mfPaused, rc);
247 }
248
249 pThis->mX11Monitor.nextConfigurationEvent();
250
251 if ( pThis->mfPaused
252 || pThis->mX11MonitorThreadStopping)
253 {
254 pThis->mX11Monitor.stop();
255 }
256 }
257
258 VBClLogVerbose(2, "X11 monitor thread ended\n");
259
260 return rc;
261}
262
263/**
264 * Start the X11 window configuration change monitor thread.
265 */
266int SeamlessMain::startX11MonitorThread(void)
267{
268 mX11MonitorThreadStopping = false;
269
270 if (isX11MonitorThreadRunning())
271 return VINF_SUCCESS;
272
273 int rc = RTThreadCreate(&mX11MonitorThread, x11MonitorThread, this, 0,
274 RTTHREADTYPE_MSG_PUMP, RTTHREADFLAGS_WAITABLE,
275 "seamless x11");
276 if (RT_SUCCESS(rc))
277 rc = RTThreadUserWait(mX11MonitorThread, RT_MS_30SEC);
278
279 if (RT_FAILURE(rc))
280 VBClLogError("Failed to start X11 monitor thread, rc=%Rrc\n", rc);
281
282 return rc;
283}
284
285/**
286 * Stops the monitor thread.
287 */
288int SeamlessMain::stopX11MonitorThread(void)
289{
290 if (!isX11MonitorThreadRunning())
291 return VINF_SUCCESS;
292
293 mX11MonitorThreadStopping = true;
294 if (!mX11Monitor.interruptEventWait())
295 {
296 VBClLogError("Unable to notify X11 monitor thread\n");
297 return VERR_INVALID_STATE;
298 }
299
300 int rcThread;
301 int rc = RTThreadWait(mX11MonitorThread, RT_MS_30SEC, &rcThread);
302 if (RT_SUCCESS(rc))
303 rc = rcThread;
304
305 if (RT_SUCCESS(rc))
306 {
307 mX11MonitorThread = NIL_RTTHREAD;
308 }
309 else
310 VBClLogError("Waiting for X11 monitor thread to stop failed, rc=%Rrc\n", rc);
311
312 return rc;
313}
314
315/**
316 * @interface_method_impl{VBCLSERVICE,pfnInit}
317 */
318static DECLCALLBACK(int) vbclSeamlessInit(void)
319{
320 return g_Svc.mSeamless.init();
321}
322
323/**
324 * @interface_method_impl{VBCLSERVICE,pfnWorker}
325 */
326static DECLCALLBACK(int) vbclSeamlessWorker(bool volatile *pfShutdown)
327{
328 return g_Svc.mSeamless.worker(pfShutdown);
329}
330
331/**
332 * @interface_method_impl{VBCLSERVICE,pfnStop}
333 */
334static DECLCALLBACK(void) vbclSeamlessStop(void)
335{
336 return g_Svc.mSeamless.stop();
337}
338
339/**
340 * @interface_method_impl{VBCLSERVICE,pfnTerm}
341 */
342static DECLCALLBACK(int) vbclSeamlessTerm(void)
343{
344 return g_Svc.mSeamless.term();
345}
346
347VBCLSERVICE g_SvcSeamless =
348{
349 "seamless", /* szName */
350 "Seamless Mode Support", /* pszDescription */
351 ".vboxclient-seamless", /* pszPidFilePathTemplate */
352 NULL, /* pszUsage */
353 NULL, /* pszOptions */
354 NULL, /* pfnOption */
355 vbclSeamlessInit, /* pfnInit */
356 vbclSeamlessWorker, /* pfnWorker */
357 vbclSeamlessStop, /* pfnStop*/
358 vbclSeamlessTerm /* pfnTerm */
359};
360
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