Changeset 93371 in vbox for trunk/src/VBox
- Timestamp:
- Jan 20, 2022 5:48:35 PM (3 years ago)
- Location:
- trunk/src/VBox/Additions/x11/VBoxClient
- Files:
-
- 1 added
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Additions/x11/VBoxClient/Makefile.kmk
r93115 r93371 56 56 VBoxDRMClient_SOURCES = \ 57 57 display-drm.cpp \ 58 display-ipc.cpp \ 58 59 logging.cpp 59 60 … … 125 126 VBoxClient_DEFS += VBOX_WITH_VMSVGA 126 127 VBoxClient_SOURCES += \ 127 display-svga-x11.cpp 128 display-svga-x11.cpp \ 129 display-svga-session.cpp \ 130 display-ipc.cpp \ 131 display-helper-gnome3.cpp \ 132 display-helper-generic.cpp 133 134 ### include $(PATH_SUB_CURRENT)/helpers/Makefile.kmk 128 135 endif 129 136 -
trunk/src/VBox/Additions/x11/VBoxClient/display-drm.cpp
r93360 r93371 1 1 /* $Id$ */ 2 2 /** @file 3 * X11 guest client - VMSVGA emulation resize event pass-through to drm guest 4 * driver. 3 * A user space daemon which communicates with VirtualBox host interface 4 * and performs VMSVGA-specific guest screen resize and communicates with 5 * Desktop Environment helper daemon over IPC. 5 6 */ 6 7 … … 18 19 19 20 /* 20 * Known things to test when changing this code. All assume a guest with VMSVGA 21 * active and controlled by X11 or Wayland, and Guest Additions installed and 22 * running, unless otherwise stated. 23 * - On Linux 4.6 and later guests, VBoxClient --vmsvga should be running as 24 * root and not as the logged-in user. Dynamic resizing should work for all 25 * screens in any environment which handles kernel resize notifications, 26 * including at log-in screens. Test GNOME Shell Wayland and GNOME Shell 27 * under X.Org or Unity or KDE at the log-in screen and after log-in. 28 * - Linux 4.10 changed the user-kernel-ABI introduced in 4.6: test both. 29 * - On other guests (than Linux 4.6 or later) running X.Org Server 1.3 or 30 * later, VBoxClient --vmsvga should never be running as root, and should run 31 * (and dynamic resizing and screen enable/disable should work for all 32 * screens) whenever a user is logged in to a supported desktop environment. 33 * - On guests running X.Org Server 1.2 or older, VBoxClient --vmsvga should 34 * never run as root and should run whenever a user is logged in to a 35 * supported desktop environment. Dynamic resizing should work for the first 36 * screen, and enabling others should not be possible. 37 * - When VMSVGA is not enabled, VBoxClient --vmsvga should never stay running. 21 * General notes 22 * 23 * This service supposed to be started on early boot. On start it will try to find 24 * compatible VMSVGA graphics card and terminate immediately if not found. 25 * VMSVGA functionality implemented here is only supported starting from vmgfx 26 * driver version 2.10 which was introduced in vanilla Linux kernel 4.6. When compatible 27 * graphics card is found, service will start a worker loop in order to receive screen 28 * update data from host and apply it to local DRM stack. 29 * 30 * In addition, it will start a local IPC server in order to communicate with Desktop 31 * Environment specific service(s). Currently, it will propagate to IPC client information 32 * which display should be set as primary on Desktop Environment level. As well as 33 * receive screen layout change events obtained on Desktop Environment level and send it 34 * back to host, so host and guest will have the same screen layout representation. 35 * 36 * Logging is implemented in a way that errors are always printed out, VBClLogVerbose(1) and 37 * VBClLogVerbose(2) are used for debugging purposes. Verbosity level 1 is for messages related 38 * to daemon itself (excluding IPC), level 2 is for IPC communication debugging. In order to see 39 * logging on a host side it is enough to do: 40 * 41 * echo 1 > /sys/module/vboxguest/parameters/r3_log_to_host. 42 * 43 * 44 * Threads 45 * 46 * DrmResizeThread - this thread listens for display layout update events from host. 47 * Once event is received, it either injects new screen layout data into DRM stack, 48 * and/or asks IPC client(s) to set primary display. This thread is accessing IPC 49 * client connection list when it needs to sent new primary display data to all the 50 * connected clients. 51 * 52 * DrmIpcSRV - this thread is a main loop for IPC server. It accepts new connection(s), 53 * authenticates it and starts new client thread IpcCLT-XXX for processing client 54 * requests. This thread is accessing IPC client connection list by adding a new 55 * connection data into it. 56 * 57 * IpcCLT-%u - this thread processes all the client data. Suffix '-%u' in thread name is PID 58 * of a remote client process. Typical name for client thread would be IpcCLT-1234. This 59 * thread is accessing IPC client connection list when it removes connection data from it 60 * when actual IPC connection is closed. Due to IPRT thread name limitation, actual thread 61 * name will be cropped by 15 characters. 62 * 63 * 64 * Locking 65 * 66 * g_ipcClientConnectionsListCritSect - protects access to list of IPC client connections. 67 * It is used by each thread - DrmResizeThread, DrmIpcSRV and IpcCLT-XXX. 68 * 69 * g_monitorPositionsCritSect - serializes access to host interface when guest Desktop 70 * Environment reports display layout changes. 38 71 */ 39 72 40 73 #include "VBoxClient.h" 74 #include "display-ipc.h" 41 75 42 76 #include <VBox/VBoxGuestLib.h> 43 77 78 #include <iprt/getopt.h> 44 79 #include <iprt/assert.h> 45 80 #include <iprt/file.h> … … 50 85 #include <iprt/thread.h> 51 86 #include <iprt/asm.h> 87 #include <iprt/localipc.h> 88 52 89 #include <unistd.h> 53 90 #include <stdio.h> 54 91 #include <limits.h> 55 92 #include <signal.h> 93 #include <grp.h> 94 #include <errno.h> 56 95 57 96 #ifdef RT_OS_LINUX … … 76 115 #define VMW_RENDER_DEVICE_MINOR_END (192) 77 116 78 /** Maximum number of supported screens. DRM and X11 both limit this to 32. */79 /** @todo if this ever changes, dynamically allocate resizeable arrays in the80 * context structure. */81 #define VMW_MAX_HEADS (32)82 83 117 /** Name of DRM resize thread. */ 84 118 #define DRM_RESIZE_THREAD_NAME "DrmResizeThread" 85 119 86 /* Time in milliseconds to wait for host events. */ 87 #define DRM_HOST_EVENT_RX_TIMEOUT_MS (500) 120 /** Name of DRM IPC server thread. */ 121 #define DRM_IPC_SERVER_THREAD_NAME "DrmIpcSRV" 122 /** Maximum length of thread name. */ 123 #define DRM_IPC_THREAD_NAME_MAX (16) 124 /** Name pattern of DRM IPC client thread. */ 125 #define DRM_IPC_CLIENT_THREAD_NAME_PTR "IpcCLT-%u" 126 /** Maximum number of simultaneous IPC client connections. */ 127 #define DRM_IPC_SERVER_CONNECTIONS_MAX (16) 128 129 /** IPC client connections counter. */ 130 static volatile uint32_t g_cDrmIpcConnections = 0; 88 131 89 132 /** DRM version structure. */ … … 102 145 AssertCompileSize(struct DRMVERSION, 8 + 7 * sizeof(void *)); 103 146 104 /** Rectangle structure for geometry of a single screen. */105 struct DRMVMWRECT106 {107 int32_t x;108 int32_t y;109 uint32_t w;110 uint32_t h;111 };112 AssertCompileSize(struct DRMVMWRECT, 16);113 114 147 /** Preferred screen layout information for DRM_VMW_UPDATE_LAYOUT IoCtl. The 115 148 * rects argument is a cast pointer to an array of drm_vmw_rect. */ … … 122 155 AssertCompileSize(struct DRMVMWUPDATELAYOUT, 16); 123 156 124 /** These two parameters are mostly unused. Defined here in order to satisfy linking requirements. */ 157 /** A node of IPC client connections list. */ 158 typedef struct VBOX_DRMIPC_CLIENT_CONNECTION_LIST_NODE 159 { 160 /** The list node. */ 161 RTLISTNODE Node; 162 /** List node payload. */ 163 PVBOX_DRMIPC_CLIENT pClient; 164 } VBOX_DRMIPC_CLIENT_CONNECTION_LIST_NODE; 165 166 /* Pointer to VBOX_DRMIPC_CLIENT_CONNECTION_LIST_NODE. */ 167 typedef VBOX_DRMIPC_CLIENT_CONNECTION_LIST_NODE *PVBOX_DRMIPC_CLIENT_CONNECTION_LIST_NODE; 168 169 /** IPC client connections list. */ 170 static VBOX_DRMIPC_CLIENT_CONNECTION_LIST_NODE g_ipcClientConnectionsList; 171 172 /** IPC client connections list critical section. */ 173 static RTCRITSECT g_ipcClientConnectionsListCritSect; 174 175 /** Critical section used for reporting monitors position back to host. */ 176 static RTCRITSECT g_monitorPositionsCritSect; 177 178 /** Counter of how often our daemon has been re-spawned. */ 125 179 unsigned g_cRespawn = 0; 180 /** Logging verbosity level. */ 126 181 unsigned g_cVerbosity = 0; 127 182 … … 133 188 134 189 /** 190 * Go over all existing IPC client connection and put set-primary-screen request 191 * data into TX queue of each of them . 192 * 193 * @return IPRT status code. 194 * @param u32PrimaryDisplay Primary display ID. 195 */ 196 static int vbDrmIpcBroadcastPrimaryDisplay(uint32_t u32PrimaryDisplay); 197 198 /** 135 199 * Attempts to open DRM device by given path and check if it is 136 * c ompatible for screen resize.137 * 138 * @return DRM device handle on success orNIL_RTFILE otherwise.200 * capable for screen resize. 201 * 202 * @return DRM device handle on success, NIL_RTFILE otherwise. 139 203 * @param szPathPattern Path name pattern to the DRM device. 140 204 * @param uInstance Driver / device instance. 141 205 */ 142 static RTFILE drmTryDevice(const char *szPathPattern, uint8_t uInstance)206 static RTFILE vbDrmTryDevice(const char *szPathPattern, uint8_t uInstance) 143 207 { 144 208 int rc = VERR_NOT_FOUND; … … 170 234 && vmwgfxVersion.cMinor >= DRM_DRIVER_VERSION_MINOR_MIN))) 171 235 { 172 VBClLogInfo(" VBoxDRMClient:found compatible device: %s\n", szPath);236 VBClLogInfo("found compatible device: %s\n", szPath); 173 237 } 174 238 else … … 182 246 else 183 247 { 184 VBClLogError(" VBoxDRMClient:unable to construct path to DRM device: %Rrc\n", rc);248 VBClLogError("unable to construct path to DRM device: %Rrc\n", rc); 185 249 } 186 250 … … 191 255 * Attempts to find and open DRM device to be used for screen resize. 192 256 * 193 * @return DRM device handle on success orNIL_RTFILE otherwise.194 */ 195 static RTFILE drmOpenVmwgfx(void)257 * @return DRM device handle on success, NIL_RTFILE otherwise. 258 */ 259 static RTFILE vbDrmOpenVmwgfx(void) 196 260 { 197 261 /* Control devices for drm graphics driver control devices go from … … 207 271 for (i = VMW_CONTROL_DEVICE_MINOR_START; i < VMW_RENDER_DEVICE_MINOR_START; i++) 208 272 { 209 hDevice = drmTryDevice("/dev/dri/controlD%u", i);273 hDevice = vbDrmTryDevice("/dev/dri/controlD%u", i); 210 274 if (hDevice != NIL_RTFILE) 211 275 return hDevice; … … 215 279 for (i = VMW_RENDER_DEVICE_MINOR_START; i <= VMW_RENDER_DEVICE_MINOR_END; i++) 216 280 { 217 hDevice = drmTryDevice("/dev/dri/renderD%u", i);281 hDevice = vbDrmTryDevice("/dev/dri/renderD%u", i); 218 282 if (hDevice != NIL_RTFILE) 219 283 return hDevice; 220 284 } 221 285 222 VBClLogError(" VBoxDRMClient:unable to find DRM device\n");286 VBClLogError("unable to find DRM device\n"); 223 287 224 288 return hDevice; … … 229 293 * into monitors layout array to be passed to DRM stack. 230 294 * 231 * @return VINF_SUCCESS on success, IPRT error code otherwise.295 * @return VINF_SUCCESS on success, VERR_DUPLICATE if monitors layout was not changed, IPRT error code otherwise. 232 296 * @param aDisplaysIn Input displays array. 233 297 * @param cDisplaysIn Number of elements in input displays array. 234 298 * @param aDisplaysOut Output displays array. 235 299 * @param cDisplaysOutMax Number of elements in output displays array. 300 * @param pu32PrimaryDisplay ID of a display which marked as primary. 236 301 * @param pcActualDisplays Number of displays to report to DRM stack (number of enabled displays). 237 302 */ 238 static int drmValidateLayout(VMMDevDisplayDef *aDisplaysIn, uint32_t cDisplaysIn, 239 struct DRMVMWRECT *aDisplaysOut, uint32_t cDisplaysOutMax, uint32_t *pcActualDisplays) 303 static int vbDrmValidateLayout(VMMDevDisplayDef *aDisplaysIn, uint32_t cDisplaysIn, 304 struct VBOX_DRMIPC_VMWRECT *aDisplaysOut, uint32_t *pu32PrimaryDisplay, 305 uint32_t cDisplaysOutMax, uint32_t *pcActualDisplays) 240 306 { 241 307 /* This array is a cache of what was received from DevVMM so far. 242 308 * DevVMM may send to us partial information bout scree layout. This 243 309 * cache remembers entire picture. */ 244 static struct VMMDevDisplayDef aVmMonitorsCache[V MW_MAX_HEADS];310 static struct VMMDevDisplayDef aVmMonitorsCache[VBOX_DRMIPC_MONITORS_MAX]; 245 311 /* Number of valid (enabled) displays in output array. */ 246 312 uint32_t cDisplaysOut = 0; … … 249 315 250 316 /* Make sure input array fits cache size. */ 251 if (cDisplaysIn > V MW_MAX_HEADS)252 { 253 VBClLogError(" VBoxDRMClient:unable to validate screen layout: input (%u) array does not fit to cache size (%u)\n",254 cDisplaysIn, VMW_MAX_HEADS);317 if (cDisplaysIn > VBOX_DRMIPC_MONITORS_MAX) 318 { 319 VBClLogError("unable to validate screen layout: input (%u) array does not fit to cache size (%u)\n", 320 cDisplaysIn, VBOX_DRMIPC_MONITORS_MAX); 255 321 return VERR_INVALID_PARAMETER; 256 322 } … … 259 325 if (cDisplaysIn > cDisplaysOutMax) 260 326 { 261 VBClLogError(" VBoxDRMClient:unable to validate screen layout: input array (%u) is bigger than output one (%u)\n",262 cDisplaysIn, cDisplaysOut);327 VBClLogError("unable to validate screen layout: input array (%u) is bigger than output one (%u)\n", 328 cDisplaysIn, cDisplaysOut); 263 329 return VERR_INVALID_PARAMETER; 264 330 } … … 267 333 if (!(cDisplaysIn > 0 && cDisplaysOutMax > 0)) 268 334 { 269 VBClLogError(" VBoxDRMClient:unable to validate screen layout: invalid size of either input (%u) or output display array\n",270 cDisplaysIn, cDisplaysOutMax);335 VBClLogError("unable to validate screen layout: invalid size of either input (%u) or output display array\n", 336 cDisplaysIn, cDisplaysOutMax); 271 337 return VERR_INVALID_PARAMETER; 272 338 } … … 276 342 { 277 343 uint32_t idDisplay = aDisplaysIn[i].idDisplay; 278 if (idDisplay < V MW_MAX_HEADS)344 if (idDisplay < VBOX_DRMIPC_MONITORS_MAX) 279 345 { 280 346 aVmMonitorsCache[idDisplay].idDisplay = idDisplay; … … 288 354 else 289 355 { 290 VBClLogError(" VBoxDRMClient:received display ID (0x%x, position %u) is invalid\n", idDisplay, i);356 VBClLogError("received display ID (0x%x, position %u) is invalid\n", idDisplay, i); 291 357 /* If monitor configuration cannot be placed into cache, consider entire cache is invalid. */ 292 358 fValid = false; … … 295 361 296 362 /* Now, go though complete cache and check if it is valid. */ 297 for (uint32_t i = 0; i < V MW_MAX_HEADS; i++)363 for (uint32_t i = 0; i < VBOX_DRMIPC_MONITORS_MAX; i++) 298 364 { 299 365 if (i == 0) … … 301 367 if (aVmMonitorsCache[i].fDisplayFlags & VMMDEV_DISPLAY_DISABLED) 302 368 { 303 VBClLogError(" VBoxDRMClient: unable to validate screen layout: first monitor is not allowed to be disabled");369 VBClLogError("unable to validate screen layout: first monitor is not allowed to be disabled\n"); 304 370 fValid = false; 305 371 } … … 309 375 else 310 376 { 311 /* Check if there is no hole in between monitors (i.e., if current monitor is enabled, but pr ivious one does not). */377 /* Check if there is no hole in between monitors (i.e., if current monitor is enabled, but previous one does not). */ 312 378 if ( !(aVmMonitorsCache[i].fDisplayFlags & VMMDEV_DISPLAY_DISABLED) 313 379 && aVmMonitorsCache[i - 1].fDisplayFlags & VMMDEV_DISPLAY_DISABLED) 314 380 { 315 VBClLogError(" VBoxDRMClient:unable to validate screen layout: there is a hole in displays layout config, "316 "monitor (%u) is ENABLED while (%u) does not\n", i, i - 1);381 VBClLogError("unable to validate screen layout: there is a hole in displays layout config, " 382 "monitor (%u) is ENABLED while (%u) does not\n", i, i - 1); 317 383 fValid = false; 318 384 } 319 385 else 320 386 { 321 /* Align displays next to each other (if needed) and check if there is no holes in between monitors. */ 322 if (!(aVmMonitorsCache[i].fDisplayFlags & VMMDEV_DISPLAY_ORIGIN)) 323 { 324 aVmMonitorsCache[i].xOrigin = aVmMonitorsCache[i - 1].xOrigin + aVmMonitorsCache[i - 1].cx; 325 aVmMonitorsCache[i].yOrigin = aVmMonitorsCache[i - 1].yOrigin; 326 } 387 /* Always align screens since unaligned layout will result in disaster. */ 388 aVmMonitorsCache[i].xOrigin = aVmMonitorsCache[i - 1].xOrigin + aVmMonitorsCache[i - 1].cx; 389 aVmMonitorsCache[i].yOrigin = aVmMonitorsCache[i - 1].yOrigin; 327 390 328 391 /* Only count enabled monitors. */ … … 336 399 if (fValid) 337 400 { 401 /* Start with invalid display ID. */ 402 uint32_t u32PrimaryDisplay = VBOX_DRMIPC_MONITORS_MAX; 403 338 404 for (uint32_t i = 0; i < cDisplaysOut; i++) 339 405 { … … 343 409 aDisplaysOut[i].h = aVmMonitorsCache[i].cy; 344 410 345 VBClLogInfo("VBoxDRMClient: update monitor %u parameters: %dx%d, (%d, %d)\n", 346 i, 347 aDisplaysOut[i].w, aDisplaysOut[i].h, 348 aDisplaysOut[i].x, aDisplaysOut[i].y); 349 350 } 351 411 if (aVmMonitorsCache[i].fDisplayFlags & VMMDEV_DISPLAY_PRIMARY) 412 { 413 /* Make sure display layout has only one primary display 414 * set (for display 0, host side sets primary flag, so exclude it). */ 415 Assert(u32PrimaryDisplay == 0 || u32PrimaryDisplay == VBOX_DRMIPC_MONITORS_MAX); 416 u32PrimaryDisplay = i; 417 } 418 419 VBClLogVerbose(1, "update monitor %u parameters: %dx%d, (%d, %d)\n", 420 i, aDisplaysOut[i].w, aDisplaysOut[i].h, aDisplaysOut[i].x, aDisplaysOut[i].y); 421 } 422 423 *pu32PrimaryDisplay = u32PrimaryDisplay; 352 424 *pcActualDisplays = cDisplaysOut; 353 425 } … … 360 432 * 361 433 * @return VINF_SUCCESS on success, IPRT error code otherwise. 362 * @param hDevice 363 * @param paRects 364 * @param cRects 365 */ 366 static int drmSendHints(RTFILE hDevice, struct DRMVMWRECT *paRects, uint32_t cRects)434 * @param hDevice Handle to opened DRM device. 435 * @param paRects Array of screen configuration data. 436 * @param cRects Number of elements in screen configuration array. 437 */ 438 static int vbDrmSendHints(RTFILE hDevice, struct VBOX_DRMIPC_VMWRECT *paRects, uint32_t cRects) 367 439 { 368 440 int rc = 0; … … 372 444 curuid = getuid(); 373 445 374 /* Ch enge effective user id. */446 /* Change effective user id. */ 375 447 if (setreuid(0, 0) == 0) 376 448 { … … 386 458 if (setreuid(curuid, 0) != 0) 387 459 { 388 VBClLogError(" VBoxDRMClient:reset of setreuid failed after drm ioctl");460 VBClLogError("reset of setreuid failed after drm ioctl"); 389 461 rc = VERR_ACCESS_DENIED; 390 462 } … … 392 464 else 393 465 { 394 VBClLogError(" VBoxDRMClient:setreuid failed during drm ioctl\n");466 VBClLogError("setreuid failed during drm ioctl\n"); 395 467 rc = VERR_ACCESS_DENIED; 396 468 } … … 400 472 401 473 /** 402 * This function converts vmwgfx monitors layout data into an array of monitors offsets 474 * Send monitor positions to host (thread safe). 475 * 476 * This function is accessed from DRMResize thread and from IPC Client thread. 477 * 478 * @return IPRT status code. 479 * @param cDisplays Number of displays (elements in pDisplays). 480 * @param pDisplays Displays parameters as it was sent to vmwgfx driver. 481 */ 482 static int vbDrmSendMonitorPositionsSync(uint32_t cDisplays, struct RTPOINT *pDisplays) 483 { 484 int rc; 485 486 rc = RTCritSectEnter(&g_monitorPositionsCritSect); 487 if (RT_SUCCESS(rc)) 488 { 489 rc = VbglR3SeamlessSendMonitorPositions(cDisplays, pDisplays); 490 int rc2 = RTCritSectLeave(&g_monitorPositionsCritSect); 491 if (RT_FAILURE(rc2)) 492 VBClLogError("vbDrmSendMonitorPositionsSync: unable to leave critical section, rc=%Rrc\n", rc); 493 } 494 else 495 VBClLogError("vbDrmSendMonitorPositionsSync: unable to enter critical section, rc=%Rrc\n", rc); 496 497 return rc; 498 } 499 500 /** 501 * This function converts vmwgfx monitors layout data into an array of monitor offsets 403 502 * and sends it back to the host in order to ensure that host and guest have the same 404 503 * monitors layout representation. 405 504 * 406 * @return IPRT status code.407 * @param cDisplaysNumber of displays (elements in pDisplays).408 * @param pDisplaysDisplays parameters as it was sent to vmwgfx driver.409 */ 410 static int drmSendMonitorPositions(uint32_t cDisplays, struct DRMVMWRECT *pDisplays)411 { 412 static RTPOINT aPositions[V MW_MAX_HEADS];413 414 if (!pDisplays || !cDisplays || cDisplays > V MW_MAX_HEADS)505 * @return IPRT status code. 506 * @param cDisplays Number of displays (elements in pDisplays). 507 * @param pDisplays Displays parameters as it was sent to vmwgfx driver. 508 */ 509 static int drmSendMonitorPositions(uint32_t cDisplays, struct VBOX_DRMIPC_VMWRECT *pDisplays) 510 { 511 static RTPOINT aPositions[VBOX_DRMIPC_MONITORS_MAX]; 512 513 if (!pDisplays || !cDisplays || cDisplays > VBOX_DRMIPC_MONITORS_MAX) 415 514 { 416 515 return VERR_INVALID_PARAMETER; … … 424 523 } 425 524 426 return VbglR3SeamlessSendMonitorPositions(cDisplays, aPositions);525 return vbDrmSendMonitorPositionsSync(cDisplays, aPositions); 427 526 } 428 527 429 528 /** Worker thread for resize task. */ 430 static DECLCALLBACK(int) drmResizeWorker(RTTHREAD ThreadSelf, void *pvUser)431 { 432 int rc ;529 static DECLCALLBACK(int) vbDrmResizeWorker(RTTHREAD ThreadSelf, void *pvUser) 530 { 531 int rc = VERR_GENERAL_FAILURE; 433 532 RTFILE hDevice = (RTFILE)pvUser; 434 533 … … 445 544 uint32_t events; 446 545 447 VMMDevDisplayDef aDisplaysIn[V MW_MAX_HEADS];546 VMMDevDisplayDef aDisplaysIn[VBOX_DRMIPC_MONITORS_MAX]; 448 547 uint32_t cDisplaysIn = 0; 449 548 450 struct DRMVMWRECT aDisplaysOut[VMW_MAX_HEADS];549 struct VBOX_DRMIPC_VMWRECT aDisplaysOut[VBOX_DRMIPC_MONITORS_MAX]; 451 550 uint32_t cDisplaysOut = 0; 452 551 … … 456 555 /* Query the first size without waiting. This lets us e.g. pick up 457 556 * the last event before a guest reboot when we start again after. */ 458 rc = VbglR3GetDisplayChangeRequestMulti(V MW_MAX_HEADS, &cDisplaysIn, aDisplaysIn, fAck);557 rc = VbglR3GetDisplayChangeRequestMulti(VBOX_DRMIPC_MONITORS_MAX, &cDisplaysIn, aDisplaysIn, fAck); 459 558 fAck = true; 460 if (RT_FAILURE(rc)) 461 { 462 VBClLogError("Failed to get display change request, rc=%Rrc\n", rc); 463 } 464 else 465 { 559 if (RT_SUCCESS(rc)) 560 { 561 uint32_t u32PrimaryDisplay = VBOX_DRMIPC_MONITORS_MAX; 562 static uint32_t u32PrimaryDisplayLast = VBOX_DRMIPC_MONITORS_MAX; 563 466 564 /* Validate displays layout and push it to DRM stack if valid. */ 467 rc = drmValidateLayout(aDisplaysIn, cDisplaysIn, aDisplaysOut, sizeof(aDisplaysOut), &cDisplaysOut);565 rc = vbDrmValidateLayout(aDisplaysIn, cDisplaysIn, aDisplaysOut, &u32PrimaryDisplay, sizeof(aDisplaysOut), &cDisplaysOut); 468 566 if (RT_SUCCESS(rc)) 469 567 { 470 rc = drmSendHints(hDevice, aDisplaysOut, cDisplaysOut);471 VBClLogInfo(" VBoxDRMClient:push screen layout data of %u display(s) to DRM stack has %s (%Rrc)\n",472 cDisplaysOut, RT_SUCCESS(rc) ? "succeeded" : "failed", rc);568 rc = vbDrmSendHints(hDevice, aDisplaysOut, cDisplaysOut); 569 VBClLogInfo("push screen layout data of %u display(s) to DRM stack has %s (%Rrc)\n", 570 cDisplaysOut, RT_SUCCESS(rc) ? "succeeded" : "failed", rc); 473 571 /* In addition, notify host that configuration was successfully applied to the guest vmwgfx driver. */ 474 572 if (RT_SUCCESS(rc)) … … 476 574 rc = drmSendMonitorPositions(cDisplaysOut, aDisplaysOut); 477 575 if (RT_FAILURE(rc)) 576 VBClLogError("cannot send host notification: %Rrc\n", rc); 577 578 /* If information about primary display is present in display layout, send it to DE over IPC. */ 579 if (u32PrimaryDisplay != VBOX_DRMIPC_MONITORS_MAX 580 && u32PrimaryDisplayLast != u32PrimaryDisplay) 478 581 { 479 VBClLogError("VBoxDRMClient: cannot send host notification: %Rrc\n", rc); 582 rc = vbDrmIpcBroadcastPrimaryDisplay(u32PrimaryDisplay); 583 584 /* Cache last value in order to avoid sending duplicate data over IPC. */ 585 u32PrimaryDisplayLast = u32PrimaryDisplay; 586 587 VBClLogVerbose(2, "DE was notified that display %u is now primary, rc=%Rrc\n", u32PrimaryDisplay, rc); 480 588 } 589 else 590 VBClLogVerbose(2, "do not notify DE that display %u is now primary, rc=%Rrc\n", u32PrimaryDisplay, rc); 481 591 } 482 592 } 593 else if (rc == VERR_DUPLICATE) 594 VBClLogVerbose(2, "do not notify DRM stack about monitors layout change, rc=%Rrc\n", rc); 483 595 else 484 {485 VBClLogError("VBoxDRMClient: displays layout is invalid, will not notify guest driver, rc=%Rrc\n", rc);486 }487 }596 VBClLogError("displays layout is invalid, will not notify guest driver, rc=%Rrc\n", rc); 597 } 598 else 599 VBClLogError("Failed to get display change request, rc=%Rrc\n", rc); 488 600 489 601 do 490 602 { 491 rc = VbglR3WaitEvent(VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST, DRM_HOST_EVENT_RX_TIMEOUT_MS, &events);603 rc = VbglR3WaitEvent(VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST, VBOX_DRMIPC_RX_TIMEOUT_MS, &events); 492 604 } while (rc == VERR_TIMEOUT && !ASMAtomicReadBool(&g_fShutdown)); 493 605 494 606 if (ASMAtomicReadBool(&g_fShutdown)) 495 607 { 496 VBClLogInfo("VBoxDRMClient: exitting resize thread: shutdown requested\n"); 608 VBClLogInfo("exiting resize thread: shutdown requested\n"); 609 /* This is a case when we should return positive status. */ 610 rc = (rc == VERR_TIMEOUT) ? VINF_SUCCESS : rc; 497 611 break; 498 612 } 499 613 else if (RT_FAILURE(rc)) 500 { 501 VBClLogFatalError("Failure waiting for event, rc=%Rrc\n", rc); 502 } 503 } 504 505 return 0; 506 } 507 508 static void drmRequestShutdown(int sig) 509 { 510 RT_NOREF1(sig); 511 614 VBClLogFatalError("VBoxDRMClient: resize thread: failure waiting for event, rc=%Rrc\n", rc); 615 } 616 617 return rc; 618 } 619 620 /** 621 * Go over all existing IPC client connection and put set-primary-screen request 622 * data into TX queue of each of them . 623 * 624 * @return IPRT status code. 625 * @param u32PrimaryDisplay Primary display ID. 626 */ 627 static int vbDrmIpcBroadcastPrimaryDisplay(uint32_t u32PrimaryDisplay) 628 { 629 int rc; 630 631 rc = RTCritSectEnter(&g_ipcClientConnectionsListCritSect); 632 if (RT_SUCCESS(rc)) 633 { 634 if (!RTListIsEmpty(&g_ipcClientConnectionsList.Node)) 635 { 636 PVBOX_DRMIPC_CLIENT_CONNECTION_LIST_NODE pEntry; 637 RTListForEach(&g_ipcClientConnectionsList.Node, pEntry, VBOX_DRMIPC_CLIENT_CONNECTION_LIST_NODE, Node) 638 { 639 AssertReturn(pEntry, VERR_INVALID_PARAMETER); 640 AssertReturn(pEntry->pClient, VERR_INVALID_PARAMETER); 641 AssertReturn(pEntry->pClient->hThread, VERR_INVALID_PARAMETER); 642 643 rc = vbDrmIpcSetPrimaryDisplay(pEntry->pClient, u32PrimaryDisplay); 644 645 VBClLogInfo("thread %s notified IPC Client that display %u is now primary, rc=%Rrc\n", 646 RTThreadGetName(pEntry->pClient->hThread), u32PrimaryDisplay, rc); 647 } 648 } 649 650 int rc2 = RTCritSectLeave(&g_ipcClientConnectionsListCritSect); 651 if (RT_FAILURE(rc2)) 652 VBClLogError("notify DE: unable to leave critical section, rc=%Rrc\n", rc2); 653 } 654 else 655 VBClLogError("notify DE: unable to enter critical section, rc=%Rrc\n", rc); 656 657 return rc; 658 } 659 660 /** 661 * Main loop for IPC client connection handling. 662 * 663 * @return IPRT status code. 664 * @param pClient Pointer to IPC client data. 665 */ 666 static int vbDrmIpcConnectionProc(PVBOX_DRMIPC_CLIENT pClient) 667 { 668 int rc = VERR_GENERAL_FAILURE; 669 670 AssertReturn(pClient, VERR_INVALID_PARAMETER); 671 672 /* This loop handles incoming messages. */ 673 for (;;) 674 { 675 rc = vbDrmIpcConnectionHandler(pClient); 676 677 /* Try to detect if we should shutdown as early as we can. */ 678 if (ASMAtomicReadBool(&g_fShutdown)) 679 break; 680 681 /* Normal case. No data received within short interval. */ 682 if (rc == VERR_TIMEOUT) 683 { 684 continue; 685 } 686 else if (RT_FAILURE(rc)) 687 { 688 /* Terminate connection handling in case of error. */ 689 VBClLogError("unable to handle IPC session, rc=%Rrc\n", rc); 690 break; 691 } 692 } 693 694 return rc; 695 } 696 697 /** 698 * Add IPC client connection data into list of connections. 699 * 700 * List size is limited indirectly by DRM_IPC_SERVER_CONNECTIONS_MAX value. 701 * This function should only be invoked from client thread context 702 * (from vbDrmIpcClientWorker() in particular). 703 * 704 * @return IPRT status code. 705 * @param pClient Client connection information to add to the list. 706 */ 707 static int vbDrmIpcClientsListAdd(PVBOX_DRMIPC_CLIENT_CONNECTION_LIST_NODE pClientNode) 708 { 709 int rc; 710 711 AssertReturn(pClientNode, VERR_INVALID_PARAMETER); 712 713 rc = RTCritSectEnter(&g_ipcClientConnectionsListCritSect); 714 if (RT_SUCCESS(rc)) 715 { 716 RTListAppend(&g_ipcClientConnectionsList.Node, &pClientNode->Node); 717 718 int rc2 = RTCritSectLeave(&g_ipcClientConnectionsListCritSect); 719 if (RT_FAILURE(rc2)) 720 VBClLogError("add client connection: unable to leave critical section, rc=%Rrc\n", rc2); 721 } 722 else 723 VBClLogError("add client connection: unable to enter critical section, rc=%Rrc\n", rc); 724 725 return rc; 726 } 727 728 /** 729 * Remove IPC client connection data from list of connections. 730 * 731 * This function should only be invoked from client thread context 732 * (from vbDrmIpcClientWorker() in particular). 733 * 734 * @return IPRT status code. 735 * @param pClient Client connection information to remove from the list. 736 */ 737 static int vbDrmIpcClientsListRemove(PVBOX_DRMIPC_CLIENT_CONNECTION_LIST_NODE pClientNode) 738 { 739 int rc; 740 PVBOX_DRMIPC_CLIENT_CONNECTION_LIST_NODE pEntry, pNextEntry, pFound = NULL; 741 742 AssertReturn(pClientNode, VERR_INVALID_PARAMETER); 743 744 rc = RTCritSectEnter(&g_ipcClientConnectionsListCritSect); 745 if (RT_SUCCESS(rc)) 746 { 747 748 if (!RTListIsEmpty(&g_ipcClientConnectionsList.Node)) 749 { 750 RTListForEachSafe(&g_ipcClientConnectionsList.Node, pEntry, pNextEntry, VBOX_DRMIPC_CLIENT_CONNECTION_LIST_NODE, Node) 751 { 752 if (pEntry == pClientNode) 753 pFound = (PVBOX_DRMIPC_CLIENT_CONNECTION_LIST_NODE)RTListNodeRemoveRet(&pEntry->Node); 754 } 755 } 756 else 757 VBClLogError("remove client connection: connections list empty, node %p not there\n", pClientNode); 758 759 int rc2 = RTCritSectLeave(&g_ipcClientConnectionsListCritSect); 760 if (RT_FAILURE(rc2)) 761 VBClLogError("remove client connection: unable to leave critical section, rc=%Rrc\n", rc2); 762 } 763 else 764 VBClLogError("remove client connection: unable to enter critical section, rc=%Rrc\n", rc); 765 766 if (!pFound) 767 VBClLogError("remove client connection: node not found\n"); 768 769 return !rc && pFound ? VINF_SUCCESS : VERR_INVALID_PARAMETER; 770 } 771 772 /** 773 * @interface_method_impl{VBOX_DRMIPC_CLIENT,pfnRxCb} 774 */ 775 static int vbDrmIpcClientRxCallBack(uint8_t idCmd, void *pvData, uint32_t cbData) 776 { 777 int rc = VERR_INVALID_PARAMETER; 778 779 AssertReturn(pvData, VERR_INVALID_PARAMETER); 780 AssertReturn(cbData, VERR_INVALID_PARAMETER); 781 782 switch (idCmd) 783 { 784 case VBOXDRMIPCSRVCMD_REPORT_DISPLAY_OFFSETS: 785 { 786 PVBOX_DRMIPC_COMMAND_REPORT_DISPLAY_OFFSETS pCmd = (PVBOX_DRMIPC_COMMAND_REPORT_DISPLAY_OFFSETS)pvData; 787 AssertReturn(cbData == sizeof(VBOX_DRMIPC_COMMAND_REPORT_DISPLAY_OFFSETS), VERR_INVALID_PARAMETER); 788 rc = vbDrmSendMonitorPositionsSync(pCmd->cOffsets, pCmd->paOffsets); 789 break; 790 } 791 792 default: 793 { 794 VBClLogError("received unknown IPC command 0x%x\n", idCmd); 795 break; 796 } 797 } 798 799 return rc; 800 } 801 802 /** Worker thread for IPC client task. */ 803 static DECLCALLBACK(int) vbDrmIpcClientWorker(RTTHREAD ThreadSelf, void *pvUser) 804 { 805 VBOX_DRMIPC_CLIENT hClient = VBOX_DRMIPC_CLIENT_INITIALIZER; 806 RTLOCALIPCSESSION hSession = (RTLOCALIPCSESSION)pvUser; 807 int rc; 808 809 AssertReturn(RT_VALID_PTR(hSession), VERR_INVALID_PARAMETER); 810 811 /* Initialize client session resources. */ 812 rc = vbDrmIpcClientInit(&hClient, ThreadSelf, hSession, VBOX_DRMIPC_TX_QUEUE_SIZE, vbDrmIpcClientRxCallBack); 813 if (RT_SUCCESS(rc)) 814 { 815 /* Add IPC client connection data into clients list. */ 816 VBOX_DRMIPC_CLIENT_CONNECTION_LIST_NODE hClientNode = { { 0, 0 } , &hClient }; 817 818 rc = vbDrmIpcClientsListAdd(&hClientNode); 819 if (RT_SUCCESS(rc)) 820 { 821 rc = RTThreadUserSignal(ThreadSelf); 822 if (RT_SUCCESS(rc)) 823 { 824 /* Start spinning the connection. */ 825 VBClLogInfo("IPC client connection started\n", rc); 826 rc = vbDrmIpcConnectionProc(&hClient); 827 VBClLogInfo("IPC client connection ended, rc=%Rrc\n", rc); 828 } 829 else 830 VBClLogError("unable to report IPC client connection handler start, rc=%Rrc\n", rc); 831 832 /* Remove IPC client connection data from clients list. */ 833 rc = vbDrmIpcClientsListRemove(&hClientNode); 834 if (RT_FAILURE(rc)) 835 VBClLogError("unable to remove IPC client session from list of connections, rc=%Rrc\n", rc); 836 } 837 else 838 VBClLogError("unable to add IPC client connection to the list, rc=%Rrc\n"); 839 840 /* Disconnect remote peer if still connected. */ 841 if (RT_VALID_PTR(hSession)) 842 { 843 rc = RTLocalIpcSessionClose(hSession); 844 VBClLogInfo("IPC session closed, rc=%Rrc\n", rc); 845 } 846 847 /* Connection handler loop has ended, release session resources. */ 848 rc = vbDrmIpcClientReleaseResources(&hClient); 849 if (RT_FAILURE(rc)) 850 VBClLogError("unable to release IPC client session, rc=%Rrc\n", rc); 851 852 ASMAtomicDecU32(&g_cDrmIpcConnections); 853 } 854 else 855 VBClLogError("unable to initialize IPC client session, rc=%Rrc\n", rc); 856 857 VBClLogInfo("closing IPC client session, rc=%Rrc\n", rc); 858 859 return rc; 860 } 861 862 /** 863 * Start processing thread for IPC client requests handling. 864 * 865 * @returns IPRT status code. 866 * @param hSession IPC client connection handle. 867 */ 868 static int vbDrmIpcClientStart(RTLOCALIPCSESSION hSession) 869 { 870 int rc; 871 RTTHREAD hThread = 0; 872 RTPROCESS hProcess = 0; 873 874 rc = RTLocalIpcSessionQueryProcess(hSession, &hProcess); 875 if (RT_SUCCESS(rc)) 876 { 877 char pszThreadName[DRM_IPC_THREAD_NAME_MAX]; 878 RT_ZERO(pszThreadName); 879 880 RTStrPrintf2(pszThreadName, DRM_IPC_THREAD_NAME_MAX, DRM_IPC_CLIENT_THREAD_NAME_PTR, hProcess); 881 882 /* Attempt to start IPC client connection handler task. */ 883 rc = RTThreadCreate(&hThread, vbDrmIpcClientWorker, (void *)hSession, 0, 884 RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, pszThreadName); 885 if (RT_SUCCESS(rc)) 886 { 887 rc = RTThreadUserWait(hThread, RT_MS_5SEC); 888 } 889 } 890 891 return rc; 892 } 893 894 /** Worker thread for IPC server task. */ 895 static DECLCALLBACK(int) vbDrmIpcServerWorker(RTTHREAD ThreadSelf, void *pvUser) 896 { 897 int rc = VERR_GENERAL_FAILURE; 898 RTLOCALIPCSERVER hIpcServer = (RTLOCALIPCSERVER)pvUser; 899 900 RT_NOREF1(ThreadSelf); 901 902 AssertReturn(hIpcServer, VERR_INVALID_PARAMETER); 903 904 /* This loop accepts incoming connections. */ 905 for (;;) 906 { 907 RTLOCALIPCSESSION hClientSession; 908 909 /* Wait for incoming connection. */ 910 rc = RTLocalIpcServerListen(hIpcServer, &hClientSession); 911 if (RT_SUCCESS(rc)) 912 { 913 VBClLogVerbose(2, "new IPC session\n"); 914 915 if (ASMAtomicIncU32(&g_cDrmIpcConnections) <= DRM_IPC_SERVER_CONNECTIONS_MAX) 916 { 917 /* Authenticate remote peer. */ 918 rc = vbDrmIpcAuth(hClientSession); 919 if (RT_SUCCESS(rc)) 920 { 921 /* Start incoming connection handler thread. */ 922 rc = vbDrmIpcClientStart(hClientSession); 923 VBClLogVerbose(2, "connection processing ended, rc=%Rrc\n", rc); 924 } 925 else 926 VBClLogError("IPC authentication failed, rc=%Rrc\n", rc); 927 } 928 else 929 rc = VERR_RESOURCE_BUSY; 930 931 /* Release resources in case of error. */ 932 if (RT_FAILURE(rc)) 933 { 934 VBClLogError("maximum amount of IPC client connections reached, dropping connection\n"); 935 936 int rc2 = RTLocalIpcSessionClose(hClientSession); 937 if (RT_FAILURE(rc2)) 938 VBClLogError("unable to close IPC session, rc=%Rrc\n", rc2); 939 940 ASMAtomicDecU32(&g_cDrmIpcConnections); 941 } 942 } 943 else 944 VBClLogError("IPC authentication failed, rc=%Rrc\n", rc); 945 946 /* Check shutdown was requested. */ 947 if (ASMAtomicReadBool(&g_fShutdown)) 948 { 949 VBClLogInfo("exiting IPC thread: shutdown requested\n"); 950 break; 951 } 952 953 /* Wait a bit before spinning a loop if something went wrong. */ 954 if (RT_FAILURE(rc)) 955 RTThreadSleep(VBOX_DRMIPC_RX_RELAX_MS); 956 } 957 958 return rc; 959 } 960 961 /** A signal handler. */ 962 static void vbDrmRequestShutdown(int sig) 963 { 964 RT_NOREF(sig); 512 965 ASMAtomicWriteBool(&g_fShutdown, true); 513 966 } … … 515 968 int main(int argc, char *argv[]) 516 969 { 970 /** Custom log prefix to be used for logger instance of this process. */ 971 static const char *pszLogPrefix = "VBoxDRMClient:"; 972 973 static const RTGETOPTDEF s_aOptions[] = { { "--verbose", 'v', RTGETOPT_REQ_NOTHING }, }; 974 RTGETOPTUNION ValueUnion; 975 RTGETOPTSTATE GetState; 976 int ch; 977 517 978 RTFILE hDevice = NIL_RTFILE; 518 979 RTFILE hPidFile; 519 980 981 RTLOCALIPCSERVER hIpcServer; 982 RTTHREAD vbDrmIpcThread; 983 int rcDrmIpcThread = 0; 984 520 985 RTTHREAD drmResizeThread; 521 986 int rcDrmResizeThread = 0; 522 523 int rc = RTR3InitExe(argc, &argv, 0); 987 int rc, rc2 = 0; 988 989 rc = RTR3InitExe(argc, &argv, 0); 524 990 if (RT_FAILURE(rc)) 525 991 return RTMsgInitFailure(rc); … … 529 995 VBClLogFatalError("VBoxDRMClient: VbglR3InitUser failed: %Rrc", rc); 530 996 997 /* Process command line options. */ 998 rc = RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0, 0 /* fFlags */); 999 if (RT_FAILURE(rc)) 1000 VBClLogFatalError("VBoxDRMClient: unable to process command line options, rc=%Rrc\n", rc); 1001 while ((ch = RTGetOpt(&GetState, &ValueUnion)) != 0) 1002 { 1003 switch (ch) 1004 { 1005 case 'v': 1006 { 1007 g_cVerbosity++; 1008 break; 1009 } 1010 1011 case VERR_GETOPT_UNKNOWN_OPTION: 1012 { 1013 VBClLogFatalError("unknown command line option '%s'\n", ValueUnion.psz); 1014 return RTEXITCODE_SYNTAX; 1015 1016 } 1017 1018 default: 1019 break; 1020 } 1021 } 1022 531 1023 rc = VBClLogCreate(""); 532 1024 if (RT_FAILURE(rc)) 533 1025 VBClLogFatalError("VBoxDRMClient: failed to setup logging, rc=%Rrc\n", rc); 534 535 PRTLOGGER pReleaseLog = RTLogRelGetDefaultInstance(); 536 if (pReleaseLog) 537 { 538 rc = RTLogDestinations(pReleaseLog, "stdout"); 539 if (RT_FAILURE(rc)) 540 VBClLogFatalError("VBoxDRMClient: failed to redirert error output, rc=%Rrc", rc); 541 } 542 else 543 { 544 VBClLogFatalError("VBoxDRMClient: failed to get logger instance"); 545 } 1026 VBClLogSetLogPrefix(pszLogPrefix); 546 1027 547 1028 /* Check PID file before attempting to initialize anything. */ … … 549 1030 if (rc == VERR_FILE_LOCK_VIOLATION) 550 1031 { 551 VBClLogInfo(" VBoxDRMClient:already running, exiting\n");1032 VBClLogInfo("already running, exiting\n"); 552 1033 return RTEXITCODE_SUCCESS; 553 1034 } 554 1035 if (RT_FAILURE(rc)) 555 1036 { 556 VBClLogError(" VBoxDRMClient:unable to lock PID file (%Rrc), exiting\n", rc);1037 VBClLogError("unable to lock PID file (%Rrc), exiting\n", rc); 557 1038 return RTEXITCODE_FAILURE; 558 1039 } 559 1040 560 hDevice = drmOpenVmwgfx();1041 hDevice = vbDrmOpenVmwgfx(); 561 1042 if (hDevice == NIL_RTFILE) 562 1043 return RTEXITCODE_FAILURE; … … 569 1050 } 570 1051 rc = VbglR3AcquireGuestCaps(VMMDEV_GUEST_SUPPORTS_GRAPHICS, 0, false); 571 if (rc == VERR_RESOURCE_BUSY) /* Someone else has already acquired it. */572 {573 return RTEXITCODE_FAILURE;574 }575 1052 if (RT_FAILURE(rc)) 576 1053 { … … 580 1057 581 1058 /* Setup signals: gracefully terminate on SIGINT, SIGTERM. */ 582 if ( signal(SIGINT, drmRequestShutdown) == SIG_ERR583 || signal(SIGTERM, drmRequestShutdown) == SIG_ERR)584 { 585 VBClLogError(" VBoxDRMClient:unable to setup signals\n");1059 if ( signal(SIGINT, vbDrmRequestShutdown) == SIG_ERR 1060 || signal(SIGTERM, vbDrmRequestShutdown) == SIG_ERR) 1061 { 1062 VBClLogError("unable to setup signals\n"); 586 1063 return RTEXITCODE_FAILURE; 587 1064 } 588 1065 1066 /* Init IPC client connection list. */ 1067 RTListInit(&g_ipcClientConnectionsList.Node); 1068 rc = RTCritSectInit(&g_ipcClientConnectionsListCritSect); 1069 if (RT_FAILURE(rc)) 1070 { 1071 VBClLogError("unable to initialize IPC client connection list critical section\n"); 1072 return RTEXITCODE_FAILURE; 1073 } 1074 1075 /* Init critical section which is used for reporting monitors offset back to host. */ 1076 rc = RTCritSectInit(&g_monitorPositionsCritSect); 1077 if (RT_FAILURE(rc)) 1078 { 1079 VBClLogError("unable to initialize monitors position critical section\n"); 1080 return RTEXITCODE_FAILURE; 1081 } 1082 1083 /* Instantiate IPC server for VBoxClient service communication. */ 1084 rc = RTLocalIpcServerCreate(&hIpcServer, VBOX_DRMIPC_SERVER_NAME, 0); 1085 if (RT_FAILURE(rc)) 1086 { 1087 VBClLogError("unable to setup IPC server, rc=%Rrc\n", rc); 1088 return RTEXITCODE_FAILURE; 1089 } 1090 1091 struct group *pGrp; 1092 pGrp = getgrnam(VBOX_DRMIPC_USER_GROUP); 1093 if (pGrp) 1094 { 1095 rc = RTLocalIpcServerGrantGroupAccess(hIpcServer, pGrp->gr_gid); 1096 if (RT_FAILURE(rc)) 1097 VBClLogError("unable to grant IPC server socket access to '" VBOX_DRMIPC_USER_GROUP "', rc=%Rrc\n", rc); 1098 } 1099 else 1100 VBClLogError("unable to grant IPC server socket access to '" VBOX_DRMIPC_USER_GROUP "', group does not exist\n"); 1101 589 1102 /* Attempt to start DRM resize task. */ 590 rc = RTThreadCreate(&drmResizeThread, drmResizeWorker, (void *)hDevice, 0,1103 rc = RTThreadCreate(&drmResizeThread, vbDrmResizeWorker, (void *)hDevice, 0, 591 1104 RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, DRM_RESIZE_THREAD_NAME); 592 1105 if (RT_SUCCESS(rc)) 593 1106 { 594 rc = RTThreadWait(drmResizeThread, RT_INDEFINITE_WAIT, &rcDrmResizeThread); 595 VBClLogInfo("VBoxDRMClient: %s thread exitted with status %Rrc\n", DRM_RESIZE_THREAD_NAME, rcDrmResizeThread); 596 rc |= rcDrmResizeThread; 597 } 1107 /* Attempt to start IPC task. */ 1108 rc = RTThreadCreate(&vbDrmIpcThread, vbDrmIpcServerWorker, (void *)hIpcServer, 0, 1109 RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, DRM_IPC_SERVER_THREAD_NAME); 1110 if (RT_SUCCESS(rc)) 1111 { 1112 /* HACK ALERT! 1113 * The sequence of RTThreadWait(drmResizeThread) -> RTLocalIpcServerDestroy() -> RTThreadWait(vbDrmIpcThread) 1114 * is intentional! Once process received a signal, it will pull g_fShutdown flag, which in turn will cause 1115 * drmResizeThread to quit. The vbDrmIpcThread might hang on accept() call, so we terminate IPC server to 1116 * release it and then wait for its termination. */ 1117 1118 rc = RTThreadWait(drmResizeThread, RT_INDEFINITE_WAIT, &rcDrmResizeThread); 1119 VBClLogInfo("%s thread exited with status, rc=%Rrc\n", DRM_RESIZE_THREAD_NAME, rcDrmResizeThread); 1120 1121 rc = RTLocalIpcServerCancel(hIpcServer); 1122 if (RT_FAILURE(rc)) 1123 VBClLogError("unable to notify IPC server about shutdown, rc=%Rrc\n", rc); 1124 1125 /* Wait for threads to terminate gracefully. */ 1126 rc = RTThreadWait(vbDrmIpcThread, RT_INDEFINITE_WAIT, &rcDrmIpcThread); 1127 VBClLogInfo("%s thread exited with status, rc=%Rrc\n", DRM_IPC_SERVER_THREAD_NAME, rcDrmResizeThread); 1128 1129 } 1130 else 1131 VBClLogError("unable to start IPC thread, rc=%Rrc\n", rc); 1132 } 1133 else 1134 VBClLogError("unable to start resize thread, rc=%Rrc\n", rc); 1135 1136 rc = RTLocalIpcServerDestroy(hIpcServer); 1137 if (RT_FAILURE(rc)) 1138 VBClLogError("unable to stop IPC server, rc=%Rrc\n", rc); 1139 1140 rc2 = RTCritSectDelete(&g_monitorPositionsCritSect); 1141 if (RT_FAILURE(rc2)) 1142 VBClLogError("unable to destroy g_monitorPositionsCritSect critsect, rc=%Rrc\n", rc2); 1143 1144 rc2 = RTCritSectDelete(&g_ipcClientConnectionsListCritSect); 1145 if (RT_FAILURE(rc2)) 1146 VBClLogError("unable to destroy g_ipcClientConnectionsListCritSect critsect, rc=%Rrc\n", rc2); 598 1147 599 1148 RTFileClose(hDevice); 600 1149 601 VBClLogInfo(" VBoxDRMClient:releasing PID file lock\n");1150 VBClLogInfo("releasing PID file lock\n"); 602 1151 VbglR3ClosePidFile(g_pszPidFile, hPidFile); 603 1152 1153 VBClLogDestroy(); 1154 604 1155 return rc == 0 ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE; 605 1156 } -
trunk/src/VBox/Additions/x11/VBoxClient/main.cpp
r93115 r93371 49 49 #define VBOXCLIENT_OPT_SEAMLESS VBOXCLIENT_OPT_SERVICES + 3 50 50 #define VBOXCLIENT_OPT_VMSVGA VBOXCLIENT_OPT_SERVICES + 4 51 #define VBOXCLIENT_OPT_VMSVGA_SESSION VBOXCLIENT_OPT_SERVICES + 5 51 52 52 53 … … 256 257 #endif 257 258 #ifdef VBOX_WITH_VMSVGA 258 "--vmsvga" 259 "--vmsvga|" 260 "--vmsvga-session" 259 261 #endif 260 262 "\n[-d|--nodaemon]\n", pcszFileName); … … 275 277 #ifdef VBOX_WITH_VMSVGA 276 278 RTPrintf(" --vmsvga starts VMSVGA dynamic resizing for X11/Wayland guests\n"); 279 RTPrintf(" --vmsvga-session starts Desktop Environment specific screen assistant for X11/Wayland guests\n" 280 " (VMSVGA graphics adapter only)\n"); 277 281 #endif 278 282 RTPrintf(" -f, --foreground run in the foreground (no daemonizing)\n"); … … 374 378 #ifdef VBOX_WITH_VMSVGA 375 379 { "--vmsvga", VBOXCLIENT_OPT_VMSVGA, RTGETOPT_REQ_NOTHING }, 380 { "--vmsvga-session", VBOXCLIENT_OPT_VMSVGA_SESSION, RTGETOPT_REQ_NOTHING }, 376 381 #endif 377 382 }; … … 482 487 return vbclSyntaxOnlyOneService(); 483 488 g_Service.pDesc = &g_SvcDisplaySVGA; 489 break; 490 } 491 case VBOXCLIENT_OPT_VMSVGA_SESSION: 492 { 493 if (g_Service.pDesc) 494 return vbclSyntaxOnlyOneService(); 495 g_Service.pDesc = &g_SvcDisplaySVGASession; 484 496 break; 485 497 } … … 520 532 return RTMsgErrorExitFailure("VbglR3InitUser failed: %Rrc", rc); 521 533 522 rc = VBClLogCreate(g_szLogFile[0] ? g_szLogFile : NULL);534 rc = VBClLogCreate(g_szLogFile[0] ? g_szLogFile : ""); 523 535 if (RT_FAILURE(rc)) 524 536 return RTMsgErrorExitFailure("Failed to create release log '%s', rc=%Rrc\n", … … 551 563 if (RT_FAILURE(rc)) 552 564 VBClLogFatalError("Creating PID file path failed: %Rrc\n", rc); 553 if (fDaemonise) 554 rc = VbglR3Daemonize(false /* fNoChDir */, false /* fNoClose */, fRespawn, &g_cRespawn); 555 if (RT_FAILURE(rc)) 556 VBClLogFatalError("Daemonizing service failed: %Rrc\n", rc); 557 if (g_szPidFile[0]) 558 rc = VbglR3PidFile(g_szPidFile, &g_hPidFile); 565 } 566 567 if (fDaemonise) 568 rc = VbglR3Daemonize(false /* fNoChDir */, false /* fNoClose */, fRespawn, &g_cRespawn); 569 if (RT_FAILURE(rc)) 570 VBClLogFatalError("Daemonizing service failed: %Rrc\n", rc); 571 572 if (g_szPidFile[0]) 573 { 574 rc = VbglR3PidFile(g_szPidFile, &g_hPidFile); 559 575 if (rc == VERR_FILE_LOCK_VIOLATION) /* Already running. */ 560 576 return RTEXITCODE_SUCCESS;
Note:
See TracChangeset
for help on using the changeset viewer.