VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/testcase/tstIntNetR0.cpp@ 27339

Last change on this file since 27339 was 26574, checked in by vboxsync, 15 years ago

Networking: Preparing to make the driver return a send buffer to the device emulation.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 28.6 KB
Line 
1/* $Id: tstIntNetR0.cpp 26574 2010-02-16 12:44:10Z vboxsync $ */
2/** @file
3 * Internal networking - Usermode testcase for the kernel mode bits.
4 *
5 * This is a bit hackish as we're mixing context here, however it is
6 * very useful when making changes to the internal networking service.
7 */
8
9/*
10 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
11 *
12 * This file is part of VirtualBox Open Source Edition (OSE), as
13 * available from http://www.virtualbox.org. This file is free software;
14 * you can redistribute it and/or modify it under the terms of the GNU
15 * General Public License (GPL) as published by the Free Software
16 * Foundation, in version 2 as it comes in the "COPYING" file of the
17 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
18 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
19 *
20 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
21 * Clara, CA 95054 USA or visit http://www.sun.com if you need
22 * additional information or have any questions.
23 */
24
25
26/*******************************************************************************
27* Header Files *
28*******************************************************************************/
29#define RTMEM_WRAP_TO_EF_APIS // debugging debugging remove
30#define INTNET_POISON_READ_FRAMES // debugging debugging remove
31#define IN_INTNET_TESTCASE
32#define IN_INTNET_R3
33#include <VBox/cdefs.h>
34#undef INTNETR0DECL
35#define INTNETR0DECL INTNETR3DECL
36#undef DECLR0CALLBACKMEMBER
37#define DECLR0CALLBACKMEMBER(type, name, args) DECLR3CALLBACKMEMBER(type, name, args)
38#include <VBox/types.h>
39typedef void *MYPSUPDRVSESSION;
40#define PSUPDRVSESSION MYPSUPDRVSESSION
41
42#include <VBox/intnet.h>
43#include <VBox/sup.h>
44#include <VBox/err.h>
45#include <iprt/stream.h>
46#include <iprt/alloc.h>
47#include <iprt/initterm.h>
48#include <iprt/thread.h>
49#include <iprt/time.h>
50#include <iprt/asm.h>
51#include <iprt/getopt.h>
52
53
54/*******************************************************************************
55* Structures and Typedefs *
56*******************************************************************************/
57/**
58 * Security objectype.
59 */
60typedef enum SUPDRVOBJTYPE
61{
62 /** The usual invalid object. */
63 SUPDRVOBJTYPE_INVALID = 0,
64 /** Internal network. */
65 SUPDRVOBJTYPE_INTERNAL_NETWORK,
66 /** Internal network interface. */
67 SUPDRVOBJTYPE_INTERNAL_NETWORK_INTERFACE,
68 /** The first invalid object type in this end. */
69 SUPDRVOBJTYPE_END,
70 /** The usual 32-bit type size hack. */
71 SUPDRVOBJTYPE_32_BIT_HACK = 0x7ffffff
72} SUPDRVOBJTYPE;
73
74/**
75 * Object destructor callback.
76 * This is called for reference counted objectes when the count reaches 0.
77 *
78 * @param pvObj The object pointer.
79 * @param pvUser1 The first user argument.
80 * @param pvUser2 The second user argument.
81 */
82typedef DECLCALLBACK(void) FNSUPDRVDESTRUCTOR(void *pvObj, void *pvUser1, void *pvUser2);
83/** Pointer to a FNSUPDRVDESTRUCTOR(). */
84typedef FNSUPDRVDESTRUCTOR *PFNSUPDRVDESTRUCTOR;
85
86
87/**
88 * Dummy
89 */
90typedef struct OBJREF
91{
92 PFNSUPDRVDESTRUCTOR pfnDestructor;
93 void *pvUser1;
94 void *pvUser2;
95 uint32_t volatile cRefs;
96} OBJREF, *POBJREF;
97
98
99/*******************************************************************************
100* Global Variables *
101*******************************************************************************/
102/** The error count. */
103unsigned g_cErrors = 0;
104
105/** Fake session handle. */
106const PSUPDRVSESSION g_pSession = (PSUPDRVSESSION)0xdeadface;
107
108/** Testframe 0 */
109struct TESTFRAME
110{
111 uint16_t au16[7];
112} g_TestFrame0 = { { /* dst:*/ 0xffff, 0xffff, 0xffff, /*src:*/0x8086, 0, 0, 0x0800 } },
113 g_TestFrame1 = { { /* dst:*/ 0, 0, 0, /*src:*/0x8086, 0, 1, 0x0800 } };
114
115
116INTNETR3DECL(void *) SUPR0ObjRegister(PSUPDRVSESSION pSession, SUPDRVOBJTYPE enmType, PFNSUPDRVDESTRUCTOR pfnDestructor, void *pvUser1, void *pvUser2)
117{
118 if (pSession != g_pSession)
119 {
120 RTPrintf("tstIntNetR0: Invalid session pointer %p, %s!\n", pSession, __FUNCTION__);
121 g_cErrors++;
122 return NULL;
123 }
124 POBJREF pRef = (POBJREF)RTMemAlloc(sizeof(OBJREF));
125 if (!pRef)
126 return NULL;
127 pRef->cRefs = 1;
128 pRef->pfnDestructor = pfnDestructor;
129 pRef->pvUser1 = pvUser1;
130 pRef->pvUser2 = pvUser2;
131 return pRef;
132}
133
134INTNETR3DECL(int) SUPR0ObjAddRefEx(void *pvObj, PSUPDRVSESSION pSession, bool fNoBlocking)
135{
136 if (pSession != g_pSession)
137 {
138 RTPrintf("tstIntNetR0: Invalid session pointer %p, %s!\n", pSession, __FUNCTION__);
139 g_cErrors++;
140 return VERR_INVALID_PARAMETER;
141 }
142 POBJREF pRef = (POBJREF)pvObj;
143 ASMAtomicIncU32(&pRef->cRefs);
144 return VINF_SUCCESS;
145}
146
147INTNETR3DECL(int) SUPR0ObjAddRef(void *pvObj, PSUPDRVSESSION pSession)
148{
149 return SUPR0ObjAddRefEx(pvObj, pSession, false);
150}
151
152INTNETR3DECL(int) SUPR0ObjRelease(void *pvObj, PSUPDRVSESSION pSession)
153{
154 if (pSession != g_pSession)
155 {
156 RTPrintf("tstIntNetR0: Invalid session pointer %p, %s!\n", pSession, __FUNCTION__);
157 g_cErrors++;
158 return VERR_INVALID_PARAMETER;
159 }
160 POBJREF pRef = (POBJREF)pvObj;
161 if (!ASMAtomicDecU32(&pRef->cRefs))
162 {
163 pRef->pfnDestructor(pRef, pRef->pvUser1, pRef->pvUser2);
164 RTMemFree(pRef);
165 return VINF_OBJECT_DESTROYED;
166 }
167 return VINF_SUCCESS;
168}
169
170INTNETR3DECL(int) SUPR0ObjVerifyAccess(void *pvObj, PSUPDRVSESSION pSession, const char *pszObjName)
171{
172 if (pSession != g_pSession)
173 {
174 RTPrintf("tstIntNetR0: Invalid session pointer %p, %s!\n", pSession, __FUNCTION__);
175 g_cErrors++;
176 return VERR_INVALID_PARAMETER;
177 }
178 return VINF_SUCCESS;
179}
180
181INTNETR3DECL(int) SUPR0MemAlloc(PSUPDRVSESSION pSession, uint32_t cb, PRTR0PTR ppvR0, PRTR3PTR ppvR3)
182{
183 if (pSession != g_pSession)
184 {
185 RTPrintf("tstIntNetR0: Invalid session pointer %p, %s!\n", pSession, __FUNCTION__);
186 g_cErrors++;
187 return VERR_INVALID_PARAMETER;
188 }
189 void *pv = RTMemAlloc(cb);
190 if (!pv)
191 return VERR_NO_MEMORY;
192 *ppvR0 = (RTR0PTR)pv;
193 if (ppvR3)
194 *ppvR3 = pv;
195 return VINF_SUCCESS;
196}
197
198INTNETR3DECL(int) SUPR0MemFree(PSUPDRVSESSION pSession, RTHCUINTPTR uPtr)
199{
200 if (pSession != g_pSession)
201 {
202 RTPrintf("tstIntNetR0: Invalid session pointer %p, %s!\n", pSession, __FUNCTION__);
203 g_cErrors++;
204 return VERR_INVALID_PARAMETER;
205 }
206 RTMemFree((void *)uPtr);
207 return VINF_SUCCESS;
208}
209
210
211
212/* ugly but necessary for making R0 code compilable for R3. */
213#undef LOG_GROUP
214#include "../SrvIntNetR0.cpp"
215
216typedef struct MYARGS
217{
218 PINTNET pIntNet;
219 PINTNETBUF pBuf;
220 INTNETIFHANDLE hIf;
221 RTMAC Mac;
222 uint64_t u64Start;
223 uint64_t u64End;
224} MYARGS, *PMYARGS;
225
226
227#define TEST_TRANSFER_SIZE (_1M*384)
228
229/**
230 * Send thread.
231 * This is constantly broadcasting frames to the network.
232 */
233DECLCALLBACK(int) SendThread(RTTHREAD Thread, void *pvArg)
234{
235 PMYARGS pArgs = (PMYARGS)pvArg;
236
237 /*
238 * Send 64 MB of data.
239 */
240 uint8_t abBuf[4096] = {0};
241 PRTMAC pMacSrc = (PRTMAC)&abBuf[0];
242 PRTMAC pMacDst = pMacSrc + 1;
243 *pMacSrc = pArgs->Mac;
244 *pMacDst = pArgs->Mac;
245 pMacDst->au16[2] = pArgs->Mac.au16[2] ? 0 : 1;
246 unsigned *puFrame = (unsigned *)(pMacDst + 1);
247 unsigned iFrame = 0;
248 uint32_t cbSent = 0;
249 uint32_t cSend = 0;
250 pArgs->u64Start = RTTimeNanoTS();
251 for (; cbSent < TEST_TRANSFER_SIZE; iFrame++)
252 {
253 const unsigned cb = iFrame % 1519 + 12 + sizeof(unsigned);
254 *puFrame = iFrame;
255#if 0
256 int rc = INTNETR0IfSend(pArgs->pIntNet, pArgs->hIf, g_pSession, abBuf, cb);
257#else
258 INTNETSG Sg;
259 intnetR0SgInitTemp(&Sg, abBuf, cb);
260 int rc = intnetR0RingWriteFrame(&pArgs->pBuf->Send, &Sg, NULL);
261 if (RT_SUCCESS(rc))
262 rc = INTNETR0IfSend(pArgs->pIntNet, pArgs->hIf, g_pSession, NULL, 0);
263#endif
264 if (RT_FAILURE(rc))
265 {
266 g_cErrors++;
267 RTPrintf("tstIntNetR0: Failed sending %d bytes, rc=%Rrc (%d)\n", cb, rc, INTNETRingGetWritable(&pArgs->pBuf->Send));
268 }
269 cbSent += cb;
270 }
271
272 /*
273 * Termination frames.
274 */
275 puFrame[0] = 0xffffdead;
276 puFrame[1] = 0xffffdead;
277 puFrame[2] = 0xffffdead;
278 puFrame[3] = 0xffffdead;
279 for (unsigned c = 0; c < 20; c++)
280 {
281 int rc = INTNETR0IfSend(pArgs->pIntNet, pArgs->hIf, g_pSession, abBuf, sizeof(RTMAC) * 2 + sizeof(unsigned) * 4);
282 if (RT_FAILURE(rc))
283 {
284 g_cErrors++;
285 RTPrintf("tstIntNetR0: send failed, rc=%Rrc\n", rc);
286 }
287 RTThreadSleep(1);
288 }
289
290 RTPrintf("tstIntNetR0: sender thread %.6Rhxs terminating.\n"
291 "tstIntNetR0: iFrame=%u cb=%'u\n",
292 &pArgs->Mac, iFrame, cbSent);
293 return 0;
294}
295
296
297/** Ignore lost frames. It only makes things worse to bitch about it. */
298#define IGNORE_LOST_FRAMES
299
300/**
301 * Receive thread.
302 * This is reading stuff from the network.
303 */
304DECLCALLBACK(int) ReceiveThread(RTTHREAD Thread, void *pvArg)
305{
306 uint32_t cbReceived = 0;
307 uint32_t cLostFrames = 0;
308 uint32_t iFrame = UINT32_MAX;
309 PMYARGS pArgs = (PMYARGS)pvArg;
310 for (;;)
311 {
312 /*
313 * Wait for data.
314 */
315 int rc = INTNETR0IfWait(pArgs->pIntNet, pArgs->hIf, g_pSession, RT_INDEFINITE_WAIT);
316 switch (rc)
317 {
318 case VERR_INTERRUPTED:
319 case VINF_SUCCESS:
320 break;
321 case VERR_SEM_DESTROYED:
322 RTPrintf("tstIntNetR0: receiver thread %.6Rhxs terminating. iFrame=%u cb=%'u c=%'u cLost=%'u\n",
323 &pArgs->Mac, iFrame, cbReceived, iFrame - cLostFrames, cLostFrames);
324 return VINF_SUCCESS;
325
326 default:
327 RTPrintf("tstIntNetR0: receiver thread %.6Rhxs got odd return value %Rrc! iFrame=%u cb=%'u c=%'u cLost=%'u\n",
328 &pArgs->Mac, rc, iFrame, cbReceived, iFrame - cLostFrames, cLostFrames);
329 g_cErrors++;
330 return rc;
331 }
332
333 /*
334 * Read data.
335 */
336 while (INTNETRingHasMoreToRead(&pArgs->pBuf->Recv))
337 {
338 uint8_t abBuf[16384];
339 uint32_t cb = INTNETRingReadAndSkipFrame(&pArgs->pBuf->Recv, abBuf);
340 unsigned *puFrame = (unsigned *)&abBuf[sizeof(RTMAC) * 2];
341
342 /* check for termination frame. */
343 if ( cb == sizeof(RTMAC) * 2 + sizeof(unsigned) * 4
344 && puFrame[0] == 0xffffdead
345 && puFrame[1] == 0xffffdead
346 && puFrame[2] == 0xffffdead
347 && puFrame[3] == 0xffffdead)
348 {
349 pArgs->u64End = RTTimeNanoTS();
350 RTPrintf("tstIntNetR0: receiver thread %.6Rhxs terminating.\n"
351 "tstIntNetR0: iFrame=%u cb=%'u c=%'u %'uKB/s %'ufps cLost=%'u \n",
352 &pArgs->Mac, iFrame, cbReceived, iFrame - cLostFrames,
353 (unsigned)(cbReceived * 1000000000.0 / 1024 / (pArgs->u64End - pArgs->u64Start)),
354 (unsigned)((iFrame - cLostFrames) * 1000000000.0 / (pArgs->u64End - pArgs->u64Start)),
355 cLostFrames);
356 return VINF_SUCCESS;
357 }
358
359 /* validate frame header */
360 PRTMAC pMacSrc = (PRTMAC)&abBuf[0];
361 PRTMAC pMacDst = pMacSrc + 1;
362 if ( pMacDst->au16[0] != 0x8086
363 || pMacDst->au16[1] != 0
364 || pMacDst->au16[2] != pArgs->Mac.au16[2]
365 || pMacSrc->au16[0] != 0x8086
366 || pMacSrc->au16[1] != 0
367 || pMacSrc->au16[2] == pArgs->Mac.au16[2])
368 {
369 RTPrintf("tstIntNetR0: receiver thread %.6Rhxs received frame header: %.16Rhxs\n",
370 &pArgs->Mac, abBuf);
371 g_cErrors++;
372 }
373
374 /* frame stuff and stats. */
375 int off = iFrame + 1 - *puFrame;
376 if (off)
377 {
378 if (off > 0)
379 {
380 RTPrintf("tstIntNetR0: receiver thread %.6Rhxs: iFrame=%d *puFrame=%d off=%d\n",
381 &pArgs->Mac, iFrame, *puFrame, off);
382 g_cErrors++;
383 cLostFrames++;
384 }
385 else
386 {
387 cLostFrames += -off;
388#ifndef IGNORE_LOST_FRAMES
389 if (off < 50)
390 {
391 RTPrintf("tstIntNetR0: receiver thread %.6Rhxs: iFrame=%d *puFrame=%d off=%d\n",
392 &pArgs->Mac, iFrame, *puFrame, off);
393 g_cErrors++;
394 }
395#endif
396 }
397 }
398 iFrame = *puFrame;
399 cbReceived += cb;
400 }
401 }
402}
403
404int main(int argc, char **argv)
405{
406 /*
407 * Init the runtime and parse arguments.
408 */
409 RTR3Init();
410
411 static RTGETOPTDEF const s_aOptions[] =
412 {
413 { "--recv-buffer", 'r', RTGETOPT_REQ_UINT32 },
414 { "--send-buffer", 's', RTGETOPT_REQ_UINT32 },
415 };
416
417 uint32_t cbRecv = 32 * _1K;
418 uint32_t cbSend = 1536*2;
419
420 int ch;
421 RTGETOPTUNION Value;
422 RTGETOPTSTATE GetState;
423 RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
424 while ((ch = RTGetOpt(&GetState, &Value)))
425 switch (ch)
426 {
427 case 'r':
428 cbRecv = Value.u32;
429 break;
430
431 case 's':
432 cbSend = Value.u32;
433 break;
434
435 default:
436 return RTGetOptPrintError(ch, &Value);
437 }
438
439 /*
440 * Create an INTNET instance.
441 */
442 RTPrintf("tstIntNetR0: TESTING cbSend=%d cbRecv=%d ...\n", cbSend, cbRecv);
443 PINTNET pIntNet;
444 int rc = INTNETR0Create(&pIntNet);
445 if (RT_FAILURE(rc))
446 {
447 RTPrintf("tstIntNetR0: INTNETR0Create failed, rc=%Rrc\n");
448 return 1;
449 }
450
451 /*
452 * Create two interfaces.
453 */
454 INTNETIFHANDLE hIf0 = INTNET_HANDLE_INVALID;
455 rc = INTNETR0Open(pIntNet, g_pSession, "test", kIntNetTrunkType_None, "", 0, 1536*2 + 4, 0x8000, &hIf0);
456 if (RT_SUCCESS(rc))
457 {
458 if (hIf0 != INTNET_HANDLE_INVALID)
459 {
460 INTNETIFHANDLE hIf1 = INTNET_HANDLE_INVALID;
461 rc = INTNETR0Open(pIntNet, g_pSession, "test", kIntNetTrunkType_None, NULL, 0, 1536*2 + 4, 0x8000, &hIf1);
462 if (RT_SUCCESS(rc))
463 {
464 if (hIf1 != INTNET_HANDLE_INVALID)
465 {
466 PINTNETBUF pBuf0;
467 rc = INTNETR0IfGetRing0Buffer(pIntNet, hIf0, g_pSession, &pBuf0);
468 if (RT_FAILURE(rc) || !pBuf0)
469 {
470 RTPrintf("tstIntNetR0: INTNETIfGetRing0Buffer failed! pBuf0=%p rc=%Rrc\n", pBuf0, rc);
471 g_cErrors++;
472 }
473 PINTNETBUF pBuf1;
474 rc = INTNETR0IfGetRing0Buffer(pIntNet, hIf1, g_pSession, &pBuf1);
475 if (RT_FAILURE(rc))
476 {
477 RTPrintf("tstIntNetR0: INTNETIfGetRing0Buffer failed! pBuf1=%p rc=%Rrc\n", pBuf1, rc);
478 g_cErrors++;
479 }
480
481 rc = INTNETR0IfSetActive(pIntNet, hIf0, g_pSession, true);
482 if (RT_FAILURE(rc))
483 {
484 RTPrintf("tstIntNetR0: INTNETR0IfSetActive failed! rc=%Rrc\n", rc);
485 g_cErrors++;
486 }
487 rc = INTNETR0IfSetActive(pIntNet, hIf1, g_pSession, true);
488 if (RT_FAILURE(rc))
489 {
490 RTPrintf("tstIntNetR0: INTNETR0IfSetActive failed! rc=%Rrc\n", rc);
491 g_cErrors++;
492 }
493
494
495 /*
496 * Test basic waiting.
497 */
498 rc = INTNETR0IfWait(pIntNet, hIf0, g_pSession, 1);
499 if (rc != VERR_TIMEOUT)
500 {
501 RTPrintf("tstIntNetR0: INTNETIfWait returned %Rrc expected VERR_TIMEOUT (hIf0)\n", rc);
502 g_cErrors++;
503 }
504 rc = INTNETR0IfWait(pIntNet, hIf1, g_pSession, 0);
505 if (rc != VERR_TIMEOUT)
506 {
507 RTPrintf("tstIntNetR0: INTNETIfWait returned %Rrc expected VERR_TIMEOUT (hIf1)\n", rc);
508 g_cErrors++;
509 }
510
511 /*
512 * Send and receive.
513 */
514 rc = INTNETR0IfSend(pIntNet, hIf0, g_pSession, &g_TestFrame0, sizeof(g_TestFrame0));
515 if (RT_SUCCESS(rc))
516 {
517 rc = INTNETR0IfWait(pIntNet, hIf0, g_pSession, 1);
518 if (rc != VERR_TIMEOUT)
519 {
520 RTPrintf("tstIntNetR0: INTNETIfWait returned %Rrc expected VERR_TIMEOUT (hIf0, 2nd)\n", rc);
521 g_cErrors++;
522 }
523 rc = INTNETR0IfWait(pIntNet, hIf1, g_pSession, 0);
524 if (rc == VINF_SUCCESS)
525 {
526 /* receive it */
527 uint8_t abBuf[sizeof(g_TestFrame0)];
528 const unsigned cbExpect = RT_ALIGN(sizeof(g_TestFrame0) + sizeof(INTNETHDR), sizeof(INTNETHDR));
529 if (INTNETRingGetReadable(&pBuf1->Recv) != cbExpect)
530 {
531 RTPrintf("tstIntNetR0: %d readable bytes, expected %d!\n", INTNETRingGetReadable(&pBuf1->Recv), cbExpect);
532 g_cErrors++;
533 }
534 uint32_t cb = INTNETRingReadAndSkipFrame(&pBuf1->Recv, abBuf);
535 if (cb != sizeof(g_TestFrame0))
536 {
537 RTPrintf("tstIntNetR0: read %d frame bytes, expected %d!\n", cb, sizeof(g_TestFrame0));
538 g_cErrors++;
539 }
540 else if (memcmp(abBuf, &g_TestFrame0, sizeof(g_TestFrame0)))
541 {
542 RTPrintf("tstIntNetR0: Got invalid data!\n"
543 "received: %.*Rhxs\n"
544 "expected: %.*Rhxs\n",
545 cb, abBuf, sizeof(g_TestFrame0), &g_TestFrame0);
546 g_cErrors++;
547 }
548
549 /*
550 * Send a packet from If1 just to set its MAC address.
551 */
552 rc = INTNETR0IfSend(pIntNet, hIf1, g_pSession, &g_TestFrame1, sizeof(g_TestFrame1));
553 if (RT_FAILURE(rc))
554 {
555 RTPrintf("tstIntNetR0: INTNETIfSend returned %Rrc! (hIf1)\n", rc);
556 g_cErrors++;
557 }
558
559
560 /*
561 * Start threaded testcase.
562 * Give it 5 mins to finish.
563 */
564 if (!g_cErrors)
565 {
566 MYARGS Args0;
567 RT_ZERO(Args0);
568 Args0.hIf = hIf0;
569 Args0.pBuf = pBuf0;
570 Args0.pIntNet = pIntNet;
571 Args0.Mac.au16[0] = 0x8086;
572 Args0.Mac.au16[1] = 0;
573 Args0.Mac.au16[2] = 0;
574
575 MYARGS Args1;
576 RT_ZERO(Args1);
577 Args1.hIf = hIf1;
578 Args1.pBuf = pBuf1;
579 Args1.pIntNet = pIntNet;
580 Args1.Mac.au16[0] = 0x8086;
581 Args1.Mac.au16[1] = 0;
582 Args1.Mac.au16[2] = 1;
583
584 RTTHREAD ThreadRecv0 = NIL_RTTHREAD;
585 RTTHREAD ThreadRecv1 = NIL_RTTHREAD;
586 RTTHREAD ThreadSend0 = NIL_RTTHREAD;
587 RTTHREAD ThreadSend1 = NIL_RTTHREAD;
588 rc = RTThreadCreate(&ThreadRecv0, ReceiveThread, &Args0, 0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "RECV0");
589 if (RT_SUCCESS(rc))
590 rc = RTThreadCreate(&ThreadRecv1, ReceiveThread, &Args1, 0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "RECV1");
591 if (RT_SUCCESS(rc))
592 rc = RTThreadCreate(&ThreadSend0, SendThread, &Args0, 0, RTTHREADTYPE_EMULATION, RTTHREADFLAGS_WAITABLE, "SEND0");
593 if (RT_SUCCESS(rc))
594 rc = RTThreadCreate(&ThreadSend1, SendThread, &Args1, 0, RTTHREADTYPE_EMULATION, RTTHREADFLAGS_WAITABLE, "SEND1");
595 if (RT_SUCCESS(rc))
596 {
597 int rc2 = VINF_SUCCESS;
598 rc = RTThreadWait(ThreadSend0, 5*60*1000, &rc2);
599 AssertRC(rc);
600 if (RT_SUCCESS(rc))
601 {
602 ThreadSend0 = NIL_RTTHREAD;
603 rc = RTThreadWait(ThreadSend1, 5*60*1000, RT_SUCCESS(rc2) ? &rc2 : NULL);
604 AssertRC(rc);
605 if (RT_SUCCESS(rc))
606 ThreadSend1 = NIL_RTTHREAD;
607 }
608 if ( RT_SUCCESS(rc)
609 && RT_SUCCESS(rc2))
610 {
611 /*
612 * Wait a bit for the receivers to finish up.
613 */
614 unsigned cYields = 100000;
615 while ( ( INTNETRingHasMoreToRead(&pBuf0->Recv)
616 || INTNETRingHasMoreToRead(&pBuf1->Recv))
617 && cYields-- > 0)
618 RTThreadYield();
619
620 uint64_t u64Elapsed = RT_MAX(Args0.u64End, Args1.u64End) - RT_MIN(Args0.u64Start, Args1.u64Start);
621 uint64_t u64Speed = (uint64_t)((2 * TEST_TRANSFER_SIZE / 1024) / (u64Elapsed / 1000000000.0));
622 RTPrintf("tstIntNetR0: transfered %d bytes in %'RU64 ns (%'RU64 KB/s)\n",
623 2 * TEST_TRANSFER_SIZE, u64Elapsed, u64Speed);
624
625 /*
626 * Closing time...
627 */
628 rc = RTThreadWait(ThreadRecv0, 5000, &rc2);
629 if (RT_SUCCESS(rc))
630 ThreadRecv0 = NIL_RTTHREAD;
631 if (RT_FAILURE(rc) || RT_FAILURE(rc2))
632 {
633 RTPrintf("tstIntNetR0: Failed waiting on receiver thread 0, rc=%Rrc, rc2=%Rrc\n", rc, rc2);
634 g_cErrors++;
635 }
636
637 rc = RTThreadWait(ThreadRecv1, 5000, &rc2);
638 if (RT_SUCCESS(rc))
639 ThreadRecv1 = NIL_RTTHREAD;
640 if (RT_FAILURE(rc) || RT_FAILURE(rc2))
641 {
642 RTPrintf("tstIntNetR0: Failed waiting on receiver thread 1, rc=%Rrc, rc2=%Rrc\n", rc, rc2);
643 g_cErrors++;
644 }
645
646 rc = INTNETR0IfClose(pIntNet, hIf0, g_pSession);
647 if (RT_SUCCESS(rc))
648 {
649 hIf0 = INTNET_HANDLE_INVALID;
650 pBuf0 = NULL;
651 }
652 else
653 {
654 RTPrintf("tstIntNetR0: INTNETIfClose failed, rc=%Rrc! (hIf0)\n", rc);
655 g_cErrors++;
656 }
657
658 rc = INTNETR0IfClose(pIntNet, hIf1, g_pSession);
659 if (RT_SUCCESS(rc))
660 {
661 hIf1 = INTNET_HANDLE_INVALID;
662 pBuf1 = NULL;
663 }
664 else
665 {
666 RTPrintf("tstIntNetR0: INTNETIfClose failed, rc=%Rrc! (hIf1)\n", rc);
667 g_cErrors++;
668 }
669
670
671 /* check if the network still exist... */
672 if (pIntNet->pNetworks)
673 {
674 RTPrintf("tstIntNetR0: The network wasn't deleted! (g_cErrors=%d)\n", g_cErrors);
675 g_cErrors++;
676 }
677 }
678 else
679 {
680 RTPrintf("tstIntNetR0: Waiting on senders failed, rc=%Rrc, rc2=%Rrc\n", rc, rc2);
681 g_cErrors++;
682 }
683
684 /*
685 * Give them a chance to complete...
686 */
687 RTThreadWait(ThreadRecv0, 5000, NULL);
688 RTThreadWait(ThreadRecv1, 5000, NULL);
689 RTThreadWait(ThreadSend0, 5000, NULL);
690 RTThreadWait(ThreadSend1, 5000, NULL);
691
692 }
693 else
694 {
695 RTPrintf("tstIntNetR0: Failed to create threads, rc=%Rrc\n", rc);
696 g_cErrors++;
697 }
698 }
699 }
700 else
701 {
702 RTPrintf("tstIntNetR0: INTNETIfWait returned %Rrc expected VINF_SUCCESS (hIf1)\n", rc);
703 g_cErrors++;
704 }
705 }
706 else
707 {
708 RTPrintf("tstIntNetR0: INTNETIfSend returned %Rrc! (hIf0)\n", rc);
709 g_cErrors++;
710 }
711 }
712 else
713 {
714 RTPrintf("tstIntNetR0: INTNETOpen returned invalid handle on success! (hIf1)\n");
715 g_cErrors++;
716 }
717
718 if (hIf1 != INTNET_HANDLE_INVALID)
719 rc = INTNETR0IfClose(pIntNet, hIf1, g_pSession);
720 }
721 else
722 {
723 RTPrintf("tstIntNetR0: INTNETOpen failed for the 2nd interface! rc=%Rrc\n", rc);
724 g_cErrors++;
725 }
726
727 if (hIf0 != INTNET_HANDLE_INVALID)
728 rc = INTNETR0IfClose(pIntNet, hIf0, g_pSession);
729 }
730 else
731 {
732 RTPrintf("tstIntNetR0: INTNETOpen returned invalid handle on success! (hIf0)\n");
733 g_cErrors++;
734 }
735 }
736 else
737 {
738 RTPrintf("tstIntNetR0: INTNETOpen failed for the 1st interface! rc=%Rrc\n", rc);
739 g_cErrors++;
740 }
741
742 /*
743 * Destroy the service.
744 */
745 INTNETR0Destroy(pIntNet);
746
747 /*
748 * Summary.
749 */
750 if (!g_cErrors)
751 RTPrintf("tstIntNetR0: SUCCESS\n");
752 else
753 RTPrintf("tstIntNetR0: FAILURE - %d errors\n", g_cErrors);
754
755 return !!g_cErrors;
756}
757
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