VirtualBox

Changeset 15898 in vbox for trunk/src/VBox


Ignore:
Timestamp:
Jan 12, 2009 2:42:51 PM (16 years ago)
Author:
vboxsync
Message:

HostServices/SharedClipboard: did some cleaning up of the X11 host clipboard code and removed the race-prone timeouts

Location:
trunk/src/VBox/HostServices/SharedClipboard
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/HostServices/SharedClipboard/VBoxClipboard.h

    r8155 r15898  
    2525#define LOG_GROUP LOG_GROUP_HGCM
    2626#include <VBox/log.h>
    27 
    28 enum {
    29     /** The number of milliseconds before the clipboard times out. */
    30     CLIPBOARDTIMEOUT = 2000
    31 };
    3227
    3328struct _VBOXCLIPBOARDCONTEXT;
  • trunk/src/VBox/HostServices/SharedClipboard/x11.cpp

    r15883 r15898  
    194194
    195195    LogFlowFunc(("u32Format=%02X\n", u32Format));
     196    /* Assert that no other transfer is in process (requests are serialised)
     197     * and that the last transfer cleaned up properly. */
     198    AssertLogRelReturn(   pCtx->pClient->data.pv == NULL
     199                       && pCtx->pClient->data.cb == 0
     200                       && pCtx->pClient->data.u32Format == 0,
     201                       VERR_WRONG_ORDER
     202                      );
     203    /* No one else (X11 or VBox) should currently be waiting.  The first because
     204     * requests from X11 are serialised and the second because VBox previously
     205     * grabbed the clipboard, so it should not be waiting for data from us. */
     206    AssertLogRelReturn (ASMAtomicCmpXchgU32(&pCtx->waiter, 1, 0), VERR_DEADLOCK);
    196207    if (pClient == 0)
    197208    {
     209        /* This can legitimately happen if we disconnect during a request for
     210         * data from X11. */
    198211        LogFunc(("host requested guest clipboard data after guest had disconnected.\n"));
    199212        pCtx->guestFormats = 0;
     
    201214        return VERR_TIMEOUT;
    202215    }
    203     if (!(   pCtx->pClient->data.pv == NULL
    204           && pCtx->pClient->data.cb == 0
    205           && pCtx->pClient->data.u32Format == 0))
    206     {
    207         LogRel(("vboxClipboardReadDataFromClient: a guest to host clipboard transfer has been requested, but another is in progress, or has not cleaned up properly.\n"));
    208         AssertMsgFailed(("A guest to host clipboard transfer has been requested, but another is in progress, or has not cleaned up properly.\n"));
    209     }
    210 
    211     /* Only one of the guest and the host should be waiting at any one time */
    212     if (!ASMAtomicCmpXchgU32(&pCtx->waiter, 1, 0))
    213     {
    214         LogRel(("vboxClipboardReadDataFromClient: deadlock situation - the host and the guest are both waiting for data from the other.\n"));
    215         return VERR_DEADLOCK;
    216     }
    217216    /* Request data from the guest */
    218217    vboxSvcClipboardReportMsg (pCtx->pClient, VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA, u32Format);
    219218    /* Which will signal us when it is ready. */
    220     if (RTSemEventWait(pCtx->waitForData, CLIPBOARDTIMEOUT) != VINF_SUCCESS)
    221     {
    222         LogRel(("vboxClipboardReadDataFromClient: vboxSvcClipboardReportMsg failed to complete within %d milliseconds\n", CLIPBOARDTIMEOUT));
     219    int rc = RTSemEventWait(pCtx->waitForData, RT_INDEFINITE_WAIT);
     220    AssertLogRelRCSuccess(rc);
     221    if (RT_FAILURE(rc))
     222    {
     223        /* I believe this should not happen.  Wait until the assertions arrive
     224         * to prove the contrary. */
    223225        pCtx->guestFormats = 0;
    224226        pCtx->waiter = 0;
    225         return VERR_TIMEOUT;
     227        return rc;
    226228    }
    227229    pCtx->waiter = 0;
     
    684686    XtAppMainLoop(g_ctx.appContext);
    685687    g_ctx.formatList.clear();
    686     RTSemEventDestroy(g_ctx.waitForData);
    687     RTSemMutexDestroy(g_ctx.asyncMutex);
    688688    LogRel(("Shared clipboard: host clipboard thread terminated successfully\n"));
    689689    return VINF_SUCCESS;
     
    848848    LogRel(("vboxClipboardDestroy: shutting down host clipboard\n"));
    849849
     850    /* Drop the reference to the client, in case it is still there.  This will
     851     * cause any outstanding clipboard data requests from X11 to fail
     852     * immediately. */
     853    g_ctx.pClient = NULL;
    850854    /* Set the termination flag. */
    851855    XtAppSetExitFlag(g_ctx.appContext);
     
    856860    XSendEvent(XtDisplay(g_ctx.widget), XtWindow(g_ctx.widget), false, 0, &ev);
    857861    XFlush(XtDisplay(g_ctx.widget));
     862    if (g_ctx.eOwner == GUEST)
     863        /* X11 may be waiting for data from VBox.  At this point it is no
     864         * longer going to arrive, and we must release it to allow the event
     865         * loop to terminate.  In this case the buffer where VBox would have
     866         * written the clipboard data will still be empty and we will just
     867         * return "no data" to X11.  Any subsequent attempts to get the data
     868         * from VBox will fail immediately as the client reference is gone. */
     869        RTSemEventSignal(g_ctx.waitForData);
    858870    do
    859871    {
     
    863875    } while ((VERR_TIMEOUT == rc) && (count < 300));
    864876    if (RT_SUCCESS(rc))
     877    {
     878        /*
     879         * No one should be waiting on this by now.  Justification:
     880         *  - Case 1: VBox is waiting for data from X11:
     881         *      Not possible, as it would be waiting on this thread.
     882         *  - Case 2: X11 is waiting for data from VBox:
     883         *      Not possible, as we checked that the X11 event thread exited
     884         *      successfully.
     885         */
     886        RTSemEventDestroy(g_ctx.waitForData);
     887        RTSemMutexDestroy(g_ctx.asyncMutex);
    865888        AssertRC(rcThread);
     889    }
    866890    else
    867891        LogRel(("vboxClipboardDestroy: rc=%Rrc\n", rc));
     
    889913
    890914    /* Only one client is supported for now */
    891     if (g_ctx.pClient != 0)
    892     {
    893         LogRel(("vboxClipboardConnect: attempted to connect, but a client appears to be already running.\n"));
    894         AssertReturn(g_ctx.pClient == 0, VERR_NOT_SUPPORTED);
    895     }
     915    AssertLogRelReturn(g_ctx.pClient == 0, VERR_NOT_SUPPORTED);
    896916
    897917    pClient->pCtx = &g_ctx;
     
    10451065        /* If vboxClipboardReadDataFromVBox fails then pClient may be invalid */
    10461066        LogRelFunc (("vboxClipboardReadDataFromVBox returned %Rrc%s\n", rc,
    1047                      RT_SUCCESS(rc) ? ", g_ctx.pClient->data.cb == 0" :  ""));
     1067                    RT_SUCCESS(rc) ? ", g_ctx.pClient->data.cb == 0" :  ""));
    10481068        vboxClipboardEmptyGuestBuffer();
    10491069        return false;
     
    11201140        /* If vboxClipboardReadDataFromVBox fails then pClient may be invalid */
    11211141        LogRelFunc (("vboxClipboardReadDataFromVBox returned %Rrc%s\n", rc,
    1122                       RT_SUCCESS(rc) ? ", g_ctx.pClient->data.cb == 0" :  ""));
     1142                     RT_SUCCESS(rc) ? ", g_ctx.pClient->data.cb == 0" :  ""));
    11231143        vboxClipboardEmptyGuestBuffer();
    11241144        return false;
     
    13191339
    13201340    LogFlowFunc(("\n"));
     1341    /* Drop requests that we receive too late. */
     1342    if (g_ctx.eOwner != GUEST)
     1343        return false;
    13211344    if (   (*atomSelection != g_ctx.atomClipboard)
    13221345        && (*atomSelection != g_ctx.atomPrimary)
     
    14751498            return VERR_NO_DATA;  /* The guest thinks we have data and we don't */
    14761499        }
    1477         /* Only one of the host and the guest should ever be waiting. */
    1478         if (!ASMAtomicCmpXchgU32(&g_ctx.waiter, 1, 0))
    1479         {
    1480             LogRel(("vboxClipboardReadData: detected a deadlock situation - the host and the guest are waiting for each other.\n"));
    1481             return VERR_DEADLOCK;
    1482         }
     1500        /* No one else (VBox or X11) should currently be waiting.  The first because
     1501         * requests from VBox are serialised and the second because X11 previously
     1502         * grabbed the clipboard, so it should not be waiting for data from us. */
     1503        AssertLogRelReturn (ASMAtomicCmpXchgU32(&g_ctx.waiter, 1, 0), VERR_DEADLOCK);
    14831504        g_ctx.requestHostFormat = g_ctx.hostTextFormat;
    14841505        g_ctx.requestBuffer = pv;
     
    14921513                            vboxClipboardGetDataFromX11, reinterpret_cast<XtPointer>(g_ctx.pClient),
    14931514                            CurrentTime);
    1494         /* When the data arrives, the vboxClipboardGetProc callback will be called.  The
     1515        /* When the data arrives, the vboxClipboardGetDataFromX11 callback will be called.  The
    14951516           callback will signal the event semaphore when it has processed the data for us. */
    14961517
    1497 #ifdef RT_OS_SOLARIS
    1498         /*
    1499          * Trusted Xorg requires a bigger timeout.
    1500          */
    1501         unsigned long cTimeoutMillies = CLIPBOARDTIMEOUT;
    1502         if (is_system_labeled())
    1503             cTimeoutMillies = 1000 * 120;
    1504 
    1505         if (RTSemEventWait(g_ctx.waitForData, cTimeoutMillies) != VINF_SUCCESS)
    1506 #else
    1507         if (RTSemEventWait(g_ctx.waitForData, CLIPBOARDTIMEOUT) != VINF_SUCCESS)
    1508 #endif
     1518        int rc = RTSemEventWait(g_ctx.waitForData, RT_INDEFINITE_WAIT);
     1519        if (RT_FAILURE(rc))
    15091520        {
    1510             /* No need to polute the release log for this. */
    1511             // LogRel(("vboxClipboardReadDataFromClient: XtGetSelectionValue failed to complete within %d milliseconds\n", CLIPBOARDTIMEOUT));
    1512             /* A time out can legitimately occur if a client is temporarily too busy to answer fast */
    1513             // g_ctx.hostTextFormat = INVALID;
    1514             // g_ctx.hostBitmapFormat = INVALID;
    15151521            g_ctx.waiter = 0;
    1516             return VERR_TIMEOUT;
     1522            return rc;
    15171523        }
    15181524        g_ctx.waiter = 0;
     
    15421548    LogFlowFunc (("called\n"));
    15431549
    1544     /*
    1545      * The guest returns data that was requested in the WM_RENDERFORMAT handler.
    1546      */
    1547     if (!(   pClient->data.pv == NULL
    1548           && pClient->data.cb == 0
    1549           && pClient->data.u32Format == 0))
    1550     {
    1551         LogRel(("vboxClipboardWriteData: clipboard data has arrived from the guest, but another transfer is in process or has not cleaned up properly.\n"));
    1552         AssertMsgFailed(("vboxClipboardWriteData: clipboard data has arrived from the guest, but another transfer is in process or has not cleaned up properly.\n"));
    1553     }
     1550    /* Assert that no other transfer is in process (requests are serialised)
     1551     * or has not cleaned up properly. */
     1552    AssertLogRelReturnVoid (   pClient->data.pv == NULL
     1553                            && pClient->data.cb == 0
     1554                            && pClient->data.u32Format == 0);
    15541555
    15551556    if (cb > 0)
     
    15671568    RTSemEventSignal(g_ctx.waitForData);
    15681569}
     1570
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