VirtualBox

Changeset 47122 in vbox for trunk/src/VBox


Ignore:
Timestamp:
Jul 12, 2013 2:34:26 PM (12 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
87216
Message:

IPRT/localipc-win.cpp: Update (waiting on data now is properly getting interrupted on server destruction), more testcases (work in progress).

Location:
trunk/src/VBox/Runtime
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/r3/win/localipc-win.cpp

    r47083 r47122  
    5252#include <iprt/string.h>
    5353#include <iprt/thread.h>
     54#include <iprt/time.h>
    5455
    5556#include "internal/magics.h"
     
    148149    /** Set if there is already pending I/O. */
    149150    bool                fIOPending;
     151    /** Set if the zero byte read that the poll code using is pending. */
     152    bool                fZeroByteRead;
    150153    /** Indicates that there is a pending cancel request. */
    151154    bool volatile       fCancelled;
     
    162165    /** Amount of allocated buffer space. */
    163166    size_t              cbBounceBufAlloc;
     167    /** Buffer for the zero byte read.
     168     *  Used in RTLocalIpcSessionWaitForData(). */
     169    uint8_t             abBuf[8];
    164170} RTLOCALIPCSESSIONINT;
    165171/** Pointer to a local IPC session instance (Windows). */
     
    414420    ASMAtomicUoWriteU32(&pThis->u32Magic, ~RTLOCALIPCSERVER_MAGIC);
    415421    ASMAtomicUoWriteBool(&pThis->fCancelled, true);
     422    Assert(pThis->cRefs);
    416423    pThis->cRefs--;
    417424
    418     if (pThis->cRefs > 0)
     425    if (pThis->cRefs)
    419426    {
    420427        BOOL fRc = SetEvent(pThis->hEvent);
     
    462469        SetLastError(NO_ERROR);
    463470        BOOL fRc = ConnectNamedPipe(pThis->hNmPipe, &pThis->OverlappedIO);
    464         DWORD err = fRc ? NO_ERROR : GetLastError();
     471        DWORD dwErr = fRc ? NO_ERROR : GetLastError();
    465472        if (    !fRc
    466             &&  err == ERROR_IO_PENDING)
     473            &&  dwErr == ERROR_IO_PENDING)
    467474        {
    468475            WaitForSingleObject(pThis->hEvent, INFINITE);
    469476            DWORD dwIgnored;
    470477            fRc = GetOverlappedResult(pThis->hNmPipe, &pThis->OverlappedIO, &dwIgnored, FALSE /* bWait*/);
    471             err = fRc ? NO_ERROR : GetLastError();
     478            dwErr = fRc ? NO_ERROR : GetLastError();
    472479        }
    473480
     
    484491             */
    485492            if (   fRc
    486                 || err == ERROR_PIPE_CONNECTED)
     493                || dwErr == ERROR_PIPE_CONNECTED)
    487494            {
    488495                HANDLE hNmPipe;
     
    505512            }
    506513            else
    507                 rc = RTErrConvertFromWin32(err);
     514                rc = RTErrConvertFromWin32(dwErr);
    508515        }
    509516        else
     
    516523             */
    517524            if (    fRc
    518                 ||  err == ERROR_PIPE_CONNECTED)
     525                ||  dwErr == ERROR_PIPE_CONNECTED)
    519526                fRc = DisconnectNamedPipe(pThis->hNmPipe);
    520             else if (err == ERROR_IO_PENDING)
     527            else if (dwErr == ERROR_IO_PENDING)
    521528                fRc = CancelIo(pThis->hNmPipe);
    522529            else
     
    550557     * and signal the event (to wake up anyone in/at WaitForSingleObject).
    551558     */
    552     RTCritSectEnter(&pThis->CritSect);
    553 
    554     ASMAtomicUoWriteBool(&pThis->fCancelled, true);
    555     BOOL fRc = SetEvent(pThis->hEvent);
    556     AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc);
    557 
    558     RTCritSectLeave(&pThis->CritSect);
    559 
    560     return VINF_SUCCESS;
     559    int rc = RTCritSectEnter(&pThis->CritSect);
     560    if (RT_SUCCESS(rc))
     561    {
     562        ASMAtomicUoWriteBool(&pThis->fCancelled, true);
     563        BOOL fRc = SetEvent(pThis->hEvent);
     564        AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc);
     565
     566        rc = RTCritSectLeave(&pThis->CritSect);
     567    }
     568
     569    return rc;
    561570}
    562571
     
    632641    pThis->cRefs = 1; /* The one we return. */
    633642    pThis->fIOPending = false;
     643    pThis->fZeroByteRead = false;
    634644    pThis->fCancelled = false;
    635645    pThis->pbBounceBuf = NULL;
     
    767777    {
    768778        /* No concurrent readers, sorry. */
    769         if (pThis->cRefs == 0)
     779        if (pThis->cRefs == 1)
    770780        {
    771781            pThis->cRefs++;
     
    915925    {
    916926        /* No concurrent writers, sorry. */
    917         if (pThis->cRefs == 0)
     927        if (pThis->cRefs == 1)
    918928        {
    919929            pThis->cRefs++;
     
    10061016    AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, VERR_INVALID_HANDLE);
    10071017
     1018    uint64_t const StartMsTS = RTTimeMilliTS();
     1019
    10081020    int rc = RTCritSectEnter(&pThis->CritSect);
     1021    if (RT_FAILURE(rc))
     1022        return rc;
     1023    for (unsigned iLoop = 0;; iLoop++)
     1024    {
     1025        HANDLE hWait = INVALID_HANDLE_VALUE;
     1026
     1027        if (pThis->fIOPending)
     1028            hWait = pThis->OverlappedIO.hEvent;
     1029        else
     1030        {
     1031            /* Peek at the pipe buffer and see how many bytes it contains. */
     1032            DWORD cbAvailable;
     1033            BOOL fRc = PeekNamedPipe(pThis->hNmPipe, NULL, 0, NULL, &cbAvailable, NULL);
     1034            if (   fRc
     1035                && cbAvailable)
     1036            {
     1037                rc = VINF_SUCCESS;
     1038                break;
     1039            }
     1040            else if (!fRc)
     1041            {
     1042                rc = RTErrConvertFromWin32(GetLastError());
     1043                break;
     1044            }
     1045
     1046            /* Start a zero byte read operation that we can wait on. */
     1047            if (cMillies == 0)
     1048            {
     1049                rc = VERR_TIMEOUT;
     1050                break;
     1051            }
     1052            AssertBreakStmt(pThis->cRefs == 1, rc = VERR_WRONG_ORDER);
     1053            fRc = ResetEvent(pThis->OverlappedIO.hEvent); Assert(fRc == TRUE);
     1054            DWORD cbRead = 0;
     1055            if (ReadFile(pThis->hNmPipe, pThis->abBuf, 0, &cbRead, &pThis->OverlappedIO))
     1056            {
     1057                rc = VINF_SUCCESS;
     1058                if (iLoop > 10)
     1059                    RTThreadYield();
     1060            }
     1061            else if (GetLastError() == ERROR_IO_PENDING)
     1062            {
     1063                pThis->cRefs++;
     1064                pThis->fIOPending = true;
     1065                pThis->fZeroByteRead = true;
     1066                hWait = pThis->OverlappedIO.hEvent;
     1067            }
     1068            else
     1069                rc = RTErrConvertFromWin32(GetLastError());
     1070        }
     1071
     1072        if (RT_FAILURE(rc))
     1073            break;
     1074
     1075        /*
     1076         * Check for timeout.
     1077         */
     1078        DWORD cMsMaxWait = INFINITE;
     1079        if (   cMillies != RT_INDEFINITE_WAIT
     1080            && (   hWait != INVALID_HANDLE_VALUE
     1081                || iLoop > 10)
     1082           )
     1083        {
     1084            uint64_t cElapsed = RTTimeMilliTS() - StartMsTS;
     1085            if (cElapsed >= cMillies)
     1086            {
     1087                rc = VERR_TIMEOUT;
     1088                break;
     1089            }
     1090            cMsMaxWait = cMillies - (uint32_t)cElapsed;
     1091        }
     1092
     1093        /*
     1094         * Wait.
     1095         */
     1096        if (hWait != INVALID_HANDLE_VALUE)
     1097        {
     1098            RTCritSectLeave(&pThis->CritSect);
     1099
     1100            DWORD dwRc = WaitForSingleObject(hWait, cMsMaxWait);
     1101            if (dwRc == WAIT_OBJECT_0)
     1102                rc = VINF_SUCCESS;
     1103            else if (dwRc == WAIT_TIMEOUT)
     1104                rc = VERR_TIMEOUT;
     1105            else if (dwRc == WAIT_ABANDONED)
     1106                rc = VERR_INVALID_HANDLE;
     1107            else
     1108                rc = RTErrConvertFromWin32(GetLastError());
     1109
     1110            if (   RT_FAILURE(rc)
     1111                && pThis->u32Magic != RTLOCALIPCSESSION_MAGIC)
     1112                return rc;
     1113
     1114            int rc2 = RTCritSectEnter(&pThis->CritSect);
     1115            AssertRC(rc2);
     1116            if (pThis->fZeroByteRead)
     1117            {
     1118                Assert(pThis->cRefs);
     1119                pThis->cRefs--;
     1120                pThis->fIOPending = false;
     1121
     1122                if (rc != VINF_SUCCESS)
     1123                {
     1124                    BOOL fRc = CancelIo(pThis->hNmPipe);
     1125                    Assert(fRc == TRUE);
     1126                }
     1127
     1128                DWORD cbRead = 0;
     1129                BOOL fRc = GetOverlappedResult(pThis->hNmPipe, &pThis->OverlappedIO, &cbRead, TRUE /*fWait*/);
     1130                if (   !fRc
     1131                    && RT_SUCCESS(rc))
     1132                {
     1133                    DWORD dwRc = GetLastError();
     1134                    if (dwRc == ERROR_OPERATION_ABORTED)
     1135                        rc = VERR_CANCELLED;
     1136                    else
     1137                        rc = RTErrConvertFromWin32(dwRc);
     1138                }
     1139            }
     1140
     1141            if (RT_FAILURE(rc))
     1142                break;
     1143        }
     1144    }
     1145
     1146    int rc2 = RTCritSectLeave(&pThis->CritSect);
    10091147    if (RT_SUCCESS(rc))
    1010     {
    1011         /* No concurrent waiters, sorry. */
    1012         if (pThis->cRefs == 0)
    1013         {
    1014             pThis->cRefs++;
    1015             pThis->fCancelled = false; /* Reset canellation status. */
    1016             RTCritSectLeave(&pThis->CritSect);
    1017 
    1018             DWORD dwTimeout = cMillies == RT_INDEFINITE_WAIT
    1019                             ? INFINITE : cMillies;
    1020             DWORD dwRc = WaitForSingleObject(pThis->OverlappedIO.hEvent, dwTimeout);
    1021 
    1022             RTCritSectEnter(&pThis->CritSect);
    1023             if (dwRc == WAIT_TIMEOUT)
    1024             {
    1025                 rc = VERR_TIMEOUT;
    1026             }
    1027             else if (dwRc == WAIT_ABANDONED)
    1028             {
    1029                 rc = VERR_BROKEN_PIPE;
    1030             }
    1031             else if (dwRc == WAIT_FAILED)
    1032                 rc = RTErrConvertFromWin32(GetLastError());
    1033             else if (pThis->fCancelled)
    1034                 rc = VERR_CANCELLED;
    1035 
    1036             pThis->cRefs--;
    1037         }
    1038         else
    1039             rc = VERR_WRONG_ORDER;
    1040         RTCritSectLeave(&pThis->CritSect);
    1041     }
     1148        rc = rc2;
    10421149
    10431150    return rc;
  • trunk/src/VBox/Runtime/testcase/tstRTLocalIpc.cpp

    r47084 r47122  
    7171static int testServerListenAndCancel(RTTEST hTest, const char *pszExecPath)
    7272{
    73     RTTestISub("testServerListenAndCancel");
     73    RTTestSub(hTest, "testServerListenAndCancel");
    7474
    7575    RTLOCALIPCSERVER ipcServer;
     
    118118        RTLOCALIPCSESSION ipcSession;
    119119        rc = RTLocalIpcServerListen(pCtx->hServer, &ipcSession);
    120 #ifdef DEBUG_andy
    121         RTTestPrintf(pCtx->hTest, RTTESTLVL_INFO, "testSessionConnectionThread: Listening returned with rc=%Rrc\n", rc);
    122 #endif
     120        RTTestPrintf(pCtx->hTest, RTTESTLVL_DEBUG, "testSessionConnectionThread: Listening returned with rc=%Rrc\n", rc);
    123121        if (RT_SUCCESS(rc))
    124122        {
     
    151149static int testSessionConnection(RTTEST hTest, const char *pszExecPath)
    152150{
    153     RTTestISub("testSessionConnection");
     151    RTTestSub(hTest, "testSessionConnection");
    154152
    155153    RTLOCALIPCSERVER ipcServer;
     
    158156    if (RT_SUCCESS(rc))
    159157    {
    160 #if 0
     158#ifndef VBOX_TESTCASES_WITH_NO_THREADING
    161159        LOCALIPCTHREADCTX threadCtx = { ipcServer, hTest };
    162160
     
    181179                RTTEST_CHECK_RC(hTest, RTThreadWait(hThread,
    182180                                                    30 * 1000 /* 30s timeout */, &threadRc), VINF_SUCCESS);
    183                 RTTEST_CHECK_RC_BREAK(hTest, threadRc,  VINF_SUCCESS);
     181                RTTEST_CHECK_RC_BREAK(hTest, threadRc,  VERR_CANCELLED);
    184182                RTTestPrintf(hTest, RTTESTLVL_INFO, "Server thread terminated successfully\n");
    185                 RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcServerDestroy(ipcServer),  VINF_SUCCESS);
     183                RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcServerDestroy(ipcServer), VINF_SUCCESS);
    186184                RTTEST_CHECK_BREAK(hTest, stsChild.enmReason == RTPROCEXITREASON_NORMAL);
    187185                RTTEST_CHECK_BREAK(hTest, stsChild.iStatus == 0);
     
    190188        }
    191189        else
    192             RTTestIFailed("Unable to create thread for cancelling server, rc=%Rrc\n", rc);
     190            RTTestFailed(hTest, "Unable to create thread for cancelling server, rc=%Rrc\n", rc);
    193191#else
    194192        do
     
    205203            }
    206204            else
    207                 RTTestIFailed("Error while listening, rc=%Rrc\n", rc);
     205                RTTestFailed(hTest, "Error while listening, rc=%Rrc\n", rc);
    208206
    209207        } while (0);
     
    211209    }
    212210    else
    213         RTTestIFailed("Unable to create IPC server, rc=%Rrc\n", rc);
     211        RTTestFailed(hTest, "Unable to create IPC server, rc=%Rrc\n", rc);
    214212
    215213    return VINF_SUCCESS;
    216214}
    217215
     216static DECLCALLBACK(int) testSessionWaitThread(RTTHREAD hSelf, void *pvUser)
     217{
     218    PLOCALIPCTHREADCTX pCtx = (PLOCALIPCTHREADCTX)pvUser;
     219    AssertPtr(pCtx);
     220
     221    int rc;
     222    for (;;)
     223    {
     224        RTTestPrintf(pCtx->hTest, RTTESTLVL_INFO, "testSessionWaitThread: Listening for incoming connections ...\n");
     225        RTLOCALIPCSESSION ipcSession;
     226        rc = RTLocalIpcServerListen(pCtx->hServer, &ipcSession);
     227        if (RT_SUCCESS(rc))
     228        {
     229            RTTestPrintf(pCtx->hTest, RTTESTLVL_INFO, "testSessionWaitThread: Got new client connection, waiting a bit ...\n");
     230            RTThreadSleep(2000);
     231            rc = RTLocalIpcSessionClose(ipcSession);
     232        }
     233        else
     234        {
     235            RTTestPrintf(pCtx->hTest, RTTESTLVL_INFO, "testSessionWaitThread: Listening ended with rc=%Rrc\n", rc);
     236            break;
     237        }
     238    }
     239
     240    RTTestPrintf(pCtx->hTest, RTTESTLVL_INFO, "testSessionWaitThread: Ended with rc=%Rrc\n", rc);
     241    return rc;
     242}
     243
     244static RTEXITCODE testSessionWaitChild(int argc, char **argv, RTTEST hTest)
     245{
     246    do
     247    {
     248        RTThreadSleep(2000); /* Fudge. */
     249        RTLOCALIPCSESSION clientSession;
     250        RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcSessionConnect(&clientSession, "tstRTLocalIpcSessionWait",
     251                                                              0 /* Flags */), VINF_SUCCESS);
     252        RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcSessionWaitForData(clientSession, 100       /* 100ms timeout */),
     253                                                                  VERR_TIMEOUT);
     254        /* Next, try 60s timeout. Should be returning way earlier because the server closed the
     255         * connection after the first client connected. */
     256        RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcSessionWaitForData(clientSession, 60 * 1000),
     257                                                                  VERR_BROKEN_PIPE);
     258        /* Last try, also should fail because the server should be not around anymore. */
     259        RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcSessionWaitForData(clientSession, 5 * 1000),
     260                                                                  VERR_BROKEN_PIPE);
     261        RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcSessionClose(clientSession), VINF_SUCCESS);
     262
     263    } while (0);
     264
     265    return !RTTestErrorCount(hTest) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
     266}
     267
     268static int testSessionWait(RTTEST hTest, const char *pszExecPath)
     269{
     270    RTTestSub(hTest, "testSessionWait");
     271
     272    RTLOCALIPCSERVER ipcServer;
     273    int rc = RTLocalIpcServerCreate(&ipcServer, "tstRTLocalIpcSessionWait",
     274                                    RTLOCALIPC_FLAGS_MULTI_SESSION);
     275    if (RT_SUCCESS(rc))
     276    {
     277        LOCALIPCTHREADCTX threadCtx = { ipcServer, hTest };
     278
     279        /* Spawn a simple worker thread and let it listen for incoming connections.
     280         * In the meanwhile we try to cancel the server and see what happens. */
     281        RTTHREAD hThread;
     282        rc = RTThreadCreate(&hThread, testSessionWaitThread,
     283                            &threadCtx, 0 /* Stack */, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "tstIpc3");
     284        if (RT_SUCCESS(rc))
     285        {
     286            do
     287            {
     288                RTPROCESS hProc;
     289                const char *apszArgs[4] = { pszExecPath, "child", "tstRTLocalIpcSessionWaitFork", NULL };
     290                RTTEST_CHECK_RC_BREAK(hTest, RTProcCreate(pszExecPath, apszArgs,
     291                                                          RTENV_DEFAULT, 0 /* fFlags*/, &hProc), VINF_SUCCESS);
     292                RTThreadSleep(5000); /* Let the server run for some time ... */
     293                RTTestPrintf(hTest, RTTESTLVL_INFO, "Cancelling server listening\n");
     294                RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcServerCancel(ipcServer), VINF_SUCCESS);
     295                /* Wait for the server thread to terminate. */
     296                int threadRc;
     297                RTTEST_CHECK_RC(hTest, RTThreadWait(hThread,
     298                                                    30 * 1000 /* 30s timeout */, &threadRc), VINF_SUCCESS);
     299                RTTEST_CHECK_RC_BREAK(hTest, threadRc, VERR_CANCELLED);
     300                RTTEST_CHECK_RC(hTest, RTLocalIpcServerDestroy(ipcServer), VINF_SUCCESS);
     301                RTTestPrintf(hTest, RTTESTLVL_INFO, "Server thread terminated successfully\n");
     302                /* Check if the child ran successfully. */
     303                RTPROCSTATUS stsChild;
     304                RTTEST_CHECK_RC_BREAK(hTest, RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &stsChild), VINF_SUCCESS);
     305                RTTestPrintf(hTest, RTTESTLVL_INFO, "Child terminated\n");
     306                RTTEST_CHECK_BREAK(hTest, stsChild.enmReason == RTPROCEXITREASON_NORMAL);
     307                RTTEST_CHECK_BREAK(hTest, stsChild.iStatus == 0);
     308            }
     309            while (0);
     310        }
     311        else
     312            RTTestFailed(hTest, "Unable to create thread for cancelling server, rc=%Rrc\n", rc);
     313    }
     314    else
     315        RTTestFailed(hTest, "Unable to create IPC server, rc=%Rrc\n", rc);
     316
     317    return VINF_SUCCESS;
     318}
     319
    218320static RTEXITCODE mainChild(int argc, char **argv)
    219321{
     322    if (argc < 3) /* Safety first. */
     323        return RTEXITCODE_FAILURE;
    220324    /* Note: We assume argv[2] always contains the actual test type to perform. */
    221325    RTTEST hTest;
     
    225329    RTTestBanner(hTest);
    226330
     331    RTAssertSetMayPanic(false);
     332#ifdef DEBUG_andy
     333    RTAssertSetQuiet(true);
     334#endif
     335
    227336    if (!RTStrICmp(argv[2], "tstRTLocalIpcSessionConnectionFork"))
    228337        rcExit = testSessionConnectionChild(argc, argv, hTest);
     338    else if (!RTStrICmp(argv[2], "tstRTLocalIpcSessionWaitFork"))
     339        rcExit = testSessionWaitChild(argc, argv, hTest);
    229340
    230341    return RTTestSummaryAndDestroy(hTest);
     
    283394    if (RTTestErrorCount(hTest) == 0)
    284395    {
    285 #ifndef DEBUG_andy
    286396        RTTESTI_CHECK_RC_RET(testServerListenAndCancel(hTest, szExecPath), VINF_SUCCESS, 1);
    287 #endif
    288397        RTTESTI_CHECK_RC_RET(testSessionConnection(hTest, szExecPath), VINF_SUCCESS, 1);
     398        RTTESTI_CHECK_RC_RET(testSessionWait(hTest, szExecPath), VINF_SUCCESS, 1);
    289399    }
    290400
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