Changeset 52586 in vbox for trunk/src/VBox/Additions/x11/VBoxClient
- Timestamp:
- Sep 3, 2014 2:38:53 PM (10 years ago)
- Location:
- trunk/src/VBox/Additions/x11/VBoxClient
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Additions/x11/VBoxClient/VBoxClient.h
r52562 r52586 50 50 /** Run the service main loop */ 51 51 int (*run)(struct VBCLSERVICE **ppInterface, bool fDaemonised); 52 /** Pause the service loop. This must be safe to call on a different thread 53 * and potentially before @a run is or after it exits. 54 * This is called by the VT monitoring thread to allow the service to disable 55 * itself when the X server is switched out. If the monitoring functionality 56 * is available then @a pause or @a resume will be called as soon as it starts 57 * up. */ 52 /** Pause the service loop. This is used to allow the service to disable 53 * itself when the X server is switched out. It must be safe to call on a 54 * different thread if the VT monitoring thread is used. */ 58 55 int (*pause)(struct VBCLSERVICE **ppInterface); 59 56 /** Resume after pausing. The same applies here as for @a pause. */ … … 79 76 } 80 77 78 union _XEvent; /* We do not want to pull in the X11 header files here. */ 79 extern void VBClCheckXOrgVT(union _XEvent *pEvent); 80 extern int VBClStartVTMonitor(); 81 81 82 extern struct VBCLSERVICE **VBClGetClipboardService(); 82 83 extern struct VBCLSERVICE **VBClGetSeamlessService(); -
trunk/src/VBox/Additions/x11/VBoxClient/display.cpp
r52562 r52586 349 349 { 350 350 struct DISPLAYSERVICE *pSelf = getClassFromInterface(ppInterface); 351 int rc; 351 352 352 353 if (!pSelf->mfInit) 353 354 return VERR_WRONG_ORDER; 355 rc = VBClStartVTMonitor(); 356 if (RT_FAILURE(rc)) 357 VBClFatalError(("Failed to start the VT monitor thread: %Rrc\n", rc)); 354 358 runDisplay(&pSelf->mState); 355 359 return VERR_INTERNAL_ERROR; /* "Should never reach here." */ -
trunk/src/VBox/Additions/x11/VBoxClient/main.cpp
r52577 r52586 150 150 } 151 151 152 /** Connect to the X server and return the "XFree86_VT" root window property, 153 * or 0 on failure. */ 154 static unsigned long getXOrgVT(Display *pDisplay) 152 /** Check whether X.Org has acquired or lost the current virtual terminal and 153 * call the service @a pause() or @a resume() call-back if appropriate. 154 * The functionality is provided by the vboxvideo driver for pre-1.16 X servers 155 * and by 1.16 and later series servers. 156 * This can either be called directly from a service's event loop or the service 157 * can call VBClStartVTMonitor() to start an event loop in a separate thread. 158 * Property notification for the root window should be selected first. Services 159 * are not required to check VT changes if they do not need the information. 160 * @param pEvent an event received on a display connection which will be 161 * checked to see if it is change to the XFree86_has_VT property 162 */ 163 void VBClCheckXOrgVT(union _XEvent *pEvent) 155 164 { 156 165 Atom actualType; 157 166 int actualFormat; 158 unsigned long cItems, cbLeft, cVT = 0; 167 unsigned long cItems, cbLeft; 168 bool fHasVT = false; 159 169 unsigned long *pValue; 160 161 XGetWindowProperty(pDisplay, DefaultRootWindow(pDisplay), 162 XInternAtom(pDisplay, "XFree86_VT", False), 0, 1, False, 163 XA_INTEGER, &actualType, &actualFormat, &cItems, &cbLeft, 164 (unsigned char **)&pValue); 170 int rc; 171 Display *pDisplay = pEvent->xany.display; 172 Atom hasVT = XInternAtom(pDisplay, "XFree86_has_VT", False); 173 174 if ( pEvent->type != PropertyNotify 175 || pEvent->xproperty.window != DefaultRootWindow(pDisplay) 176 || pEvent->xproperty.atom != hasVT) 177 return; 178 XGetWindowProperty(pDisplay, DefaultRootWindow(pDisplay), hasVT, 0, 1, 179 False, XA_INTEGER, &actualType, &actualFormat, &cItems, 180 &cbLeft, (unsigned char **)&pValue); 165 181 if (cItems && actualFormat == 32) 166 182 { 167 cVT = *pValue;183 fHasVT = *pValue != 0; 168 184 XFree(pValue); 169 185 } 170 return cVT; 171 } 172 173 /** Check whether the current virtual terminal is the one running the X server. 174 */ 175 static void checkVTSysfs(RTFILE hFile, uint32_t cVT) 176 { 177 char szTTY[7] = ""; 178 uint32_t cTTY; 179 size_t cbRead; 180 int rc; 181 const char *pcszStage; 182 183 do { 184 pcszStage = "reading /sys/class/tty/tty0/active"; 185 rc = RTFileReadAt(hFile, 0, (void *)szTTY, sizeof(szTTY), &cbRead); 186 else 187 return; 188 if (fHasVT) 189 { 190 rc = (*g_pService)->resume(g_pService); 186 191 if (RT_FAILURE(rc)) 187 break; 188 szTTY[cbRead - 1] = '\0'; 189 pcszStage = "getting VT number from sysfs file"; 190 rc = RTStrToUInt32Full(&szTTY[3], 10, &cTTY); 192 VBClFatalError(("Error resuming the service: %Rrc\n")); 193 } 194 if (!fHasVT) 195 { 196 rc = (*g_pService)->pause(g_pService); 191 197 if (RT_FAILURE(rc)) 192 break; 193 pcszStage = "entering critical section"; 194 rc = RTCritSectEnter(&g_critSect); 195 if (RT_FAILURE(rc)) 196 break; 197 pcszStage = "asking service to pause or resume"; 198 if (cTTY == cVT) 199 rc = (*g_pService)->resume(g_pService); 200 else 201 rc = (*g_pService)->pause(g_pService); 202 if (RT_FAILURE(rc)) 203 break; 204 pcszStage = "leaving critical section"; 205 rc = RTCritSectLeave(&g_critSect); 206 } while(false); 207 if (RT_FAILURE(rc)) 208 { 209 LogRelFunc(("VBoxClient: failed at stage: \"%s\" rc: %Rrc cVT: %d szTTY: %s.\n", 210 pcszStage, rc, (int) cVT, szTTY)); 211 if (RTCritSectIsOwner(&g_critSect)) 212 RTCritSectLeave(&g_critSect); 213 VBClCleanUp(); 214 } 215 } 216 217 /** Poll for TTY changes using sysfs and for X server disconnection. 218 * Reading from the start of the pollable file "/sys/class/tty/tty0/active" 219 * returns the currently active TTY as a string of the form "tty<n>", with n 220 * greater than zero. Polling for POLLPRI returns when the TTY changes. 221 * @a cVT should be zero if we do not know the X server's VT. */ 222 static void pollTTYAndXServer(Display *pDisplay, uint32_t cVT) 223 { 224 RTFILE hFile = NIL_RTFILE; 225 struct pollfd pollFD[2]; 226 unsigned cPollFD = 1; 227 int rc; 228 229 pollFD[1].fd = -1; 230 pollFD[1].revents = 0; 231 /* This block could be Linux-only, but keeping it on Solaris too, where it 232 * should just fail gracefully, gives us more code path coverage. */ 233 if (cVT) 234 { 235 rc = RTFileOpen(&hFile, "/sys/class/tty/tty0/active", 236 RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN); 237 if (RT_SUCCESS(rc)) 238 { 239 pollFD[1].fd = RTFileToNative(hFile); 240 pollFD[1].events = POLLPRI; 241 cPollFD = 2; 242 } 243 } 244 AssertRelease(pollFD[1].fd >= 0 || cPollFD == 1); 245 pollFD[0].fd = ConnectionNumber(pDisplay); 246 pollFD[0].events = POLLIN; 247 while (true) 248 { 249 if (hFile != NIL_RTFILE) 250 checkVTSysfs(hFile, cVT); 251 /* The only point of this loop is to trigger the I/O error handler if 252 * appropriate. */ 253 while (XPending(pDisplay)) 254 { 255 XEvent ev; 256 257 XNextEvent(pDisplay, &ev); 258 } 259 /* If we get caught in a tight loop for some reason try to limit the 260 * damage. */ 261 if (poll(pollFD, cPollFD, 0) > 0) 262 { 263 LogRel(("Monitor thread: unexpectedly fast event, revents=0x%x, 0x%x.\n", 264 pollFD[0].revents, pollFD[1].revents)); 265 RTThreadYield(); 266 } 267 if ( (poll(pollFD, cPollFD, -1) < 0 && errno != EINTR) 268 || pollFD[0].revents & POLLNVAL 269 || pollFD[1].revents & POLLNVAL) 270 { 271 LogRel(("Monitor thread: poll failed, stopping.\n")); 272 VBClCleanUp(); 273 } 198 VBClFatalError(("Error pausing the service: %Rrc\n")); 274 199 } 275 200 } … … 283 208 { 284 209 Display *pDisplay; 285 unsigned long cVT; 286 RTFILE hFile; 210 bool fHasVT = true; 287 211 288 212 pDisplay = XOpenDisplay(NULL); 289 213 if (!pDisplay) 290 return VINF_SUCCESS;291 cVT = getXOrgVT(pDisplay);292 /* Note: cVT will be 0 if we failed to get it. This is valid. */293 pollTTYAndXServer(pDisplay, (uint32_t) cVT);294 /* Should never get here. */295 return VINF_SUCCESS; 296 } 297 298 /** 299 * Start the thread which notifies the service when we switch to a different300 * VT or back, and terminates us when the X server exits. The first is best 301 * effort functionality: XFree86 4.3 and older do not report their VT via the 302 * "XFree86_VT" root window property at all, and pre-2.6.38 Linux does not 303 * provide the interface in "sysfs" which we use. If there is a need for this304 * to work with pre-2.6.38 Linux we can send the VT_GETSTATE ioctl to305 * /dev/console at regular intervals.306 */ 307 static int startMonitorThread()214 VBClFatalError(("Failed to open the X11 display\n")); 215 XSelectInput(pDisplay, DefaultRootWindow(pDisplay), PropertyChangeMask); 216 while (true) 217 { 218 XEvent event; 219 220 XNextEvent(pDisplay, &event); 221 VBClCheckXOrgVT(&event); 222 } 223 return VINF_SUCCESS; /* Should never be reached. */ 224 } 225 226 /** 227 * Start a thread which notifies the service when we switch to a different 228 * VT or back, and terminates us when the X server exits. This should be called 229 * by most services which do not regularly run an X11 event loop. 230 */ 231 int VBClStartVTMonitor() 308 232 { 309 233 return RTThreadCreate(NULL, pfnMonitorThread, NULL, 0, … … 441 365 if (RT_FAILURE(rc)) 442 366 VBClFatalError(("Initialising critical section: %Rrc\n", rc)); 443 if (RT_FAILURE(rc))444 VBClFatalError(("Initialising critical section: %Rrc\n", rc));445 367 rc = RTPathUserHome(g_szPidFile, sizeof(g_szPidFile)); 446 368 if (RT_FAILURE(rc)) … … 469 391 if (RT_FAILURE(rc)) 470 392 VBClFatalError(("Initialising service: %Rrc\n", rc)); 471 rc = startMonitorThread(); 472 if (RT_FAILURE(rc)) 473 VBClFatalError(("Starting monitor thread: %Rrc\n", rc)); 474 (*g_pService)->run(g_pService, fDaemonise); /* Should never return. */ 393 rc = (*g_pService)->run(g_pService, fDaemonise); 394 if (RT_FAILURE(rc)) 395 VBClFatalError(("Service main loop failed: %Rrc\n", rc)); 475 396 VBClCleanUp(); 476 return 1;477 } 397 return 0; 398 } -
trunk/src/VBox/Additions/x11/VBoxClient/seamless.cpp
r52564 r52586 377 377 if (!pSelf->mIsInitialised) 378 378 return VERR_INTERNAL_ERROR; 379 rc = VBClStartVTMonitor(); 380 if (RT_FAILURE(rc)) 381 VBClFatalError(("Failed to start the VT monitor thread: %Rrc\n", rc)); 379 382 /* This only exits on error. */ 380 383 rc = pSelf->mSeamless.run(); -
trunk/src/VBox/Additions/x11/VBoxClient/testcase/tstSeamlessX11.cpp
r52562 r52586 31 31 RTPrintf("Fatal error: %s", pszMessage); 32 32 exit(1); 33 } 34 35 int VBClStartVTMonitor() 36 { 37 return VINF_SUCCESS; 33 38 } 34 39
Note:
See TracChangeset
for help on using the changeset viewer.