VirtualBox

Changeset 93371 in vbox for trunk/src/VBox


Ignore:
Timestamp:
Jan 20, 2022 5:48:35 PM (3 years ago)
Author:
vboxsync
Message:

Additions: Linux: introduce VBoxClient --vmsvga-session service and connect it to VBoxDRMClient over IPC, bugref:10134.

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  
    5656VBoxDRMClient_SOURCES = \
    5757    display-drm.cpp \
     58    display-ipc.cpp \
    5859    logging.cpp
    5960
     
    125126 VBoxClient_DEFS    += VBOX_WITH_VMSVGA
    126127 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
    128135endif
    129136
  • trunk/src/VBox/Additions/x11/VBoxClient/display-drm.cpp

    r93360 r93371  
    11/* $Id$ */
    22/** @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.
    56 */
    67
     
    1819
    1920/*
    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.
    3871 */
    3972
    4073#include "VBoxClient.h"
     74#include "display-ipc.h"
    4175
    4276#include <VBox/VBoxGuestLib.h>
    4377
     78#include <iprt/getopt.h>
    4479#include <iprt/assert.h>
    4580#include <iprt/file.h>
     
    5085#include <iprt/thread.h>
    5186#include <iprt/asm.h>
     87#include <iprt/localipc.h>
     88
    5289#include <unistd.h>
    5390#include <stdio.h>
    5491#include <limits.h>
    5592#include <signal.h>
     93#include <grp.h>
     94#include <errno.h>
    5695
    5796#ifdef RT_OS_LINUX
     
    76115#define VMW_RENDER_DEVICE_MINOR_END     (192)
    77116
    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 the
    80  *  context structure. */
    81 #define VMW_MAX_HEADS                   (32)
    82 
    83117/** Name of DRM resize thread. */
    84118#define DRM_RESIZE_THREAD_NAME          "DrmResizeThread"
    85119
    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. */
     130static volatile uint32_t g_cDrmIpcConnections = 0;
    88131
    89132/** DRM version structure. */
     
    102145AssertCompileSize(struct DRMVERSION, 8 + 7 * sizeof(void *));
    103146
    104 /** Rectangle structure for geometry of a single screen. */
    105 struct DRMVMWRECT
    106 {
    107     int32_t x;
    108     int32_t y;
    109     uint32_t w;
    110     uint32_t h;
    111 };
    112 AssertCompileSize(struct DRMVMWRECT, 16);
    113 
    114147/** Preferred screen layout information for DRM_VMW_UPDATE_LAYOUT IoCtl.  The
    115148 *  rects argument is a cast pointer to an array of drm_vmw_rect. */
     
    122155AssertCompileSize(struct DRMVMWUPDATELAYOUT, 16);
    123156
    124 /** These two parameters are mostly unused. Defined here in order to satisfy linking requirements. */
     157/** A node of IPC client connections list. */
     158typedef 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. */
     167typedef VBOX_DRMIPC_CLIENT_CONNECTION_LIST_NODE *PVBOX_DRMIPC_CLIENT_CONNECTION_LIST_NODE;
     168
     169/** IPC client connections list.  */
     170static VBOX_DRMIPC_CLIENT_CONNECTION_LIST_NODE g_ipcClientConnectionsList;
     171
     172/** IPC client connections list critical section. */
     173static RTCRITSECT g_ipcClientConnectionsListCritSect;
     174
     175/** Critical section used for reporting monitors position back to host. */
     176static RTCRITSECT g_monitorPositionsCritSect;
     177
     178/** Counter of how often our daemon has been re-spawned. */
    125179unsigned g_cRespawn = 0;
     180/** Logging verbosity level. */
    126181unsigned g_cVerbosity = 0;
    127182
     
    133188
    134189/**
     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 */
     196static int vbDrmIpcBroadcastPrimaryDisplay(uint32_t u32PrimaryDisplay);
     197
     198/**
    135199 * Attempts to open DRM device by given path and check if it is
    136  * compatible for screen resize.
    137  *
    138  * @return  DRM device handle on success or NIL_RTFILE otherwise.
     200 * capable for screen resize.
     201 *
     202 * @return  DRM device handle on success, NIL_RTFILE otherwise.
    139203 * @param   szPathPattern       Path name pattern to the DRM device.
    140204 * @param   uInstance           Driver / device instance.
    141205 */
    142 static RTFILE drmTryDevice(const char *szPathPattern, uint8_t uInstance)
     206static RTFILE vbDrmTryDevice(const char *szPathPattern, uint8_t uInstance)
    143207{
    144208    int rc = VERR_NOT_FOUND;
     
    170234                        && vmwgfxVersion.cMinor >= DRM_DRIVER_VERSION_MINOR_MIN)))
    171235            {
    172                 VBClLogInfo("VBoxDRMClient: found compatible device: %s\n", szPath);
     236                VBClLogInfo("found compatible device: %s\n", szPath);
    173237            }
    174238            else
     
    182246    else
    183247    {
    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);
    185249    }
    186250
     
    191255 * Attempts to find and open DRM device to be used for screen resize.
    192256 *
    193  * @return  DRM device handle on success or NIL_RTFILE otherwise.
    194  */
    195 static RTFILE drmOpenVmwgfx(void)
     257 * @return  DRM device handle on success, NIL_RTFILE otherwise.
     258 */
     259static RTFILE vbDrmOpenVmwgfx(void)
    196260{
    197261    /* Control devices for drm graphics driver control devices go from
     
    207271    for (i = VMW_CONTROL_DEVICE_MINOR_START; i < VMW_RENDER_DEVICE_MINOR_START; i++)
    208272    {
    209         hDevice = drmTryDevice("/dev/dri/controlD%u", i);
     273        hDevice = vbDrmTryDevice("/dev/dri/controlD%u", i);
    210274        if (hDevice != NIL_RTFILE)
    211275            return hDevice;
     
    215279    for (i = VMW_RENDER_DEVICE_MINOR_START; i <= VMW_RENDER_DEVICE_MINOR_END; i++)
    216280    {
    217         hDevice = drmTryDevice("/dev/dri/renderD%u", i);
     281        hDevice = vbDrmTryDevice("/dev/dri/renderD%u", i);
    218282        if (hDevice != NIL_RTFILE)
    219283            return hDevice;
    220284    }
    221285
    222     VBClLogError("VBoxDRMClient: unable to find DRM device\n");
     286    VBClLogError("unable to find DRM device\n");
    223287
    224288    return hDevice;
     
    229293 * into monitors layout array to be passed to DRM stack.
    230294 *
    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.
    232296 * @param   aDisplaysIn         Input displays array.
    233297 * @param   cDisplaysIn         Number of elements in input displays array.
    234298 * @param   aDisplaysOut        Output displays array.
    235299 * @param   cDisplaysOutMax     Number of elements in output displays array.
     300 * @param   pu32PrimaryDisplay  ID of a display which marked as primary.
    236301 * @param   pcActualDisplays    Number of displays to report to DRM stack (number of enabled displays).
    237302 */
    238 static int drmValidateLayout(VMMDevDisplayDef *aDisplaysIn, uint32_t cDisplaysIn,
    239                              struct DRMVMWRECT *aDisplaysOut, uint32_t cDisplaysOutMax, uint32_t *pcActualDisplays)
     303static int vbDrmValidateLayout(VMMDevDisplayDef *aDisplaysIn, uint32_t cDisplaysIn,
     304                             struct VBOX_DRMIPC_VMWRECT *aDisplaysOut, uint32_t *pu32PrimaryDisplay,
     305                             uint32_t cDisplaysOutMax, uint32_t *pcActualDisplays)
    240306{
    241307    /* This array is a cache of what was received from DevVMM so far.
    242308     * DevVMM may send to us partial information bout scree layout. This
    243309     * cache remembers entire picture. */
    244     static struct VMMDevDisplayDef aVmMonitorsCache[VMW_MAX_HEADS];
     310    static struct VMMDevDisplayDef aVmMonitorsCache[VBOX_DRMIPC_MONITORS_MAX];
    245311    /* Number of valid (enabled) displays in output array. */
    246312    uint32_t cDisplaysOut = 0;
     
    249315
    250316    /* Make sure input array fits cache size. */
    251     if (cDisplaysIn > VMW_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);
    255321        return VERR_INVALID_PARAMETER;
    256322    }
     
    259325    if (cDisplaysIn > cDisplaysOutMax)
    260326    {
    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);
    263329        return VERR_INVALID_PARAMETER;
    264330    }
     
    267333    if (!(cDisplaysIn > 0 && cDisplaysOutMax > 0))
    268334    {
    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);
    271337        return VERR_INVALID_PARAMETER;
    272338    }
     
    276342    {
    277343        uint32_t idDisplay = aDisplaysIn[i].idDisplay;
    278         if (idDisplay < VMW_MAX_HEADS)
     344        if (idDisplay < VBOX_DRMIPC_MONITORS_MAX)
    279345        {
    280346            aVmMonitorsCache[idDisplay].idDisplay = idDisplay;
     
    288354        else
    289355        {
    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);
    291357            /* If monitor configuration cannot be placed into cache, consider entire cache is invalid. */
    292358            fValid = false;
     
    295361
    296362    /* Now, go though complete cache and check if it is valid. */
    297     for (uint32_t i = 0; i < VMW_MAX_HEADS; i++)
     363    for (uint32_t i = 0; i < VBOX_DRMIPC_MONITORS_MAX; i++)
    298364    {
    299365        if (i == 0)
     
    301367            if (aVmMonitorsCache[i].fDisplayFlags & VMMDEV_DISPLAY_DISABLED)
    302368            {
    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");
    304370                fValid = false;
    305371            }
     
    309375        else
    310376        {
    311             /* Check if there is no hole in between monitors (i.e., if current monitor is enabled, but privious 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). */
    312378            if (   !(aVmMonitorsCache[i].fDisplayFlags & VMMDEV_DISPLAY_DISABLED)
    313379                && aVmMonitorsCache[i - 1].fDisplayFlags & VMMDEV_DISPLAY_DISABLED)
    314380            {
    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);
    317383                fValid = false;
    318384            }
    319385            else
    320386            {
    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;
    327390
    328391                /* Only count enabled monitors. */
     
    336399    if (fValid)
    337400    {
     401        /* Start with invalid display ID. */
     402        uint32_t u32PrimaryDisplay = VBOX_DRMIPC_MONITORS_MAX;
     403
    338404        for (uint32_t i = 0; i < cDisplaysOut; i++)
    339405        {
     
    343409            aDisplaysOut[i].h = aVmMonitorsCache[i].cy;
    344410
    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;
    352424        *pcActualDisplays = cDisplaysOut;
    353425    }
     
    360432 *
    361433 * @return  VINF_SUCCESS on success, IPRT error code otherwise.
    362  * @param   hDevice             Handle to opened DRM device.
    363  * @param   paRects             Array of screen configuration data.
    364  * @param   cRects              Number of elements in screen configuration array.
    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 */
     438static int vbDrmSendHints(RTFILE hDevice, struct VBOX_DRMIPC_VMWRECT *paRects, uint32_t cRects)
    367439{
    368440    int rc = 0;
     
    372444    curuid = getuid();
    373445
    374     /* Chenge effective user id. */
     446    /* Change effective user id. */
    375447    if (setreuid(0, 0) == 0)
    376448    {
     
    386458        if (setreuid(curuid, 0) != 0)
    387459        {
    388             VBClLogError("VBoxDRMClient: reset of setreuid failed after drm ioctl");
     460            VBClLogError("reset of setreuid failed after drm ioctl");
    389461            rc = VERR_ACCESS_DENIED;
    390462        }
     
    392464    else
    393465    {
    394         VBClLogError("VBoxDRMClient: setreuid failed during drm ioctl\n");
     466        VBClLogError("setreuid failed during drm ioctl\n");
    395467        rc = VERR_ACCESS_DENIED;
    396468    }
     
    400472
    401473/**
    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 */
     482static 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
    403502 * and sends it back to the host in order to ensure that host and guest have the same
    404503 * monitors layout representation.
    405504 *
    406  * @return IPRT status code.
    407  * @param cDisplays     Number of displays (elements in pDisplays).
    408  * @param pDisplays     Displays parameters as it was sent to vmwgfx driver.
    409  */
    410 static int drmSendMonitorPositions(uint32_t cDisplays, struct DRMVMWRECT *pDisplays)
    411 {
    412     static RTPOINT aPositions[VMW_MAX_HEADS];
    413 
    414     if (!pDisplays || !cDisplays || cDisplays > VMW_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 */
     509static 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)
    415514    {
    416515        return VERR_INVALID_PARAMETER;
     
    424523    }
    425524
    426     return VbglR3SeamlessSendMonitorPositions(cDisplays, aPositions);
     525    return vbDrmSendMonitorPositionsSync(cDisplays, aPositions);
    427526}
    428527
    429528/** Worker thread for resize task. */
    430 static DECLCALLBACK(int) drmResizeWorker(RTTHREAD ThreadSelf, void *pvUser)
    431 {
    432     int rc;
     529static DECLCALLBACK(int) vbDrmResizeWorker(RTTHREAD ThreadSelf, void *pvUser)
     530{
     531    int rc = VERR_GENERAL_FAILURE;
    433532    RTFILE hDevice = (RTFILE)pvUser;
    434533
     
    445544        uint32_t events;
    446545
    447         VMMDevDisplayDef aDisplaysIn[VMW_MAX_HEADS];
     546        VMMDevDisplayDef aDisplaysIn[VBOX_DRMIPC_MONITORS_MAX];
    448547        uint32_t cDisplaysIn = 0;
    449548
    450         struct DRMVMWRECT aDisplaysOut[VMW_MAX_HEADS];
     549        struct VBOX_DRMIPC_VMWRECT aDisplaysOut[VBOX_DRMIPC_MONITORS_MAX];
    451550        uint32_t cDisplaysOut = 0;
    452551
     
    456555        /* Query the first size without waiting.  This lets us e.g. pick up
    457556         * the last event before a guest reboot when we start again after. */
    458         rc = VbglR3GetDisplayChangeRequestMulti(VMW_MAX_HEADS, &cDisplaysIn, aDisplaysIn, fAck);
     557        rc = VbglR3GetDisplayChangeRequestMulti(VBOX_DRMIPC_MONITORS_MAX, &cDisplaysIn, aDisplaysIn, fAck);
    459558        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
    466564            /* 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);
    468566            if (RT_SUCCESS(rc))
    469567            {
    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);
    473571                /* In addition, notify host that configuration was successfully applied to the guest vmwgfx driver. */
    474572                if (RT_SUCCESS(rc))
     
    476574                    rc = drmSendMonitorPositions(cDisplaysOut, aDisplaysOut);
    477575                    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)
    478581                    {
    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);
    480588                    }
     589                    else
     590                        VBClLogVerbose(2, "do not notify DE that display %u is now primary, rc=%Rrc\n", u32PrimaryDisplay, rc);
    481591                }
    482592            }
     593            else if (rc == VERR_DUPLICATE)
     594                VBClLogVerbose(2, "do not notify DRM stack about monitors layout change, rc=%Rrc\n", rc);
    483595            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);
    488600
    489601        do
    490602        {
    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);
    492604        } while (rc == VERR_TIMEOUT && !ASMAtomicReadBool(&g_fShutdown));
    493605
    494606        if (ASMAtomicReadBool(&g_fShutdown))
    495607        {
    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;
    497611            break;
    498612        }
    499613        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 */
     627static 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 */
     666static 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 */
     707static 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 */
     737static 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 */
     775static 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. */
     803static 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 */
     868static 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. */
     895static 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. */
     962static void vbDrmRequestShutdown(int sig)
     963{
     964    RT_NOREF(sig);
    512965    ASMAtomicWriteBool(&g_fShutdown, true);
    513966}
     
    515968int main(int argc, char *argv[])
    516969{
     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
    517978    RTFILE hDevice = NIL_RTFILE;
    518979    RTFILE hPidFile;
    519980
     981    RTLOCALIPCSERVER hIpcServer;
     982    RTTHREAD vbDrmIpcThread;
     983    int rcDrmIpcThread = 0;
     984
    520985    RTTHREAD drmResizeThread;
    521986    int rcDrmResizeThread = 0;
    522 
    523     int rc = RTR3InitExe(argc, &argv, 0);
     987    int rc, rc2 = 0;
     988
     989    rc = RTR3InitExe(argc, &argv, 0);
    524990    if (RT_FAILURE(rc))
    525991        return RTMsgInitFailure(rc);
     
    529995        VBClLogFatalError("VBoxDRMClient: VbglR3InitUser failed: %Rrc", rc);
    530996
     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
    5311023    rc = VBClLogCreate("");
    5321024    if (RT_FAILURE(rc))
    5331025        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);
    5461027
    5471028    /* Check PID file before attempting to initialize anything. */
     
    5491030    if (rc == VERR_FILE_LOCK_VIOLATION)
    5501031    {
    551         VBClLogInfo("VBoxDRMClient: already running, exiting\n");
     1032        VBClLogInfo("already running, exiting\n");
    5521033        return RTEXITCODE_SUCCESS;
    5531034    }
    5541035    if (RT_FAILURE(rc))
    5551036    {
    556         VBClLogError("VBoxDRMClient: unable to lock PID file (%Rrc), exiting\n", rc);
     1037        VBClLogError("unable to lock PID file (%Rrc), exiting\n", rc);
    5571038        return RTEXITCODE_FAILURE;
    5581039    }
    5591040
    560     hDevice = drmOpenVmwgfx();
     1041    hDevice = vbDrmOpenVmwgfx();
    5611042    if (hDevice == NIL_RTFILE)
    5621043        return RTEXITCODE_FAILURE;
     
    5691050    }
    5701051    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     }
    5751052    if (RT_FAILURE(rc))
    5761053    {
     
    5801057
    5811058    /* Setup signals: gracefully terminate on SIGINT, SIGTERM. */
    582     if (   signal(SIGINT, drmRequestShutdown) == SIG_ERR
    583         || 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");
    5861063        return RTEXITCODE_FAILURE;
    5871064    }
    5881065
     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
    5891102    /* Attempt to start DRM resize task. */
    590     rc = RTThreadCreate(&drmResizeThread, drmResizeWorker, (void *)hDevice, 0,
     1103    rc = RTThreadCreate(&drmResizeThread, vbDrmResizeWorker, (void *)hDevice, 0,
    5911104                        RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, DRM_RESIZE_THREAD_NAME);
    5921105    if (RT_SUCCESS(rc))
    5931106    {
    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);
    5981147
    5991148    RTFileClose(hDevice);
    6001149
    601     VBClLogInfo("VBoxDRMClient: releasing PID file lock\n");
     1150    VBClLogInfo("releasing PID file lock\n");
    6021151    VbglR3ClosePidFile(g_pszPidFile, hPidFile);
    6031152
     1153    VBClLogDestroy();
     1154
    6041155    return rc == 0 ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
    6051156}
  • trunk/src/VBox/Additions/x11/VBoxClient/main.cpp

    r93115 r93371  
    4949#define VBOXCLIENT_OPT_SEAMLESS             VBOXCLIENT_OPT_SERVICES + 3
    5050#define VBOXCLIENT_OPT_VMSVGA               VBOXCLIENT_OPT_SERVICES + 4
     51#define VBOXCLIENT_OPT_VMSVGA_SESSION       VBOXCLIENT_OPT_SERVICES + 5
    5152
    5253
     
    256257#endif
    257258#ifdef VBOX_WITH_VMSVGA
    258              "--vmsvga"
     259             "--vmsvga|"
     260             "--vmsvga-session"
    259261#endif
    260262             "\n[-d|--nodaemon]\n", pcszFileName);
     
    275277#ifdef VBOX_WITH_VMSVGA
    276278    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");
    277281#endif
    278282    RTPrintf("  -f, --foreground     run in the foreground (no daemonizing)\n");
     
    374378#ifdef VBOX_WITH_VMSVGA
    375379        { "--vmsvga",                       VBOXCLIENT_OPT_VMSVGA,                    RTGETOPT_REQ_NOTHING },
     380        { "--vmsvga-session",               VBOXCLIENT_OPT_VMSVGA_SESSION,            RTGETOPT_REQ_NOTHING },
    376381#endif
    377382    };
     
    482487                    return vbclSyntaxOnlyOneService();
    483488                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;
    484496                break;
    485497            }
     
    520532        return RTMsgErrorExitFailure("VbglR3InitUser failed: %Rrc", rc);
    521533
    522     rc = VBClLogCreate(g_szLogFile[0] ? g_szLogFile : NULL);
     534    rc = VBClLogCreate(g_szLogFile[0] ? g_szLogFile : "");
    523535    if (RT_FAILURE(rc))
    524536        return RTMsgErrorExitFailure("Failed to create release log '%s', rc=%Rrc\n",
     
    551563        if (RT_FAILURE(rc))
    552564            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);
    559575        if (rc == VERR_FILE_LOCK_VIOLATION)  /* Already running. */
    560576            return RTEXITCODE_SUCCESS;
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette