VirtualBox

Changeset 22341 in vbox for trunk/src/VBox/Devices


Ignore:
Timestamp:
Aug 19, 2009 10:45:59 AM (15 years ago)
Author:
vboxsync
Message:

NAT: replacing PDM queue with req queue which processed with NATRx thread.
The req worker processing the queue's items waits if RX buffers are available before
sending the packet.

File:
1 edited

Legend:

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

    r22277 r22341  
    118118        x.s_addr = def;                                 \
    119119}while(0)
     120
     121#define QUEUE_SIZE 50
    120122
    121123/*******************************************************************************
     
    150152    PRTREQQUEUE             pReqQueue;
    151153    /* Send queue */
     154#ifndef SLIRP_SPLIT_CAN_OUTPUT
    152155    PPDMQUEUE               pSendQueue;
    153 
    154     RTSEMEVENT semStatus;
     156#endif
     157
    155158#ifdef VBOX_WITH_SLIRP_MT
    156159    PPDMTHREAD              pGuestThread;
     
    171174    PPDMTHREAD              thrNATRx;
    172175    RTSEMEVENT              semNATRx;
    173     bool                    fCanOutput;
    174176    STAMCOUNTER             StatNATRxWakeups;
     177    PRTREQQUEUE             pGuestQueue;
    175178#endif
    176179} DRVNAT;
     
    178181typedef DRVNAT *PDRVNAT;
    179182
    180 #ifdef SLIRP_SPLIT_CAN_OUTPUT
    181 static DECLCALLBACK(int) drvNATRx(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
    182  {
    183     PDRVNAT pThis = PDMINS_2_DATA(pDrvIns, PDRVNAT);
    184     if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
    185         return VINF_SUCCESS;
    186     while (pThread->enmState == PDMTHREADSTATE_RUNNING)
    187     {
    188         int rc;
    189         bool fHaveRxBuffers;
    190         do {
    191             rc = pThis->pPort->pfnWaitReceiveAvail(pThis->pPort, 0);
    192             fHaveRxBuffers = RT_SUCCESS(rc);
    193             if (!fHaveRxBuffers) RTThreadSleep(2);
    194         } while (!fHaveRxBuffers && pThread->enmState == PDMTHREADSTATE_RUNNING);
    195 
    196         if (!pThis->fCanOutput && fHaveRxBuffers)
    197         {
    198             int rc;
    199             pThis->fCanOutput = fHaveRxBuffers;
    200             /*we need inform NAT thread*/
    201 #ifndef RT_OS_WINDOWS
    202             /* kick select() */
    203             rc = RTFileWrite(pThis->PipeWrite, "", 1, NULL);
    204             AssertRC(rc);
    205 #else
    206             /* kick WSAWaitForMultipleEvents */
    207             rc = WSASetEvent(pThis->hWakeupEvent);
    208             AssertRelease(rc == TRUE);
    209 #endif
    210         }
    211         pThis->fCanOutput = fHaveRxBuffers;
    212         RTSemEventWait(pThis->semNATRx, RT_INDEFINITE_WAIT);
    213     }
    214     return VINF_SUCCESS;
    215 }
    216 
    217 
    218 static DECLCALLBACK(int) drvNATRxWakeup(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
    219 {
    220     PDRVNAT pThis = PDMINS_2_DATA(pDrvIns, PDRVNAT);
    221     int rc = RTSemEventSignal(pThis->semNATRx);
    222     STAM_COUNTER_INC(&pThis->StatNATRxWakeups);
    223     AssertReleaseRC(rc);
    224     return VINF_SUCCESS;
    225 }
    226 #endif
    227 
    228183/**
    229184 * NAT queue item.
    230185 */
    231 enum
    232 {
    233     SLIRP_CHECK,
    234     SLIRP_SEND
    235 };
    236 
    237186typedef struct DRVNATQUEUITEM
    238187{
     
    248197typedef DRVNATQUEUITEM *PDRVNATQUEUITEM;
    249198
     199
     200static void drvNATNotifyNATThr(PDRVNAT pThis);
     201
     202#ifdef SLIRP_SPLIT_CAN_OUTPUT
     203static DECLCALLBACK(int) drvNATRx(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
     204 {
     205    uint16_t iSendCounter = 0;
     206    PDRVNAT pThis = PDMINS_2_DATA(pDrvIns, PDRVNAT);
     207    if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
     208        return VINF_SUCCESS;
     209    while (pThread->enmState == PDMTHREADSTATE_RUNNING)
     210    {
     211        RTReqProcess(pThis->pGuestQueue, 0);
     212        RTSemEventWait(pThis->semNATRx, RT_INDEFINITE_WAIT);
     213    }
     214    return VINF_SUCCESS;
     215}
     216
     217
     218static DECLCALLBACK(int) drvNATRxWakeup(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
     219{
     220    PDRVNAT pThis = PDMINS_2_DATA(pDrvIns, PDRVNAT);
     221    int rc = RTSemEventSignal(pThis->semNATRx);
     222    STAM_COUNTER_INC(&pThis->StatNATRxWakeups);
     223    AssertReleaseRC(rc);
     224    return VINF_SUCCESS;
     225}
     226
     227static DECLCALLBACK(void) drvNATRxWorker(PDRVNAT pThis, uint8_t *pu8Buf, int cb)
     228{
     229    int rc;
     230    if (RT_FAILURE(pThis->pPort->pfnWaitReceiveAvail(pThis->pPort, RT_INDEFINITE_WAIT)))
     231    {
     232        AssertMsgFailed(("No RX available even on indefinite wait"));
     233    }
     234    rc = pThis->pPort->pfnReceive(pThis->pPort, pu8Buf, cb);
     235    RTMemFree(pu8Buf);
     236    AssertRC(rc);
     237}
     238#endif
     239
    250240/** Converts a pointer to NAT::INetworkConnector to a PRDVNAT. */
    251241#define PDMINETWORKCONNECTOR_2_DRVNAT(pInterface)   ( (PDRVNAT)((uintptr_t)pInterface - RT_OFFSETOF(DRVNAT, INetworkConnector)) )
     
    311301    rc = RTReqQueue(pReq, 0); /* don't wait, we have to wakeup the NAT thread fist */
    312302    AssertReleaseRC(rc);
     303    drvNATNotifyNATThr(pThis);
     304    LogFlow(("drvNATSend: end\n"));
     305    return VINF_SUCCESS;
     306}
     307
     308static void drvNATNotifyNATThr(PDRVNAT pThis)
     309{
     310    int rc;
    313311#ifndef RT_OS_WINDOWS
    314312    /* kick select() */
    315313    rc = RTFileWrite(pThis->PipeWrite, "", 1, NULL);
    316     AssertRC(rc);
    317314#else
    318315    /* kick WSAWaitForMultipleEvents */
    319316    rc = WSASetEvent(pThis->hWakeupEvent);
    320     AssertRelease(rc == TRUE);
    321 #endif
    322 
    323     LogFlow(("drvNATSend: end\n"));
    324     return VINF_SUCCESS;
    325 }
    326 
     317#endif
     318    AssertReleaseRC(rc);
     319}
    327320
    328321/**
     
    396389    if (RT_LIKELY(rc == VERR_TIMEOUT))
    397390    {
    398 #ifndef RT_OS_WINDOWS
    399         /* kick select() */
    400         rc = RTFileWrite(pThis->PipeWrite, "", 1, NULL);
    401         AssertRC(rc);
    402 #else
    403         /* kick WSAWaitForMultipleEvents() */
    404         rc = WSASetEvent(pThis->hWakeupEvent);
    405         AssertRelease(rc == TRUE);
    406 #endif
     391        drvNATNotifyNATThr(pThis);
    407392        rc = RTReqWait(pReq, RT_INDEFINITE_WAIT);
    408393        AssertReleaseRC(rc);
     
    443428    {
    444429        nFDs = -1;
    445 
    446430        /*
    447431         * To prevent concurent execution of sending/receving threads
     
    524508            continue;
    525509        }
    526 
    527510        /* poll the sockets in any case */
    528511        Log2(("%s: poll\n", __FUNCTION__));
     
    538521# endif
    539522#endif /* RT_OS_WINDOWS */
    540 #ifdef SLIRP_SPLIT_CAN_OUTPUT
    541         if (!pThis->fCanOutput)
    542             drvNATRxWakeup(pThis->pDrvIns, pThis->thrNATRx);
    543 #endif
    544523    }
    545524
     
    548527
    549528
    550 /**
    551  * Unblock the send thread so it can respond to a state change.
    552  *
    553  * @returns VBox status code.
    554  * @param   pDevIns     The pcnet device instance.
    555  * @param   pThread     The send thread.
    556  */
    557 static DECLCALLBACK(int) drvNATAsyncIoWakeup(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
    558 {
    559     PDRVNAT pThis = PDMINS_2_DATA(pDrvIns, PDRVNAT);
    560 
    561 #ifndef RT_OS_WINDOWS
    562     /* kick select() */
    563     int rc = RTFileWrite(pThis->PipeWrite, "", 1, NULL);
    564     AssertRC(rc);
    565 #else /* !RT_OS_WINDOWS */
    566     /* kick WSAWaitForMultipleEvents() */
    567     WSASetEvent(pThis->hWakeupEvent);
    568 #endif /* RT_OS_WINDOWS */
    569 
    570     return VINF_SUCCESS;
    571 }
    572 
    573 #ifdef VBOX_WITH_SLIRP_MT
    574 
    575 static DECLCALLBACK(int) drvNATAsyncIoGuest(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
    576 {
    577     PDRVNAT pThis = PDMINS_2_DATA(pDrvIns, PDRVNAT);
    578 
    579     if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
    580         return VINF_SUCCESS;
    581     while (pThread->enmState == PDMTHREADSTATE_RUNNING)
    582     {
    583         slirp_process_queue(pThis->pNATState);
    584     }
    585     return VINF_SUCCESS;
    586 }
    587 
    588 
    589 static DECLCALLBACK(int) drvNATAsyncIoGuestWakeup(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
    590 {
    591     PDRVNAT pThis = PDMINS_2_DATA(pDrvIns, PDRVNAT);
    592 
    593     return VINF_SUCCESS;
    594 }
    595 
    596 #endif /* VBOX_WITH_SLIRP_MT */
     529        /**
     530         * Unblock the send thread so it can respond to a state change.
     531         *
     532         * @returns VBox status code.
     533         * @param   pDevIns     The pcnet device instance.
     534         * @param   pThread     The send thread.
     535         */
     536        static DECLCALLBACK(int) drvNATAsyncIoWakeup(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
     537        {
     538            PDRVNAT pThis = PDMINS_2_DATA(pDrvIns, PDRVNAT);
     539
     540        #ifndef RT_OS_WINDOWS
     541            /* kick select() */
     542            int rc = RTFileWrite(pThis->PipeWrite, "", 1, NULL);
     543            AssertRC(rc);
     544        #else /* !RT_OS_WINDOWS */
     545            /* kick WSAWaitForMultipleEvents() */
     546            WSASetEvent(pThis->hWakeupEvent);
     547        #endif /* RT_OS_WINDOWS */
     548
     549            return VINF_SUCCESS;
     550        }
     551
     552        #ifdef VBOX_WITH_SLIRP_MT
     553
     554        static DECLCALLBACK(int) drvNATAsyncIoGuest(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
     555        {
     556            PDRVNAT pThis = PDMINS_2_DATA(pDrvIns, PDRVNAT);
     557
     558            if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
     559                return VINF_SUCCESS;
     560            while (pThread->enmState == PDMTHREADSTATE_RUNNING)
     561            {
     562                slirp_process_queue(pThis->pNATState);
     563            }
     564            return VINF_SUCCESS;
     565        }
     566
     567
     568        static DECLCALLBACK(int) drvNATAsyncIoGuestWakeup(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
     569        {
     570            PDRVNAT pThis = PDMINS_2_DATA(pDrvIns, PDRVNAT);
     571
     572            return VINF_SUCCESS;
     573        }
     574
     575        #endif /* VBOX_WITH_SLIRP_MT */
    597576
    598577/**
     
    603582int slirp_can_output(void *pvUser)
    604583{
    605 #ifdef SLIRP_SPLIT_CAN_OUTPUT
    606    PDRVNAT pThis = (PDRVNAT)pvUser;
    607    return pThis->fCanOutput;
    608 #else
    609584    return 1;
    610 #endif
    611585}
    612586
     
    628602    Assert(pThis);
    629603
     604#ifndef SLIRP_SPLIT_CAN_OUTPUT
    630605    PDRVNATQUEUITEM pItem = (PDRVNATQUEUITEM)PDMQueueAlloc(pThis->pSendQueue);
    631606    if (pItem)
     
    649624    STAM_COUNTER_INC(&pThis->StatQueuePktDropped);
    650625    RTMemFree((void *)pu8Buf);
    651 }
    652 
    653 
     626#else
     627    PRTREQ pReq = NULL;
     628    /* don't queue new requests when the NAT thread is about to stop */
     629    if (pThis->pThread->enmState != PDMTHREADSTATE_RUNNING)
     630        return;
     631    int rc = RTReqAlloc(pThis->pGuestQueue, &pReq, RTREQTYPE_INTERNAL);
     632    AssertReleaseRC(rc);
     633    pReq->u.Internal.pfn      = (PFNRT)drvNATRxWorker;
     634    pReq->u.Internal.cArgs    = 3;
     635    pReq->u.Internal.aArgs[0] = (uintptr_t)pThis;
     636    pReq->u.Internal.aArgs[1] = (uintptr_t)pu8Buf;
     637    pReq->u.Internal.aArgs[2] = (uintptr_t)cb;
     638    pReq->fFlags              = RTREQFLAGS_VOID|RTREQFLAGS_NO_WAIT;
     639    rc = RTReqQueue(pReq, 0); /* don't wait, we have to wakeup the NAT thread fist */
     640    AssertReleaseRC(rc);
     641    drvNATRxWakeup(pThis->pDrvIns, pThis->thrNATRx);
     642    STAM_COUNTER_INC(&pThis->StatQueuePktSent);
     643#endif
     644}
     645
     646
     647#ifndef SLIRP_SPLIT_CAN_OUTPUT
    654648/**
    655649 * Queue callback for processing a queued item.
     
    668662    Log(("drvNATQueueConsumer(pItem:%p, pu8Buf:%p, cb:%d)\n", pItem, pItem->pu8Buf, pItem->cb));
    669663    Log2(("drvNATQueueConsumer: pu8Buf:\n%.Rhxd\n", pItem->pu8Buf));
    670 #ifndef SLIRP_SPLIT_CAN_OUTPUT
    671664    if (RT_FAILURE(pThis->pPort->pfnWaitReceiveAvail(pThis->pPort, 0)))
    672665    {
     
    674667        return false;
    675668    }
    676 #else
    677     if (RT_FAILURE(pThis->pPort->pfnWaitReceiveAvail(pThis->pPort, 0)))
    678     {
    679         drvNATRxWakeup(pThis->pDrvIns, pThis->thrNATRx);
    680         STAM_COUNTER_INC(&pThis->StatConsumerFalse);
    681         return false;
    682     }
    683 #endif
    684669    rc = pThis->pPort->pfnReceive(pThis->pPort, pItem->pu8Buf, pItem->cb);
    685670    RTMemFree((void *)pItem->pu8Buf);
     
    689674    return RT_SUCCESS(rc);
    690675}
     676#endif
    691677
    692678
     
    1008994            }
    1009995
    1010             rc = PDMDrvHlpPDMQueueCreate(pDrvIns, sizeof(DRVNATQUEUITEM), 50, 0,
     996
     997#ifndef SLIRP_SPLIT_CAN_OUTPUT
     998            rc = PDMDrvHlpPDMQueueCreate(pDrvIns, sizeof(DRVNATQUEUITEM), QUEUE_SIZE, 0,
    1011999                                         drvNATQueueConsumer, "NAT", &pThis->pSendQueue);
    10121000            if (RT_FAILURE(rc))
     
    10151003                return rc;
    10161004            }
    1017 
    1018             rc = RTSemEventCreate(&pThis->semStatus);
    1019             AssertRC(rc);
    1020 #ifdef SLIRP_SPLIT_CAN_OUTPUT
    1021             pThis->fCanOutput = false;
     1005#else
     1006            rc = RTReqCreateQueue(&pThis->pGuestQueue);
     1007            if (RT_FAILURE(rc))
     1008            {
     1009                LogRel(("NAT: Can't create request queue\n"));
     1010                return rc;
     1011            }
    10221012            rc = PDMDrvHlpPDMThreadCreate(pDrvIns, &pThis->thrNATRx, pThis, drvNATRx,
    10231013                                          drvNATRxWakeup, 128 * _1K, RTTHREADTYPE_IO, "NATRX");
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