VirtualBox

Ignore:
Timestamp:
Apr 23, 2010 12:34:14 AM (15 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
60472
Message:

SrvIntNetR0,VBoxNetFlt: Main body of the internal locking rewrite.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Network/testcase/tstIntNetR0.cpp

    r28314 r28623  
    4141#include <VBox/sup.h>
    4242#include <VBox/err.h>
     43#include <iprt/asm.h>
     44#include <iprt/getopt.h>
     45#include <iprt/initterm.h>
     46#include <iprt/mem.h>
     47#include <iprt/mp.h>
    4348#include <iprt/stream.h>
    44 #include <iprt/alloc.h>
    45 #include <iprt/initterm.h>
    4649#include <iprt/thread.h>
    4750#include <iprt/time.h>
    48 #include <iprt/asm.h>
    49 #include <iprt/getopt.h>
     51#include <iprt/test.h>
    5052
    5153
     
    98100*   Global Variables                                                           *
    99101*******************************************************************************/
    100 /** The error count. */
    101 unsigned g_cErrors = 0;
    102 
     102/** The test handle.*/
     103static RTTEST           g_hTest      = NIL_RTTEST;
     104/** The size (in bytes) of the large transfer tests. */
     105static uint32_t         g_cbTransfer = _1M * 384;
    103106/** Fake session handle. */
    104 const PSUPDRVSESSION g_pSession = (PSUPDRVSESSION)0xdeadface;
    105 
    106 /** Testframe 0 */
    107 struct TESTFRAME
    108 {
    109     uint16_t    au16[7];
    110 } g_TestFrame0 = { { /* dst:*/ 0xffff, 0xffff, 0xffff, /*src:*/0x8086, 0, 0, 0x0800 } },
    111   g_TestFrame1 = { { /* dst:*/ 0, 0, 0,                /*src:*/0x8086, 0, 1, 0x0800 } };
     107const PSUPDRVSESSION    g_pSession   = (PSUPDRVSESSION)0xdeadface;
    112108
    113109
    114110INTNETR3DECL(void *) SUPR0ObjRegister(PSUPDRVSESSION pSession, SUPDRVOBJTYPE enmType, PFNSUPDRVDESTRUCTOR pfnDestructor, void *pvUser1, void *pvUser2)
    115111{
    116     if (pSession != g_pSession)
    117     {
    118         RTPrintf("tstIntNetR0: Invalid session pointer %p, %s!\n", pSession, __FUNCTION__);
    119         g_cErrors++;
    120         return NULL;
    121     }
    122     POBJREF pRef = (POBJREF)RTMemAlloc(sizeof(OBJREF));
     112    RTTEST_CHECK_RET(g_hTest, pSession == g_pSession, NULL);
     113    POBJREF pRef = (POBJREF)RTTestGuardedAllocTail(g_hTest, sizeof(OBJREF));
    123114    if (!pRef)
    124115        return NULL;
     
    132123INTNETR3DECL(int) SUPR0ObjAddRefEx(void *pvObj, PSUPDRVSESSION pSession, bool fNoBlocking)
    133124{
    134     if (pSession != g_pSession)
    135     {
    136         RTPrintf("tstIntNetR0: Invalid session pointer %p, %s!\n", pSession, __FUNCTION__);
    137         g_cErrors++;
    138         return VERR_INVALID_PARAMETER;
    139     }
     125    RTTEST_CHECK_RET(g_hTest, pSession == g_pSession, VERR_INVALID_PARAMETER);
    140126    POBJREF pRef = (POBJREF)pvObj;
    141127    ASMAtomicIncU32(&pRef->cRefs);
     
    150136INTNETR3DECL(int) SUPR0ObjRelease(void *pvObj, PSUPDRVSESSION pSession)
    151137{
    152     if (pSession != g_pSession)
    153     {
    154         RTPrintf("tstIntNetR0: Invalid session pointer %p, %s!\n", pSession, __FUNCTION__);
    155         g_cErrors++;
    156         return VERR_INVALID_PARAMETER;
    157     }
     138    RTTEST_CHECK_RET(g_hTest, pSession == g_pSession, VERR_INVALID_PARAMETER);
    158139    POBJREF pRef = (POBJREF)pvObj;
    159140    if (!ASMAtomicDecU32(&pRef->cRefs))
    160141    {
    161142        pRef->pfnDestructor(pRef, pRef->pvUser1, pRef->pvUser2);
    162         RTMemFree(pRef);
     143        RTTestGuardedFree(g_hTest, pRef);
    163144        return VINF_OBJECT_DESTROYED;
    164145    }
     
    168149INTNETR3DECL(int) SUPR0ObjVerifyAccess(void *pvObj, PSUPDRVSESSION pSession, const char *pszObjName)
    169150{
    170     if (pSession != g_pSession)
    171     {
    172         RTPrintf("tstIntNetR0: Invalid session pointer %p, %s!\n", pSession, __FUNCTION__);
    173         g_cErrors++;
    174         return VERR_INVALID_PARAMETER;
    175     }
     151    RTTEST_CHECK_RET(g_hTest, pSession == g_pSession, VERR_INVALID_PARAMETER);
    176152    return VINF_SUCCESS;
    177153}
     
    179155INTNETR3DECL(int) SUPR0MemAlloc(PSUPDRVSESSION pSession, uint32_t cb, PRTR0PTR ppvR0, PRTR3PTR ppvR3)
    180156{
    181     if (pSession != g_pSession)
    182     {
    183         RTPrintf("tstIntNetR0: Invalid session pointer %p, %s!\n", pSession, __FUNCTION__);
    184         g_cErrors++;
    185         return VERR_INVALID_PARAMETER;
    186     }
    187     void *pv = RTMemAlloc(cb);
     157    RTTEST_CHECK_RET(g_hTest, pSession == g_pSession, VERR_INVALID_PARAMETER);
     158    void *pv = RTTestGuardedAllocTail(g_hTest, cb);
    188159    if (!pv)
    189160        return VERR_NO_MEMORY;
     
    196167INTNETR3DECL(int) SUPR0MemFree(PSUPDRVSESSION pSession, RTHCUINTPTR uPtr)
    197168{
    198     if (pSession != g_pSession)
    199     {
    200         RTPrintf("tstIntNetR0: Invalid session pointer %p, %s!\n", pSession, __FUNCTION__);
    201         g_cErrors++;
    202         return VERR_INVALID_PARAMETER;
    203     }
    204     RTMemFree((void *)uPtr);
     169    RTTEST_CHECK_RET(g_hTest, pSession == g_pSession, VERR_INVALID_PARAMETER);
     170    RTTestGuardedFree(g_hTest, (void *)uPtr);
    205171    return VINF_SUCCESS;
    206172}
    207173
     174/* Fake non-existing ring-0 APIs. */
     175#define RTThreadIsInInterrupt(hThread)      false
     176#define RTThreadPreemptIsEnabled(hThread)   true
     177#define RTMpCpuId()                         0
     178
     179/* No CLI/POPF, please. */
     180#define RTSpinlockAcquireNoInts             RTSpinlockAcquire
     181#define RTSpinlockReleaseNoInts             RTSpinlockRelease
    208182
    209183
     
    230204typedef struct MYARGS
    231205{
    232     PINTNET pIntNet;
    233     PINTNETBUF pBuf;
    234     INTNETIFHANDLE hIf;
    235     RTMAC Mac;
    236     uint64_t u64Start;
    237     uint64_t u64End;
     206    PINTNET         pIntNet;
     207    PINTNETBUF      pBuf;
     208    INTNETIFHANDLE  hIf;
     209    RTMAC           Mac;
     210    uint64_t        u64Start;
     211    uint64_t        u64End;
    238212} MYARGS, *PMYARGS;
    239213
    240214
    241 #define TEST_TRANSFER_SIZE (_1M*384)
     215/**
     216 * Frame header used when testing.
     217 */
     218#pragma pack(1)
     219typedef struct MYFRAMEHDR
     220{
     221    RTMAC       SrcMac;
     222    RTMAC       DstMac;
     223    uint32_t    iFrame;
     224    uint32_t    auEos[3];
     225} MYFRAMEHDR;
     226#pragma pack()
    242227
    243228/**
     
    248233{
    249234    PMYARGS pArgs = (PMYARGS)pvArg;
    250 
    251     /*
    252      * Send 64 MB of data.
    253      */
    254     uint8_t abBuf[4096] = {0};
    255     PRTMAC  pMacSrc = (PRTMAC)&abBuf[0];
    256     PRTMAC  pMacDst = pMacSrc + 1;
    257     *pMacSrc = pArgs->Mac;
    258     *pMacDst = pArgs->Mac;
    259     pMacDst->au16[2] = pArgs->Mac.au16[2] ? 0 : 1;
    260     unsigned *puFrame = (unsigned *)(pMacDst + 1);
    261     unsigned iFrame = 0;
    262     uint32_t cbSent = 0;
    263     uint32_t cSend  = 0;
     235    int rc;
     236
     237    /*
     238     * Send g_cbTransfer of data.
     239     */
     240    uint8_t         abBuf[4096] = {0};
     241    MYFRAMEHDR     *pHdr    = (MYFRAMEHDR *)&abBuf[0];
     242    uint32_t        iFrame  = 0;
     243    uint32_t        cbSent  = 0;
     244    uint32_t        cSend   = 0;
     245
     246    pHdr->SrcMac            = pArgs->Mac;
     247    pHdr->DstMac            = pArgs->Mac;
     248    pHdr->DstMac.au16[2]    = (pArgs->Mac.au16[2] + 1) % 2;
     249
    264250    pArgs->u64Start = RTTimeNanoTS();
    265     for (; cbSent < TEST_TRANSFER_SIZE; iFrame++)
    266     {
    267         const unsigned cb = iFrame % 1519 + 12 + sizeof(unsigned);
    268         *puFrame = iFrame;
     251    for (; cbSent < g_cbTransfer; iFrame++)
     252    {
     253        const unsigned cb = iFrame % 1519 + sizeof(RTMAC) * 2 + sizeof(unsigned);
     254         pHdr->iFrame = iFrame;
    269255
    270256        INTNETSG Sg;
    271257        INTNETSgInitTemp(&Sg, abBuf, cb);
    272         int rc = intnetR0RingWriteFrame(&pArgs->pBuf->Send, &Sg, NULL);
     258        RTTEST_CHECK_RC_OK(g_hTest, rc = intnetR0RingWriteFrame(&pArgs->pBuf->Send, &Sg, NULL));
    273259        if (RT_SUCCESS(rc))
    274             rc = INTNETR0IfSend(pArgs->pIntNet, pArgs->hIf, g_pSession);
    275         if (RT_FAILURE(rc))
    276         {
    277             g_cErrors++;
    278             RTPrintf("tstIntNetR0: Failed sending %d bytes, rc=%Rrc (%d)\n", cb, rc, INTNETRingGetWritable(&pArgs->pBuf->Send));
    279         }
     260            RTTEST_CHECK_RC_OK(g_hTest, rc = INTNETR0IfSend(pArgs->pIntNet, pArgs->hIf, g_pSession));
    280261        cbSent += cb;
    281262    }
     
    284265     * Termination frames.
    285266     */
    286     puFrame[0] = 0xffffdead;
    287     puFrame[1] = 0xffffdead;
    288     puFrame[2] = 0xffffdead;
    289     puFrame[3] = 0xffffdead;
     267    pHdr->iFrame  = 0xffffdead;
     268    pHdr->auEos[0] = 0xffffdead;
     269    pHdr->auEos[1] = 0xffffdead;
     270    pHdr->auEos[2] = 0xffffdead;
    290271    for (unsigned c = 0; c < 20; c++)
    291272    {
    292         int rc = tstIntNetSendBuf(pArgs->pIntNet, &pArgs->pBuf->Send, pArgs->hIf, g_pSession,
    293                                   abBuf, sizeof(RTMAC) * 2 + sizeof(unsigned) * 4);
    294         if (RT_FAILURE(rc))
    295         {
    296             g_cErrors++;
    297             RTPrintf("tstIntNetR0: send failed, rc=%Rrc\n", rc);
    298         }
     273        RTTEST_CHECK_RC_OK(g_hTest, rc = tstIntNetSendBuf(pArgs->pIntNet, &pArgs->pBuf->Send, pArgs->hIf, g_pSession,
     274                                                          abBuf, sizeof(RTMAC) * 2 + sizeof(unsigned) * 4));
    299275        RTThreadSleep(1);
    300276    }
    301277
    302     RTPrintf("tstIntNetR0: sender   thread %.6Rhxs terminating.\n"
    303              "tstIntNetR0:   iFrame=%u  cb=%'u\n",
    304              &pArgs->Mac, iFrame, cbSent);
     278    RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS,
     279                 "sender   thread %.6Rhxs terminating.\n"
     280                 "iFrame=%u  cb=%'u\n",
     281                 &pArgs->Mac, iFrame, cbSent);
    305282    return 0;
    306283}
     
    322299    for (;;)
    323300    {
     301        /*
     302         * Read data.
     303         */
     304        while (INTNETRingHasMoreToRead(&pArgs->pBuf->Recv))
     305        {
     306            uint8_t     abBuf[16384];
     307            MYFRAMEHDR *pHdr = (MYFRAMEHDR *)&abBuf[0];
     308            uint32_t    cb   = INTNETRingReadAndSkipFrame(&pArgs->pBuf->Recv, abBuf);
     309
     310            /* check for termination frame. */
     311            if (    pHdr->iFrame   == 0xffffdead
     312                &&  pHdr->auEos[0] == 0xffffdead
     313                &&  pHdr->auEos[1] == 0xffffdead
     314                &&  pHdr->auEos[2] == 0xffffdead)
     315            {
     316                pArgs->u64End = RTTimeNanoTS();
     317                RTThreadSleep(10);
     318                RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS,
     319                             "receiver thread %.6Rhxs terminating.\n"
     320                             "  iFrame=%u  cb=%'u  c=%'u  %'uKB/s  %'ufps  cLost=%'u \n",
     321                             &pArgs->Mac, iFrame, cbReceived, iFrame - cLostFrames,
     322                             (unsigned)(cbReceived * 1000000000.0 / 1024 / (pArgs->u64End - pArgs->u64Start)),
     323                             (unsigned)((iFrame - cLostFrames) * 1000000000.0 / (pArgs->u64End - pArgs->u64Start)),
     324                             cLostFrames);
     325                return VINF_SUCCESS;
     326            }
     327
     328            /* validate frame header */
     329            if (    pHdr->DstMac.au16[0] != pArgs->Mac.au16[0]
     330                ||  pHdr->DstMac.au16[1] != pArgs->Mac.au16[1]
     331                ||  pHdr->DstMac.au16[2] != pArgs->Mac.au16[2]
     332                ||  pHdr->SrcMac.au16[0] != pArgs->Mac.au16[0]
     333                ||  pHdr->SrcMac.au16[1] != pArgs->Mac.au16[1]
     334                ||  pHdr->SrcMac.au16[2] != (pArgs->Mac.au16[2] + 1) % 2)
     335            {
     336                RTTestFailed(g_hTest, "receiver thread %.6Rhxs received frame header: %.16Rhxs\n", &pArgs->Mac, abBuf);
     337            }
     338
     339            /* frame stuff and stats. */
     340            int32_t off = pHdr->iFrame - (iFrame + 1);
     341            if (off)
     342            {
     343                if (off > 0)
     344                {
     345#ifndef IGNORE_LOST_FRAMES
     346                    RTTestFailed(g_hTest, "receiver thread %.6Rhxs: iFrame=%#x *puFrame=%#x off=%d\n",
     347                                 &pArgs->Mac, iFrame, pHdr->iFrame, off);
     348#endif
     349                    cLostFrames += off;
     350                }
     351                else
     352                {
     353                    cLostFrames++;
     354                    RTTestFailed(g_hTest, "receiver thread %.6Rhxs: iFrame=%#x *puFrame=%#x off=%d\n",
     355                                 &pArgs->Mac, iFrame, pHdr->iFrame, off);
     356                }
     357            }
     358            iFrame = pHdr->iFrame;
     359            cbReceived += cb;
     360        }
     361
    324362        /*
    325363         * Wait for data.
     
    332370                break;
    333371            case VERR_SEM_DESTROYED:
    334                 RTPrintf("tstIntNetR0: receiver thread %.6Rhxs terminating. iFrame=%u cb=%'u c=%'u cLost=%'u\n",
    335                          &pArgs->Mac, iFrame, cbReceived, iFrame - cLostFrames, cLostFrames);
     372                RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS,
     373                             "receiver thread %.6Rhxs terminating. iFrame=%u cb=%'u c=%'u cLost=%'u\n",
     374                             &pArgs->Mac, iFrame, cbReceived, iFrame - cLostFrames, cLostFrames);
    336375                return VINF_SUCCESS;
    337376
    338377            default:
    339                 RTPrintf("tstIntNetR0: receiver thread %.6Rhxs got odd return value %Rrc! iFrame=%u cb=%'u c=%'u cLost=%'u\n",
    340                          &pArgs->Mac, rc, iFrame, cbReceived, iFrame - cLostFrames, cLostFrames);
    341                 g_cErrors++;
     378                RTTestFailed(g_hTest, "receiver thread %.6Rhxs got odd return value %Rrc! iFrame=%u cb=%'u c=%'u cLost=%'u\n",
     379                             &pArgs->Mac, rc, iFrame, cbReceived, iFrame - cLostFrames, cLostFrames);
    342380                return rc;
    343381        }
    344382
     383    }
     384}
     385
     386
     387/**
     388 * Test state.
     389 */
     390typedef struct TSTSTATE
     391{
     392    PINTNET         pIntNet;
     393
     394    PINTNETBUF      pBuf0;
     395    INTNETIFHANDLE  hIf0;
     396
     397    PINTNETBUF      pBuf1;
     398    INTNETIFHANDLE  hIf1;
     399} TSTSTATE;
     400typedef TSTSTATE *PTSTSTATE;
     401
     402
     403/**
     404 * Open two internal network interfaces.
     405 *
     406 * @returns IPRT status of the first failure.
     407 * @param   pThis               The test instance.
     408 */
     409static int tstOpenInterfaces(PTSTSTATE pThis, const char *pszNetwork, uint32_t cbSend, uint32_t cbRecv)
     410{
     411    pThis->hIf0 = INTNET_HANDLE_INVALID;
     412    RTTESTI_CHECK_RC_OK_RET(INTNETR0Open(pThis->pIntNet, g_pSession, pszNetwork, kIntNetTrunkType_None, "",
     413                                         0/*fFlags*/, cbSend, cbRecv, &pThis->hIf0), rcCheck);
     414    RTTESTI_CHECK_RET(pThis->hIf0 != INTNET_HANDLE_INVALID, VERR_INTERNAL_ERROR);
     415    RTTESTI_CHECK_RC_RET(INTNETR0IfGetRing0Buffer(pThis->pIntNet, pThis->hIf0, g_pSession, &pThis->pBuf0), VINF_SUCCESS, rcCheck);
     416    RTTESTI_CHECK_RET(pThis->pBuf0, VERR_INTERNAL_ERROR);
     417
     418
     419    pThis->hIf1 = INTNET_HANDLE_INVALID;
     420    RTTESTI_CHECK_RC_OK_RET(INTNETR0Open(pThis->pIntNet, g_pSession, pszNetwork, kIntNetTrunkType_None, "",
     421                                         0/*fFlags*/, cbSend, cbRecv, &pThis->hIf1), rcCheck);
     422    RTTESTI_CHECK_RET(pThis->hIf1 != INTNET_HANDLE_INVALID, VERR_INTERNAL_ERROR);
     423    RTTESTI_CHECK_RC_RET(INTNETR0IfGetRing0Buffer(pThis->pIntNet, pThis->hIf1, g_pSession, &pThis->pBuf1), VINF_SUCCESS, rcCheck);
     424    RTTESTI_CHECK_RET(pThis->pBuf1, VERR_INTERNAL_ERROR);
     425
     426    return VINF_SUCCESS;
     427}
     428
     429/**
     430 * Close the interfaces.
     431 *
     432 * @param   pThis               The test instance.
     433 */
     434static void tstCloseInterfaces(PTSTSTATE pThis)
     435{
     436    int rc;
     437    RTTESTI_CHECK_RC_OK(rc = INTNETR0IfClose(pThis->pIntNet, pThis->hIf0, g_pSession));
     438    if (RT_SUCCESS(rc))
     439    {
     440        pThis->hIf0  = INTNET_HANDLE_INVALID;
     441        pThis->pBuf0 = NULL;
     442    }
     443
     444    RTTESTI_CHECK_RC_OK(rc = INTNETR0IfClose(pThis->pIntNet, pThis->hIf1, g_pSession));
     445    if (RT_SUCCESS(rc))
     446    {
     447        pThis->hIf1  = INTNET_HANDLE_INVALID;
     448        pThis->pBuf1 = NULL;
     449    }
     450
     451    /* The network should be dead now. */
     452    RTTESTI_CHECK(pThis->pIntNet->pNetworks == NULL);
     453}
     454
     455/**
     456 * Do the bi-directional transfer test.
     457 */
     458static void tstBidirectionalTransfer(PTSTSTATE pThis)
     459{
     460    MYARGS Args0;
     461    RT_ZERO(Args0);
     462    Args0.hIf         = pThis->hIf0;
     463    Args0.pBuf        = pThis->pBuf0;
     464    Args0.pIntNet     = pThis->pIntNet;
     465    Args0.Mac.au16[0] = 0x8086;
     466    Args0.Mac.au16[1] = 0;
     467    Args0.Mac.au16[2] = 0;
     468
     469    MYARGS Args1;
     470    RT_ZERO(Args1);
     471    Args1.hIf         = pThis->hIf1;
     472    Args1.pBuf        = pThis->pBuf1;
     473    Args1.pIntNet     = pThis->pIntNet;
     474    Args1.Mac.au16[0] = 0x8086;
     475    Args1.Mac.au16[1] = 0;
     476    Args1.Mac.au16[2] = 1;
     477
     478    RTTHREAD ThreadRecv0 = NIL_RTTHREAD;
     479    RTTHREAD ThreadRecv1 = NIL_RTTHREAD;
     480    RTTHREAD ThreadSend0 = NIL_RTTHREAD;
     481    RTTHREAD ThreadSend1 = NIL_RTTHREAD;
     482    RTTESTI_CHECK_RC_OK_RETV(RTThreadCreate(&ThreadRecv0, ReceiveThread, &Args0, 0, RTTHREADTYPE_IO,        RTTHREADFLAGS_WAITABLE, "RECV0"));
     483    RTTESTI_CHECK_RC_OK_RETV(RTThreadCreate(&ThreadRecv1, ReceiveThread, &Args1, 0, RTTHREADTYPE_IO,        RTTHREADFLAGS_WAITABLE, "RECV1"));
     484    RTTESTI_CHECK_RC_OK_RETV(RTThreadCreate(&ThreadSend0, SendThread,    &Args0, 0, RTTHREADTYPE_EMULATION, RTTHREADFLAGS_WAITABLE, "SEND0"));
     485    RTTESTI_CHECK_RC_OK_RETV(RTThreadCreate(&ThreadSend1, SendThread,    &Args1, 0, RTTHREADTYPE_EMULATION, RTTHREADFLAGS_WAITABLE, "SEND1"));
     486
     487    int rc2 = VINF_SUCCESS;
     488    int rc;
     489    RTTESTI_CHECK_RC_OK(rc = RTThreadWait(ThreadSend0, 5*60*1000, &rc2));
     490    if (RT_SUCCESS(rc))
     491    {
     492        RTTESTI_CHECK_RC_OK(rc2);
     493        ThreadSend0 = NIL_RTTHREAD;
     494        RTTESTI_CHECK_RC_OK(rc = RTThreadWait(ThreadSend1, 5*60*1000, RT_SUCCESS(rc2) ? &rc2 : NULL));
     495        if (RT_SUCCESS(rc))
     496        {
     497            ThreadSend1 = NIL_RTTHREAD;
     498            RTTESTI_CHECK_RC_OK(rc2);
     499        }
     500    }
     501    if (RTTestErrorCount(g_hTest) == 0)
     502    {
    345503        /*
    346          * Read data.
     504         * Wait a bit for the receivers to finish up.
    347505         */
    348         while (INTNETRingHasMoreToRead(&pArgs->pBuf->Recv))
     506        unsigned cYields = 100000;
     507        while (     (  INTNETRingHasMoreToRead(&pThis->pBuf0->Recv)
     508                    || INTNETRingHasMoreToRead(&pThis->pBuf1->Recv))
     509               &&   cYields-- > 0)
     510            RTThreadYield();
     511
     512        uint64_t u64Elapsed = RT_MAX(Args0.u64End, Args1.u64End) - RT_MIN(Args0.u64Start, Args1.u64Start);
     513        uint64_t u64Speed = (uint64_t)((2 * g_cbTransfer / 1024) / (u64Elapsed / 1000000000.0));
     514        RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS,
     515                     "transfered %u bytes in %'RU64 ns (%'RU64 KB/s)\n",
     516                     2 * g_cbTransfer, u64Elapsed, u64Speed);
     517
     518        /*
     519         * Wait for the threads to finish up...
     520         */
     521        RTTESTI_CHECK_RC_OK(rc = RTThreadWait(ThreadRecv0, 5000, &rc2));
     522        if (RT_SUCCESS(rc))
    349523        {
    350             uint8_t abBuf[16384];
    351             uint32_t cb = INTNETRingReadAndSkipFrame(&pArgs->pBuf->Recv, abBuf);
    352             unsigned *puFrame = (unsigned *)&abBuf[sizeof(RTMAC) * 2];
    353 
    354             /* check for termination frame. */
    355             if (    cb == sizeof(RTMAC) * 2 + sizeof(unsigned) * 4
    356                 &&  puFrame[0] == 0xffffdead
    357                 &&  puFrame[1] == 0xffffdead
    358                 &&  puFrame[2] == 0xffffdead
    359                 &&  puFrame[3] == 0xffffdead)
    360             {
    361                 pArgs->u64End = RTTimeNanoTS();
    362                 RTPrintf("tstIntNetR0: receiver thread %.6Rhxs terminating.\n"
    363                          "tstIntNetR0:   iFrame=%u  cb=%'u  c=%'u  %'uKB/s  %'ufps  cLost=%'u \n",
    364                          &pArgs->Mac, iFrame, cbReceived, iFrame - cLostFrames,
    365                          (unsigned)(cbReceived * 1000000000.0 / 1024 / (pArgs->u64End - pArgs->u64Start)),
    366                          (unsigned)((iFrame - cLostFrames) * 1000000000.0 / (pArgs->u64End - pArgs->u64Start)),
    367                          cLostFrames);
    368                 return VINF_SUCCESS;
    369             }
    370 
    371             /* validate frame header */
    372             PRTMAC pMacSrc = (PRTMAC)&abBuf[0];
    373             PRTMAC pMacDst = pMacSrc + 1;
    374             if (    pMacDst->au16[0] != 0x8086
    375                 ||  pMacDst->au16[1] != 0
    376                 ||  pMacDst->au16[2] != pArgs->Mac.au16[2]
    377                 ||  pMacSrc->au16[0] != 0x8086
    378                 ||  pMacSrc->au16[1] != 0
    379                 ||  pMacSrc->au16[2] == pArgs->Mac.au16[2])
    380             {
    381                 RTPrintf("tstIntNetR0: receiver thread %.6Rhxs received frame header: %.16Rhxs\n",
    382                          &pArgs->Mac, abBuf);
    383                 g_cErrors++;
    384             }
    385 
    386             /* frame stuff and stats. */
    387             int off = iFrame + 1 - *puFrame;
    388             if (off)
    389             {
    390                 if (off > 0)
    391                 {
    392                     RTPrintf("tstIntNetR0: receiver thread %.6Rhxs: iFrame=%d *puFrame=%d off=%d\n",
    393                              &pArgs->Mac, iFrame, *puFrame, off);
    394                     g_cErrors++;
    395                     cLostFrames++;
    396                 }
    397                 else
    398                 {
    399                     cLostFrames += -off;
    400 #ifndef IGNORE_LOST_FRAMES
    401                     if (off < 50)
    402                     {
    403                         RTPrintf("tstIntNetR0: receiver thread %.6Rhxs: iFrame=%d *puFrame=%d off=%d\n",
    404                                  &pArgs->Mac, iFrame, *puFrame, off);
    405                         g_cErrors++;
    406                     }
    407 #endif
    408                 }
    409             }
    410             iFrame = *puFrame;
    411             cbReceived += cb;
     524            RTTESTI_CHECK_RC_OK(rc2);
     525            ThreadRecv0 = NIL_RTTHREAD;
    412526        }
    413     }
    414 }
     527
     528        RTTESTI_CHECK_RC_OK(rc = RTThreadWait(ThreadRecv1, 5000, &rc2));
     529        if (RT_SUCCESS(rc))
     530        {
     531            RTTESTI_CHECK_RC_OK(rc2);
     532            ThreadRecv1 = NIL_RTTHREAD;
     533        }
     534    }
     535
     536    /*
     537     * Give them a chance to complete...
     538     */
     539    RTThreadWait(ThreadRecv0, 5000, NULL);
     540    RTThreadWait(ThreadRecv1, 5000, NULL);
     541    RTThreadWait(ThreadSend0, 5000, NULL);
     542    RTThreadWait(ThreadSend1, 5000, NULL);
     543
     544
     545    /*
     546     * Display statistics.
     547     */
     548    RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS,
     549                 "Buf0: Yields-OK=%llu Yields-NOK=%llu Lost=%llu Bad=%llu\n",
     550                 pThis->pBuf0->cStatYieldsOk.c,
     551                 pThis->pBuf0->cStatYieldsNok.c,
     552                 pThis->pBuf0->cStatLost.c,
     553                 pThis->pBuf0->cStatBadFrames.c);
     554    RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS,
     555                 "Buf0.Recv: Frames=%llu Bytes=%llu Overflows=%llu\n",
     556                 pThis->pBuf0->Recv.cStatFrames,
     557                 pThis->pBuf0->Recv.cbStatWritten.c,
     558                 pThis->pBuf0->Recv.cOverflows.c);
     559    RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS,
     560                 "Buf0.Send: Frames=%llu Bytes=%llu Overflows=%llu\n",
     561                 pThis->pBuf0->Send.cStatFrames,
     562                 pThis->pBuf0->Send.cbStatWritten.c,
     563                 pThis->pBuf0->Send.cOverflows.c);
     564
     565    RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS,
     566                 "Buf1: Yields-OK=%llu Yields-NOK=%llu Lost=%llu Bad=%llu\n",
     567                 pThis->pBuf1->cStatYieldsOk.c,
     568                 pThis->pBuf1->cStatYieldsNok.c,
     569                 pThis->pBuf1->cStatLost.c,
     570                 pThis->pBuf1->cStatBadFrames.c);
     571    RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS,
     572                 "Buf1.Recv: Frames=%llu Bytes=%llu Overflows=%llu\n",
     573                 pThis->pBuf1->Recv.cStatFrames,
     574                 pThis->pBuf1->Recv.cbStatWritten.c,
     575                 pThis->pBuf1->Recv.cOverflows.c);
     576    RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS,
     577                 "Buf1.Send: Frames=%llu Bytes=%llu Overflows=%llu\n",
     578                 pThis->pBuf1->Send.cStatFrames,
     579                 pThis->pBuf1->Send.cbStatWritten.c,
     580                 pThis->pBuf1->Send.cOverflows.c);
     581
     582}
     583
     584/**
     585 * Performs a simple broadcast test.
     586 *
     587 * @param   pThis               The test instance.
     588 * @param   fHeadGuard          Whether to use a head or tail guard.
     589 */
     590static void doBroadcastTest(PTSTSTATE pThis, bool fHeadGuard)
     591{
     592    static uint16_t const s_au16Frame[7] = { /* dst:*/ 0xffff, 0xffff, 0xffff, /*src:*/0x8086, 0, 0, 0x0800 };
     593
     594    RTTESTI_CHECK_RC_RETV(tstIntNetSendBuf(pThis->pIntNet, &pThis->pBuf0->Send, pThis->hIf0,
     595                                           g_pSession, &s_au16Frame, sizeof(s_au16Frame)),
     596                          VINF_SUCCESS);
     597
     598    /* No echo, please */
     599    RTTESTI_CHECK_RC_RETV(INTNETR0IfWait(pThis->pIntNet, pThis->hIf0, g_pSession, 1), VERR_TIMEOUT);
     600
     601    /* The other interface should see it though.  But Wait should only return once, thank you. */
     602    RTTESTI_CHECK_RC_RETV(INTNETR0IfWait(pThis->pIntNet, pThis->hIf1, g_pSession, 1), VINF_SUCCESS);
     603    RTTESTI_CHECK_RC_RETV(INTNETR0IfWait(pThis->pIntNet, pThis->hIf1, g_pSession, 0), VERR_TIMEOUT);
     604
     605    /* Receive the data. */
     606    const unsigned cbExpect = RT_ALIGN(sizeof(s_au16Frame) + sizeof(INTNETHDR), sizeof(INTNETHDR));
     607    RTTESTI_CHECK_MSG(INTNETRingGetReadable(&pThis->pBuf1->Recv) == cbExpect,
     608                      ("%#x vs. %#x\n", INTNETRingGetReadable(&pThis->pBuf1->Recv), cbExpect));
     609
     610    void *pvBuf;
     611    RTTESTI_CHECK_RC_OK_RETV(RTTestGuardedAlloc(g_hTest, sizeof(s_au16Frame), 1, fHeadGuard, &pvBuf));
     612    uint32_t cb;
     613    RTTESTI_CHECK_MSG_RETV((cb = INTNETRingReadAndSkipFrame(&pThis->pBuf1->Recv, pvBuf)) == sizeof(s_au16Frame),
     614                           ("%#x vs. %#x\n", cb, sizeof(s_au16Frame)));
     615
     616    if (memcmp(pvBuf, &s_au16Frame, sizeof(s_au16Frame)))
     617        RTTestIFailed("Got invalid data!\n"
     618                      "received: %.*Rhxs\n"
     619                      "expected: %.*Rhxs\n",
     620                      cb, pvBuf, sizeof(s_au16Frame), &s_au16Frame);
     621}
     622
     623/**
     624 * Performs a simple unicast test.
     625 *
     626 * @param   pThis               The test instance.
     627 * @param   fHeadGuard          Whether to use a head or tail guard.
     628 */
     629static void doUnicastTest(PTSTSTATE pThis, bool fHeadGuard)
     630{
     631    static uint16_t const s_au16Frame[7] = { /* dst:*/ 0x8086, 0, 0,      /*src:*/0x8086, 0, 1, 0x0800 };
     632
     633    RTTESTI_CHECK_RC_RETV(tstIntNetSendBuf(pThis->pIntNet, &pThis->pBuf1->Send, pThis->hIf1,
     634                                           g_pSession, s_au16Frame, sizeof(s_au16Frame)),
     635                          VINF_SUCCESS);
     636
     637    /* No echo, please */
     638    RTTESTI_CHECK_RC_RETV(INTNETR0IfWait(pThis->pIntNet, pThis->hIf1, g_pSession, 1), VERR_TIMEOUT);
     639
     640    /* The other interface should see it though.  But Wait should only return once, thank you. */
     641    RTTESTI_CHECK_RC_RETV(INTNETR0IfWait(pThis->pIntNet, pThis->hIf0, g_pSession, 1), VINF_SUCCESS);
     642    RTTESTI_CHECK_RC_RETV(INTNETR0IfWait(pThis->pIntNet, pThis->hIf0, g_pSession, 0), VERR_TIMEOUT);
     643
     644    /* Receive the data. */
     645    const unsigned cbExpect = RT_ALIGN(sizeof(s_au16Frame) + sizeof(INTNETHDR), sizeof(INTNETHDR));
     646    RTTESTI_CHECK_MSG(INTNETRingGetReadable(&pThis->pBuf0->Recv) == cbExpect,
     647                      ("%#x vs. %#x\n", INTNETRingGetReadable(&pThis->pBuf0->Recv), cbExpect));
     648
     649    void *pvBuf;
     650    RTTESTI_CHECK_RC_OK_RETV(RTTestGuardedAlloc(g_hTest, sizeof(s_au16Frame), 1, fHeadGuard, &pvBuf));
     651    uint32_t cb;
     652    RTTESTI_CHECK_MSG_RETV((cb = INTNETRingReadAndSkipFrame(&pThis->pBuf0->Recv, pvBuf)) == sizeof(s_au16Frame),
     653                           ("%#x vs. %#x\n", cb, sizeof(s_au16Frame)));
     654
     655    if (memcmp(pvBuf, &s_au16Frame, sizeof(s_au16Frame)))
     656        RTTestIFailed("Got invalid data!\n"
     657                      "received: %.*Rhxs\n"
     658                      "expected: %.*Rhxs\n",
     659                      cb, pvBuf, sizeof(s_au16Frame), s_au16Frame);
     660}
     661
     662static void doTest(PTSTSTATE pThis, uint32_t cbRecv, uint32_t cbSend)
     663{
     664
     665    /*
     666     * Create an INTNET instance.
     667     */
     668    RTTestISub("INTNETR0Create");
     669    RTTESTI_CHECK_RC_RETV(INTNETR0Create(&pThis->pIntNet), VINF_SUCCESS);
     670
     671    /*
     672     * Create two interfaces and activate them.
     673     */
     674    RTTestISub("Network creation");
     675    int rc = tstOpenInterfaces(pThis, "test", cbSend, cbRecv);
     676    if (RT_FAILURE(rc))
     677        return;
     678    RTTESTI_CHECK_RC(INTNETR0IfSetActive(pThis->pIntNet, pThis->hIf0, g_pSession, true), VINF_SUCCESS);
     679    RTTESTI_CHECK_RC(INTNETR0IfSetActive(pThis->pIntNet, pThis->hIf1, g_pSession, true), VINF_SUCCESS);
     680
     681    /*
     682     * Test basic waiting.
     683     */
     684    RTTestISub("INTNETR0IfWait");
     685    RTTESTI_CHECK_RC(INTNETR0IfWait(pThis->pIntNet, pThis->hIf0, g_pSession, 1), VERR_TIMEOUT);
     686    RTTESTI_CHECK_RC(INTNETR0IfWait(pThis->pIntNet, pThis->hIf0, g_pSession, 0), VERR_TIMEOUT);
     687    RTTESTI_CHECK_RC(INTNETR0IfWait(pThis->pIntNet, pThis->hIf1, g_pSession, 1), VERR_TIMEOUT);
     688    RTTESTI_CHECK_RC(INTNETR0IfWait(pThis->pIntNet, pThis->hIf1, g_pSession, 0), VERR_TIMEOUT);
     689
     690    /*
     691     * Broadcast send and receive.
     692     * (This establishes the MAC address of the 1st interface.)
     693     */
     694    RTTestISub("Broadcast");
     695    doBroadcastTest(pThis, false /*fHeadGuard*/);
     696    doBroadcastTest(pThis, true /*fHeadGuard*/);
     697
     698    /*
     699     * Unicast send and receive.
     700     * (This establishes the MAC address of the 2nd interface.)
     701     */
     702    RTTestISub("Unicast");
     703    doUnicastTest(pThis, false /*fHeadGuard*/);
     704    doUnicastTest(pThis, true /*fHeadGuard*/);
     705
     706    /*
     707     * Do the big bi-directional transfer test if the basics worked out.
     708     */
     709    if (!RTTestIErrorCount())
     710    {
     711        RTTestISubF("bi-directional benchmark, cbSend=%u, cbRecv=%u, cbTransfer=%u",
     712                    pThis->pBuf0->cbSend, pThis->pBuf0->cbRecv, g_cbTransfer);
     713        tstBidirectionalTransfer(pThis);
     714    }
     715
     716    /*
     717     * Destroy the service.
     718     */
     719    tstCloseInterfaces(pThis);
     720    INTNETR0Destroy(pThis->pIntNet);
     721}
     722
    415723
    416724int main(int argc, char **argv)
    417725{
    418     /*
    419      * Init the runtime and parse arguments.
    420      */
    421     RTR3Init();
    422 
     726    int rc = RTTestInitAndCreate("tstIntNetR0", &g_hTest);
     727    if (rc)
     728        return rc;
     729
     730    /*
     731     * Parse the arguments.
     732     */
    423733    static RTGETOPTDEF const s_aOptions[] =
    424734    {
    425         { "--recv-buffer",  'r', RTGETOPT_REQ_UINT32 },
    426         { "--send-buffer",  's', RTGETOPT_REQ_UINT32 },
     735        { "--recv-buffer",   'r', RTGETOPT_REQ_UINT32 },
     736        { "--send-buffer",   's', RTGETOPT_REQ_UINT32 },
     737        { "--transfer-size", 'l', RTGETOPT_REQ_UINT32 },
    427738    };
    428739
    429     uint32_t cbRecv = 32 * _1K;
    430     uint32_t cbSend = 1536*2;
     740    uint32_t cbSend = 1536*2 + 4;
     741    uint32_t cbRecv = 0x8000;
    431742
    432743    int ch;
     
    437748        switch (ch)
    438749        {
     750            case 'l':
     751                g_cbTransfer = Value.u32;
     752                break;
     753
    439754            case 'r':
    440755                cbRecv = Value.u32;
     
    450765
    451766    /*
    452      * Create an INTNET instance.
    453      */
    454     RTPrintf("tstIntNetR0: TESTING cbSend=%d cbRecv=%d ...\n", cbSend, cbRecv);
    455     PINTNET pIntNet;
    456     int rc = INTNETR0Create(&pIntNet);
    457     if (RT_FAILURE(rc))
    458     {
    459         RTPrintf("tstIntNetR0: INTNETR0Create failed, rc=%Rrc\n");
    460         return 1;
    461     }
    462 
    463     /*
    464      * Create two interfaces.
    465      */
    466     INTNETIFHANDLE hIf0 = INTNET_HANDLE_INVALID;
    467     rc = INTNETR0Open(pIntNet, g_pSession, "test", kIntNetTrunkType_None, "", 0, 1536*2 + 4, 0x8000, &hIf0);
    468     if (RT_SUCCESS(rc))
    469     {
    470         if (hIf0 != INTNET_HANDLE_INVALID)
    471         {
    472             INTNETIFHANDLE hIf1 = INTNET_HANDLE_INVALID;
    473             rc = INTNETR0Open(pIntNet, g_pSession, "test", kIntNetTrunkType_None, NULL, 0, 1536*2 + 4, 0x8000, &hIf1);
    474             if (RT_SUCCESS(rc))
    475             {
    476                 if (hIf1 != INTNET_HANDLE_INVALID)
    477                 {
    478                     PINTNETBUF pBuf0;
    479                     rc = INTNETR0IfGetRing0Buffer(pIntNet, hIf0, g_pSession, &pBuf0);
    480                     if (RT_FAILURE(rc) || !pBuf0)
    481                     {
    482                         RTPrintf("tstIntNetR0: INTNETIfGetRing0Buffer failed! pBuf0=%p rc=%Rrc\n", pBuf0, rc);
    483                         g_cErrors++;
    484                     }
    485                     PINTNETBUF pBuf1;
    486                     rc = INTNETR0IfGetRing0Buffer(pIntNet, hIf1, g_pSession, &pBuf1);
    487                     if (RT_FAILURE(rc))
    488                     {
    489                         RTPrintf("tstIntNetR0: INTNETIfGetRing0Buffer failed! pBuf1=%p rc=%Rrc\n", pBuf1, rc);
    490                         g_cErrors++;
    491                     }
    492 
    493                     rc = INTNETR0IfSetActive(pIntNet, hIf0, g_pSession, true);
    494                     if (RT_FAILURE(rc))
    495                     {
    496                         RTPrintf("tstIntNetR0: INTNETR0IfSetActive failed! rc=%Rrc\n", rc);
    497                         g_cErrors++;
    498                     }
    499                     rc = INTNETR0IfSetActive(pIntNet, hIf1, g_pSession, true);
    500                     if (RT_FAILURE(rc))
    501                     {
    502                         RTPrintf("tstIntNetR0: INTNETR0IfSetActive failed! rc=%Rrc\n", rc);
    503                         g_cErrors++;
    504                     }
    505 
    506 
    507                     /*
    508                      * Test basic waiting.
    509                      */
    510                     rc = INTNETR0IfWait(pIntNet, hIf0, g_pSession, 1);
    511                     if (rc != VERR_TIMEOUT)
    512                     {
    513                         RTPrintf("tstIntNetR0: INTNETIfWait returned %Rrc expected VERR_TIMEOUT (hIf0)\n", rc);
    514                         g_cErrors++;
    515                     }
    516                     rc = INTNETR0IfWait(pIntNet, hIf1, g_pSession, 0);
    517                     if (rc != VERR_TIMEOUT)
    518                     {
    519                         RTPrintf("tstIntNetR0: INTNETIfWait returned %Rrc expected VERR_TIMEOUT (hIf1)\n", rc);
    520                         g_cErrors++;
    521                     }
    522 
    523                     /*
    524                      * Send and receive.
    525                      */
    526                     rc = tstIntNetSendBuf(pIntNet, &pBuf0->Send, hIf0, g_pSession, &g_TestFrame0, sizeof(g_TestFrame0));
    527                     if (RT_SUCCESS(rc))
    528                     {
    529                         rc = INTNETR0IfWait(pIntNet, hIf0, g_pSession, 1);
    530                         if (rc != VERR_TIMEOUT)
    531                         {
    532                             RTPrintf("tstIntNetR0: INTNETIfWait returned %Rrc expected VERR_TIMEOUT (hIf0, 2nd)\n", rc);
    533                             g_cErrors++;
    534                         }
    535                         rc = INTNETR0IfWait(pIntNet, hIf1, g_pSession, 0);
    536                         if (rc == VINF_SUCCESS)
    537                         {
    538                             /* receive it */
    539                             uint8_t abBuf[sizeof(g_TestFrame0)];
    540                             const unsigned cbExpect = RT_ALIGN(sizeof(g_TestFrame0) + sizeof(INTNETHDR), sizeof(INTNETHDR));
    541                             if (INTNETRingGetReadable(&pBuf1->Recv) != cbExpect)
    542                             {
    543                                 RTPrintf("tstIntNetR0: %d readable bytes, expected %d!\n", INTNETRingGetReadable(&pBuf1->Recv), cbExpect);
    544                                 g_cErrors++;
    545                             }
    546                             uint32_t cb = INTNETRingReadAndSkipFrame(&pBuf1->Recv, abBuf);
    547                             if (cb != sizeof(g_TestFrame0))
    548                             {
    549                                 RTPrintf("tstIntNetR0: read %d frame bytes, expected %d!\n", cb, sizeof(g_TestFrame0));
    550                                 g_cErrors++;
    551                             }
    552                             else if (memcmp(abBuf, &g_TestFrame0, sizeof(g_TestFrame0)))
    553                             {
    554                                 RTPrintf("tstIntNetR0: Got invalid data!\n"
    555                                          "received: %.*Rhxs\n"
    556                                          "expected: %.*Rhxs\n",
    557                                          cb, abBuf, sizeof(g_TestFrame0), &g_TestFrame0);
    558                                 g_cErrors++;
    559                             }
    560 
    561                             /*
    562                              * Send a packet from If1 just to set its MAC address.
    563                              */
    564                             rc = tstIntNetSendBuf(pIntNet, &pBuf1->Send, hIf1, g_pSession, &g_TestFrame1, sizeof(g_TestFrame1));
    565                             if (RT_FAILURE(rc))
    566                             {
    567                                 RTPrintf("tstIntNetR0: INTNETIfSend returned %Rrc! (hIf1)\n", rc);
    568                                 g_cErrors++;
    569                             }
    570 
    571 
    572                             /*
    573                              * Start threaded testcase.
    574                              * Give it 5 mins to finish.
    575                              */
    576                             if (!g_cErrors)
    577                             {
    578                                 MYARGS Args0;
    579                                 RT_ZERO(Args0);
    580                                 Args0.hIf = hIf0;
    581                                 Args0.pBuf = pBuf0;
    582                                 Args0.pIntNet = pIntNet;
    583                                 Args0.Mac.au16[0] = 0x8086;
    584                                 Args0.Mac.au16[1] = 0;
    585                                 Args0.Mac.au16[2] = 0;
    586 
    587                                 MYARGS Args1;
    588                                 RT_ZERO(Args1);
    589                                 Args1.hIf = hIf1;
    590                                 Args1.pBuf = pBuf1;
    591                                 Args1.pIntNet = pIntNet;
    592                                 Args1.Mac.au16[0] = 0x8086;
    593                                 Args1.Mac.au16[1] = 0;
    594                                 Args1.Mac.au16[2] = 1;
    595 
    596                                 RTTHREAD ThreadRecv0 = NIL_RTTHREAD;
    597                                 RTTHREAD ThreadRecv1 = NIL_RTTHREAD;
    598                                 RTTHREAD ThreadSend0 = NIL_RTTHREAD;
    599                                 RTTHREAD ThreadSend1 = NIL_RTTHREAD;
    600                                 rc = RTThreadCreate(&ThreadRecv0, ReceiveThread, &Args0, 0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "RECV0");
    601                                 if (RT_SUCCESS(rc))
    602                                     rc = RTThreadCreate(&ThreadRecv1, ReceiveThread, &Args1, 0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "RECV1");
    603                                 if (RT_SUCCESS(rc))
    604                                     rc = RTThreadCreate(&ThreadSend0, SendThread, &Args0, 0, RTTHREADTYPE_EMULATION, RTTHREADFLAGS_WAITABLE, "SEND0");
    605                                 if (RT_SUCCESS(rc))
    606                                     rc = RTThreadCreate(&ThreadSend1, SendThread, &Args1, 0, RTTHREADTYPE_EMULATION, RTTHREADFLAGS_WAITABLE, "SEND1");
    607                                 if (RT_SUCCESS(rc))
    608                                 {
    609                                     int rc2 = VINF_SUCCESS;
    610                                     rc = RTThreadWait(ThreadSend0, 5*60*1000, &rc2);
    611                                     AssertRC(rc);
    612                                     if (RT_SUCCESS(rc))
    613                                     {
    614                                         ThreadSend0 = NIL_RTTHREAD;
    615                                         rc = RTThreadWait(ThreadSend1, 5*60*1000, RT_SUCCESS(rc2) ? &rc2 : NULL);
    616                                         AssertRC(rc);
    617                                         if (RT_SUCCESS(rc))
    618                                             ThreadSend1 = NIL_RTTHREAD;
    619                                     }
    620                                     if (    RT_SUCCESS(rc)
    621                                         &&  RT_SUCCESS(rc2))
    622                                     {
    623                                         /*
    624                                          * Wait a bit for the receivers to finish up.
    625                                          */
    626                                         unsigned cYields = 100000;
    627                                         while (     (  INTNETRingHasMoreToRead(&pBuf0->Recv)
    628                                                     || INTNETRingHasMoreToRead(&pBuf1->Recv))
    629                                                &&   cYields-- > 0)
    630                                             RTThreadYield();
    631 
    632                                         uint64_t u64Elapsed = RT_MAX(Args0.u64End, Args1.u64End) - RT_MIN(Args0.u64Start, Args1.u64Start);
    633                                         uint64_t u64Speed = (uint64_t)((2 * TEST_TRANSFER_SIZE / 1024) / (u64Elapsed / 1000000000.0));
    634                                         RTPrintf("tstIntNetR0: transfered %d bytes in %'RU64 ns (%'RU64 KB/s)\n",
    635                                                  2 * TEST_TRANSFER_SIZE, u64Elapsed, u64Speed);
    636 
    637                                         /*
    638                                          * Closing time...
    639                                          */
    640                                         rc = RTThreadWait(ThreadRecv0, 5000, &rc2);
    641                                         if (RT_SUCCESS(rc))
    642                                             ThreadRecv0 = NIL_RTTHREAD;
    643                                         if (RT_FAILURE(rc) || RT_FAILURE(rc2))
    644                                         {
    645                                             RTPrintf("tstIntNetR0: Failed waiting on receiver thread 0, rc=%Rrc, rc2=%Rrc\n", rc, rc2);
    646                                             g_cErrors++;
    647                                         }
    648 
    649                                         rc = RTThreadWait(ThreadRecv1, 5000, &rc2);
    650                                         if (RT_SUCCESS(rc))
    651                                             ThreadRecv1 = NIL_RTTHREAD;
    652                                         if (RT_FAILURE(rc) || RT_FAILURE(rc2))
    653                                         {
    654                                             RTPrintf("tstIntNetR0: Failed waiting on receiver thread 1, rc=%Rrc, rc2=%Rrc\n", rc, rc2);
    655                                             g_cErrors++;
    656                                         }
    657 
    658                                         rc = INTNETR0IfClose(pIntNet, hIf0, g_pSession);
    659                                         if (RT_SUCCESS(rc))
    660                                         {
    661                                             hIf0 = INTNET_HANDLE_INVALID;
    662                                             pBuf0 = NULL;
    663                                         }
    664                                         else
    665                                         {
    666                                             RTPrintf("tstIntNetR0: INTNETIfClose failed, rc=%Rrc! (hIf0)\n", rc);
    667                                             g_cErrors++;
    668                                         }
    669 
    670                                         rc = INTNETR0IfClose(pIntNet, hIf1, g_pSession);
    671                                         if (RT_SUCCESS(rc))
    672                                         {
    673                                             hIf1 = INTNET_HANDLE_INVALID;
    674                                             pBuf1 = NULL;
    675                                         }
    676                                         else
    677                                         {
    678                                             RTPrintf("tstIntNetR0: INTNETIfClose failed, rc=%Rrc! (hIf1)\n", rc);
    679                                             g_cErrors++;
    680                                         }
    681 
    682 
    683                                         /* check if the network still exist... */
    684                                         if (pIntNet->pNetworks)
    685                                         {
    686                                             RTPrintf("tstIntNetR0: The network wasn't deleted! (g_cErrors=%d)\n", g_cErrors);
    687                                             g_cErrors++;
    688                                         }
    689                                     }
    690                                     else
    691                                     {
    692                                         RTPrintf("tstIntNetR0: Waiting on senders failed, rc=%Rrc, rc2=%Rrc\n", rc, rc2);
    693                                         g_cErrors++;
    694                                     }
    695 
    696                                     /*
    697                                      * Give them a chance to complete...
    698                                      */
    699                                     RTThreadWait(ThreadRecv0, 5000, NULL);
    700                                     RTThreadWait(ThreadRecv1, 5000, NULL);
    701                                     RTThreadWait(ThreadSend0, 5000, NULL);
    702                                     RTThreadWait(ThreadSend1, 5000, NULL);
    703 
    704                                 }
    705                                 else
    706                                 {
    707                                     RTPrintf("tstIntNetR0: Failed to create threads, rc=%Rrc\n", rc);
    708                                     g_cErrors++;
    709                                 }
    710                             }
    711                         }
    712                         else
    713                         {
    714                             RTPrintf("tstIntNetR0: INTNETIfWait returned %Rrc expected VINF_SUCCESS (hIf1)\n", rc);
    715                             g_cErrors++;
    716                         }
    717                     }
    718                     else
    719                     {
    720                         RTPrintf("tstIntNetR0: INTNETIfSend returned %Rrc! (hIf0)\n", rc);
    721                         g_cErrors++;
    722                     }
    723                 }
    724                 else
    725                 {
    726                     RTPrintf("tstIntNetR0: INTNETOpen returned invalid handle on success! (hIf1)\n");
    727                     g_cErrors++;
    728                 }
    729 
    730                 if (hIf1 != INTNET_HANDLE_INVALID)
    731                     rc = INTNETR0IfClose(pIntNet, hIf1, g_pSession);
    732             }
    733             else
    734             {
    735                 RTPrintf("tstIntNetR0: INTNETOpen failed for the 2nd interface! rc=%Rrc\n", rc);
    736                 g_cErrors++;
    737             }
    738 
    739             if (hIf0 != INTNET_HANDLE_INVALID)
    740                 rc = INTNETR0IfClose(pIntNet, hIf0, g_pSession);
    741         }
    742         else
    743         {
    744             RTPrintf("tstIntNetR0: INTNETOpen returned invalid handle on success! (hIf0)\n");
    745             g_cErrors++;
    746         }
    747     }
    748     else
    749     {
    750         RTPrintf("tstIntNetR0: INTNETOpen failed for the 1st interface! rc=%Rrc\n", rc);
    751         g_cErrors++;
    752     }
    753 
    754     /*
    755      * Destroy the service.
    756      */
    757     INTNETR0Destroy(pIntNet);
    758 
    759     /*
    760      * Summary.
    761      */
    762     if (!g_cErrors)
    763         RTPrintf("tstIntNetR0: SUCCESS\n");
    764     else
    765         RTPrintf("tstIntNetR0: FAILURE - %d errors\n", g_cErrors);
    766 
    767     return !!g_cErrors;
    768 }
    769 
     767     * Do the testing and report summary.
     768     */
     769    TSTSTATE This;
     770    RT_ZERO(This);
     771    doTest(&This, cbRecv, cbSend);
     772
     773    return RTTestSummaryAndDestroy(g_hTest);
     774}
     775
Note: See TracChangeset for help on using the changeset viewer.

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