VirtualBox

Ignore:
Timestamp:
Oct 26, 2020 4:19:35 PM (4 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
141096
Message:

Shared Clipboard/X11: More work on untangling the threading code (bugref:9848):

  • Renamed thread-related functions to share a common prefix to easier identify their usage.
  • Xt app / context [init|uninit]ialization is now done in the thread itself instead on behalf of another thread.
  • Untangled init/uninit code into threaded and non-threaded parts. The testcases were calling threading stuff even if they never used it.
Location:
trunk/src/VBox/GuestHost/SharedClipboard
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/GuestHost/SharedClipboard/clipboard-x11.cpp

    r86710 r86712  
    8181*********************************************************************************************************************************/
    8282#ifdef TESTCASE
    83 extern void tstClipQueueToEventThread(void (*proc)(void *, void *), void *client_data);
     83extern void tstThreadScheduleCall(void (*proc)(void *, void *), void *client_data);
    8484extern void tstClipRequestData(SHCLX11CTX* pCtx, SHCLX11FMTIDX target, void *closure);
    8585extern void tstRequestTargets(SHCLX11CTX* pCtx);
     
    9393SHCL_X11_DECL(Atom) clipGetAtom(PSHCLX11CTX pCtx, const char *pszName);
    9494SHCL_X11_DECL(void) clipQueryX11Formats(PSHCLX11CTX pCtx);
     95
     96static int          clipInitInternal(PSHCLX11CTX pCtx);
     97static void         clipUninitInternal(PSHCLX11CTX pCtx);
    9598
    9699
     
    395398 * writing to the wakeup pipe which it monitors.
    396399 */
    397 static int clipQueueToEventThread(PSHCLX11CTX pCtx,
     400static int clipThreadScheduleCall(PSHCLX11CTX pCtx,
    398401                                  void (*proc)(void *, void *),
    399402                                  void *client_data)
    400403{
    401404    LogFlowFunc(("proc=%p, client_data=%p\n", proc, client_data));
    402 
    403     int rc = VINF_SUCCESS;
    404405
    405406#ifndef TESTCASE
     
    407408                    (XtPointer)client_data);
    408409    ssize_t cbWritten = write(pCtx->wakeupPipeWrite, WAKE_UP_STRING, WAKE_UP_STRING_LEN);
     410    Assert(cbWritten == WAKE_UP_STRING_LEN);
    409411    RT_NOREF(cbWritten);
    410412#else
    411413    RT_NOREF(pCtx);
    412     tstClipQueueToEventThread(proc, client_data);
    413 #endif
    414 
    415     LogFlowFuncLeaveRC(rc);
    416     return rc;
     414    tstThreadScheduleCall(proc, client_data);
     415#endif
     416
     417    LogFlowFuncLeaveRC(VINF_SUCCESS);
     418    return VINF_SUCCESS;
    417419}
    418420
     
    843845 * @param   pvUser                  Pointer to the X11 clipboard context to use.
    844846 */
    845 static DECLCALLBACK(int) clipEventThread(RTTHREAD hThreadSelf, void *pvUser)
     847static DECLCALLBACK(int) clipThreadMain(RTTHREAD hThreadSelf, void *pvUser)
    846848{
    847849    RT_NOREF(hThreadSelf);
    848850    AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
    849851
    850     LogRel(("Shared Clipboard: Starting X11 event thread\n"));
     852    LogRel2(("Shared Clipboard: Starting X11 event thread\n"));
    851853
    852854    PSHCLX11CTX pCtx = (SHCLX11CTX *)pvUser;
     855
     856    clipInitInternal(pCtx);
    853857
    854858    if (pCtx->fGrabClipboardOnStart)
     
    865869    }
    866870
    867     LogRel(("Shared Clipboard: X11 event thread terminated successfully\n"));
     871    clipUninitInternal(pCtx);
     872
     873    LogRel2(("Shared Clipboard: X11 event thread terminated successfully\n"));
    868874    return VINF_SUCCESS;
    869 }
    870 #endif
    871 
    872 /**
    873  * X11 specific uninitialisation for the shared clipboard.
    874  *
    875  * @param   pCtx                The X11 clipboard context to use.
    876  */
    877 static void clipUninit(PSHCLX11CTX pCtx)
    878 {
    879     AssertPtrReturnVoid(pCtx);
    880     if (pCtx->pWidget)
    881     {
    882         /* Valid widget + invalid appcontext = bug.  But don't return yet. */
    883         AssertPtr(pCtx->appContext);
    884         clipUnregisterContext(pCtx);
    885         XtDestroyWidget(pCtx->pWidget);
    886     }
    887     pCtx->pWidget = NULL;
    888     if (pCtx->appContext)
    889         XtDestroyApplicationContext(pCtx->appContext);
    890     pCtx->appContext = NULL;
    891     if (pCtx->wakeupPipeRead != 0)
    892         close(pCtx->wakeupPipeRead);
    893     if (pCtx->wakeupPipeWrite != 0)
    894         close(pCtx->wakeupPipeWrite);
    895     pCtx->wakeupPipeRead = 0;
    896     pCtx->wakeupPipeWrite = 0;
    897875}
    898876
     
    903881 * @param   pvUserData          Pointer to the X11 clipboard context to use.
    904882 */
    905 static void clipStopEventThreadWorker(void *pvUserData, void *)
    906 {
    907 
     883static void clipThreadSignalStop(void *pvUserData, void *)
     884{
    908885    PSHCLX11CTX pCtx = (PSHCLX11CTX)pvUserData;
    909886
     
    917894}
    918895
    919 #ifndef TESTCASE
    920896/**
    921897 * Sets up the XFixes library and load the XFixesSelectSelectionInput symbol.
     
    980956 * @param   pvUserData          Pointer to the X11 clipboard context to use.
    981957 */
    982 static void clipDrainWakeupPipe(XtPointer pvUserData, int *, XtInputId *)
     958static void clipThreadDrainWakeupPipe(XtPointer pvUserData, int *, XtInputId *)
    983959{
    984960    LogFlowFuncEnter();
     
    991967
    992968/**
    993  * X11 specific initialisation for the shared clipboard.
     969 * X11-specific initialisation for the Shared Clipboard.
     970 *
     971 * Note: Must be called from the thread serving the Xt stuff.
    994972 *
    995973 * @returns VBox status code.
    996  * @param   pCtx                The X11 clipboard context to use.
    997  */
    998 static int clipInit(PSHCLX11CTX pCtx)
    999 {
    1000     /* Create a window and make it a clipboard viewer. */
    1001     int cArgc = 0;
    1002     char *pcArgv = 0;
    1003     int rc = VINF_SUCCESS;
    1004     Display *pDisplay;
     974 * @param   pCtx                The X11 clipboard context to init.
     975 */
     976static int clipInitInternal(PSHCLX11CTX pCtx)
     977{
     978    LogFlowFunc(("pCtx=%p\n", pCtx));
    1005979
    1006980    /* Make sure we are thread safe. */
     
    1013987     */
    1014988    XtToolkitInitialize();
     989
     990    int rc = VINF_SUCCESS;
     991
     992    Assert(pCtx->appContext == NULL); /* No nested initialization. */
    1015993    pCtx->appContext = XtCreateApplicationContext();
    1016     pDisplay = XtOpenDisplay(pCtx->appContext, 0, 0, "VBoxShCl", 0, 0, &cArgc, &pcArgv);
    1017     if (NULL == pDisplay)
     994    if (pCtx->appContext == NULL)
     995    {
     996        LogRel(("Shared Clipboard: Failed to create Xt application context\n"));
     997        return VERR_NOT_SUPPORTED; /** @todo Fudge! */
     998    }
     999
     1000    /* Create a window and make it a clipboard viewer. */
     1001    int      cArgc  = 0;
     1002    char    *pcArgv = 0;
     1003    Display *pDisplay = XtOpenDisplay(pCtx->appContext, 0, 0, "VBoxShCl", 0, 0, &cArgc, &pcArgv);
     1004    if (pDisplay == NULL)
    10181005    {
    10191006        LogRel(("Shared Clipboard: Failed to connect to the X11 clipboard - the window system may not be running\n"));
    10201007        rc = VERR_NOT_SUPPORTED;
    10211008    }
     1009
    10221010#ifndef TESTCASE
    10231011    if (RT_SUCCESS(rc))
     
    10351023                                           pDisplay, XtNwidth, 1, XtNheight,
    10361024                                           1, NULL);
    1037         if (NULL == pCtx->pWidget)
    1038         {
    1039             LogRel(("Shared Clipboard: Failed to construct the X11 window for the shared clipboard manager\n"));
    1040             rc = VERR_NO_MEMORY;
     1025        if (pCtx->pWidget == NULL)
     1026        {
     1027            LogRel(("Shared Clipboard: Failed to construct the X11 window\n"));
     1028            rc = VERR_NO_MEMORY; /** @todo r=andy Improve this. */
    10411029        }
    10421030        else
     
    10481036        XtSetMappedWhenManaged(pCtx->pWidget, false);
    10491037        XtRealizeWidget(pCtx->pWidget);
     1038
    10501039#ifndef TESTCASE
    10511040        /* Enable clipboard update notification. */
     
    10561045    }
    10571046
    1058     /*
    1059      * Create the pipes.
    1060      */
    1061     int pipes[2];
    1062     if (!pipe(pipes))
    1063     {
    1064         pCtx->wakeupPipeRead = pipes[0];
    1065         pCtx->wakeupPipeWrite = pipes[1];
    1066         if (!XtAppAddInput(pCtx->appContext, pCtx->wakeupPipeRead,
    1067                            (XtPointer) XtInputReadMask,
    1068                            clipDrainWakeupPipe, (XtPointer) pCtx))
    1069             rc = VERR_NO_MEMORY;  /* What failure means is not doc'ed. */
    1070         if (   RT_SUCCESS(rc)
    1071             && (fcntl(pCtx->wakeupPipeRead, F_SETFL, O_NONBLOCK) != 0))
    1072             rc = RTErrConvertFromErrno(errno);
    1073         if (RT_FAILURE(rc))
    1074             LogRel(("Shared Clipboard: Failed to setup the termination mechanism\n"));
    1075     }
    1076     else
    1077         rc = RTErrConvertFromErrno(errno);
    10781047    if (RT_FAILURE(rc))
    1079         clipUninit(pCtx);
    1080     if (RT_FAILURE(rc))
     1048    {
    10811049        LogRel(("Shared Clipboard: Initialisation failed: %Rrc\n", rc));
     1050        clipUninitInternal(pCtx);
     1051    }
     1052
     1053    LogFlowFuncLeaveRC(rc);
    10821054    return rc;
    10831055}
    10841056
    10851057/**
    1086  * Initializes the X11 context of the Shared Clipboard.
     1058 * X11-specific uninitialisation for the Shared Clipboard.
     1059 *
     1060 * Note: Must be called from the thread serving the Xt stuff.
     1061 *
     1062 * @param   pCtx                The X11 clipboard context to uninit.
     1063 */
     1064static void clipUninitInternal(PSHCLX11CTX pCtx)
     1065{
     1066    AssertPtrReturnVoid(pCtx);
     1067
     1068    LogFlowFunc(("pCtx=%p\n", pCtx));
     1069
     1070    if (pCtx->pWidget)
     1071    {
     1072        /* Valid widget + invalid appcontext = bug.  But don't return yet. */
     1073        AssertPtr(pCtx->appContext);
     1074        clipUnregisterContext(pCtx);
     1075
     1076        XtDestroyWidget(pCtx->pWidget);
     1077        pCtx->pWidget = NULL;
     1078    }
     1079
     1080    if (pCtx->appContext)
     1081    {
     1082        XtDestroyApplicationContext(pCtx->appContext);
     1083        pCtx->appContext = NULL;
     1084    }
     1085
     1086    LogFlowFuncLeaveRC(VINF_SUCCESS);
     1087}
     1088
     1089/**
     1090 * Initializes a X11 context of the Shared Clipboard.
    10871091 *
    10881092 * @returns VBox status code.
     
    10981102    AssertPtrReturn(pParent, VERR_INVALID_POINTER);
    10991103#endif
     1104
     1105    LogFlowFunc(("pCtx=%p\n", pCtx));
     1106
     1107    int rc = VINF_SUCCESS;
    11001108
    11011109    RT_BZERO(pCtx, sizeof(SHCLX11CTX));
     
    11201128#endif
    11211129
    1122     LogFlowFuncLeaveRC(VINF_SUCCESS);
    1123     return VINF_SUCCESS;
    1124 }
    1125 
    1126 /**
    1127  * Destructs the Shared Clipboard X11 context.
     1130#ifdef TESTCASE
     1131    if (RT_SUCCESS(rc))
     1132    {
     1133        /** @todo The testcases currently do not utilize the threading code. So init stuff here. */
     1134        rc = clipInitInternal(pCtx);
     1135    }
     1136#endif
     1137
     1138    LogFlowFuncLeaveRC(rc);
     1139    return rc;
     1140}
     1141
     1142/**
     1143 * Destroys a Shared Clipboard X11 context.
    11281144 *
    11291145 * @param   pCtx                The X11 clipboard context to destroy.
     
    11331149    if (!pCtx)
    11341150        return;
     1151
     1152    LogFlowFunc(("pCtx=%p\n", pCtx));
     1153
     1154#ifdef TESTCASE
     1155    /** @todo The testcases currently do not utilize the threading code. So uninit stuff here. */
     1156    clipUninitInternal(pCtx);
     1157#endif
    11351158
    11361159    if (pCtx->fHaveX11)
     
    11431166}
    11441167
    1145 /**
    1146  * Announces to the X11 backend that we are ready to start.
     1168#ifndef TESTCASE
     1169/**
     1170 * Starts our own Xt even thread for handling Shared Clipboard messages.
    11471171 *
    11481172 * @returns VBox status code.
     
    11601184        return VINF_SUCCESS;
    11611185
    1162     int rc = clipInit(pCtx);
     1186    pCtx->fGrabClipboardOnStart = fGrab;
     1187
     1188    clipResetX11Formats(pCtx);
     1189
     1190    int rc;
     1191
     1192    /*
     1193     * Create the pipes.
     1194     ** @todo r=andy Replace this with RTPipe API.
     1195     */
     1196    int pipes[2];
     1197    if (!pipe(pipes))
     1198    {
     1199        pCtx->wakeupPipeRead = pipes[0];
     1200        pCtx->wakeupPipeWrite = pipes[1];
     1201        if (!XtAppAddInput(pCtx->appContext, pCtx->wakeupPipeRead,
     1202                           (XtPointer) XtInputReadMask,
     1203                           clipThreadDrainWakeupPipe, (XtPointer) pCtx))
     1204            rc = VERR_NO_MEMORY;  /* What failure means is not doc'ed. */
     1205        if (   RT_SUCCESS(rc)
     1206            && (fcntl(pCtx->wakeupPipeRead, F_SETFL, O_NONBLOCK) != 0))
     1207            rc = RTErrConvertFromErrno(errno);
     1208        if (RT_FAILURE(rc))
     1209            LogRel(("Shared Clipboard: Failed to setup the termination mechanism\n"));
     1210    }
     1211    else
     1212        rc = RTErrConvertFromErrno(errno);
     1213
    11631214    if (RT_SUCCESS(rc))
    11641215    {
    1165         clipResetX11Formats(pCtx);
    1166         pCtx->fGrabClipboardOnStart = fGrab;
    1167 
    1168 #ifndef TESTCASE
    11691216        LogRel2(("Shared Clipboard: Starting X11 event thread ...\n"));
    11701217
    1171         rc = RTThreadCreate(&pCtx->Thread, clipEventThread, pCtx, 0,
     1218        rc = RTThreadCreate(&pCtx->Thread, clipThreadMain, pCtx, 0,
    11721219                            RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "SHCLX11");
    11731220        if (RT_SUCCESS(rc))
     
    11771224        {
    11781225            LogRel(("Shared Clipboard: Failed to start the X11 event thread with %Rrc\n", rc));
    1179             clipUninit(pCtx);
     1226            clipUninitInternal(pCtx);
    11801227        }
    11811228        else
    11821229            LogRel2(("Shared Clipboard: X11 event thread started\n"));
    1183 #endif
    1184     }
    1185 
     1230    }
     1231
     1232    LogFlowFuncLeaveRC(rc);
    11861233    return rc;
    11871234}
    11881235
    11891236/**
    1190  * Shuts down the shared clipboard X11 backend.
     1237 * Stops the Shared Clipboard Xt even thread.
    11911238 *
    11921239 * @note  Any requests from this object to get clipboard data from VBox
     
    12061253        return VINF_SUCCESS;
    12071254
    1208     LogRel2(("Shared Clipboard: Stopping X11 event thread ...\n"));
     1255    LogRel2(("Shared Clipboard: Signalling the X11 event thread to stop\n"));
    12091256
    12101257    /* Write to the "stop" pipe. */
    1211     clipQueueToEventThread(pCtx, clipStopEventThreadWorker, (XtPointer)pCtx);
    1212 
    1213     int rc;
    1214 
    1215 #ifndef TESTCASE
     1258    clipThreadScheduleCall(pCtx, clipThreadSignalStop, (XtPointer)pCtx);
     1259
    12161260    LogRel2(("Shared Clipboard: Waiting for X11 event thread to stop ...\n"));
    12171261
    12181262    int rcThread;
    1219     rc = RTThreadWait(pCtx->Thread, RT_MS_30SEC /* msTimeout */, &rcThread);
     1263    int rc = RTThreadWait(pCtx->Thread, RT_MS_30SEC /* msTimeout */, &rcThread);
    12201264    if (RT_SUCCESS(rc))
    12211265        rc = rcThread;
    1222 
    1223     if (RT_FAILURE(rc))
     1266    if (RT_SUCCESS(rc))
     1267    {
     1268        if (pCtx->wakeupPipeRead != 0)
     1269        {
     1270            close(pCtx->wakeupPipeRead);
     1271            pCtx->wakeupPipeRead = 0;
     1272        }
     1273
     1274        if (pCtx->wakeupPipeWrite != 0)
     1275        {
     1276            close(pCtx->wakeupPipeWrite);
     1277            pCtx->wakeupPipeWrite = 0;
     1278        }
     1279    }
     1280
     1281    if (RT_SUCCESS(rc))
     1282    {
     1283        LogRel2(("Shared Clipboard: X11 event thread stopped successfully\n"));
     1284    }
     1285    else
    12241286        LogRel(("Shared Clipboard: Stopping X11 event thread failed with %Rrc\n", rc));
    1225 #else
    1226     rc = VINF_SUCCESS;
    1227 #endif
    1228 
    1229     LogRel2(("Shared Clipboard: X11 event thread stopped\n"));
    1230 
    1231     clipUninit(pCtx);
     1287
     1288    LogFlowFuncLeaveRC(rc);
    12321289    return rc;
    12331290}
     1291#endif /* !TESTCASE */
    12341292
    12351293/**
     
    17541812        pFormats->Formats = uFormats;
    17551813
    1756         rc = clipQueueToEventThread(pCtx, ShClX11ReportFormatsToX11Worker,
     1814        rc = clipThreadScheduleCall(pCtx, ShClX11ReportFormatsToX11Worker,
    17571815                                    (XtPointer)pFormats);
    17581816    }
     
    21502208
    21512209        /* We use this to schedule a worker function on the event thread. */
    2152         rc = clipQueueToEventThread(pCtx, ShClX11ReadDataFromX11Worker, (XtPointer)pX11Req);
     2210        rc = clipThreadScheduleCall(pCtx, ShClX11ReadDataFromX11Worker, (XtPointer)pX11Req);
    21532211    }
    21542212    else
  • trunk/src/VBox/GuestHost/SharedClipboard/testcase/tstClipboardGH-X11.cpp

    r86702 r86712  
    5656void tstRequestTargets(SHCLX11CTX* pCtx);
    5757void tstClipRequestData(PSHCLX11CTX pCtx, SHCLX11FMTIDX target, void *closure);
    58 void tstClipQueueToEventThread(void (*proc)(void *, void *), void *client_data);
     58void tstThreadScheduleCall(void (*proc)(void *, void *), void *client_data);
    5959
    6060
     
    7676/* For the purpose of the test case, we just execute the procedure to be
    7777 * scheduled, as we are running single threaded. */
    78 void tstClipQueueToEventThread(void (*proc)(void *, void *), void *client_data)
     78void tstThreadScheduleCall(void (*proc)(void *, void *), void *client_data)
    7979{
    8080    proc(client_data, NULL);
     
    670670     */
    671671    SHCLX11CTX X11Ctx;
    672     rc = ShClX11Init(&X11Ctx, NULL, false);
     672    rc = ShClX11Init(&X11Ctx, NULL /* pParent */, false /* fHeadless */);
    673673    AssertRCReturn(rc, RTEXITCODE_FAILURE);
     674
    674675    char *pc;
    675676    uint32_t cbActual;
    676677    CLIPREADCBREQ *pReq = (CLIPREADCBREQ *)&pReq, *pReqRet = NULL;
    677     rc = ShClX11ThreadStart(&X11Ctx, false /* fGrab */);
    678     AssertRCReturn(rc, RTEXITCODE_FAILURE);
    679678
    680679    /* UTF-8 from X11 */
     
    889888    tstBadFormatRequestFromHost(hTest, &X11Ctx);
    890889
    891     rc = ShClX11ThreadStop(&X11Ctx);
    892     AssertRCReturn(rc, RTEXITCODE_FAILURE);
    893890    ShClX11Destroy(&X11Ctx);
    894891
     
    896893     * Headless clipboard tests
    897894     */
    898     rc = ShClX11Init(&X11Ctx, NULL, true);
    899     AssertRCReturn(rc, RTEXITCODE_FAILURE);
    900     rc = ShClX11ThreadStart(&X11Ctx, false /* fGrab */);
     895    rc = ShClX11Init(&X11Ctx, NULL /* pParent */, true /* fHeadless */);
    901896    AssertRCReturn(rc, RTEXITCODE_FAILURE);
    902897
     
    919914    tstNoSelectionOwnership(&X11Ctx, "reading from VBox, headless clipboard");
    920915
    921     rc = ShClX11ThreadStop(&X11Ctx);
    922     AssertRCReturn(rc, RTEXITCODE_FAILURE);
    923 
    924916    ShClX11Destroy(&X11Ctx);
     917    /* Note: Doing this twice is intentional. */
     918    ShClX11Destroy(&X11Ctx);
    925919
    926920    return RTTestSummaryAndDestroy(hTest);
Note: See TracChangeset for help on using the changeset viewer.

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