VirtualBox

Changeset 14204 in vbox for trunk


Ignore:
Timestamp:
Nov 14, 2008 1:00:50 PM (16 years ago)
Author:
vboxsync
Message:

NAT: next try to get synchronization right

Location:
trunk/src/VBox/Devices/Network
Files:
3 edited

Legend:

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

    r14202 r14204  
    4444# endif
    4545# include <errno.h>
    46 # include<iprt/semaphore.h>
     46# include <iprt/semaphore.h>
     47# include <iprt/req.h>
    4748#endif
    4849
     
    7778    char                    *pszBootFile;
    7879#ifdef VBOX_WITH_SIMPLEFIED_SLIRP_SYNC
    79     /*polling thread*/
     80    /* polling thread */
    8081    PPDMTHREAD              pThread;
    81     /*used for wakep of poling thread*/
    82     RTSEMEVENT              semSndMutex;
    83     RTSEMEVENT              semLinkMutex;
    84 #ifndef RT_OS_WINDOWS
     82    /** Queue for NAT-thread-external events. */
     83    PRTREQQUEUE             pReqQueue;
     84# ifndef RT_OS_WINDOWS
    8585    /** The write end of the control pipe. */
    8686    RTFILE                  PipeWrite;
    8787    /** The read end of the control pipe. */
    8888    RTFILE                  PipeRead;
    89 #else
    90     /*for send event from guest*/
    91     HANDLE                  hSendEvent;
    92     HANDLE                  hNetEvent;
    93 #endif
    94     /** Send buffer */
    95     char                    cBuffer[1600];
    96     size_t                  sBufferSize;
     89# else
     90    /** for external notification */
     91    HANDLE                  hWakeupEvent;
     92# endif
    9793#endif
    9894} DRVNAT, *PDRVNAT;
     
    10298
    10399
     100/**
     101 * Worker function for drvNATSend().
     102 * @thread "NAT" thread.
     103 */
     104static void drvNATSendWorker(PDRVNAT pThis, const void *pvBuf, size_t cb)
     105{
     106    Assert(pThis->enmLinkState == PDMNETWORKLINKSTATE_UP);
     107    if (pThis->enmLinkState == PDMNETWORKLINKSTATE_UP)
     108        slirp_input(pThis->pNATState, (uint8_t *)pvBuf, cb);
     109}
    104110
    105111/**
     
    121127#ifdef VBOX_WITH_SIMPLEFIED_SLIRP_SYNC
    122128
     129    PRTREQ pReq = NULL;
    123130    int rc;
    124     /*notify select to wakeup*/
    125     AssertRelease(cb <= sizeof(pThis->cBuffer));
    126     memcpy(pThis->cBuffer, pvBuf, cb);
    127     pThis->sBufferSize = cb;
     131    /* don't queue new requests when the NAT thread is about to stop */
     132    if (pThis->pThread->enmState != PDMTHREADSTATE_RUNNING)
     133        return VINF_SUCCESS;
     134    rc = RTReqAlloc(pThis->pReqQueue, &pReq, RTREQTYPE_INTERNAL);
     135    AssertReleaseRC(rc);
     136    pReq->u.Internal.pfn      = (PFNRT)drvNATSendWorker;
     137    pReq->u.Internal.cArgs    = 3;
     138    pReq->u.Internal.aArgs[0] = (uintptr_t)pThis;
     139    pReq->u.Internal.aArgs[1] = (uintptr_t)pvBuf;
     140    pReq->u.Internal.aArgs[2] = (uintptr_t)cb;
     141    pReq->fFlags              = RTREQFLAGS_VOID;
     142    rc = RTReqQueue(pReq, 0); /* don't wait, we have to wakeup the NAT thread fist */
     143    if (RT_LIKELY(rc == VERR_TIMEOUT))
     144    {
    128145# ifndef RT_OS_WINDOWS
    129     rc = RTFileWrite(pThis->PipeWrite, "1", 2, NULL);
    130     AssertRC(rc);
     146        /* kick select() */
     147        rc = RTFileWrite(pThis->PipeWrite, "", 1, NULL);
     148        AssertRC(rc);
    131149# else
    132     rc = WSASetEvent(pThis->hSendEvent);
    133     AssertRelease(rc == TRUE);
     150        /* kick WSAWaitForMultipleEvents */
     151        rc = WSASetEvent(pThis->hWakeupEvent);
     152        AssertRelease(rc == TRUE);
    134153# endif
    135     RTSemEventWait(pThis->semSndMutex, RT_INDEFINITE_WAIT);
    136 
    137 #else /* ! VBOX_WITH_SIMPLEFIED_SLIRP_SYNC */
     154        rc = RTReqWait(pReq, RT_INDEFINITE_WAIT);
     155        AssertReleaseRC(rc);
     156    }
     157    else
     158        AssertReleaseRC(rc);
     159    RTReqFree(pReq);
     160
     161#else /* !VBOX_WITH_SIMPLEFIED_SLIRP_SYNC */
    138162
    139163    int rc = RTCritSectEnter(&pThis->CritSect);
    140164    AssertReleaseRC(rc);
    141165
    142     Assert(pThis->enmLinkState == PDMNETWORKLINKSTATE_UP);
    143     if (pThis->enmLinkState == PDMNETWORKLINKSTATE_UP)
    144         slirp_input(pThis->pNATState, (uint8_t *)pvBuf, cb);
     166    drvNATSendWorker(pThis, pvBuf, cb);
    145167
    146168    RTCritSectLeave(&pThis->CritSect);
     
    169191}
    170192
    171 
    172 /**
    173  * Notification on link status changes.
    174  *
    175  * @param   pInterface      Pointer to the interface structure containing the called function pointer.
    176  * @param   enmLinkState    The new link state.
    177  * @thread  EMT
    178  */
    179 static DECLCALLBACK(void) drvNATNotifyLinkChanged(PPDMINETWORKCONNECTOR pInterface, PDMNETWORKLINKSTATE enmLinkState)
    180 {
    181     PDRVNAT pThis = PDMINETWORKCONNECTOR_2_DRVNAT(pInterface);
    182     int rc;
    183 
    184     LogFlow(("drvNATNotifyLinkChanged: enmLinkState=%d\n", enmLinkState));
    185 
    186     LogRel(("drvNATNotifyLinkChanged\n"));
    187 #ifndef VBOX_WITH_SIMPLEFIED_SLIRP_SYNC
    188     rc = RTCritSectEnter(&pThis->CritSect);
    189     AssertReleaseRC(rc);
    190 #endif
     193/**
     194 * Worker function for drvNATNotifyLinkChanged().
     195 * @thread "NAT" thread.
     196 */
     197static void drvNATNotifyLinkChangedWorker(PDRVNAT pThis, PDMNETWORKLINKSTATE enmLinkState)
     198{
    191199    pThis->enmLinkState = enmLinkState;
    192200
     
    195203        case PDMNETWORKLINKSTATE_UP:
    196204            LogRel(("NAT: link up\n"));
    197 #ifndef VBOX_WITH_SIMPLEFIED_SLIRP_SYNC
    198205            slirp_link_up(pThis->pNATState);
    199 #else /* VBOX_WITH_SIMPLEFIED_SLIRP_SYNC */
    200 # ifndef RT_OS_WINDOWS
    201             rc = RTFileWrite(pThis->PipeWrite, "2", 2, NULL);
    202             AssertRC(rc);
    203 # else
    204             WSASetEvent(pThis->hNetEvent);
    205 # endif
    206 #endif /* VBOX_WITH_SIMPLEFIED_SLIRP_SYNC */
    207206            break;
    208207
     
    210209        case PDMNETWORKLINKSTATE_DOWN_RESUME:
    211210            LogRel(("NAT: link down\n"));
    212 #ifndef VBOX_WITH_SIMPLEFIED_SLIRP_SYNC
    213211            slirp_link_down(pThis->pNATState);
    214 #else /* VBOX_WITH_SIMPLEFIED_SLIRP_SYNC */
    215 # ifndef RT_OS_WINDOWS
    216             rc = RTFileWrite(pThis->PipeWrite, "2", 2, NULL);
    217             AssertRC(rc);
    218 # else
    219             WSASetEvent(pThis->hNetEvent);
    220             RTSemEventWait(pThis->semLinkMutex, RT_INDEFINITE_WAIT);
    221 # endif
    222 #endif /* VBOX_WITH_SIMPLEFIED_SLIRP_SYNC */
    223212            break;
    224213
     
    226215            AssertMsgFailed(("drvNATNotifyLinkChanged: unexpected link state %d\n", enmLinkState));
    227216    }
     217}
     218
     219/**
     220 * Notification on link status changes.
     221 *
     222 * @param   pInterface      Pointer to the interface structure containing the called function pointer.
     223 * @param   enmLinkState    The new link state.
     224 * @thread  EMT
     225 */
     226static DECLCALLBACK(void) drvNATNotifyLinkChanged(PPDMINETWORKCONNECTOR pInterface, PDMNETWORKLINKSTATE enmLinkState)
     227{
     228    PDRVNAT pThis = PDMINETWORKCONNECTOR_2_DRVNAT(pInterface);
     229
     230    LogFlow(("drvNATNotifyLinkChanged: enmLinkState=%d\n", enmLinkState));
     231
     232#ifdef VBOX_WITH_SIMPLEFIED_SLIRP_SYNC
     233
     234    PRTREQ pReq = NULL;
     235    bool fWait;
     236    /* don't queue new requests when the NAT thread is about to stop */
     237    if (pThis->pThread->enmState != PDMTHREADSTATE_RUNNING)
     238        return;
     239    int rc = RTReqAlloc(pThis->pReqQueue, &pReq, RTREQTYPE_INTERNAL);
     240    AssertReleaseRC(rc);
     241    pReq->u.Internal.pfn      = (PFNRT)drvNATNotifyLinkChangedWorker;
     242    pReq->u.Internal.cArgs    = 2;
     243    pReq->u.Internal.aArgs[0] = (uintptr_t)pThis;
     244    pReq->u.Internal.aArgs[1] = (uintptr_t)enmLinkState;
     245    pReq->fFlags              = RTREQFLAGS_VOID;
     246    rc = RTReqQueue(pReq, 0); /* don't wait, we have to wakeup the NAT thread fist */
     247    if (RT_LIKELY(rc == VERR_TIMEOUT))
     248    {
     249# ifndef RT_OS_WINDOWS
     250        /* kick select() */
     251        rc = RTFileWrite(pThis->PipeWrite, "", 1, NULL);
     252        AssertRC(rc);
     253# else
     254        /* kick WSAWaitForMultipleEvents() */
     255        rc = WSASetEvent(pThis->hWakeupEvent);
     256        AssertRelease(rc == TRUE);
     257# endif
     258        rc = RTReqWait(pReq, RT_INDEFINITE_WAIT);
     259        AssertReleaseRC(rc);
     260    }
     261    else
     262        AssertReleaseRC(rc);
     263    RTReqFree(pReq);
     264
     265#else /* !VBOX_WITH_SIMPLEFIED_SLIRP_SYNC */
     266
     267    int rc = RTCritSectEnter(&pThis->CritSect);
     268    AssertReleaseRC(rc);
     269    drvNATNotifyLinkChangedWorker(pThis, enmLinkState);
     270    RTCritSectLeave(&pThis->CritSect);
     271
     272#endif /* VBOX_WITH_SIMPLEFIED_SLIRP_SYNC */
     273}
     274
     275
    228276#ifndef VBOX_WITH_SIMPLEFIED_SLIRP_SYNC
    229     RTCritSectLeave(&pThis->CritSect);
    230 #endif
    231 }
    232 
    233 
    234 #ifndef VBOX_WITH_SIMPLEFIED_SLIRP_SYNC
     277
    235278/**
    236279 * Poller callback.
     
    259302    RTCritSectLeave(&pThis->CritSect);
    260303}
    261 #else
     304
     305#else /* VBOX_WITH_SIMPLEFIED_SLIRP_SYNC */
    262306
    263307static DECLCALLBACK(int) drvNATAsyncIoThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
     
    287331    while (pThread->enmState == PDMTHREADSTATE_RUNNING)
    288332    {
    289 
    290333        FD_ZERO(&ReadFDs);
    291334        FD_ZERO(&WriteFDs);
     
    308351            {
    309352                /* drain the pipe */
    310                 char ch[2];
     353                char ch[1];
    311354                size_t cbRead;
    312                 RTFileRead(pThis->PipeRead, &ch, 2, &cbRead);
    313                 switch (ch[0])
    314                 {
    315                     case '1':
    316                         /* called from drvNATSend */
    317                         slirp_input(pThis->pNATState, (uint8_t *)pThis->cBuffer, pThis->sBufferSize);
    318                         RTSemEventSignal(pThis->semSndMutex);
    319                         break;
    320                     case '2':
    321                         /* wakeup only */
    322                         break;
    323                 }
     355                RTFileRead(pThis->PipeRead, &ch, 1, &cbRead);
    324356            }
     357            /* process _all_ outstanding requests but don't wait */
     358            while (RT_SUCCESS(RTReqProcess(pThis->pReqQueue, 0)))
     359                ;
    325360        }
    326361# else /* RT_OS_WINDOWS */
     
    336371        if (event == WSA_WAIT_TIMEOUT)
    337372        {
     373            /* only check for slow/fast timers */
    338374            slirp_select_poll(pThis->pNATState, NULL, NULL, NULL);
    339375            continue;
    340376        }
    341377
    342         /*
    343          * see WSAWaitForMultipleEvents documentation: return value is a minimal index in array
    344          */
    345         if ((event - WSA_WAIT_EVENT_0) >= VBOX_SEND_EVENT_INDEX)
    346             slirp_select_poll(pThis->pNATState, &ReadFDs, &WriteFDs, &XcptFDs);
    347 
    348         if ((event - WSA_WAIT_EVENT_0) == VBOX_SEND_EVENT_INDEX)
    349         {
    350             /** XXX distinguish between drvNATSend and wakeup only */
    351             slirp_input(pThis->pNATState, (uint8_t *)&pThis->cBuffer[0], pThis->sBufferSize);
    352             WSAResetEvent(pThis->hSendEvent);
    353             RTSemEventSignal(pThis->semSndMutex);
    354         }
    355         if ((event - WSA_WAIT_EVENT_0) == VBOX_NET_EVENT_INDEX)
    356         {
    357             switch(pThis->enmLinkState)
    358             {
    359                 case PDMNETWORKLINKSTATE_UP:
    360                     slirp_link_up(pThis->pNATState);
    361                     break;
    362                 case PDMNETWORKLINKSTATE_DOWN:
    363                 case PDMNETWORKLINKSTATE_DOWN_RESUME:
    364                     slirp_link_down(pThis->pNATState);
    365                     break;
    366             }
    367             WSAResetEvent(pThis->hNetEvent);
    368             RTSemEventSignal(pThis->semLinkMutex);
    369             break;
    370         }
     378        /* poll the sockets in any case */
     379        slirp_select_poll(pThis->pNATState, &ReadFDs, &WriteFDs, &XcptFDs);
     380        /* process _all_ outstanding requests but don't wait */
     381        while (RT_SUCCESS(RTReqProcess(This->pReqQueue, 0)))
     382            ;
    371383# endif /* RT_OS_WINDOWS */
    372384    }
     
    387399
    388400# ifndef RT_OS_WINDOWS
    389     int rc = RTFileWrite(pThis->PipeWrite, "2", 2, NULL);
     401    /* kick select() */
     402    int rc = RTFileWrite(pThis->PipeWrite, "", 1, NULL);
    390403    AssertRC(rc);
    391404# else
    392    WSASetEvent(pThis->hNetEvent);
     405    /* kick WSAWaitForMultipleEvents() */
     406    WSASetEvent(pThis->hNetEvent);
    393407# endif
    394     RTSemEventSignal(pThis->semSndMutex);
     408
    395409    return VINF_SUCCESS;
    396410}
    397411
    398 #endif
     412#endif /* VBOX_WITH_SIMPLEFIED_SLIRP_SYNC */
     413
    399414
    400415/**
     
    491506    RTCritSectLeave(&pThis->CritSect);
    492507    RTCritSectDelete(&pThis->CritSect);
    493 #else
    494     RTSemEventDestroy(pThis->semLinkMutex);
    495     RTSemEventDestroy(pThis->semSndMutex);
    496508#endif
    497509}
     
    726738            pDrvIns->pDrvHlp->pfnPDMPollerRegister(pDrvIns, drvNATPoller);
    727739#else
    728             rc = RTSemEventCreate(&pThis->semLinkMutex);
    729             AssertReleaseRC(rc);
    730             rc = RTSemEventCreate(&pThis->semSndMutex);
    731             AssertReleaseRC(rc);
     740            rc = RTReqCreateQueue(&pThis->pReqQueue);
     741            if (RT_FAILURE(rc))
     742                return rc;
    732743
    733744# ifndef RT_OS_WINDOWS
     
    745756            pThis->PipeWrite = fds[1];
    746757# else
    747             pThis->hSendEvent = WSACreateEvent();
    748             pThis->hNetEvent = WSACreateEvent();
    749             slirp_register_external_event(pThis->pNATState, pThis->hSendEvent, VBOX_SEND_EVENT_INDEX);
    750             slirp_register_external_event(pThis->pNATState, pThis->hNetEvent, VBOX_NET_EVENT_INDEX);
     758            pThis->hSendWakeup = CreateEvent(NULL, FALSE, FALSE, NULL); /* auto-reset event */
     759            slirp_register_external_event(pThis->pNATState, pThis->hWakeupEvent, VBOX_WAKEUP_EVENT_INDEX);
    751760# endif
    752761
  • trunk/src/VBox/Devices/Network/slirp/libslirp.h

    r14196 r14204  
    5151
    5252#if defined(VBOX_WITH_SIMPLEFIED_SLIRP_SYNC) && defined(RT_OS_WINDOWS)
    53 #define VBOX_NET_EVENT_INDEX 0
    54 #define VBOX_SEND_EVENT_INDEX 1
    55 #define VBOX_SOCKET_EVENT_INDEX 2
     53/**
     54 * This event is for
     55 *  - slirp_input
     56 *  - slirp_link_up
     57 *  - slirp_link_down
     58 *  - wakeup
     59 *
     60 * The event index should be smaller than VBOX_SOCKET_EVENT_INDEX to ensure
     61 * that we can detect if that event was set (WSAWaitForMultipleEvents()
     62 * returns the index of the first active event).
     63 */
     64#define VBOX_WAKEUP_EVENT_INDEX         0
     65
     66/*
     67 * UDP/TCP socket state change (socket ready to receive, to send, ...)
     68 */
     69#define VBOX_SOCKET_EVENT_INDEX         1
     70
     71/*
     72 * The number of events for WSAWaitForMultipleEvents().
     73 */
     74#define VBOX_EVENT_COUNT                2
     75
    5676HANDLE *slirp_get_events(PNATState pData);
    5777void slirp_register_external_event(PNATState pData, HANDLE hEvent, int index);
    5878#endif
     79
    5980#ifdef __cplusplus
    6081}
  • trunk/src/VBox/Devices/Network/slirp/slirp_state.h

    r14200 r14204  
    117117    struct socket *udp_last_so;
    118118#if defined(VBOX_WITH_SIMPLEFIED_SLIRP_SYNC) && defined(RT_OS_WINDOWS)
    119 #define VBOX_SOCKET_EVENT (pData->phEvents[VBOX_SOCKET_EVENT_INDEX])
    120 #define VBOX_EVENT_COUNT 3
     119# define VBOX_SOCKET_EVENT (pData->phEvents[VBOX_SOCKET_EVENT_INDEX])
    121120    HANDLE phEvents[VBOX_EVENT_COUNT];
    122121#endif
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