- Timestamp:
- Oct 17, 2015 7:40:40 PM (9 years ago)
- svn:sync-xref-src-repo-rev:
- 103484
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/testcase/tstRTLocalIpc.cpp
r58282 r58289 1 1 /* $Id$ */ 2 2 /** @file 3 * IPRT Testcase - RTLocalIpc .3 * IPRT Testcase - RTLocalIpc API. 4 4 */ 5 5 … … 29 29 * Header Files * 30 30 *********************************************************************************************************************************/ 31 #include <iprt/localipc.h> 32 33 #include <iprt/asm.h> 31 34 #include <iprt/env.h> 32 #include <iprt/ localipc.h>35 #include <iprt/initterm.h> 33 36 #include <iprt/mem.h> 37 #include <iprt/message.h> 34 38 #include <iprt/path.h> 35 39 #include <iprt/process.h> … … 41 45 42 46 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.*/ 51 static RTTEST g_hTest; 52 53 583 54 584 55 static void testBasics(void) … … 625 96 } 626 97 98 99 100 /********************************************************************************************************************************* 101 * * 102 * testSessionConnection - Connecting. * 103 * * 104 *********************************************************************************************************************************/ 105 106 static 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 */ 137 static 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 151 static 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 227 static 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 */ 261 static 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 */ 300 static 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 384 static 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 454 static 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 499 static 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 */ 540 static 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 */ 579 static 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 662 static 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 */ 734 static 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 */ 778 static 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 627 851 int main(int argc, char **argv) 628 852 { 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; 657 927 658 928 /* 659 929 * Summary. 660 930 */ 661 return RTTestSummaryAndDestroy( hTest);662 } 663 931 return RTTestSummaryAndDestroy(g_hTest); 932 } 933
Note:
See TracChangeset
for help on using the changeset viewer.