- Timestamp:
- Jan 30, 2014 10:43:54 AM (11 years ago)
- Location:
- trunk/src/VBox/Additions/x11/VBoxClient
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Additions/x11/VBoxClient/VBoxClient.h
r44528 r50281 33 33 /** Run the service main loop */ 34 34 virtual int run(bool fDaemonised = false) = 0; 35 /** Clean up any global resources before we shut down hard */ 35 /** Pause the service loop. This must be safe to call on a different thread 36 * and potentially before @run is or after it exits. */ 37 virtual void pause() { } 38 /** Resume after pausing. The same applies here as for @a pause. */ 39 virtual void resume() { } 40 /** Clean up any global resources before we shut down hard. Calling 41 * @a pause or @a resume later than @a cleanup must not cause errors. */ 36 42 virtual void cleanup() = 0; 37 43 /** Virtual destructor. Not used */ -
trunk/src/VBox/Additions/x11/VBoxClient/main.cpp
r48945 r50281 18 18 19 19 #include <sys/types.h> 20 #if 0 21 #include <sys/vt.h> 22 #endif 20 23 #include <stdlib.h> /* For exit */ 21 24 #include <stdio.h> … … 23 26 #include <unistd.h> 24 27 #include <errno.h> 28 #include <poll.h> 25 29 #include <signal.h> 26 30 27 31 #include <X11/Xlib.h> 32 #include <X11/Xatom.h> 28 33 29 34 #include <iprt/critsect.h> 30 35 #include <iprt/env.h> 36 #include <iprt/file.h> 31 37 #include <iprt/initterm.h> 32 38 #include <iprt/message.h> … … 35 41 #include <iprt/stream.h> 36 42 #include <iprt/string.h> 43 #include <iprt/types.h> 37 44 #include <VBox/VBoxGuestLib.h> 38 45 #include <VBox/log.h> … … 53 60 * cleanup routine. */ 54 61 static RTFILE g_hPidFile; 55 /** Global critical section used to protect the clean-up routine, which can be 56 * called from different threads. 57 */ 58 RTCRITSECT g_critSect; 62 /** Global critical section held during the clean-up routine (to prevent it 63 * being called on multiple threads at once) or things which may not happen 64 * during clean-up (e.g. pausing and resuming the service). 65 */ 66 RTCRITSECT g_cleanupCritSect; 59 67 60 68 /** Clean up if we get a signal or something. This is extern so that we … … 65 73 * async-safe. Until we fix this application properly, we should be sure 66 74 * never to exit from anywhere except from this method. */ 67 int rc = RTCritSectEnter(&g_c ritSect);75 int rc = RTCritSectEnter(&g_cleanupCritSect); 68 76 if (RT_FAILURE(rc)) 69 77 { … … 136 144 } 137 145 146 /** Connect to the X server and return the "XFree86_VT" root window property, 147 * or 0 on failure. */ 148 static unsigned long getXOrgVT(void) 149 { 150 Display *pDisplay; 151 Atom actualType; 152 int actualFormat; 153 unsigned long cItems, cbLeft, cVT = 0; 154 unsigned long *pValue; 155 156 pDisplay = XOpenDisplay(NULL); 157 if (!pDisplay) 158 return VINF_SUCCESS; 159 XGetWindowProperty(pDisplay, DefaultRootWindow(pDisplay), 160 XInternAtom(pDisplay, "XFree86_VT", False), 0, 1, False, 161 XA_INTEGER, &actualType, &actualFormat, &cItems, &cbLeft, 162 (unsigned char **)&pValue); 163 if (cItems && actualFormat == 32) 164 { 165 cVT = *pValue; 166 XFree(pValue); 167 } 168 XCloseDisplay(pDisplay); 169 return cVT; 170 } 171 172 #ifdef RT_OS_LINUX 173 /** Poll for TTY changes using sysfs. Reading from the start of the pollable 174 * file "/sys/class/tty/tty0/active" returns the currently active TTY as a 175 * string of the form "tty<n>", with n greater than zero. Polling for POLLPRI 176 * returns when the TTY changes. */ 177 static bool pollTTYSysfs(uint32_t cVT) 178 { 179 RTFILE hFile; 180 struct pollfd pollFD; 181 182 if (RT_SUCCESS(RTFileOpen(&hFile, "/sys/class/tty/tty0/active", 183 RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN))) 184 { 185 pollFD.fd = RTFileToNative(hFile); 186 pollFD.events = POLLPRI; 187 while (true) 188 { 189 char szTTY[7]; 190 uint32_t cTTY; 191 size_t cbRead; 192 193 if (RT_FAILURE(RTFileReadAt(hFile, 0, (void *)szTTY, sizeof(szTTY), 194 &cbRead))) 195 { 196 LogRel(("VT monitor thread: read failed, stopping.\n")); 197 break; 198 } 199 szTTY[6] = '\0'; 200 cTTY = RTStrToUInt32(&szTTY[3]); 201 if (!cTTY) 202 { 203 LogRel(("VT monitor thread: failed to read the TTY, stopping.\n")); 204 break; 205 } 206 if (cTTY == cVT) 207 g_pService->resume(); 208 else 209 g_pService->pause(); 210 /* If we get caught in a tight loop for some reason try to limit the 211 * damage. */ 212 if (poll(&pollFD, 1, 0) > 0) 213 { 214 LogRel(("VT monitor thread: unexpectedly fast event, revents=0x%x.\n", 215 pollFD.revents)); 216 RTThreadYield(); 217 } 218 if ( (poll(&pollFD, 1, -1) < 0 && errno != EINVAL) 219 || pollFD.revents & POLLNVAL) 220 { 221 LogRel(("VT monitor thread: poll failed, stopping.\n")); 222 break; 223 } 224 } 225 RTFileClose(hFile); 226 } 227 else 228 return false; 229 return true; 230 } 231 #endif /* defined RT_OS_LINUX */ 232 233 #if 0 234 /** @note This is disabled because I believe that our existing code works well 235 * enough on the pre-Linux 2.6.38 systems where it would be needed. 236 * I will leave the code in place in case that proves to be wrong. */ 237 /** Here we monitor the active VT by performing a VT_STATE ioctl on 238 * /dev/console at regular intervals. Unfortunately we can only monitor the 239 * first sixteen virtual terminals this way, so if the X server is running on 240 * a higher one we do not even try. */ 241 static bool pollTTYDevConsole(unsigned long cVT) 242 { 243 RTFILE hFile; 244 245 if (cVT >= 16) 246 return false; 247 if (RT_SUCCESS(RTFileOpen(&hFile, "/dev/console", 248 RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN))) 249 { 250 while (true) 251 { 252 struct vt_stat vtStat; 253 int rc; 254 255 if ( RT_FAILURE(RTFileIoCtl(hFile, VT_GETSTATE, &vtStat, 256 sizeof(vtStat), &rc)) 257 || rc) 258 { 259 LogRel(("VT monitor thread: ioctl failed, stopping.\n")); 260 break; 261 } 262 if (vtStat.v_active == cVT) 263 g_pService->resume(); 264 else 265 g_pService->pause(); 266 RTThreadSleep(1000); 267 } 268 RTFileClose(hFile); 269 } 270 else 271 return false; 272 return true; 273 } 274 #endif 275 276 #ifdef RT_OS_LINUX 277 /** 278 * Thread which notifies the service when we switch to a different VT or back. 279 * @note runs until programme exit. 280 * @todo take "g_cleanupCritSect" while pausing/resuming the service to ensure 281 * that they do not happen after clean-up starts. We actually want to 282 * prevent racing with the static destructor for the service object, as 283 * there is (I think) no guarantee that the VT thread will stop before the 284 * destructor is called on programme exit. 285 */ 286 static int pfnVTMonitorThread(RTTHREAD self, void *pvUser) 287 { 288 unsigned long cVT; 289 RTFILE hFile; 290 291 cVT = getXOrgVT(); 292 if (!cVT) 293 return VINF_SUCCESS; 294 if (!pollTTYSysfs((uint32_t) cVT)) 295 #if 0 /* Probably not needed, see comment before function. */ 296 pollTTYDevConsole(cVT); 297 #else 298 true; 299 #endif 300 return VINF_SUCCESS; 301 } 302 303 /** 304 * Start the thread which notifies the service when we switch to a different 305 * VT or back. This is best effort functionality (XFree86 4.3 and older do not 306 * report their VT via the "XFree86_VT" root window property at all), so we 307 * only fail if actual thread creation fails. 308 */ 309 static int startVTMonitorThread() 310 { 311 return RTThreadCreate(NULL, pfnVTMonitorThread, NULL, 0, 312 RTTHREADTYPE_INFREQUENT_POLLER, 0, "VT_MONITOR"); 313 } 314 #endif /* defined RT_OS_LINUX */ 315 138 316 /** 139 317 * Print out a usage message and exit with success. … … 190 368 191 369 /* Initialise our global clean-up critical section */ 192 rc = RTCritSectInit(&g_c ritSect);370 rc = RTCritSectInit(&g_cleanupCritSect); 193 371 if (RT_FAILURE(rc)) 194 372 { … … 307 485 /* Set an X11 I/O error handler, so that we can shutdown properly on fatal errors. */ 308 486 XSetIOErrorHandler(vboxClientXLibIOErrorHandler); 487 #ifdef RT_OS_LINUX 488 rc = startVTMonitorThread(); 489 if (RT_FAILURE(rc)) 490 { 491 RTPrintf("Failed to start the VT monitor thread (%Rrc). Exiting.\n", 492 rc); 493 LogRel(("Failed to start the VT monitor thread (%Rrc). Exiting.\n", 494 rc)); 495 VbglR3Term(); 496 return 1; 497 } 498 #endif /* defined RT_OS_LINUX */ 309 499 g_pService->run(fDaemonise); 310 500 VBoxClient::CleanUp();
Note:
See TracChangeset
for help on using the changeset viewer.