VirtualBox

Changeset 58289 in vbox for trunk/src


Ignore:
Timestamp:
Oct 17, 2015 7:40:40 PM (9 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
103484
Message:

tstRTLocalIpc: Added client thread test variants (all clients were child processes) and a simple roundtrip performance measurements. Some code cleanups.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/testcase/tstRTLocalIpc.cpp

    r58282 r58289  
    11/* $Id$ */
    22/** @file
    3  * IPRT Testcase - RTLocalIpc.
     3 * IPRT Testcase - RTLocalIpc API.
    44 */
    55
     
    2929*   Header Files                                                                                                                 *
    3030*********************************************************************************************************************************/
     31#include <iprt/localipc.h>
     32
     33#include <iprt/asm.h>
    3134#include <iprt/env.h>
    32 #include <iprt/localipc.h>
     35#include <iprt/initterm.h>
    3336#include <iprt/mem.h>
     37#include <iprt/message.h>
    3438#include <iprt/path.h>
    3539#include <iprt/process.h>
     
    4145
    4246
    43 typedef struct LOCALIPCTHREADCTX
    44 {
    45     /** The IPC server handle. */
    46     RTLOCALIPCSERVER hServer;
    47     /** The test handle. */
    48     RTTEST hTest;
    49 } LOCALIPCTHREADCTX, *PLOCALIPCTHREADCTX;
    50 
    51 static int testServerListenAndCancel2(const char *pszExecPath)
    52 {
    53     const char *apszArgs[4] = { pszExecPath, "child", "testServerListenAndCancel", NULL };
    54     RTPROCESS hProc;
    55     int rc = RTProcCreate(pszExecPath, apszArgs, RTENV_DEFAULT, 0 /* fFlags*/, &hProc);
    56 
    57     return rc;
    58 }
    59 
    60 static DECLCALLBACK(int) testServerListenAndCancelThread(RTTHREAD hSelf, void *pvUser)
    61 {
    62     PRTLOCALIPCSERVER phServer = (PRTLOCALIPCSERVER)pvUser;
    63     AssertPtr(phServer);
    64 
    65     RTThreadSleep(5000); /* Wait a bit to simulate waiting in main thread. */
    66 
    67     int rc = RTLocalIpcServerCancel(*phServer);
    68     AssertRC(rc);
    69 
    70     return 0;
    71 }
    72 
    73 static int testServerListenAndCancel(RTTEST hTest, const char *pszExecPath)
    74 {
    75     RTTestSub(hTest, "testServerListenAndCancel");
    76 
    77     RTLOCALIPCSERVER hIpcServer;
    78     int rc = RTLocalIpcServerCreate(&hIpcServer, "testServerListenAndCancel",
    79                                     RTLOCALIPC_FLAGS_MULTI_SESSION);
    80     if (RT_SUCCESS(rc))
    81     {
    82         /* Spawn a simple worker thread and let it listen for incoming connections.
    83          * In the meanwhile we try to cancel the server and see what happens. */
    84         RTTHREAD hThread;
    85         rc = RTThreadCreate(&hThread, testServerListenAndCancelThread,
    86                             &hIpcServer, 0 /* Stack */, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "tstIpc1");
    87         if (RT_SUCCESS(rc))
    88         {
    89             do
    90             {
    91                 RTTestPrintf(hTest, RTTESTLVL_INFO, "Listening for incoming connections ...\n");
    92                 RTLOCALIPCSESSION hIpcSession;
    93                 RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcServerListen(hIpcServer, &hIpcSession), VERR_CANCELLED);
    94                 RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcServerCancel(hIpcServer), VINF_SUCCESS);
    95                 RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcServerDestroy(hIpcServer), VINF_SUCCESS);
    96 
    97                 RTTestPrintf(hTest, RTTESTLVL_INFO, "Waiting for thread to exit ...\n");
    98                 RTTEST_CHECK_RC(hTest, RTThreadWait(hThread, 30 * 1000 /* 30s timeout */, NULL), VINF_SUCCESS);
    99             } while (0);
    100         }
    101         else
    102             RTTestIFailed("Unable to create thread for cancelling server, rc=%Rrc\n", rc);
    103     }
    104     else
    105         RTTestIFailed("Unable to create IPC server, rc=%Rrc\n", rc);
    106 
    107     return VINF_SUCCESS;
    108 }
    109 
    110 static DECLCALLBACK(int) testServerListenThread(RTTHREAD hSelf, void *pvUser)
    111 {
    112     PLOCALIPCTHREADCTX pCtx = (PLOCALIPCTHREADCTX)pvUser;
    113     AssertPtr(pCtx);
    114 
    115     int rc;
    116     RTTestPrintf(pCtx->hTest, RTTESTLVL_INFO, "testServerListenThread: Listening for incoming connections ...\n");
    117     for (;;)
    118     {
    119         RTLOCALIPCSESSION hIpcSession;
    120         rc = RTLocalIpcServerListen(pCtx->hServer, &hIpcSession);
    121         RTTestPrintf(pCtx->hTest, RTTESTLVL_DEBUG, "testServerListenThread: Listening returned with rc=%Rrc\n", rc);
    122         if (RT_SUCCESS(rc))
    123         {
    124             RTTestPrintf(pCtx->hTest, RTTESTLVL_INFO, "testServerListenThread: Got new client connection\n");
    125             RTTEST_CHECK_RC(pCtx->hTest, RTLocalIpcSessionClose(hIpcSession), VINF_SUCCESS);
    126         }
    127         else
    128             break;
    129     }
    130 
    131     RTTestPrintf(pCtx->hTest, RTTESTLVL_INFO, "testServerListenThread: Ended with rc=%Rrc\n", rc);
    132     return rc;
    133 }
    134 
    135 static RTEXITCODE testSessionConnectionChild(int argc, char **argv, RTTEST hTest)
    136 {
    137     do
    138     {
    139         RTThreadSleep(2000); /* Fudge */
    140         RTLOCALIPCSESSION hClientSession;
    141         RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcSessionConnect(&hClientSession, "tstRTLocalIpcSessionConnection",0 /* Flags */),
    142                               VINF_SUCCESS);
    143         RTThreadSleep(5000); /* Fudge */
    144         RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcSessionClose(hClientSession), VINF_SUCCESS);
    145 
    146     } while (0);
    147 
    148     return !RTTestErrorCount(hTest) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
    149 }
    150 
    151 static int testSessionConnection(RTTEST hTest, const char *pszExecPath)
    152 {
    153     RTTestSub(hTest, "testSessionConnection");
    154 
    155     RTLOCALIPCSERVER hIpcServer;
    156     int rc = RTLocalIpcServerCreate(&hIpcServer, "tstRTLocalIpcSessionConnection", RTLOCALIPC_FLAGS_MULTI_SESSION);
    157     if (RT_SUCCESS(rc))
    158     {
    159 #ifndef VBOX_TESTCASES_WITH_NO_THREADING
    160         LOCALIPCTHREADCTX threadCtx = { hIpcServer, hTest };
    161 
    162         /* Spawn a simple worker thread and let it listen for incoming connections.
    163          * In the meanwhile we try to cancel the server and see what happens. */
    164         RTTHREAD hThread;
    165         rc = RTThreadCreate(&hThread, testServerListenThread,
    166                             &threadCtx, 0 /* Stack */, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "tstIpc2");
    167         if (RT_SUCCESS(rc))
    168         {
    169             do
    170             {
    171                 RTPROCESS hProc;
    172                 const char *apszArgs[4] = { pszExecPath, "child", "testSessionConnectionChild", NULL };
    173                 RTTEST_CHECK_RC_BREAK(hTest, RTProcCreate(pszExecPath, apszArgs, RTENV_DEFAULT, 0 /* fFlags*/, &hProc),
    174                                       VINF_SUCCESS);
    175                 RTPROCSTATUS stsChild;
    176                 RTTEST_CHECK_RC_BREAK(hTest, RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &stsChild), VINF_SUCCESS);
    177                 RTTestPrintf(hTest, RTTESTLVL_INFO, "Child terminated, waiting for server thread ...\n");
    178 
    179                 RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcServerCancel(hIpcServer), VINF_SUCCESS);
    180                 int rcThread;
    181                 RTTEST_CHECK_RC(hTest, RTThreadWait(hThread, 30 * 1000 /* 30s timeout */, &rcThread), VINF_SUCCESS);
    182                 RTTEST_CHECK_RC_BREAK(hTest, rcThread,  VERR_CANCELLED);
    183                 RTTestPrintf(hTest, RTTESTLVL_INFO, "Server thread terminated successfully\n");
    184 
    185                 RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcServerDestroy(hIpcServer), VINF_SUCCESS);
    186                 hIpcServer = NIL_RTLOCALIPCSERVER;
    187 
    188                 RTTEST_CHECK_BREAK(hTest, stsChild.enmReason == RTPROCEXITREASON_NORMAL);
    189                 RTTEST_CHECK_BREAK(hTest, stsChild.iStatus == 0);
    190             } while (0);
    191         }
    192         else
    193             RTTestFailed(hTest, "Unable to create thread for cancelling server, rc=%Rrc\n", rc);
    194 #else
    195         do
    196         {
    197             RTPROCESS hProc;
    198             const char *apszArgs[4] = { pszExecPath, "child", "testSessionConnectionChild", NULL };
    199             RTTEST_CHECK_RC_BREAK(hTest, RTProcCreate(pszExecPath, apszArgs, RTENV_DEFAULT, 0 /* fFlags*/, &hProc), VINF_SUCCESS);
    200 
    201             RTLOCALIPCSESSION hIpcSession;
    202             rc = RTLocalIpcServerListen(hIpcServer, &hIpcSession);
    203             if (RT_SUCCESS(rc))
    204             {
    205                 RTTestPrintf(hTest, RTTESTLVL_INFO, "testServerListenThread: Got new client connection\n");
    206                 RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcSessionClose(hIpcSession), VINF_SUCCESS);
    207             }
    208             else
    209                 RTTestFailed(hTest, "Error while listening, rc=%Rrc\n", rc);
    210 
    211         } while (0);
    212 #endif
    213         if (hIpcServer != NIL_RTLOCALIPCSERVER)
    214             RTTEST_CHECK_RC(hTest, RTLocalIpcServerDestroy(hIpcServer), VINF_SUCCESS);
    215     }
    216     else
    217         RTTestFailed(hTest, "Unable to create IPC server, rc=%Rrc\n", rc);
    218 
    219     return VINF_SUCCESS;
    220 }
    221 
    222 static DECLCALLBACK(int) testSessionWaitThread(RTTHREAD hSelf, void *pvUser)
    223 {
    224     PLOCALIPCTHREADCTX pCtx = (PLOCALIPCTHREADCTX)pvUser;
    225     AssertPtr(pCtx);
    226 
    227     int rc;
    228     for (;;)
    229     {
    230         RTTestPrintf(pCtx->hTest, RTTESTLVL_INFO, "testSessionWaitThread: Listening for incoming connections ...\n");
    231         RTLOCALIPCSESSION hIpcSession;
    232         rc = RTLocalIpcServerListen(pCtx->hServer, &hIpcSession);
    233         if (RT_SUCCESS(rc))
    234         {
    235             RTTestPrintf(pCtx->hTest, RTTESTLVL_INFO, "testSessionWaitThread: Got new client connection, waiting a bit ...\n");
    236             RTThreadSleep(2000);
    237             rc = RTLocalIpcSessionClose(hIpcSession);
    238         }
    239         else
    240         {
    241             RTTestPrintf(pCtx->hTest, RTTESTLVL_INFO, "testSessionWaitThread: Listening ended with rc=%Rrc\n", rc);
    242             break;
    243         }
    244     }
    245 
    246     RTTestPrintf(pCtx->hTest, RTTESTLVL_INFO, "testSessionWaitThread: Ended with rc=%Rrc\n", rc);
    247     return rc;
    248 }
    249 
    250 static RTEXITCODE testSessionWaitChild(int argc, char **argv, RTTEST hTest)
    251 {
    252     do
    253     {
    254         RTThreadSleep(2000); /* Fudge. */
    255         RTLOCALIPCSESSION clientSession;
    256         RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcSessionConnect(&clientSession, "tstRTLocalIpcSessionWait",
    257                                                               0 /* Flags */), VINF_SUCCESS);
    258         RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcSessionWaitForData(clientSession, 100       /* 100ms timeout */),
    259                               VERR_TIMEOUT);
    260         /* Next, try 60s timeout. Should be returning way earlier because the server closed the
    261          * connection after the first client connected. */
    262         RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcSessionWaitForData(clientSession, 60 * 1000),
    263                               VERR_BROKEN_PIPE);
    264         /* Last try, also should fail because the server should be not around anymore. */
    265         RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcSessionWaitForData(clientSession, 5 * 1000),
    266                               VERR_BROKEN_PIPE);
    267         RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcSessionClose(clientSession), VINF_SUCCESS);
    268 
    269     } while (0);
    270 
    271     return !RTTestErrorCount(hTest) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
    272 }
    273 
    274 static int testSessionWait(RTTEST hTest, const char *pszExecPath)
    275 {
    276     RTTestSub(hTest, "testSessionWait");
    277 
    278     RTLOCALIPCSERVER hIpcServer;
    279     int rc = RTLocalIpcServerCreate(&hIpcServer, "tstRTLocalIpcSessionWait",
    280                                     RTLOCALIPC_FLAGS_MULTI_SESSION);
    281     if (RT_SUCCESS(rc))
    282     {
    283         LOCALIPCTHREADCTX threadCtx = { hIpcServer, hTest };
    284 
    285         /* Spawn a simple worker thread and let it listen for incoming connections.
    286          * In the meanwhile we try to cancel the server and see what happens. */
    287         RTTHREAD hThread;
    288         rc = RTThreadCreate(&hThread, testSessionWaitThread,
    289                             &threadCtx, 0 /* Stack */, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "tstIpc3");
    290         if (RT_SUCCESS(rc))
    291         {
    292             do
    293             {
    294                 RTPROCESS hProc;
    295                 const char *apszArgs[4] = { pszExecPath, "child", "tstRTLocalIpcSessionWaitFork", NULL };
    296                 RTTEST_CHECK_RC_BREAK(hTest, RTProcCreate(pszExecPath, apszArgs, RTENV_DEFAULT, 0 /* fFlags*/, &hProc),
    297                                       VINF_SUCCESS);
    298                 RTThreadSleep(5000); /* Let the server run for some time ... */
    299                 RTTestPrintf(hTest, RTTESTLVL_INFO, "Cancelling server listening\n");
    300                 RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcServerCancel(hIpcServer), VINF_SUCCESS);
    301                 /* Wait for the server thread to terminate. */
    302                 int rcThread;
    303                 RTTEST_CHECK_RC(hTest, RTThreadWait(hThread, 30 * 1000 /* 30s timeout */, &rcThread), VINF_SUCCESS);
    304                 RTTEST_CHECK_RC_BREAK(hTest, rcThread, VERR_CANCELLED);
    305                 RTTEST_CHECK_RC(hTest, RTLocalIpcServerDestroy(hIpcServer), VINF_SUCCESS);
    306                 RTTestPrintf(hTest, RTTESTLVL_INFO, "Server thread terminated successfully\n");
    307                 /* Check if the child ran successfully. */
    308                 RTPROCSTATUS stsChild;
    309                 RTTEST_CHECK_RC_BREAK(hTest, RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &stsChild), VINF_SUCCESS);
    310                 RTTestPrintf(hTest, RTTESTLVL_INFO, "Child terminated\n");
    311                 RTTEST_CHECK_BREAK(hTest, stsChild.enmReason == RTPROCEXITREASON_NORMAL);
    312                 RTTEST_CHECK_BREAK(hTest, stsChild.iStatus == 0);
    313             }
    314             while (0);
    315         }
    316         else
    317             RTTestFailed(hTest, "Unable to create thread for cancelling server, rc=%Rrc\n", rc);
    318     }
    319     else
    320         RTTestFailed(hTest, "Unable to create IPC server, rc=%Rrc\n", rc);
    321 
    322     return VINF_SUCCESS;
    323 }
    324 
    325 /**
    326  * Simple structure holding the test IPC messages.
    327  */
    328 typedef struct LOCALIPCTESTMSG
    329 {
    330     /** The actual message. */
    331     char szOp[255];
    332 } LOCALIPCTESTMSG, *PLOCALIPCTESTMSG;
    333 
    334 static int testSessionDataReadTestMsg(RTTEST hTest, RTLOCALIPCSESSION hSession,
    335                                       void *pvBuffer, size_t cbBuffer, const char *pszMsg)
    336 {
    337     AssertPtrReturn(pvBuffer, VERR_INVALID_POINTER);
    338     AssertPtrReturn(pszMsg, VERR_INVALID_POINTER);
    339 
    340     void *pvBufCur = pvBuffer;
    341     size_t cbReadTotal = 0;
    342     for (;;)
    343     {
    344         size_t cbRead = RTRandU32Ex(1, sizeof(LOCALIPCTESTMSG) - cbReadTotal); /* Force a bit of fragmentation. */
    345         RTTEST_CHECK_BREAK(hTest, cbRead);
    346         RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcSessionRead(hSession, pvBufCur,
    347                                                            cbBuffer,
    348                                                            &cbRead), VINF_SUCCESS);
    349         RTTEST_CHECK_BREAK(hTest, cbRead);
    350         pvBufCur     = (uint8_t *)pvBufCur + cbRead; /* Advance. */
    351         cbReadTotal += cbRead;
    352         RTTEST_CHECK_BREAK(hTest, cbReadTotal <= cbBuffer);
    353         if (cbReadTotal >= sizeof(LOCALIPCTESTMSG)) /* Got a complete test message? */
    354         {
    355             RTTEST_CHECK_BREAK(hTest, cbReadTotal == sizeof(LOCALIPCTESTMSG));
    356             PLOCALIPCTESTMSG pMsg = (PLOCALIPCTESTMSG)pvBuffer;
    357             RTTEST_CHECK_BREAK(hTest, pMsg != NULL);
    358             RTTEST_CHECK_BREAK(hTest, !RTStrCmp(pMsg->szOp, pszMsg));
    359             break;
    360         }
    361         /* Try receiving next part of the message in another round. */
    362     }
    363 
    364     return !RTTestErrorCount(hTest) ? VINF_SUCCESS : VERR_GENERAL_FAILURE /* Doesn't matter */;
    365 }
    366 
    367 static int testSessionDataThreadWorker(PLOCALIPCTHREADCTX pCtx)
    368 {
    369     AssertPtr(pCtx);
    370 
    371     size_t cbScratchBuf = _1K; /** @todo Make this random in future. */
    372     uint8_t *pvScratchBuf = (uint8_t*)RTMemAlloc(cbScratchBuf);
    373     RTTEST_CHECK_RET(pCtx->hTest, pvScratchBuf != NULL, VERR_NO_MEMORY);
    374 
    375     do
    376     {
    377         /* Note: At the moment we only support one client per run. */
    378         RTTestPrintf(pCtx->hTest, RTTESTLVL_INFO, "testSessionDataThread: Listening for incoming connections ...\n");
    379         RTLOCALIPCSESSION hSession;
    380         RTTEST_CHECK_RC_BREAK(pCtx->hTest, RTLocalIpcServerListen(pCtx->hServer, &hSession), VINF_SUCCESS);
    381         RTTestPrintf(pCtx->hTest, RTTESTLVL_INFO, "testSessionDataThread: Got new client connection\n");
    382         uint32_t cRounds = 256; /** @todo Use RTRand(). */
    383         /* Write how many rounds we're going to send data. */
    384         RTTEST_CHECK_RC_BREAK(pCtx->hTest, RTLocalIpcSessionWrite(hSession, &cRounds, sizeof(cRounds)), VINF_SUCCESS);
    385         RTTestPrintf(pCtx->hTest, RTTESTLVL_INFO, "testSessionDataThread: Written number of rounds\n");
    386         for (uint32_t i = 0; i < cRounds; i++)
    387         {
    388             LOCALIPCTESTMSG msg;
    389             RTTEST_CHECK_BREAK(pCtx->hTest, RTStrPrintf(msg.szOp, sizeof(msg.szOp),
    390                                                         "YayIGotRound%RU32FromTheServer", i) > 0);
    391             RTTEST_CHECK_RC_BREAK(pCtx->hTest, RTLocalIpcSessionWrite(hSession, &msg, sizeof(msg)), VINF_SUCCESS);
    392         }
    393         if (!RTTestErrorCount(pCtx->hTest))
    394             RTTestPrintf(pCtx->hTest, RTTESTLVL_INFO, "testSessionDataThread: Data successfully written\n");
    395         /* Try to receive the same amount of rounds from the client. */
    396         for (uint32_t i = 0; i < cRounds; i++)
    397         {
    398             RTTEST_CHECK_RC_BREAK(pCtx->hTest, RTLocalIpcSessionWaitForData(hSession, RT_INDEFINITE_WAIT),
    399                                   VINF_SUCCESS);
    400             char szMsg[32];
    401             RTTEST_CHECK_BREAK(pCtx->hTest, RTStrPrintf(szMsg, sizeof(szMsg), "YayIGotRound%RU32FromTheClient", i) > 0);
    402             RTTEST_CHECK_RC_BREAK(pCtx->hTest, testSessionDataReadTestMsg(pCtx->hTest, hSession,
    403                                                                           pvScratchBuf, cbScratchBuf,
    404                                                                           szMsg), VINF_SUCCESS);
    405             if (RTTestErrorCount(pCtx->hTest))
    406                 break;
    407         }
    408         if (!RTTestErrorCount(pCtx->hTest))
    409             RTTestPrintf(pCtx->hTest, RTTESTLVL_INFO, "testSessionDataThread: Data successfully read\n");
    410         RTTEST_CHECK_RC_BREAK(pCtx->hTest, RTLocalIpcSessionClose(hSession), VINF_SUCCESS);
    411 
    412     } while (0);
    413 
    414     RTMemFree(pvScratchBuf);
    415     return !RTTestErrorCount(pCtx->hTest) ? VINF_SUCCESS : VERR_GENERAL_FAILURE /* Doesn't matter */;
    416 }
    417 
    418 static DECLCALLBACK(int) testSessionDataThread(RTTHREAD hSelf, void *pvUser)
    419 {
    420     PLOCALIPCTHREADCTX pCtx = (PLOCALIPCTHREADCTX)pvUser;
    421     AssertPtr(pCtx);
    422 
    423     return testSessionDataThreadWorker(pCtx);
    424 }
    425 
    426 static int testSessionDataChildWorker(RTTEST hTest)
    427 {
    428     size_t cbScratchBuf = _1K; /** @todo Make this random in future. */
    429     uint8_t *pvScratchBuf = (uint8_t*)RTMemAlloc(cbScratchBuf);
    430     RTTEST_CHECK_RET(hTest, pvScratchBuf != NULL, RTEXITCODE_FAILURE);
    431 
    432     do
    433     {
    434         RTThreadSleep(2000); /* Fudge. */
    435         RTLOCALIPCSESSION hSession;
    436         RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcSessionConnect(&hSession, "tstRTLocalIpcSessionData",
    437                                                               0 /* Flags */), VINF_SUCCESS);
    438         /* Get number of rounds we want to read/write. */
    439         uint32_t cRounds = 0;
    440         RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcSessionWaitForData(hSession, RT_INDEFINITE_WAIT),
    441                                                                   VINF_SUCCESS);
    442         RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcSessionRead(hSession, &cRounds, sizeof(cRounds),
    443                                                            NULL /* Get exactly sizeof(cRounds) bytes */), VINF_SUCCESS);
    444         RTTEST_CHECK_BREAK(hTest, cRounds == 256); /** @todo Check for != 0 when using RTRand(). */
    445         /* Receive all rounds. */
    446         for (uint32_t i = 0; i < cRounds; i++)
    447         {
    448             RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcSessionWaitForData(hSession, RT_INDEFINITE_WAIT),
    449                                                                       VINF_SUCCESS);
    450             char szMsg[32];
    451             RTTEST_CHECK_BREAK(hTest, RTStrPrintf(szMsg, sizeof(szMsg), "YayIGotRound%RU32FromTheServer", i) > 0);
    452             RTTEST_CHECK_RC_BREAK(hTest, testSessionDataReadTestMsg(hTest, hSession,
    453                                                                     pvScratchBuf, cbScratchBuf,
    454                                                                     szMsg), VINF_SUCCESS);
    455             if (RTTestErrorCount(hTest))
    456                 break;
    457         }
    458         /* Send all rounds back to the server. */
    459         for (uint32_t i = 0; i < cRounds; i++)
    460         {
    461             LOCALIPCTESTMSG msg;
    462             RTTEST_CHECK_BREAK(hTest, RTStrPrintf(msg.szOp, sizeof(msg.szOp),
    463                                                   "YayIGotRound%RU32FromTheClient", i) > 0);
    464             RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcSessionWrite(hSession, &msg, sizeof(msg)), VINF_SUCCESS);
    465         }
    466         RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcSessionClose(hSession), VINF_SUCCESS);
    467 
    468     } while (0);
    469 
    470     RTMemFree(pvScratchBuf);
    471     return !RTTestErrorCount(hTest) ? VINF_SUCCESS : VERR_GENERAL_FAILURE /* Doesn't matter */;
    472 }
    473 
    474 static DECLCALLBACK(int) testSessionDataChildAsThread(RTTHREAD hSelf, void *pvUser)
    475 {
    476     PRTTEST phTest = (PRTTEST)pvUser;
    477     AssertPtr(phTest);
    478     return testSessionDataChildWorker(*phTest);
    479 }
    480 
    481 static RTEXITCODE testSessionDataChild(int argc, char **argv, RTTEST hTest)
    482 {
    483     return RT_SUCCESS(testSessionDataChildWorker(hTest)) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
    484 }
    485 
    486 static int testSessionData(RTTEST hTest, const char *pszExecPath)
    487 {
    488     RTTestSub(hTest, "testSessionData");
    489 
    490     RTLOCALIPCSERVER hIpcServer;
    491     int rc = RTLocalIpcServerCreate(&hIpcServer, "tstRTLocalIpcSessionData",
    492                                     RTLOCALIPC_FLAGS_MULTI_SESSION);
    493     if (RT_SUCCESS(rc))
    494     {
    495         LOCALIPCTHREADCTX threadCtx = { hIpcServer, hTest };
    496 #if 0
    497         /* Run server + client in threads instead of fork'ed processes (useful for debugging). */
    498         RTTHREAD hThreadServer, hThreadClient;
    499         rc = RTThreadCreate(&hThreadServer, testSessionDataThread,
    500                             &threadCtx, 0 /* Stack */, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "tstIpc4");
    501         if (RT_SUCCESS(rc))
    502             rc = RTThreadCreate(&hThreadClient, testSessionDataChildAsThread,
    503                                 &hTest, 0 /* Stack */, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "tstIpc5");
    504         if (RT_SUCCESS(rc))
    505         {
    506             do
    507             {
    508                 int rcThread;
    509                 RTTEST_CHECK_RC(hTest, RTThreadWait(hThreadServer,
    510                                                     5 * 60 * 1000 /* 5 minutes timeout */, &rcThread), VINF_SUCCESS);
    511                 RTTEST_CHECK_RC_BREAK(hTest, rcThread, VINF_SUCCESS);
    512                 RTTEST_CHECK_RC(hTest, RTThreadWait(hThreadClient,
    513                                                     5 * 60 * 1000 /* 5 minutes timeout */, &rcThread), VINF_SUCCESS);
    514                 RTTEST_CHECK_RC_BREAK(hTest, rcThread, VINF_SUCCESS);
    515 
    516             } while (0);
    517         }
    518 #else
    519         /* Spawn a simple worker thread and let it listen for incoming connections.
    520          * In the meanwhile we try to cancel the server and see what happens. */
    521         RTTHREAD hThread;
    522         rc = RTThreadCreate(&hThread, testSessionDataThread,
    523                             &threadCtx, 0 /* Stack */, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "tstIpc4");
    524         if (RT_SUCCESS(rc))
    525         {
    526             do
    527             {
    528                 RTPROCESS hProc;
    529                 const char *apszArgs[4] = { pszExecPath, "child", "tstRTLocalIpcSessionDataFork", NULL };
    530                 RTTEST_CHECK_RC_BREAK(hTest, RTProcCreate(pszExecPath, apszArgs,
    531                                                           RTENV_DEFAULT, 0 /* fFlags*/, &hProc), VINF_SUCCESS);
    532                 /* Wait for the server thread to terminate. */
    533                 int rcThread;
    534                 RTTEST_CHECK_RC(hTest, RTThreadWait(hThread,
    535                                                     5 * 60 * 1000 /* 5 minutes timeout */, &rcThread), VINF_SUCCESS);
    536                 RTTEST_CHECK_RC_BREAK(hTest, rcThread, VINF_SUCCESS);
    537                 RTTEST_CHECK_RC(hTest, RTLocalIpcServerDestroy(hIpcServer), VINF_SUCCESS);
    538                 RTTestPrintf(hTest, RTTESTLVL_INFO, "Server thread terminated successfully\n");
    539                 /* Check if the child ran successfully. */
    540                 RTPROCSTATUS stsChild;
    541                 RTTEST_CHECK_RC_BREAK(hTest, RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &stsChild), VINF_SUCCESS);
    542                 RTTestPrintf(hTest, RTTESTLVL_INFO, "Child terminated\n");
    543                 RTTEST_CHECK_BREAK(hTest, stsChild.enmReason == RTPROCEXITREASON_NORMAL);
    544                 RTTEST_CHECK_BREAK(hTest, stsChild.iStatus == 0);
    545             }
    546             while (0);
    547         }
    548         else
    549             RTTestFailed(hTest, "Unable to create thread for cancelling server, rc=%Rrc\n", rc);
    550 #endif
    551     }
    552     else
    553         RTTestFailed(hTest, "Unable to create IPC server, rc=%Rrc\n", rc);
    554 
    555     return !RTTestErrorCount(hTest) ? VINF_SUCCESS : VERR_GENERAL_FAILURE /* Doesn't matter */;
    556 }
    557 
    558 static RTEXITCODE mainChild(int argc, char **argv)
    559 {
    560     if (argc < 3) /* Safety first. */
    561         return RTEXITCODE_FAILURE;
    562     /* Note: We assume argv[2] always contains the actual test type to perform. */
    563     RTTEST hTest;
    564     RTEXITCODE rcExit = RTTestInitAndCreate(argv[2], &hTest);
    565     if (rcExit)
    566         return rcExit;
    567     RTTestBanner(hTest);
    568 
    569     RTAssertSetMayPanic(false);
    570 #ifdef DEBUG_andy
    571     RTAssertSetQuiet(false);
    572 #endif
    573 
    574     if (!RTStrICmp(argv[2], "testSessionConnectionChild"))
    575         rcExit = testSessionConnectionChild(argc, argv, hTest);
    576     else if (!RTStrICmp(argv[2], "tstRTLocalIpcSessionWaitFork"))
    577         rcExit = testSessionWaitChild(argc, argv, hTest);
    578     else if (!RTStrICmp(argv[2], "tstRTLocalIpcSessionDataFork"))
    579         rcExit = testSessionDataChild(argc, argv, hTest);
    580 
    581     return RTTestSummaryAndDestroy(hTest);
    582 }
     47/*********************************************************************************************************************************
     48*   Global Variables                                                                                                             *
     49*********************************************************************************************************************************/
     50/** The test instance.*/
     51static RTTEST g_hTest;
     52
     53
    58354
    58455static void testBasics(void)
     
    62596}
    62697
     98
     99
     100/*********************************************************************************************************************************
     101*                                                                                                                                *
     102*   testSessionConnection - Connecting.                                                                                          *
     103*                                                                                                                                *
     104*********************************************************************************************************************************/
     105
     106static DECLCALLBACK(int) testServerListenThread(RTTHREAD hSelf, void *pvUser)
     107{
     108    RTLOCALIPCSERVER hIpcServer = (RTLOCALIPCSERVER)pvUser;
     109    RTTEST_CHECK_RC_OK_RET(g_hTest, RTTestSetDefault(g_hTest, NULL), rcCheck);
     110
     111    RTTESTI_CHECK_RC_OK(RTThreadUserSignal(hSelf));
     112
     113    int rc;
     114    for (;;)
     115    {
     116        RTLOCALIPCSESSION hIpcSession;
     117        rc = RTLocalIpcServerListen(hIpcServer, &hIpcSession);
     118        if (RT_SUCCESS(rc))
     119        {
     120            RTThreadSleep(8); /* windows output fudge (purely esthetical) */
     121            RTTestIPrintf(RTTESTLVL_INFO, "testServerListenThread: Got new client connection.\n");
     122            RTTESTI_CHECK_RC(RTLocalIpcSessionClose(hIpcSession), VINF_SUCCESS);
     123        }
     124        else
     125        {
     126            RTTESTI_CHECK_RC(rc, VERR_CANCELLED);
     127            break;
     128        }
     129    }
     130    return rc;
     131}
     132
     133
     134/**
     135 * Used both as a thread procedure and child process worker.
     136 */
     137static DECLCALLBACK(int) tstRTLocalIpcSessionConnectionChild(RTTHREAD hSelf, void *pvUser)
     138{
     139    RTLOCALIPCSESSION hClientSession;
     140    RTTEST_CHECK_RC_OK_RET(g_hTest, RTTestSetDefault(g_hTest, NULL), rcCheck);
     141
     142    RTTEST_CHECK_RC_RET(g_hTest, RTLocalIpcSessionConnect(&hClientSession, "tstRTLocalIpcSessionConnection",0 /* Flags */),
     143                        VINF_SUCCESS, rcCheck);
     144    RTTEST_CHECK_RC_RET(g_hTest, RTLocalIpcSessionClose(hClientSession),
     145                        VINF_SUCCESS, rcCheck);
     146
     147    return VINF_SUCCESS;
     148}
     149
     150
     151static void testSessionConnection(const char *pszExecPath)
     152{
     153    RTTestISub(!pszExecPath ? "Connect from thread" : "Connect from child");
     154
     155    /*
     156     * Create the test server.
     157     */
     158    RTLOCALIPCSERVER hIpcServer;
     159    RTTESTI_CHECK_RC_RETV(RTLocalIpcServerCreate(&hIpcServer, "tstRTLocalIpcSessionConnection", RTLOCALIPC_FLAGS_MULTI_SESSION),
     160                          VINF_SUCCESS);
     161
     162    /*
     163     * Create worker thread that listens and closes incoming connections until
     164     * cancelled.
     165     */
     166    int rc;
     167    RTTHREAD hListenThread;
     168    RTTESTI_CHECK_RC_OK(rc = RTThreadCreate(&hListenThread, testServerListenThread, hIpcServer, 0 /* Stack */,
     169                                            RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "listen-1"));
     170    if (RT_SUCCESS(rc))
     171    {
     172        RTThreadUserWait(hListenThread, 32);
     173
     174        /*
     175         * Two variations here: Client connects from thread or a child process.
     176         */
     177        if (pszExecPath)
     178        {
     179            RTPROCESS hClientProc;
     180            const char *apszArgs[4] = { pszExecPath, "child", "tstRTLocalIpcSessionConnectionChild", NULL };
     181            RTTESTI_CHECK_RC_OK(rc = RTProcCreate(pszExecPath, apszArgs, RTENV_DEFAULT, 0 /* fFlags*/, &hClientProc));
     182            if (RT_SUCCESS(rc))
     183            {
     184                RTPROCSTATUS ProcStatus;
     185                RTTESTI_CHECK_RC_OK(rc = RTProcWait(hClientProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus));
     186                if (RT_SUCCESS(rc) && (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0))
     187                    RTTestIFailed("Chiled exited with enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
     188            }
     189        }
     190        else
     191        {
     192            RTTHREAD hClientThread;
     193            RTTESTI_CHECK_RC_OK(rc = RTThreadCreate(&hClientThread, tstRTLocalIpcSessionConnectionChild, NULL,
     194                                                    0 /* Stack */, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "client-1"));
     195            if (RT_SUCCESS(rc))
     196            {
     197                int rcThread;
     198                RTTESTI_CHECK_RC_OK(rc = RTThreadWait(hClientThread, RT_MS_1MIN / 2, &rcThread));
     199                if (RT_SUCCESS(rc))
     200                    RTTESTI_CHECK_RC(rcThread, VINF_SUCCESS);
     201            }
     202        }
     203
     204
     205        /*
     206         * Terminate the server thread.
     207         */
     208        //RTTestIPrintf(RTTESTLVL_INFO, "Child terminated, waiting for server thread ...\n");
     209        RTTESTI_CHECK_RC(RTLocalIpcServerCancel(hIpcServer), VINF_SUCCESS);
     210        int rcThread;
     211        RTTESTI_CHECK_RC(rc = RTThreadWait(hListenThread, 30 * 1000 /* 30s timeout */, &rcThread), VINF_SUCCESS);
     212        if (RT_SUCCESS(rc))
     213            RTTESTI_CHECK_RC(rcThread, VERR_CANCELLED);
     214    }
     215
     216    RTTESTI_CHECK_RC(RTLocalIpcServerDestroy(hIpcServer), VINF_SUCCESS);
     217}
     218
     219
     220
     221/*********************************************************************************************************************************
     222*                                                                                                                                *
     223*   testSessionWait - RTLocalIpcSessionWaitForData.                                                                              *
     224*                                                                                                                                *
     225*********************************************************************************************************************************/
     226
     227static DECLCALLBACK(int) testSessionWaitThread(RTTHREAD hSelf, void *pvUser)
     228{
     229    RTLOCALIPCSERVER hIpcServer = (RTLOCALIPCSERVER)pvUser;
     230    RTTEST_CHECK_RC_OK_RET(g_hTest, RTTestSetDefault(g_hTest, NULL), rcCheck);
     231
     232    int rc;
     233    for (;;)
     234    {
     235        RTLOCALIPCSESSION hIpcSession;
     236        rc = RTLocalIpcServerListen(hIpcServer, &hIpcSession);
     237        if (RT_SUCCESS(rc))
     238        {
     239            RTTestIPrintf(RTTESTLVL_INFO, "testSessionWaitThread: Got new client connection.\n");
     240
     241            /* Wait for the client to trigger a disconnect by writing us something. */
     242            RTTESTI_CHECK_RC(RTLocalIpcSessionWaitForData(hIpcSession, RT_MS_1MIN), VINF_SUCCESS);
     243
     244            RTTESTI_CHECK_RC(RTLocalIpcSessionClose(hIpcSession), VINF_SUCCESS);
     245            RTTESTI_CHECK_RC_OK(RTThreadUserSignal(hSelf));
     246        }
     247        else
     248        {
     249            RTTESTI_CHECK_RC(rc, VERR_CANCELLED);
     250            break;
     251        }
     252    }
     253    RTTESTI_CHECK_RC_OK(RTThreadUserSignal(hSelf));
     254    return rc;
     255}
     256
     257
     258/**
     259 * Used both as a thread procedure and child process worker.
     260 */
     261static DECLCALLBACK(int) tstRTLocalIpcSessionWaitChild(RTTHREAD hSelf, void *pvUser)
     262{
     263    RTTEST_CHECK_RC_OK_RET(g_hTest, RTTestSetDefault(g_hTest, NULL), rcCheck);
     264
     265    RTLOCALIPCSESSION hClientSession;
     266    RTTESTI_CHECK_RC_RET(RTLocalIpcSessionConnect(&hClientSession, "tstRTLocalIpcSessionWait", 0 /*fFlags*/),
     267                         VINF_SUCCESS, rcCheck);
     268
     269    /*
     270     * The server side won't write anything.  It will close the connection
     271     * as soon as we write something.
     272     */
     273    RTTESTI_CHECK_RC(RTLocalIpcSessionWaitForData(hClientSession, 0 /*cMsTimeout*/), VERR_TIMEOUT);
     274    RTTESTI_CHECK_RC(RTLocalIpcSessionWaitForData(hClientSession, 8 /*cMsTimeout*/), VERR_TIMEOUT);
     275
     276    /* Trigger server disconnect. */
     277    int rc;
     278    RTTESTI_CHECK_RC(rc = RTLocalIpcSessionWrite(hClientSession, RT_STR_TUPLE("disconnect")), VINF_SUCCESS);
     279    if (RT_SUCCESS(rc))
     280    {
     281        /*
     282         * When we wait now, we should get an broken pipe error as
     283         * the server has close its end.
     284         */
     285        RTTESTI_CHECK_RC(rc = RTLocalIpcSessionWaitForData(hClientSession, RT_MS_1MIN), VERR_BROKEN_PIPE);
     286        RTTESTI_CHECK_RC(RTLocalIpcSessionWaitForData(hClientSession, 0), VERR_BROKEN_PIPE);
     287        RTTESTI_CHECK_RC(RTLocalIpcSessionWaitForData(hClientSession, RT_MS_1SEC), VERR_BROKEN_PIPE);
     288    }
     289
     290    RTTESTI_CHECK_RC(RTLocalIpcSessionClose(hClientSession), VINF_SUCCESS);
     291
     292    return VINF_SUCCESS;
     293}
     294
     295
     296/**
     297 * @note This is identical to testSessionData with a couple of string and
     298 *       function pointers replaced.
     299 */
     300static void testSessionWait(const char *pszExecPath)
     301{
     302    RTTestISub(!pszExecPath ? "Wait for data in thread" : "Wait for data in child");
     303
     304    /*
     305     * Create the test server.
     306     */
     307    RTLOCALIPCSERVER hIpcServer;
     308    RTTESTI_CHECK_RC_RETV(RTLocalIpcServerCreate(&hIpcServer, "tstRTLocalIpcSessionWait", RTLOCALIPC_FLAGS_MULTI_SESSION),
     309                          VINF_SUCCESS);
     310
     311    /*
     312     * Create worker thread that listens and processes incoming connections
     313     * until cancelled.
     314     */
     315    int rc;
     316    RTTHREAD hListenThread;
     317    RTTESTI_CHECK_RC_OK(rc = RTThreadCreate(&hListenThread, testSessionWaitThread, hIpcServer, 0 /* Stack */,
     318                                            RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "listen-2"));
     319    if (RT_SUCCESS(rc))
     320    {
     321        /*
     322         * Create a client process or thread and connects to the server.
     323         * It will perform the wait-for-data test.
     324         */
     325        RTPROCESS hClientProc = NIL_RTPROCESS;
     326        RTTHREAD  hClientThread = NIL_RTTHREAD;
     327        if (pszExecPath)
     328        {
     329            const char *apszArgs[4] = { pszExecPath, "child", "tstRTLocalIpcSessionWaitChild", NULL };
     330            RTTESTI_CHECK_RC_OK(rc = RTProcCreate(pszExecPath, apszArgs, RTENV_DEFAULT, 0 /* fFlags*/, &hClientProc));
     331        }
     332        else
     333            RTTESTI_CHECK_RC_OK(rc = RTThreadCreate(&hClientThread, tstRTLocalIpcSessionWaitChild, g_hTest, 0 /*cbStack*/,
     334                                                    RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "client-2"));
     335
     336        /*
     337         * Wait for the server thread to indicate that it has processed one
     338         * connection, the shut it all down.
     339         */
     340        if (RT_SUCCESS(rc))
     341            RTTESTI_CHECK_RC_OK(RTThreadUserWait(hListenThread, RT_MS_1MIN / 2));
     342
     343        RTTESTI_CHECK_RC(RTLocalIpcServerCancel(hIpcServer), VINF_SUCCESS);
     344        int rcThread;
     345        RTTESTI_CHECK_RC(rc = RTThreadWait(hListenThread, RT_MS_1MIN / 2, &rcThread), VINF_SUCCESS);
     346        if (RT_SUCCESS(rc))
     347            RTTESTI_CHECK_RC(rcThread, VERR_CANCELLED);
     348
     349        RTTESTI_CHECK_RC(RTLocalIpcServerDestroy(hIpcServer), VINF_SUCCESS);
     350
     351        /*
     352         * Check that client ran successfully.
     353         */
     354        if (pszExecPath)
     355        {
     356            if (hClientProc != NIL_RTPROCESS)
     357            {
     358                RTPROCSTATUS ProcStatus;
     359                RTTESTI_CHECK_RC_OK(rc = RTProcWait(hClientProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus));
     360                if (RT_SUCCESS(rc) && (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0))
     361                    RTTestIFailed("Chiled exited with enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
     362            }
     363        }
     364        else if (hClientThread != NIL_RTTHREAD)
     365        {
     366            RTTESTI_CHECK_RC_OK(rc = RTThreadWait(hClientThread, RT_MS_1MIN / 2, &rcThread));
     367            if (RT_SUCCESS(rc))
     368                RTTESTI_CHECK_RC(rcThread, VINF_SUCCESS);
     369        }
     370    }
     371}
     372
     373
     374
     375/*********************************************************************************************************************************
     376*                                                                                                                                *
     377*   testSessionData - Data transfer integrity.                                                                                   *
     378*                                                                                                                                *
     379*********************************************************************************************************************************/
     380
     381/** The max message size. */
     382#define MAX_DATA_MSG_SIZE   _1M
     383
     384static int testSessionDataReadMessages(RTLOCALIPCSESSION hIpcSession, uint32_t cRounds)
     385{
     386    /*
     387     * Message scratch buffer.  Search message starts with a uint32_t word
     388     * that indicates the message length.  The remaining words are set to
     389     * the message number.
     390     */
     391    uint32_t *pau32ScratchBuf = (uint32_t *)RTMemAlloc(MAX_DATA_MSG_SIZE);
     392    RTTESTI_CHECK_RET(pau32ScratchBuf != NULL, VERR_NO_MEMORY);
     393
     394    int rc = VINF_SUCCESS;
     395    for (uint32_t iRound = 0; iRound < cRounds && rc == VINF_SUCCESS; iRound++)
     396    {
     397        /* Read the message length. */
     398        uint32_t cbMsg;
     399        RTTESTI_CHECK_RC_BREAK(rc = RTLocalIpcSessionRead(hIpcSession, &cbMsg, sizeof(cbMsg), NULL), VINF_SUCCESS);
     400        if (cbMsg >= sizeof(cbMsg) && cbMsg <= MAX_DATA_MSG_SIZE)
     401        {
     402            pau32ScratchBuf[0] = cbMsg;
     403
     404            /* Read the message body. */
     405            uint32_t cbLeft = cbMsg - sizeof(uint32_t);
     406            uint8_t *pbCur  = (uint8_t *)&pau32ScratchBuf[1];
     407            while (cbLeft > 0)
     408            {
     409                uint32_t cbCur = RTRandU32Ex(1, cbLeft + cbLeft / 4);
     410                cbCur = RT_MIN(cbCur, cbLeft);
     411                if ((iRound % 3) == 1)
     412                {
     413                    size_t cbRead = _1G;
     414                    RTTESTI_CHECK_RC_BREAK(rc = RTLocalIpcSessionRead(hIpcSession, pbCur, cbCur, &cbRead), VINF_SUCCESS);
     415                    RTTESTI_CHECK(cbCur >= cbRead);
     416                    cbCur = (uint32_t)cbRead;
     417                }
     418                else
     419                    RTTESTI_CHECK_RC_BREAK(rc = RTLocalIpcSessionRead(hIpcSession, pbCur, cbCur, NULL), VINF_SUCCESS);
     420                pbCur  += cbCur;
     421                cbLeft -= cbCur;
     422            }
     423
     424            /* Check the message body. */
     425            if (RT_SUCCESS(rc))
     426            {
     427                uint32_t offLast = cbMsg & (sizeof(uint32_t) - 1);
     428                if (offLast)
     429                    memcpy((uint8_t *)pau32ScratchBuf + cbMsg, (uint8_t const *)&iRound + offLast, sizeof(uint32_t) - offLast);
     430
     431                ASMCompilerBarrier(); /* Guard against theoretical alias issues in the above code.  */
     432
     433                uint32_t cWords = RT_ALIGN_32(cbMsg, sizeof(uint32_t)) / sizeof(uint32_t);
     434                for (uint32_t iWord = 1; iWord < cWords; iWord++)
     435                    if (pau32ScratchBuf[iWord] != iRound)
     436                    {
     437                        RTTestIFailed("Message body word #%u mismatch: %#x, expected %#x", pau32ScratchBuf[iWord], iRound);
     438                        break;
     439                    }
     440            }
     441        }
     442        else
     443        {
     444            RTTestIFailed("cbMsg=%#x is out of range", cbMsg);
     445            rc = VERR_OUT_OF_RANGE;
     446        }
     447    }
     448
     449    RTMemFree(pau32ScratchBuf);
     450    return rc;
     451}
     452
     453
     454static int testSessionDataWriteMessages(RTLOCALIPCSESSION hIpcSession, uint32_t cRounds)
     455{
     456    /*
     457     * Message scratch buffer.  Search message starts with a uint32_t word
     458     * that indicates the message length.  The remaining words are set to
     459     * the message number.
     460     */
     461    uint32_t   cbScratchBuf = RTRandU32Ex(64, MAX_DATA_MSG_SIZE);
     462    cbScratchBuf = RT_ALIGN_32(cbScratchBuf, sizeof(uint32_t));
     463
     464    uint32_t *pau32ScratchBuf = (uint32_t *)RTMemAlloc(cbScratchBuf);
     465    RTTESTI_CHECK_RET(pau32ScratchBuf != NULL, VERR_NO_MEMORY);
     466
     467    size_t cbSent = 0;
     468    int rc = VINF_SUCCESS;
     469    for (uint32_t iRound = 0; iRound < cRounds && rc == VINF_SUCCESS; iRound++)
     470    {
     471        /* Construct the message. */
     472        uint32_t cbMsg  = RTRandU32Ex(sizeof(uint32_t), cbScratchBuf);
     473        uint32_t cWords = RT_ALIGN_32(cbMsg, sizeof(uint32_t)) / sizeof(uint32_t);
     474
     475        uint32_t iWord  = 0;
     476        pau32ScratchBuf[iWord++] = cbMsg;
     477        while (iWord < cWords)
     478            pau32ScratchBuf[iWord++] = iRound;
     479
     480        /* Send it. */
     481        uint32_t cbLeft = cbMsg;
     482        uint8_t const *pbCur = (uint8_t *)pau32ScratchBuf;
     483        while (cbLeft > 0)
     484        {
     485            uint32_t cbCur = RT_MIN(iRound + 1, cbLeft);
     486            RTTESTI_CHECK_RC_BREAK(rc = RTLocalIpcSessionWrite(hIpcSession, pbCur, cbCur), VINF_SUCCESS);
     487            pbCur  += cbCur;
     488            cbSent += cbCur;
     489            cbLeft -= cbCur;
     490        }
     491    }
     492
     493    RTTestIPrintf(RTTESTLVL_ALWAYS, "Sent %'zu bytes over %u rounds.\n", cbSent, cRounds);
     494    RTMemFree(pau32ScratchBuf);
     495    return rc;
     496}
     497
     498
     499static DECLCALLBACK(int) testSessionDataThread(RTTHREAD hSelf, void *pvUser)
     500{
     501    RTLOCALIPCSERVER hIpcServer = (RTLOCALIPCSERVER)pvUser;
     502    RTTEST_CHECK_RC_OK_RET(g_hTest, RTTestSetDefault(g_hTest, NULL), rcCheck);
     503
     504    int rc;
     505    for (;;)
     506    {
     507        RTLOCALIPCSESSION hIpcSession;
     508        rc = RTLocalIpcServerListen(hIpcServer, &hIpcSession);
     509        if (RT_SUCCESS(rc))
     510        {
     511            RTTestIPrintf(RTTESTLVL_INFO, "testSessionDataThread: Got new client connection\n");
     512
     513            /* The server is the initator. First message sets the number of rounds. */
     514            uint32_t cRounds = RTRandU32Ex(32, _1K);
     515            RTTESTI_CHECK_RC(rc = RTLocalIpcSessionWrite(hIpcSession, &cRounds, sizeof(cRounds)), VINF_SUCCESS);
     516            if (RT_SUCCESS(rc))
     517            {
     518                rc = testSessionDataWriteMessages(hIpcSession, cRounds);
     519                if (RT_SUCCESS(rc))
     520                    rc = testSessionDataReadMessages(hIpcSession, cRounds);
     521            }
     522
     523            RTTESTI_CHECK_RC(RTLocalIpcSessionClose(hIpcSession), VINF_SUCCESS);
     524            RTTESTI_CHECK_RC_OK(RTThreadUserSignal(hSelf));
     525        }
     526        else
     527        {
     528            RTTESTI_CHECK_RC(rc, VERR_CANCELLED);
     529            break;
     530        }
     531    }
     532    RTTESTI_CHECK_RC_OK(RTThreadUserSignal(hSelf));
     533    return rc;
     534}
     535
     536
     537/**
     538 * Used both as a thread procedure and child process worker.
     539 */
     540static DECLCALLBACK(int) tstRTLocalIpcSessionDataChild(RTTHREAD hSelf, void *pvUser)
     541{
     542    RTTEST_CHECK_RC_OK_RET(g_hTest, RTTestSetDefault(g_hTest, NULL), rcCheck);
     543
     544    /*
     545     * Connect.
     546     */
     547    RTLOCALIPCSESSION hClientSession;
     548    RTTESTI_CHECK_RC_RET(RTLocalIpcSessionConnect(&hClientSession, "tstRTLocalIpcSessionData", 0 /*fFlags*/),
     549                         VINF_SUCCESS, rcCheck);
     550
     551    /*
     552     * The server first sends us a rounds count.
     553     */
     554    int rc;
     555    uint32_t cRounds = 0;
     556    RTTESTI_CHECK_RC(rc = RTLocalIpcSessionRead(hClientSession, &cRounds, sizeof(cRounds), NULL), VINF_SUCCESS);
     557    if (RT_SUCCESS(rc))
     558    {
     559        if (cRounds >= 32 && cRounds <= _1K)
     560        {
     561            rc = testSessionDataReadMessages(hClientSession, cRounds);
     562            if (RT_SUCCESS(rc))
     563                rc = testSessionDataWriteMessages(hClientSession, cRounds);
     564        }
     565        else
     566            RTTestIFailed("cRounds=%#x is out of range", cRounds);
     567    }
     568
     569    RTTESTI_CHECK_RC(RTLocalIpcSessionClose(hClientSession), VINF_SUCCESS);
     570
     571    return rc;
     572}
     573
     574
     575/**
     576 * @note This is identical to testSessionWait with a couple of string and
     577 *       function pointers replaced.
     578 */
     579static void testSessionData(const char *pszExecPath)
     580{
     581    RTTestISub(!pszExecPath ? "Data exchange with thread" : "Data exchange with child");
     582
     583    /*
     584     * Create the test server.
     585     */
     586    RTLOCALIPCSERVER hIpcServer;
     587    RTTESTI_CHECK_RC_RETV(RTLocalIpcServerCreate(&hIpcServer, "tstRTLocalIpcSessionData", RTLOCALIPC_FLAGS_MULTI_SESSION),
     588                          VINF_SUCCESS);
     589
     590    /*
     591     * Create worker thread that listens and processes incoming connections
     592     * until cancelled.
     593     */
     594    int rc;
     595    RTTHREAD hListenThread;
     596    RTTESTI_CHECK_RC_OK(rc = RTThreadCreate(&hListenThread, testSessionDataThread, hIpcServer, 0 /* Stack */,
     597                                            RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "listen-3"));
     598    if (RT_SUCCESS(rc))
     599    {
     600        /*
     601         * Create a client thread or process.
     602         */
     603        RTPROCESS hClientProc   = NIL_RTPROCESS;
     604        RTTHREAD  hClientThread = NIL_RTTHREAD;
     605        if (pszExecPath)
     606        {
     607            const char *apszArgs[4] = { pszExecPath, "child", "tstRTLocalIpcSessionDataChild", NULL };
     608            RTTESTI_CHECK_RC_OK(rc = RTProcCreate(pszExecPath, apszArgs, RTENV_DEFAULT, 0 /* fFlags*/, &hClientProc));
     609        }
     610        else
     611            RTTESTI_CHECK_RC_OK(rc = RTThreadCreate(&hClientThread, tstRTLocalIpcSessionDataChild, g_hTest, 0 /*cbStack*/,
     612                                                    RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "client-2"));
     613
     614        /*
     615         * Wait for the server thread to indicate that it has processed one
     616         * connection, the shut it all down.
     617         */
     618        if (RT_SUCCESS(rc))
     619            RTTESTI_CHECK_RC_OK(RTThreadUserWait(hListenThread, RT_MS_1MIN / 2));
     620
     621        RTTESTI_CHECK_RC(RTLocalIpcServerCancel(hIpcServer), VINF_SUCCESS);
     622        int rcThread;
     623        RTTESTI_CHECK_RC(rc = RTThreadWait(hListenThread, RT_MS_1MIN / 2, &rcThread), VINF_SUCCESS);
     624        if (RT_SUCCESS(rc))
     625            RTTESTI_CHECK_RC(rcThread, VERR_CANCELLED);
     626
     627        RTTESTI_CHECK_RC(RTLocalIpcServerDestroy(hIpcServer), VINF_SUCCESS);
     628
     629        /*
     630         * Check that client ran successfully.
     631         */
     632        if (pszExecPath)
     633        {
     634            if (hClientProc != NIL_RTPROCESS)
     635            {
     636                RTPROCSTATUS ProcStatus;
     637                RTTESTI_CHECK_RC_OK(rc = RTProcWait(hClientProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus));
     638                if (RT_SUCCESS(rc) && (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0))
     639                    RTTestIFailed("Chiled exited with enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
     640            }
     641        }
     642        else if (hClientThread != NIL_RTTHREAD)
     643        {
     644            RTTESTI_CHECK_RC_OK(rc = RTThreadWait(hClientThread, RT_MS_1MIN / 2, &rcThread));
     645            if (RT_SUCCESS(rc))
     646                RTTESTI_CHECK_RC(rcThread, VINF_SUCCESS);
     647        }
     648    }
     649}
     650
     651
     652/*********************************************************************************************************************************
     653*                                                                                                                                *
     654*   testSessionPerf - Performance measurements.                                                                                  *
     655*                                                                                                                                *
     656*********************************************************************************************************************************/
     657
     658#define IPC_PERF_LAST_MSG   UINT32_C(0x7fffeeee)
     659#define IPC_PERF_MSG_REPLY(uMsg)    ((uMsg) | RT_BIT_32(31))
     660
     661
     662static DECLCALLBACK(int) testSessionPerfThread(RTTHREAD hSelf, void *pvUser)
     663{
     664    RTLOCALIPCSERVER hIpcServer = (RTLOCALIPCSERVER)pvUser;
     665    RTTEST_CHECK_RC_OK_RET(g_hTest, RTTestSetDefault(g_hTest, NULL), rcCheck);
     666
     667    int rc;
     668    for (;;)
     669    {
     670        RTLOCALIPCSESSION hIpcSession;
     671        rc = RTLocalIpcServerListen(hIpcServer, &hIpcSession);
     672        if (RT_SUCCESS(rc))
     673        {
     674            RTTestIPrintf(RTTESTLVL_INFO, "testSessionPerfThread: Got new client connection\n");
     675
     676            /* The server is the initator, so we start sending messages. */
     677            uint64_t cNsElapsed = _4G;
     678            uint64_t nsStart    = RTTimeNanoTS();
     679            uint32_t cMessages  = 0;
     680            for (;; )
     681            {
     682                uint32_t uMsg = cMessages;
     683                RTTESTI_CHECK_RC_BREAK(rc = RTLocalIpcSessionWrite(hIpcSession, &uMsg, sizeof(uMsg)), VINF_SUCCESS);
     684                uMsg = UINT32_MAX;
     685                RTTESTI_CHECK_RC_BREAK(rc = RTLocalIpcSessionRead(hIpcSession, &uMsg, sizeof(uMsg), NULL), VINF_SUCCESS);
     686                if (uMsg == IPC_PERF_MSG_REPLY(cMessages))
     687                { /* likely */ }
     688                else
     689                {
     690                    RTTestIFailed("uMsg=%#x expected %#x", uMsg, IPC_PERF_MSG_REPLY(cMessages));
     691                    rc = VERR_OUT_OF_RANGE;
     692                    break;
     693                }
     694
     695                /* next */
     696                cMessages++;
     697                if (cMessages & _16K)
     698                { /* likely */ }
     699                else
     700                {
     701                    cNsElapsed = RTTimeNanoTS() - nsStart;
     702                    if (cNsElapsed > 2*RT_NS_1SEC_64)
     703                    {
     704                        uint32_t uMsg = IPC_PERF_LAST_MSG;
     705                        RTTESTI_CHECK_RC_BREAK(rc = RTLocalIpcSessionWrite(hIpcSession, &uMsg, sizeof(uMsg)), VINF_SUCCESS);
     706                        break;
     707                    }
     708                }
     709            }
     710            if (RT_SUCCESS(rc))
     711            {
     712                RTThreadSleep(8); /* windows output fudge (purely esthetical) */
     713                RTTestIValue("roundtrip", cNsElapsed / cMessages, RTTESTUNIT_NS_PER_ROUND_TRIP);
     714                RTTestIValue("roundtrips", RT_NS_1SEC / (cNsElapsed / cMessages), RTTESTUNIT_OCCURRENCES_PER_SEC);
     715            }
     716
     717            RTTESTI_CHECK_RC(RTLocalIpcSessionClose(hIpcSession), VINF_SUCCESS);
     718            RTTESTI_CHECK_RC_OK(RTThreadUserSignal(hSelf));
     719        }
     720        else
     721        {
     722            RTTESTI_CHECK_RC(rc, VERR_CANCELLED);
     723            break;
     724        }
     725    }
     726    RTTESTI_CHECK_RC_OK(RTThreadUserSignal(hSelf));
     727    return rc;
     728}
     729
     730
     731/**
     732 * Used both as a thread procedure and child process worker.
     733 */
     734static DECLCALLBACK(int) tstRTLocalIpcSessionPerfChild(RTTHREAD hSelf, void *pvUser)
     735{
     736    RTTEST_CHECK_RC_OK_RET(g_hTest, RTTestSetDefault(g_hTest, NULL), rcCheck);
     737
     738    /*
     739     * Connect.
     740     */
     741    RTLOCALIPCSESSION hClientSession;
     742    RTTESTI_CHECK_RC_RET(RTLocalIpcSessionConnect(&hClientSession, "tstRTLocalIpcSessionPerf", 0 /*fFlags*/),
     743                         VINF_SUCCESS, rcCheck);
     744
     745    /*
     746     * Process messages.  Server does all the timing and stuff.
     747     */
     748    int rc = VINF_SUCCESS;
     749    for (uint32_t cMessages = 0; ; cMessages++)
     750    {
     751        /* Read the next message from the server. */
     752        uint32_t uMsg = UINT32_MAX;
     753        RTTESTI_CHECK_RC_BREAK(rc = RTLocalIpcSessionRead(hClientSession, &uMsg, sizeof(uMsg), NULL), VINF_SUCCESS);
     754        if (uMsg == cMessages)
     755        {
     756            uMsg = IPC_PERF_MSG_REPLY(uMsg);
     757            RTTESTI_CHECK_RC_BREAK(rc = RTLocalIpcSessionWrite(hClientSession, &uMsg, sizeof(uMsg)), VINF_SUCCESS);
     758        }
     759        else if (uMsg == IPC_PERF_LAST_MSG)
     760            break;
     761        else
     762        {
     763            RTTestIFailed("uMsg=%#x expected %#x", uMsg, cMessages);
     764            rc = VERR_OUT_OF_RANGE;
     765            break;
     766        }
     767    }
     768
     769    RTTESTI_CHECK_RC(RTLocalIpcSessionClose(hClientSession), VINF_SUCCESS);
     770    return rc;
     771}
     772
     773
     774/**
     775 * @note This is identical to testSessionWait with a couple of string and
     776 *       function pointers replaced.
     777 */
     778static void testSessionPerf(const char *pszExecPath)
     779{
     780    RTTestISub(!pszExecPath ? "Thread performance" : "Child performance");
     781
     782    /*
     783     * Create the test server.
     784     */
     785    RTLOCALIPCSERVER hIpcServer;
     786    RTTESTI_CHECK_RC_RETV(RTLocalIpcServerCreate(&hIpcServer, "tstRTLocalIpcSessionPerf", RTLOCALIPC_FLAGS_MULTI_SESSION),
     787                          VINF_SUCCESS);
     788
     789    /*
     790     * Create worker thread that listens and processes incoming connections
     791     * until cancelled.
     792     */
     793    int rc;
     794    RTTHREAD hListenThread;
     795    RTTESTI_CHECK_RC_OK(rc = RTThreadCreate(&hListenThread, testSessionPerfThread, hIpcServer, 0 /* Stack */,
     796                                            RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "listen-3"));
     797    if (RT_SUCCESS(rc))
     798    {
     799        /*
     800         * Create a client thread or process.
     801         */
     802        RTPROCESS hClientProc   = NIL_RTPROCESS;
     803        RTTHREAD  hClientThread = NIL_RTTHREAD;
     804        if (pszExecPath)
     805        {
     806            const char *apszArgs[4] = { pszExecPath, "child", "tstRTLocalIpcSessionPerfChild", NULL };
     807            RTTESTI_CHECK_RC_OK(rc = RTProcCreate(pszExecPath, apszArgs, RTENV_DEFAULT, 0 /* fFlags*/, &hClientProc));
     808        }
     809        else
     810            RTTESTI_CHECK_RC_OK(rc = RTThreadCreate(&hClientThread, tstRTLocalIpcSessionPerfChild, g_hTest, 0 /*cbStack*/,
     811                                                    RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "client-2"));
     812
     813        /*
     814         * Wait for the server thread to indicate that it has processed one
     815         * connection, the shut it all down.
     816         */
     817        if (RT_SUCCESS(rc))
     818            RTTESTI_CHECK_RC_OK(RTThreadUserWait(hListenThread, RT_MS_1MIN / 2));
     819
     820        RTTESTI_CHECK_RC(RTLocalIpcServerCancel(hIpcServer), VINF_SUCCESS);
     821        int rcThread;
     822        RTTESTI_CHECK_RC(rc = RTThreadWait(hListenThread, RT_MS_1MIN / 2, &rcThread), VINF_SUCCESS);
     823        if (RT_SUCCESS(rc))
     824            RTTESTI_CHECK_RC(rcThread, VERR_CANCELLED);
     825
     826        RTTESTI_CHECK_RC(RTLocalIpcServerDestroy(hIpcServer), VINF_SUCCESS);
     827
     828        /*
     829         * Check that client ran successfully.
     830         */
     831        if (pszExecPath)
     832        {
     833            if (hClientProc != NIL_RTPROCESS)
     834            {
     835                RTPROCSTATUS ProcStatus;
     836                RTTESTI_CHECK_RC_OK(rc = RTProcWait(hClientProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus));
     837                if (RT_SUCCESS(rc) && (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0))
     838                    RTTestIFailed("Chiled exited with enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
     839            }
     840        }
     841        else if (hClientThread != NIL_RTTHREAD)
     842        {
     843            RTTESTI_CHECK_RC_OK(rc = RTThreadWait(hClientThread, RT_MS_1MIN / 2, &rcThread));
     844            if (RT_SUCCESS(rc))
     845                RTTESTI_CHECK_RC(rcThread, VINF_SUCCESS);
     846        }
     847    }
     848}
     849
     850
    627851int main(int argc, char **argv)
    628852{
    629     if (   argc > 2
    630         && !RTStrICmp(argv[1], "child"))
    631         return mainChild(argc, argv);
    632 
    633     RTTEST hTest;
    634     RTEXITCODE rcExit = RTTestInitAndCreate("tstRTLocalIpc", &hTest);
    635     if (rcExit)
    636         return rcExit;
    637     RTTestBanner(hTest);
    638 
    639     char szExecPath[RTPATH_MAX];
    640     if (!RTProcGetExecutablePath(szExecPath, sizeof(szExecPath)))
    641         RTStrCopy(szExecPath, sizeof(szExecPath), argv[0]);
    642 
    643     bool fMayPanic = RTAssertSetMayPanic(false);
    644     bool fQuiet    = RTAssertSetQuiet(true);
    645     testBasics();
    646     RTAssertSetMayPanic(fMayPanic);
    647     RTAssertSetQuiet(fQuiet);
    648 
    649     if (RTTestErrorCount(hTest) == 0)
    650         testServerListenAndCancel(hTest, szExecPath);
    651     if (RTTestErrorCount(hTest) == 0)
    652         testSessionConnection(hTest, szExecPath);
    653     if (RTTestErrorCount(hTest) == 0)
    654         testSessionWait(hTest, szExecPath);
    655     if (RTTestErrorCount(hTest) == 0)
    656         testSessionData(hTest, szExecPath);
     853    int rc = RTR3InitExe(argc, &argv, 0);
     854    if (RT_FAILURE(rc))
     855        return RTMsgInitFailure(rc);
     856
     857    /*
     858     * Main process.
     859     */
     860    if (argc == 1)
     861    {
     862        rc = RTTestCreate("tstRTLocalIpc", &g_hTest);
     863        if (RT_FAILURE(rc))
     864            return RTEXITCODE_FAILURE;
     865        RTTestBanner(g_hTest);
     866
     867        /* Basics first. */
     868        bool fMayPanic = RTAssertSetMayPanic(false);
     869        bool fQuiet    = RTAssertSetQuiet(true);
     870        testBasics();
     871        RTAssertSetMayPanic(fMayPanic);
     872        RTAssertSetQuiet(fQuiet);
     873
     874        /* Do real tests if the basics are fine. */
     875        char szExecPath[RTPATH_MAX];
     876        if (RTProcGetExecutablePath(szExecPath, sizeof(szExecPath)))
     877        {
     878            if (RTTestErrorCount(g_hTest) == 0)
     879                testSessionConnection(NULL);
     880            if (RTTestErrorCount(g_hTest) == 0)
     881                testSessionConnection(szExecPath);
     882
     883            if (RTTestErrorCount(g_hTest) == 0)
     884                testSessionWait(NULL);
     885            if (RTTestErrorCount(g_hTest) == 0)
     886                testSessionWait(szExecPath);
     887
     888            if (RTTestErrorCount(g_hTest) == 0)
     889                testSessionData(NULL);
     890            if (RTTestErrorCount(g_hTest) == 0)
     891                testSessionData(szExecPath);
     892
     893            if (RTTestErrorCount(g_hTest) == 0)
     894                testSessionPerf(NULL);
     895            if (RTTestErrorCount(g_hTest) == 0)
     896                testSessionPerf(szExecPath);
     897        }
     898        else
     899            RTTestIFailed("RTProcGetExecutablePath failed");
     900    }
     901    /*
     902     * Child process.
     903     */
     904    else if (   argc == 3
     905             && !strcmp(argv[1], "child"))
     906    {
     907        rc = RTTestCreate(argv[2], &g_hTest);
     908        if (RT_FAILURE(rc))
     909            return RTEXITCODE_FAILURE;
     910
     911        if (!strcmp(argv[2], "tstRTLocalIpcSessionConnectionChild"))
     912            tstRTLocalIpcSessionConnectionChild(RTThreadSelf(), g_hTest);
     913        else if (!strcmp(argv[2], "tstRTLocalIpcSessionWaitChild"))
     914            tstRTLocalIpcSessionWaitChild(RTThreadSelf(), g_hTest);
     915        else if (!strcmp(argv[2], "tstRTLocalIpcSessionDataChild"))
     916            tstRTLocalIpcSessionDataChild(RTThreadSelf(), g_hTest);
     917        else if (!strcmp(argv[2], "tstRTLocalIpcSessionPerfChild"))
     918            tstRTLocalIpcSessionPerfChild(RTThreadSelf(), g_hTest);
     919        else
     920            RTTestIFailed("Unknown child function '%s'", argv[2]);
     921    }
     922    /*
     923     * Invalid parameters.
     924     */
     925    else
     926        return RTEXITCODE_SYNTAX;
    657927
    658928    /*
    659929     * Summary.
    660930     */
    661     return RTTestSummaryAndDestroy(hTest);
    662 }
    663 
     931    return RTTestSummaryAndDestroy(g_hTest);
     932}
     933
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