VirtualBox

source: vbox/trunk/src/VBox/Runtime/testcase/tstRTLocalIpc.cpp@ 58291

Last change on this file since 58291 was 58291, checked in by vboxsync, 9 years ago

tstRTLocalIpc.cpp: Extended the broken pipe test.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 36.5 KB
Line 
1/* $Id: tstRTLocalIpc.cpp 58291 2015-10-17 21:59:59Z vboxsync $ */
2/** @file
3 * IPRT Testcase - RTLocalIpc API.
4 */
5
6/*
7 * Copyright (C) 2013-2015 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include <iprt/localipc.h>
32
33#include <iprt/asm.h>
34#include <iprt/env.h>
35#include <iprt/initterm.h>
36#include <iprt/mem.h>
37#include <iprt/message.h>
38#include <iprt/path.h>
39#include <iprt/process.h>
40#include <iprt/rand.h>
41#include <iprt/string.h>
42#include <iprt/test.h>
43#include <iprt/thread.h>
44#include <iprt/time.h>
45
46
47/*********************************************************************************************************************************
48* Global Variables *
49*********************************************************************************************************************************/
50/** The test instance.*/
51static RTTEST g_hTest;
52
53
54
55static void testBasics(void)
56{
57 RTTestISub("Basics");
58
59 /* Server-side. */
60 RTTESTI_CHECK_RC(RTLocalIpcServerCreate(NULL, NULL, 0), VERR_INVALID_POINTER);
61 RTLOCALIPCSERVER hIpcServer;
62 int rc;
63 RTTESTI_CHECK_RC(rc = RTLocalIpcServerCreate(&hIpcServer, NULL, RTLOCALIPC_FLAGS_MULTI_SESSION), VERR_INVALID_POINTER);
64 if (RT_SUCCESS(rc)) RTLocalIpcServerDestroy(hIpcServer);
65 RTTESTI_CHECK_RC(rc = RTLocalIpcServerCreate(&hIpcServer, "", RTLOCALIPC_FLAGS_MULTI_SESSION), VERR_INVALID_NAME);
66 if (RT_SUCCESS(rc)) RTLocalIpcServerDestroy(hIpcServer);
67 RTTESTI_CHECK_RC(rc = RTLocalIpcServerCreate(&hIpcServer, "BasicTest", 1234 /* Invalid flags */), VERR_INVALID_FLAGS);
68 if (RT_SUCCESS(rc)) RTLocalIpcServerDestroy(hIpcServer);
69
70 RTTESTI_CHECK_RC(RTLocalIpcServerCancel(NULL), VERR_INVALID_HANDLE);
71 RTTESTI_CHECK_RC(RTLocalIpcServerDestroy(NULL), VINF_SUCCESS);
72
73 /* Basic server creation / destruction. */
74 RTTESTI_CHECK_RC_RETV(RTLocalIpcServerCreate(&hIpcServer, "BasicTest", RTLOCALIPC_FLAGS_MULTI_SESSION), VINF_SUCCESS);
75 RTTESTI_CHECK_RC(RTLocalIpcServerCancel(hIpcServer), VINF_SUCCESS);
76 RTTESTI_CHECK_RC(RTLocalIpcServerDestroy(hIpcServer), VINF_OBJECT_DESTROYED);
77
78 /* Client-side (per session). */
79 RTTESTI_CHECK_RC(RTLocalIpcSessionConnect(NULL, NULL, 0), VERR_INVALID_POINTER);
80 RTLOCALIPCSESSION hIpcSession;
81 RTTESTI_CHECK_RC(RTLocalIpcSessionConnect(&hIpcSession, NULL, 0), VERR_INVALID_POINTER);
82 if (RT_SUCCESS(rc)) RTLocalIpcSessionClose(hIpcSession);
83 RTTESTI_CHECK_RC(RTLocalIpcSessionConnect(&hIpcSession, "", 0), VERR_INVALID_NAME);
84 if (RT_SUCCESS(rc)) RTLocalIpcSessionClose(hIpcSession);
85 RTTESTI_CHECK_RC(RTLocalIpcSessionConnect(&hIpcSession, "BasicTest", 1234 /* Invalid flags */), VERR_INVALID_FLAGS);
86 if (RT_SUCCESS(rc)) RTLocalIpcSessionClose(hIpcSession);
87
88 RTTESTI_CHECK_RC(RTLocalIpcSessionCancel(NULL), VERR_INVALID_HANDLE);
89 RTTESTI_CHECK_RC(RTLocalIpcSessionClose(NULL), VINF_SUCCESS);
90
91 /* Basic client creation / destruction. */
92 RTTESTI_CHECK_RC_RETV(rc = RTLocalIpcSessionConnect(&hIpcSession, "BasicTest", 0), VERR_FILE_NOT_FOUND);
93 if (RT_SUCCESS(rc)) RTLocalIpcSessionClose(hIpcSession);
94 RTTESTI_CHECK_RC(RTLocalIpcServerCancel(hIpcServer), VERR_INVALID_HANDLE);
95 RTTESTI_CHECK_RC(RTLocalIpcServerDestroy(hIpcServer), VERR_INVALID_HANDLE);
96}
97
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_OBJECT_DESTROYED);
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_OBJECT_DESTROYED, 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_OBJECT_DESTROYED);
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_OBJECT_DESTROYED);
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 bool fMayPanic = RTAssertSetMayPanic(false);
290 bool fQuiet = RTAssertSetQuiet(true);
291
292 RTTESTI_CHECK_RC(RTLocalIpcSessionWrite(hClientSession, RT_STR_TUPLE("broken")), VERR_BROKEN_PIPE);
293 uint8_t abBuf[4];
294 RTTESTI_CHECK_RC(RTLocalIpcSessionRead(hClientSession, abBuf, sizeof(abBuf), NULL), VERR_BROKEN_PIPE);
295 size_t cbRead = _4M-1;
296 RTTESTI_CHECK_RC(RTLocalIpcSessionRead(hClientSession, abBuf, sizeof(abBuf), &cbRead), VERR_BROKEN_PIPE);
297
298 RTAssertSetMayPanic(fMayPanic);
299 RTAssertSetQuiet(fQuiet);
300 }
301
302 RTTESTI_CHECK_RC(RTLocalIpcSessionClose(hClientSession), VINF_OBJECT_DESTROYED);
303
304 return VINF_SUCCESS;
305}
306
307
308/**
309 * @note This is identical to testSessionData with a couple of string and
310 * function pointers replaced.
311 */
312static void testSessionWait(const char *pszExecPath)
313{
314 RTTestISub(!pszExecPath ? "Wait for data in thread" : "Wait for data in child");
315
316 /*
317 * Create the test server.
318 */
319 RTLOCALIPCSERVER hIpcServer;
320 RTTESTI_CHECK_RC_RETV(RTLocalIpcServerCreate(&hIpcServer, "tstRTLocalIpcSessionWait", RTLOCALIPC_FLAGS_MULTI_SESSION),
321 VINF_SUCCESS);
322
323 /*
324 * Create worker thread that listens and processes incoming connections
325 * until cancelled.
326 */
327 int rc;
328 RTTHREAD hListenThread;
329 RTTESTI_CHECK_RC_OK(rc = RTThreadCreate(&hListenThread, testSessionWaitThread, hIpcServer, 0 /* Stack */,
330 RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "listen-2"));
331 if (RT_SUCCESS(rc))
332 {
333 /*
334 * Create a client process or thread and connects to the server.
335 * It will perform the wait-for-data test.
336 */
337 RTPROCESS hClientProc = NIL_RTPROCESS;
338 RTTHREAD hClientThread = NIL_RTTHREAD;
339 if (pszExecPath)
340 {
341 const char *apszArgs[4] = { pszExecPath, "child", "tstRTLocalIpcSessionWaitChild", NULL };
342 RTTESTI_CHECK_RC_OK(rc = RTProcCreate(pszExecPath, apszArgs, RTENV_DEFAULT, 0 /* fFlags*/, &hClientProc));
343 }
344 else
345 RTTESTI_CHECK_RC_OK(rc = RTThreadCreate(&hClientThread, tstRTLocalIpcSessionWaitChild, g_hTest, 0 /*cbStack*/,
346 RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "client-2"));
347
348 /*
349 * Wait for the server thread to indicate that it has processed one
350 * connection, the shut it all down.
351 */
352 if (RT_SUCCESS(rc))
353 RTTESTI_CHECK_RC_OK(RTThreadUserWait(hListenThread, RT_MS_1MIN / 2));
354
355 RTTESTI_CHECK_RC(RTLocalIpcServerCancel(hIpcServer), VINF_SUCCESS);
356 int rcThread;
357 RTTESTI_CHECK_RC(rc = RTThreadWait(hListenThread, RT_MS_1MIN / 2, &rcThread), VINF_SUCCESS);
358 if (RT_SUCCESS(rc))
359 RTTESTI_CHECK_RC(rcThread, VERR_CANCELLED);
360
361 RTTESTI_CHECK_RC(RTLocalIpcServerDestroy(hIpcServer), VINF_OBJECT_DESTROYED);
362
363 /*
364 * Check that client ran successfully.
365 */
366 if (pszExecPath)
367 {
368 if (hClientProc != NIL_RTPROCESS)
369 {
370 RTPROCSTATUS ProcStatus;
371 RTTESTI_CHECK_RC_OK(rc = RTProcWait(hClientProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus));
372 if (RT_SUCCESS(rc) && (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0))
373 RTTestIFailed("Chiled exited with enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
374 }
375 }
376 else if (hClientThread != NIL_RTTHREAD)
377 {
378 RTTESTI_CHECK_RC_OK(rc = RTThreadWait(hClientThread, RT_MS_1MIN / 2, &rcThread));
379 if (RT_SUCCESS(rc))
380 RTTESTI_CHECK_RC(rcThread, VINF_SUCCESS);
381 }
382 }
383}
384
385
386
387/*********************************************************************************************************************************
388* *
389* testSessionData - Data transfer integrity. *
390* *
391*********************************************************************************************************************************/
392
393/** The max message size. */
394#define MAX_DATA_MSG_SIZE _1M
395
396static int testSessionDataReadMessages(RTLOCALIPCSESSION hIpcSession, uint32_t cRounds)
397{
398 /*
399 * Message scratch buffer. Search message starts with a uint32_t word
400 * that indicates the message length. The remaining words are set to
401 * the message number.
402 */
403 uint32_t *pau32ScratchBuf = (uint32_t *)RTMemAlloc(MAX_DATA_MSG_SIZE);
404 RTTESTI_CHECK_RET(pau32ScratchBuf != NULL, VERR_NO_MEMORY);
405
406 int rc = VINF_SUCCESS;
407 for (uint32_t iRound = 0; iRound < cRounds && rc == VINF_SUCCESS; iRound++)
408 {
409 /* Read the message length. */
410 uint32_t cbMsg;
411 RTTESTI_CHECK_RC_BREAK(rc = RTLocalIpcSessionRead(hIpcSession, &cbMsg, sizeof(cbMsg), NULL), VINF_SUCCESS);
412 if (cbMsg >= sizeof(cbMsg) && cbMsg <= MAX_DATA_MSG_SIZE)
413 {
414 pau32ScratchBuf[0] = cbMsg;
415
416 /* Read the message body. */
417 uint32_t cbLeft = cbMsg - sizeof(uint32_t);
418 uint8_t *pbCur = (uint8_t *)&pau32ScratchBuf[1];
419 while (cbLeft > 0)
420 {
421 uint32_t cbCur = RTRandU32Ex(1, cbLeft + cbLeft / 4);
422 cbCur = RT_MIN(cbCur, cbLeft);
423 if ((iRound % 3) == 1)
424 {
425 size_t cbRead = _1G;
426 RTTESTI_CHECK_RC_BREAK(rc = RTLocalIpcSessionRead(hIpcSession, pbCur, cbCur, &cbRead), VINF_SUCCESS);
427 RTTESTI_CHECK(cbCur >= cbRead);
428 cbCur = (uint32_t)cbRead;
429 }
430 else
431 RTTESTI_CHECK_RC_BREAK(rc = RTLocalIpcSessionRead(hIpcSession, pbCur, cbCur, NULL), VINF_SUCCESS);
432 pbCur += cbCur;
433 cbLeft -= cbCur;
434 }
435
436 /* Check the message body. */
437 if (RT_SUCCESS(rc))
438 {
439 uint32_t offLast = cbMsg & (sizeof(uint32_t) - 1);
440 if (offLast)
441 memcpy((uint8_t *)pau32ScratchBuf + cbMsg, (uint8_t const *)&iRound + offLast, sizeof(uint32_t) - offLast);
442
443 ASMCompilerBarrier(); /* Guard against theoretical alias issues in the above code. */
444
445 uint32_t cWords = RT_ALIGN_32(cbMsg, sizeof(uint32_t)) / sizeof(uint32_t);
446 for (uint32_t iWord = 1; iWord < cWords; iWord++)
447 if (pau32ScratchBuf[iWord] != iRound)
448 {
449 RTTestIFailed("Message body word #%u mismatch: %#x, expected %#x", pau32ScratchBuf[iWord], iRound);
450 break;
451 }
452 }
453 }
454 else
455 {
456 RTTestIFailed("cbMsg=%#x is out of range", cbMsg);
457 rc = VERR_OUT_OF_RANGE;
458 }
459 }
460
461 RTMemFree(pau32ScratchBuf);
462 return rc;
463}
464
465
466static int testSessionDataWriteMessages(RTLOCALIPCSESSION hIpcSession, uint32_t cRounds)
467{
468 /*
469 * Message scratch buffer. Search message starts with a uint32_t word
470 * that indicates the message length. The remaining words are set to
471 * the message number.
472 */
473 uint32_t cbScratchBuf = RTRandU32Ex(64, MAX_DATA_MSG_SIZE);
474 cbScratchBuf = RT_ALIGN_32(cbScratchBuf, sizeof(uint32_t));
475
476 uint32_t *pau32ScratchBuf = (uint32_t *)RTMemAlloc(cbScratchBuf);
477 RTTESTI_CHECK_RET(pau32ScratchBuf != NULL, VERR_NO_MEMORY);
478
479 size_t cbSent = 0;
480 int rc = VINF_SUCCESS;
481 for (uint32_t iRound = 0; iRound < cRounds && rc == VINF_SUCCESS; iRound++)
482 {
483 /* Construct the message. */
484 uint32_t cbMsg = RTRandU32Ex(sizeof(uint32_t), cbScratchBuf);
485 uint32_t cWords = RT_ALIGN_32(cbMsg, sizeof(uint32_t)) / sizeof(uint32_t);
486
487 uint32_t iWord = 0;
488 pau32ScratchBuf[iWord++] = cbMsg;
489 while (iWord < cWords)
490 pau32ScratchBuf[iWord++] = iRound;
491
492 /* Send it. */
493 uint32_t cbLeft = cbMsg;
494 uint8_t const *pbCur = (uint8_t *)pau32ScratchBuf;
495 while (cbLeft > 0)
496 {
497 uint32_t cbCur = RT_MIN(iRound + 1, cbLeft);
498 RTTESTI_CHECK_RC_BREAK(rc = RTLocalIpcSessionWrite(hIpcSession, pbCur, cbCur), VINF_SUCCESS);
499 pbCur += cbCur;
500 cbSent += cbCur;
501 cbLeft -= cbCur;
502 }
503 }
504
505 RTTestIPrintf(RTTESTLVL_ALWAYS, "Sent %'zu bytes over %u rounds.\n", cbSent, cRounds);
506 RTMemFree(pau32ScratchBuf);
507 return rc;
508}
509
510
511static DECLCALLBACK(int) testSessionDataThread(RTTHREAD hSelf, void *pvUser)
512{
513 RTLOCALIPCSERVER hIpcServer = (RTLOCALIPCSERVER)pvUser;
514 RTTEST_CHECK_RC_OK_RET(g_hTest, RTTestSetDefault(g_hTest, NULL), rcCheck);
515
516 int rc;
517 for (;;)
518 {
519 RTLOCALIPCSESSION hIpcSession;
520 rc = RTLocalIpcServerListen(hIpcServer, &hIpcSession);
521 if (RT_SUCCESS(rc))
522 {
523 RTTestIPrintf(RTTESTLVL_INFO, "testSessionDataThread: Got new client connection\n");
524
525 /* The server is the initator. First message sets the number of rounds. */
526 uint32_t cRounds = RTRandU32Ex(32, _1K);
527 RTTESTI_CHECK_RC(rc = RTLocalIpcSessionWrite(hIpcSession, &cRounds, sizeof(cRounds)), VINF_SUCCESS);
528 if (RT_SUCCESS(rc))
529 {
530 rc = testSessionDataWriteMessages(hIpcSession, cRounds);
531 if (RT_SUCCESS(rc))
532 rc = testSessionDataReadMessages(hIpcSession, cRounds);
533 }
534
535 RTTESTI_CHECK_RC(RTLocalIpcSessionClose(hIpcSession), VINF_OBJECT_DESTROYED);
536 RTTESTI_CHECK_RC_OK(RTThreadUserSignal(hSelf));
537 }
538 else
539 {
540 RTTESTI_CHECK_RC(rc, VERR_CANCELLED);
541 break;
542 }
543 }
544 RTTESTI_CHECK_RC_OK(RTThreadUserSignal(hSelf));
545 return rc;
546}
547
548
549/**
550 * Used both as a thread procedure and child process worker.
551 */
552static DECLCALLBACK(int) tstRTLocalIpcSessionDataChild(RTTHREAD hSelf, void *pvUser)
553{
554 RTTEST_CHECK_RC_OK_RET(g_hTest, RTTestSetDefault(g_hTest, NULL), rcCheck);
555
556 /*
557 * Connect.
558 */
559 RTLOCALIPCSESSION hClientSession;
560 RTTESTI_CHECK_RC_RET(RTLocalIpcSessionConnect(&hClientSession, "tstRTLocalIpcSessionData", 0 /*fFlags*/),
561 VINF_SUCCESS, rcCheck);
562
563 /*
564 * The server first sends us a rounds count.
565 */
566 int rc;
567 uint32_t cRounds = 0;
568 RTTESTI_CHECK_RC(rc = RTLocalIpcSessionRead(hClientSession, &cRounds, sizeof(cRounds), NULL), VINF_SUCCESS);
569 if (RT_SUCCESS(rc))
570 {
571 if (cRounds >= 32 && cRounds <= _1K)
572 {
573 rc = testSessionDataReadMessages(hClientSession, cRounds);
574 if (RT_SUCCESS(rc))
575 rc = testSessionDataWriteMessages(hClientSession, cRounds);
576 }
577 else
578 RTTestIFailed("cRounds=%#x is out of range", cRounds);
579 }
580
581 RTTESTI_CHECK_RC(RTLocalIpcSessionClose(hClientSession), VINF_OBJECT_DESTROYED);
582
583 return rc;
584}
585
586
587/**
588 * @note This is identical to testSessionWait with a couple of string and
589 * function pointers replaced.
590 */
591static void testSessionData(const char *pszExecPath)
592{
593 RTTestISub(!pszExecPath ? "Data exchange with thread" : "Data exchange with child");
594
595 /*
596 * Create the test server.
597 */
598 RTLOCALIPCSERVER hIpcServer;
599 RTTESTI_CHECK_RC_RETV(RTLocalIpcServerCreate(&hIpcServer, "tstRTLocalIpcSessionData", RTLOCALIPC_FLAGS_MULTI_SESSION),
600 VINF_SUCCESS);
601
602 /*
603 * Create worker thread that listens and processes incoming connections
604 * until cancelled.
605 */
606 int rc;
607 RTTHREAD hListenThread;
608 RTTESTI_CHECK_RC_OK(rc = RTThreadCreate(&hListenThread, testSessionDataThread, hIpcServer, 0 /* Stack */,
609 RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "listen-3"));
610 if (RT_SUCCESS(rc))
611 {
612 /*
613 * Create a client thread or process.
614 */
615 RTPROCESS hClientProc = NIL_RTPROCESS;
616 RTTHREAD hClientThread = NIL_RTTHREAD;
617 if (pszExecPath)
618 {
619 const char *apszArgs[4] = { pszExecPath, "child", "tstRTLocalIpcSessionDataChild", NULL };
620 RTTESTI_CHECK_RC_OK(rc = RTProcCreate(pszExecPath, apszArgs, RTENV_DEFAULT, 0 /* fFlags*/, &hClientProc));
621 }
622 else
623 RTTESTI_CHECK_RC_OK(rc = RTThreadCreate(&hClientThread, tstRTLocalIpcSessionDataChild, g_hTest, 0 /*cbStack*/,
624 RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "client-2"));
625
626 /*
627 * Wait for the server thread to indicate that it has processed one
628 * connection, the shut it all down.
629 */
630 if (RT_SUCCESS(rc))
631 RTTESTI_CHECK_RC_OK(RTThreadUserWait(hListenThread, RT_MS_1MIN / 2));
632
633 RTTESTI_CHECK_RC(RTLocalIpcServerCancel(hIpcServer), VINF_SUCCESS);
634 int rcThread;
635 RTTESTI_CHECK_RC(rc = RTThreadWait(hListenThread, RT_MS_1MIN / 2, &rcThread), VINF_SUCCESS);
636 if (RT_SUCCESS(rc))
637 RTTESTI_CHECK_RC(rcThread, VERR_CANCELLED);
638
639 RTTESTI_CHECK_RC(RTLocalIpcServerDestroy(hIpcServer), VINF_OBJECT_DESTROYED);
640
641 /*
642 * Check that client ran successfully.
643 */
644 if (pszExecPath)
645 {
646 if (hClientProc != NIL_RTPROCESS)
647 {
648 RTPROCSTATUS ProcStatus;
649 RTTESTI_CHECK_RC_OK(rc = RTProcWait(hClientProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus));
650 if (RT_SUCCESS(rc) && (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0))
651 RTTestIFailed("Chiled exited with enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
652 }
653 }
654 else if (hClientThread != NIL_RTTHREAD)
655 {
656 RTTESTI_CHECK_RC_OK(rc = RTThreadWait(hClientThread, RT_MS_1MIN / 2, &rcThread));
657 if (RT_SUCCESS(rc))
658 RTTESTI_CHECK_RC(rcThread, VINF_SUCCESS);
659 }
660 }
661}
662
663
664/*********************************************************************************************************************************
665* *
666* testSessionPerf - Performance measurements. *
667* *
668*********************************************************************************************************************************/
669
670#define IPC_PERF_LAST_MSG UINT32_C(0x7fffeeee)
671#define IPC_PERF_MSG_REPLY(uMsg) ((uMsg) | RT_BIT_32(31))
672
673
674static DECLCALLBACK(int) testSessionPerfThread(RTTHREAD hSelf, void *pvUser)
675{
676 RTLOCALIPCSERVER hIpcServer = (RTLOCALIPCSERVER)pvUser;
677 RTTEST_CHECK_RC_OK_RET(g_hTest, RTTestSetDefault(g_hTest, NULL), rcCheck);
678
679 int rc;
680 for (;;)
681 {
682 RTLOCALIPCSESSION hIpcSession;
683 rc = RTLocalIpcServerListen(hIpcServer, &hIpcSession);
684 if (RT_SUCCESS(rc))
685 {
686 RTTestIPrintf(RTTESTLVL_INFO, "testSessionPerfThread: Got new client connection\n");
687
688 /* The server is the initator, so we start sending messages. */
689 uint64_t cNsElapsed = _4G;
690 uint64_t nsStart = RTTimeNanoTS();
691 uint32_t cMessages = 0;
692 for (;; )
693 {
694 uint32_t uMsg = cMessages;
695 RTTESTI_CHECK_RC_BREAK(rc = RTLocalIpcSessionWrite(hIpcSession, &uMsg, sizeof(uMsg)), VINF_SUCCESS);
696 uMsg = UINT32_MAX;
697 RTTESTI_CHECK_RC_BREAK(rc = RTLocalIpcSessionRead(hIpcSession, &uMsg, sizeof(uMsg), NULL), VINF_SUCCESS);
698 if (uMsg == IPC_PERF_MSG_REPLY(cMessages))
699 { /* likely */ }
700 else
701 {
702 RTTestIFailed("uMsg=%#x expected %#x", uMsg, IPC_PERF_MSG_REPLY(cMessages));
703 rc = VERR_OUT_OF_RANGE;
704 break;
705 }
706
707 /* next */
708 cMessages++;
709 if (cMessages & _16K)
710 { /* likely */ }
711 else
712 {
713 cNsElapsed = RTTimeNanoTS() - nsStart;
714 if (cNsElapsed > 2*RT_NS_1SEC_64)
715 {
716 uMsg = IPC_PERF_LAST_MSG;
717 RTTESTI_CHECK_RC_BREAK(rc = RTLocalIpcSessionWrite(hIpcSession, &uMsg, sizeof(uMsg)), VINF_SUCCESS);
718 break;
719 }
720 }
721 }
722 if (RT_SUCCESS(rc))
723 {
724 RTThreadSleep(8); /* windows output fudge (purely esthetical) */
725 RTTestIValue("roundtrip", cNsElapsed / cMessages, RTTESTUNIT_NS_PER_ROUND_TRIP);
726 RTTestIValue("roundtrips", RT_NS_1SEC / (cNsElapsed / cMessages), RTTESTUNIT_OCCURRENCES_PER_SEC);
727 }
728
729 RTTESTI_CHECK_RC(RTLocalIpcSessionClose(hIpcSession), VINF_OBJECT_DESTROYED);
730 RTTESTI_CHECK_RC_OK(RTThreadUserSignal(hSelf));
731 }
732 else
733 {
734 RTTESTI_CHECK_RC(rc, VERR_CANCELLED);
735 break;
736 }
737 }
738 RTTESTI_CHECK_RC_OK(RTThreadUserSignal(hSelf));
739 return rc;
740}
741
742
743/**
744 * Used both as a thread procedure and child process worker.
745 */
746static DECLCALLBACK(int) tstRTLocalIpcSessionPerfChild(RTTHREAD hSelf, void *pvUser)
747{
748 RTTEST_CHECK_RC_OK_RET(g_hTest, RTTestSetDefault(g_hTest, NULL), rcCheck);
749
750 /*
751 * Connect.
752 */
753 RTLOCALIPCSESSION hClientSession;
754 RTTESTI_CHECK_RC_RET(RTLocalIpcSessionConnect(&hClientSession, "tstRTLocalIpcSessionPerf", 0 /*fFlags*/),
755 VINF_SUCCESS, rcCheck);
756
757 /*
758 * Process messages. Server does all the timing and stuff.
759 */
760 int rc = VINF_SUCCESS;
761 for (uint32_t cMessages = 0; ; cMessages++)
762 {
763 /* Read the next message from the server. */
764 uint32_t uMsg = UINT32_MAX;
765 RTTESTI_CHECK_RC_BREAK(rc = RTLocalIpcSessionRead(hClientSession, &uMsg, sizeof(uMsg), NULL), VINF_SUCCESS);
766 if (uMsg == cMessages)
767 {
768 uMsg = IPC_PERF_MSG_REPLY(uMsg);
769 RTTESTI_CHECK_RC_BREAK(rc = RTLocalIpcSessionWrite(hClientSession, &uMsg, sizeof(uMsg)), VINF_SUCCESS);
770 }
771 else if (uMsg == IPC_PERF_LAST_MSG)
772 break;
773 else
774 {
775 RTTestIFailed("uMsg=%#x expected %#x", uMsg, cMessages);
776 rc = VERR_OUT_OF_RANGE;
777 break;
778 }
779 }
780
781 RTTESTI_CHECK_RC(RTLocalIpcSessionClose(hClientSession), VINF_OBJECT_DESTROYED);
782 return rc;
783}
784
785
786/**
787 * @note This is identical to testSessionWait with a couple of string and
788 * function pointers replaced.
789 */
790static void testSessionPerf(const char *pszExecPath)
791{
792 RTTestISub(!pszExecPath ? "Thread performance" : "Child performance");
793
794 /*
795 * Create the test server.
796 */
797 RTLOCALIPCSERVER hIpcServer;
798 RTTESTI_CHECK_RC_RETV(RTLocalIpcServerCreate(&hIpcServer, "tstRTLocalIpcSessionPerf", RTLOCALIPC_FLAGS_MULTI_SESSION),
799 VINF_SUCCESS);
800
801 /*
802 * Create worker thread that listens and processes incoming connections
803 * until cancelled.
804 */
805 int rc;
806 RTTHREAD hListenThread;
807 RTTESTI_CHECK_RC_OK(rc = RTThreadCreate(&hListenThread, testSessionPerfThread, hIpcServer, 0 /* Stack */,
808 RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "listen-3"));
809 if (RT_SUCCESS(rc))
810 {
811 /*
812 * Create a client thread or process.
813 */
814 RTPROCESS hClientProc = NIL_RTPROCESS;
815 RTTHREAD hClientThread = NIL_RTTHREAD;
816 if (pszExecPath)
817 {
818 const char *apszArgs[4] = { pszExecPath, "child", "tstRTLocalIpcSessionPerfChild", NULL };
819 RTTESTI_CHECK_RC_OK(rc = RTProcCreate(pszExecPath, apszArgs, RTENV_DEFAULT, 0 /* fFlags*/, &hClientProc));
820 }
821 else
822 RTTESTI_CHECK_RC_OK(rc = RTThreadCreate(&hClientThread, tstRTLocalIpcSessionPerfChild, g_hTest, 0 /*cbStack*/,
823 RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "client-2"));
824
825 /*
826 * Wait for the server thread to indicate that it has processed one
827 * connection, the shut it all down.
828 */
829 if (RT_SUCCESS(rc))
830 RTTESTI_CHECK_RC_OK(RTThreadUserWait(hListenThread, RT_MS_1MIN / 2));
831
832 RTTESTI_CHECK_RC(RTLocalIpcServerCancel(hIpcServer), VINF_SUCCESS);
833 int rcThread;
834 RTTESTI_CHECK_RC(rc = RTThreadWait(hListenThread, RT_MS_1MIN / 2, &rcThread), VINF_SUCCESS);
835 if (RT_SUCCESS(rc))
836 RTTESTI_CHECK_RC(rcThread, VERR_CANCELLED);
837
838 RTTESTI_CHECK_RC(RTLocalIpcServerDestroy(hIpcServer), VINF_OBJECT_DESTROYED);
839
840 /*
841 * Check that client ran successfully.
842 */
843 if (pszExecPath)
844 {
845 if (hClientProc != NIL_RTPROCESS)
846 {
847 RTPROCSTATUS ProcStatus;
848 RTTESTI_CHECK_RC_OK(rc = RTProcWait(hClientProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus));
849 if (RT_SUCCESS(rc) && (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0))
850 RTTestIFailed("Chiled exited with enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
851 }
852 }
853 else if (hClientThread != NIL_RTTHREAD)
854 {
855 RTTESTI_CHECK_RC_OK(rc = RTThreadWait(hClientThread, RT_MS_1MIN / 2, &rcThread));
856 if (RT_SUCCESS(rc))
857 RTTESTI_CHECK_RC(rcThread, VINF_SUCCESS);
858 }
859 }
860}
861
862
863int main(int argc, char **argv)
864{
865 int rc = RTR3InitExe(argc, &argv, 0);
866 if (RT_FAILURE(rc))
867 return RTMsgInitFailure(rc);
868
869 /*
870 * Main process.
871 */
872 if (argc == 1)
873 {
874 rc = RTTestCreate("tstRTLocalIpc", &g_hTest);
875 if (RT_FAILURE(rc))
876 return RTEXITCODE_FAILURE;
877 RTTestBanner(g_hTest);
878
879 /* Basics first. */
880 bool fMayPanic = RTAssertSetMayPanic(false);
881 bool fQuiet = RTAssertSetQuiet(true);
882 testBasics();
883 RTAssertSetMayPanic(fMayPanic);
884 RTAssertSetQuiet(fQuiet);
885
886 /* Do real tests if the basics are fine. */
887 char szExecPath[RTPATH_MAX];
888 if (RTProcGetExecutablePath(szExecPath, sizeof(szExecPath)))
889 {
890 if (RTTestErrorCount(g_hTest) == 0)
891 testSessionConnection(NULL);
892 if (RTTestErrorCount(g_hTest) == 0)
893 testSessionConnection(szExecPath);
894
895 if (RTTestErrorCount(g_hTest) == 0)
896 testSessionWait(NULL);
897 if (RTTestErrorCount(g_hTest) == 0)
898 testSessionWait(szExecPath);
899
900 if (RTTestErrorCount(g_hTest) == 0)
901 testSessionData(NULL);
902 if (RTTestErrorCount(g_hTest) == 0)
903 testSessionData(szExecPath);
904
905 if (RTTestErrorCount(g_hTest) == 0)
906 testSessionPerf(NULL);
907 if (RTTestErrorCount(g_hTest) == 0)
908 testSessionPerf(szExecPath);
909 }
910 else
911 RTTestIFailed("RTProcGetExecutablePath failed");
912 }
913 /*
914 * Child process.
915 */
916 else if ( argc == 3
917 && !strcmp(argv[1], "child"))
918 {
919 rc = RTTestCreate(argv[2], &g_hTest);
920 if (RT_FAILURE(rc))
921 return RTEXITCODE_FAILURE;
922
923 if (!strcmp(argv[2], "tstRTLocalIpcSessionConnectionChild"))
924 tstRTLocalIpcSessionConnectionChild(RTThreadSelf(), g_hTest);
925 else if (!strcmp(argv[2], "tstRTLocalIpcSessionWaitChild"))
926 tstRTLocalIpcSessionWaitChild(RTThreadSelf(), g_hTest);
927 else if (!strcmp(argv[2], "tstRTLocalIpcSessionDataChild"))
928 tstRTLocalIpcSessionDataChild(RTThreadSelf(), g_hTest);
929 else if (!strcmp(argv[2], "tstRTLocalIpcSessionPerfChild"))
930 tstRTLocalIpcSessionPerfChild(RTThreadSelf(), g_hTest);
931 else
932 RTTestIFailed("Unknown child function '%s'", argv[2]);
933 }
934 /*
935 * Invalid parameters.
936 */
937 else
938 return RTEXITCODE_SYNTAX;
939
940 /*
941 * Summary.
942 */
943 return RTTestSummaryAndDestroy(g_hTest);
944}
945
Note: See TracBrowser for help on using the repository browser.

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