Changeset 86871 in vbox for trunk/src/VBox/Additions/x11/VBoxClient/seamless.cpp
- Timestamp:
- Nov 12, 2020 10:15:18 AM (4 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
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 }
Note:
See TracChangeset
for help on using the changeset viewer.