VirtualBox

Changeset 70481 in vbox


Ignore:
Timestamp:
Jan 7, 2018 6:46:08 PM (7 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
120093
Message:

iprt/socket,tcp,pollset: Added RTTcpCreatePair. Implemented polling fallback for winsock 1.x. Extended tstRTPoll to cover sockets and actual waiting and receiving of events on pipe & socket events.

Location:
trunk
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/iprt/mangling.h

    r70426 r70481  
    21142114# define RTTcpClientConnect                             RT_MANGLER(RTTcpClientConnect)
    21152115# define RTTcpClientConnectEx                           RT_MANGLER(RTTcpClientConnectEx)
     2116# define RTTcpCreatePair                                RT_MANGLER(RTTcpCreatePair)
    21162117# define RTTcpFlush                                     RT_MANGLER(RTTcpFlush)
    21172118# define RTTcpGetLocalAddress                           RT_MANGLER(RTTcpGetLocalAddress)
  • trunk/include/iprt/tcp.h

    r69105 r70481  
    231231
    232232/**
     233 * Creates connected pair of TCP sockets.
     234 *
     235 * @returns IPRT status code.
     236 * @param   phServer            Where to return the "server" side of the pair.
     237 * @param   phClient            Where to return the "client" side of the pair.
     238 *
     239 * @note    There is no server or client side, but we gotta call it something.
     240 */
     241RTR3DECL(int) RTTcpCreatePair(PRTSOCKET phServer, PRTSOCKET phClient, uint32_t fFlags);
     242
     243/**
    233244 * Receive data from a socket.
    234245 *
  • trunk/src/VBox/Runtime/include/internal/socket.h

    r69111 r70481  
    5555DECLHIDDEN(int) rtSocketCreateForNative(RTSOCKETINT **ppSocket, RTSOCKETNATIVE hNative);
    5656DECLHIDDEN(int) rtSocketCreate(PRTSOCKET phSocket, int iDomain, int iType, int iProtocol);
     57DECLHIDDEN(int) rtSocketCreateTcpPair(RTSOCKET *phServer, RTSOCKET *phClient);
    5758DECLHIDDEN(int) rtSocketBind(RTSOCKET hSocket, PCRTNETADDR pAddr);
    5859DECLHIDDEN(int) rtSocketBindRawAddr(RTSOCKET hSocket, void const *pvAddr, size_t cbAddr);
  • trunk/src/VBox/Runtime/r3/socket.cpp

    r70401 r70481  
    165165    /** Saved events which are only posted once. */
    166166    uint32_t            fEventsSaved;
     167    /** Set if we're using the polling fallback. */
     168    bool                fPollFallback;
     169    /** Set if the fallback polling is active (event not set). */
     170    bool volatile       fPollFallbackActive;
     171    /** Set to shut down the fallback polling thread. */
     172    bool volatile       fPollFallbackShutdown;
     173    /** Socket use to wake up the select thread. */
     174    RTSOCKETNATIVE      hPollFallbackNotifyW;
     175    /** Socket the select thread always waits on. */
     176    RTSOCKETNATIVE      hPollFallbackNotifyR;
     177    /** The fallback polling thread. */
     178    RTTHREAD            hPollFallbackThread;
    167179#endif /* RT_OS_WINDOWS */
    168180} RTSOCKETINT;
     
    189201static uint32_t volatile g_uWinSockInitedVersion = 0;
    190202#endif
     203
     204
     205/*********************************************************************************************************************************
     206*   Internal Functions                                                                                                           *
     207*********************************************************************************************************************************/
     208#ifdef RT_OS_WINDOWS
     209static void rtSocketPokePollFallbackThread(RTSOCKETINT *pThis);
     210#endif
     211
    191212
    192213
     
    480501#endif
    481502#ifdef RT_OS_WINDOWS
    482     pThis->hEvent           = WSA_INVALID_EVENT;
    483     pThis->fPollEvts        = 0;
    484     pThis->fSubscribedEvts  = 0;
    485     pThis->fEventsSaved     = 0;
     503    pThis->hEvent                   = WSA_INVALID_EVENT;
     504    pThis->fPollEvts                = 0;
     505    pThis->fSubscribedEvts          = 0;
     506    pThis->fEventsSaved             = 0;
     507    pThis->fPollFallback            = g_uWinSockInitedVersion < MAKEWORD(2, 0)
     508                                   || g_pfnWSACreateEvent == NULL
     509                                   || g_pfnWSACloseEvent == NULL
     510                                   || g_pfnWSAEventSelect == NULL
     511                                   || g_pfnWSAEnumNetworkEvents == NULL;
     512    pThis->fPollFallbackActive      = false;
     513    pThis->fPollFallbackShutdown    = false;
     514    pThis->hPollFallbackNotifyR     = NIL_RTSOCKETNATIVE;
     515    pThis->hPollFallbackNotifyW     = NIL_RTSOCKETNATIVE;
     516    pThis->hPollFallbackThread      = NIL_RTTHREAD;
    486517#endif
    487518    *ppSocket = pThis;
     
    550581
    551582
     583/**
     584 * Wrapper around socketpair() for creating a local TCP connection.
     585 *
     586 * @returns IPRT status code.
     587 * @param   phServer            Where to return the first native socket.
     588 * @param   phClient            Where to return the second native socket.
     589 */
     590static int rtSocketCreateNativeTcpPair(RTSOCKETNATIVE *phServer, RTSOCKETNATIVE *phClient)
     591{
     592#ifdef RT_OS_WINDOWS
     593    /*
     594     * Initialize WinSock and make sure we got the necessary APIs.
     595     */
     596    int rc = rtSocketInitWinsock();
     597    if (RT_FAILURE(rc))
     598        return rc;
     599    AssertReturn(g_pfnsocket, VERR_NET_NOT_UNSUPPORTED);
     600    AssertReturn(g_pfnclosesocket, VERR_NET_NOT_UNSUPPORTED);
     601    AssertReturn(g_pfnsetsockopt, VERR_NET_NOT_UNSUPPORTED);
     602    AssertReturn(g_pfnbind, VERR_NET_NOT_UNSUPPORTED);
     603    AssertReturn(g_pfngetsockname, VERR_NET_NOT_UNSUPPORTED);
     604    AssertReturn(g_pfnlisten, VERR_NET_NOT_UNSUPPORTED);
     605    AssertReturn(g_pfnaccept, VERR_NET_NOT_UNSUPPORTED);
     606    AssertReturn(g_pfnconnect, VERR_NET_NOT_UNSUPPORTED);
     607
     608    /*
     609     * Create the "server" listen socket and the "client" socket.
     610     */
     611    RTSOCKETNATIVE hListener = g_pfnsocket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
     612    if (hListener == NIL_RTSOCKETNATIVE)
     613        return rtSocketError();
     614    RTSOCKETNATIVE hClient = g_pfnsocket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
     615    if (hClient != NIL_RTSOCKETNATIVE)
     616    {
     617
     618        /*
     619         * We let WinSock choose a port number when we bind.
     620         */
     621        union
     622        {
     623            struct sockaddr_in  Ip;
     624            struct sockaddr     Generic;
     625        } uAddr;
     626        RT_ZERO(uAddr);
     627        uAddr.Ip.sin_family      = AF_INET;
     628        uAddr.Ip.sin_addr.s_addr = RT_H2N_U32_C(INADDR_LOOPBACK);
     629        //uAddr.Ip.sin_port      = 0;
     630        int fReuse = 1;
     631        rc = g_pfnsetsockopt(hListener, SOL_SOCKET, SO_REUSEADDR, (const char *)&fReuse, sizeof(fReuse));
     632        if (rc == 0)
     633        {
     634            rc = g_pfnbind(hListener, &uAddr.Generic, sizeof(uAddr.Ip));
     635            if (rc == 0)
     636            {
     637                /*
     638                 * Get the address the client should connect to.  According to the docs,
     639                 * we cannot assume that getsockname sets the IP and family.
     640                 */
     641                RT_ZERO(uAddr);
     642                int cbAddr = sizeof(uAddr.Ip);
     643                rc = g_pfngetsockname(hListener, &uAddr.Generic, &cbAddr);
     644                if (rc == 0)
     645                {
     646                    uAddr.Ip.sin_family      = AF_INET;
     647                    uAddr.Ip.sin_addr.s_addr = RT_H2N_U32_C(INADDR_LOOPBACK);
     648
     649                    /*
     650                     * Listen, connect and accept.
     651                     */
     652                    rc = g_pfnlisten(hListener, 1 /*cBacklog*/);
     653                    if (rc == 0)
     654                    {
     655                        rc = g_pfnconnect(hClient, &uAddr.Generic, sizeof(uAddr.Ip));
     656                        if (rc == 0)
     657                        {
     658                            RTSOCKETNATIVE hServer = g_pfnaccept(hListener, NULL, NULL);
     659                            if (hServer != NIL_RTSOCKETNATIVE)
     660                            {
     661                                g_pfnclosesocket(hListener);
     662
     663                                /*
     664                                 * Done!
     665                                 */
     666                                *phServer = hServer;
     667                                *phClient = hClient;
     668                                return VINF_SUCCESS;
     669                            }
     670                        }
     671                    }
     672                }
     673            }
     674        }
     675        rc = rtSocketError();
     676        g_pfnclosesocket(hClient);
     677    }
     678    else
     679        rc = rtSocketError();
     680    g_pfnclosesocket(hListener);
     681    return rc;
     682
     683#else
     684    /*
     685     * Got socket pair, so use it.
     686     */
     687    int aSockets[2] = { -1, -1 };
     688    int (socketpair(AF_INET, SOCK_STREAM, IPPROTO_TCP, aSockets) == 0)
     689    {
     690        *phServer = aSockets[0];
     691        *phClient = aSockets[0];
     692        return VINF_SUCCESS;
     693    }
     694    return rtSocketError();
     695#endif
     696}
     697
     698
     699/**
     700 * Worker for RTTcpCreatePair.
     701 *
     702 * @returns IPRT status code.
     703 * @param   phServer            Where to return the "server" side of the pair.
     704 * @param   phClient            Where to return the "client" side of the pair.
     705 * @note    There is no server or client side, but we gotta call it something.
     706 */
     707DECLHIDDEN(int) rtSocketCreateTcpPair(RTSOCKET *phServer, RTSOCKET *phClient)
     708{
     709    RTSOCKETNATIVE hServer = NIL_RTSOCKETNATIVE;
     710    RTSOCKETNATIVE hClient = NIL_RTSOCKETNATIVE;
     711    int rc = rtSocketCreateNativeTcpPair(&hServer, &hClient);
     712    if (RT_SUCCESS(rc))
     713    {
     714        rc = rtSocketCreateForNative(phServer, hServer);
     715        if (RT_SUCCESS(rc))
     716        {
     717            rc = rtSocketCreateForNative(phClient, hClient);
     718            if (RT_SUCCESS(rc))
     719                return VINF_SUCCESS;
     720            RTSocketRelease(*phServer);
     721        }
     722        else
     723        {
     724#ifdef RT_OS_WINDOWS
     725            g_pfnclosesocket(hServer);
     726#else
     727            close(hServer);
     728#endif
     729        }
     730#ifdef RT_OS_WINDOWS
     731        g_pfnclosesocket(hClient);
     732#else
     733        close(hClient);
     734#endif
     735    }
     736
     737    *phServer = NIL_RTSOCKET;
     738    *phClient = NIL_RTSOCKET;
     739    return rc;
     740}
     741
     742
    552743RTDECL(uint32_t) RTSocketRetain(RTSOCKET hSocket)
    553744{
     
    580771    if (ASMAtomicCmpXchgBool(&pThis->fClosed, true, false))
    581772    {
     773#ifdef RT_OS_WINDOWS
     774        /*
     775         * Poke the polling thread if active and give it a small chance to stop.
     776         */
     777        if (   pThis->fPollFallback
     778            && pThis->hPollFallbackThread != NIL_RTTHREAD)
     779        {
     780            ASMAtomicWriteBool(&pThis->fPollFallbackShutdown, true);
     781            rtSocketPokePollFallbackThread(pThis);
     782            int rc2 = RTThreadWait(pThis->hPollFallbackThread, RT_MS_1SEC, NULL);
     783            if (RT_SUCCESS(rc2))
     784                pThis->hPollFallbackThread = NIL_RTTHREAD;
     785        }
     786#endif
     787
    582788        /*
    583789         * Close the native handle.
     
    606812#ifdef RT_OS_WINDOWS
    607813        /*
    608          * Close the event.
     814         * Windows specific polling cleanup.
    609815         */
    610816        WSAEVENT hEvent = pThis->hEvent;
     
    612818        {
    613819            pThis->hEvent = WSA_INVALID_EVENT;
    614             Assert(g_pfnWSACloseEvent);
    615             if (g_pfnWSACloseEvent)
    616                 g_pfnWSACloseEvent(hEvent);
     820            if (!pThis->fPollFallback)
     821            {
     822                Assert(g_pfnWSACloseEvent);
     823                if (g_pfnWSACloseEvent)
     824                    g_pfnWSACloseEvent(hEvent);
     825            }
     826            else
     827                CloseHandle(hEvent);
     828        }
     829
     830        if (pThis->fPollFallback)
     831        {
     832            if (pThis->hPollFallbackNotifyW != NIL_RTSOCKETNATIVE)
     833            {
     834                g_pfnclosesocket(pThis->hPollFallbackNotifyW);
     835                pThis->hPollFallbackNotifyW = NIL_RTSOCKETNATIVE;
     836            }
     837
     838            if (pThis->hPollFallbackThread != NIL_RTTHREAD)
     839            {
     840                int rc2 = RTThreadWait(pThis->hPollFallbackThread, RT_MS_1MIN / 2, NULL);
     841                AssertRC(rc2);
     842                pThis->hPollFallbackThread = NIL_RTTHREAD;
     843            }
     844
     845            if (pThis->hPollFallbackNotifyR != NIL_RTSOCKETNATIVE)
     846            {
     847                g_pfnclosesocket(pThis->hPollFallbackNotifyR);
     848                pThis->hPollFallbackNotifyR = NIL_RTSOCKETNATIVE;
     849            }
    617850        }
    618851#endif
     
    16991932
    17001933
    1701 RTDECL(int) RTSocketSelectOneEx(RTSOCKET hSocket, uint32_t fEvents, uint32_t *pfEvents, RTMSINTERVAL cMillies)
    1702 {
    1703     /*
    1704      * Validate input.
    1705      */
    1706     RTSOCKETINT *pThis = hSocket;
    1707     AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
    1708     AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
    1709     AssertPtrReturn(pfEvents, VERR_INVALID_PARAMETER);
    1710     AssertReturn(!(fEvents & ~RTSOCKET_EVT_VALID_MASK), VERR_INVALID_PARAMETER);
    1711     AssertReturn(RTMemPoolRefCount(pThis) >= (pThis->cUsers ? 2U : 1U), VERR_CALLER_NO_REFERENCE);
    1712 
     1934/**
     1935 * Internal worker for RTSocketSelectOneEx and rtSocketPollCheck (fallback)
     1936 *
     1937 * @returns IPRT status code
     1938 * @param   pThis               The socket (valid).
     1939 * @param   fEvents             The events to select for.
     1940 * @param   pfEvents            Where to return the events.
     1941 * @param   cMillies            How long to select for, in milliseconds.
     1942 */
     1943static int rtSocketSelectOneEx(RTSOCKET pThis, uint32_t fEvents, uint32_t *pfEvents, RTMSINTERVAL cMillies)
     1944{
    17131945    RTSOCKETNATIVE hNative = pThis->hNative;
    17141946    if (hNative == NIL_RTSOCKETNATIVE)
     
    17872019#endif
    17882020    return rc;
     2021}
     2022
     2023
     2024RTDECL(int) RTSocketSelectOneEx(RTSOCKET hSocket, uint32_t fEvents, uint32_t *pfEvents, RTMSINTERVAL cMillies)
     2025{
     2026    /*
     2027     * Validate input.
     2028     */
     2029    RTSOCKETINT *pThis = hSocket;
     2030    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
     2031    AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
     2032    AssertPtrReturn(pfEvents, VERR_INVALID_PARAMETER);
     2033    AssertReturn(!(fEvents & ~RTSOCKET_EVT_VALID_MASK), VERR_INVALID_PARAMETER);
     2034    AssertReturn(RTMemPoolRefCount(pThis) >= (pThis->cUsers ? 2U : 1U), VERR_CALLER_NO_REFERENCE);
     2035
     2036    return rtSocketSelectOneEx(pThis, fEvents, pfEvents, cMillies);
    17892037}
    17902038
     
    22742522    }
    22752523    else
    2276         rc = VERR_NET_NOT_UNSUPPORTED;
     2524    {
     2525        AssertCompile(WSA_INVALID_EVENT == (WSAEVENT)NULL);
     2526        pThis->hEvent = CreateEventW(NULL, TRUE /*fManualReset*/, FALSE /*fInitialState*/,  NULL /*pwszName*/);
     2527        *phNative = (RTHCINTPTR)pThis->hEvent;
     2528        if (pThis->hEvent == WSA_INVALID_EVENT)
     2529            rc = RTErrConvertFromWin32(GetLastError());
     2530    }
    22772531
    22782532    rtSocketUnlock(pThis);
     
    22882542
    22892543/**
     2544 * Fallback poller thread.
     2545 *
     2546 * @returns VINF_SUCCESS.
     2547 * @param   hSelf               The thread handle.
     2548 * @param   pvUser              Socket instance data.
     2549 */
     2550static DECLCALLBACK(int) rtSocketPollFallbackThreadProc(RTTHREAD hSelf, void *pvUser)
     2551{
     2552    RTSOCKETINT *pThis = (RTSOCKETINT *)pvUser;
     2553    RT_NOREF(hSelf);
     2554# define __WSAFDIsSet g_pfn__WSAFDIsSet
     2555
     2556    /*
     2557     * The execution loop.
     2558     */
     2559    while (!ASMAtomicReadBool(&pThis->fPollFallbackShutdown))
     2560    {
     2561        /*
     2562         * Do the selecting (with a 15 second timeout because that seems like a good idea).
     2563         */
     2564        struct fd_set SetRead;
     2565        struct fd_set SetWrite;
     2566        struct fd_set SetXcpt;
     2567
     2568        FD_ZERO(&SetRead);
     2569        FD_ZERO(&SetWrite);
     2570        FD_ZERO(&SetXcpt);
     2571
     2572        FD_SET(pThis->hPollFallbackNotifyR, &SetRead);
     2573        FD_SET(pThis->hPollFallbackNotifyR, &SetXcpt);
     2574
     2575        bool     fActive = ASMAtomicReadBool(&pThis->fPollFallbackActive);
     2576        uint32_t fEvents;
     2577        if (!fActive)
     2578            fEvents = 0;
     2579        else
     2580        {
     2581            fEvents = ASMAtomicReadU32(&pThis->fSubscribedEvts);
     2582            if (fEvents & RTPOLL_EVT_READ)
     2583                FD_SET(pThis->hNative, &SetRead);
     2584            if (fEvents & RTPOLL_EVT_WRITE)
     2585                FD_SET(pThis->hNative, &SetWrite);
     2586            if (fEvents & RTPOLL_EVT_ERROR)
     2587                FD_SET(pThis->hNative, &SetXcpt);
     2588        }
     2589
     2590        struct timeval Timeout;
     2591        Timeout.tv_sec  = 15;
     2592        Timeout.tv_usec = 0;
     2593        int rc = g_pfnselect(INT_MAX /*ignored*/, &SetRead, &SetWrite, &SetXcpt, &Timeout);
     2594
     2595        /* Stop immediately if told to shut down. */
     2596        if (ASMAtomicReadBool(&pThis->fPollFallbackShutdown))
     2597            break;
     2598
     2599        /*
     2600         * Process the result.
     2601         */
     2602        if (rc > 0)
     2603        {
     2604            /* First the socket we're listening on. */
     2605            if (   fEvents
     2606                && (   FD_ISSET(pThis->hNative, &SetRead)
     2607                    || FD_ISSET(pThis->hNative, &SetWrite)
     2608                    || FD_ISSET(pThis->hNative, &SetXcpt)) )
     2609            {
     2610                ASMAtomicWriteBool(&pThis->fPollFallbackActive, false);
     2611                SetEvent(pThis->hEvent);
     2612            }
     2613
     2614            /* Then maintain the notification pipe.  (We only read one byte here
     2615               because we're overly paranoid wrt socket switching to blocking mode.) */
     2616            if (FD_ISSET(pThis->hPollFallbackNotifyR, &SetRead))
     2617            {
     2618                char chIgnored;
     2619                g_pfnrecv(pThis->hPollFallbackNotifyR, &chIgnored, sizeof(chIgnored), MSG_NOSIGNAL);
     2620            }
     2621        }
     2622        else
     2623            AssertMsg(rc == 0, ("%Rrc\n", rtSocketError()));
     2624    }
     2625
     2626# undef __WSAFDIsSet
     2627    return VINF_SUCCESS;
     2628}
     2629
     2630
     2631/**
     2632 * Pokes the fallback thread, making sure it gets out of whatever it's stuck in.
     2633 *
     2634 * @param   pThis               The socket handle.
     2635 */
     2636static void rtSocketPokePollFallbackThread(RTSOCKETINT *pThis)
     2637{
     2638    Assert(pThis->fPollFallback);
     2639    if (pThis->hPollFallbackThread != NIL_RTTHREAD)
     2640    {
     2641        int cbWritten = g_pfnsend(pThis->hPollFallbackNotifyW, "!", 1, MSG_NOSIGNAL);
     2642        AssertMsg(cbWritten == 1, ("cbWritten=%d err=%Rrc\n",  rtSocketError()));
     2643        RT_NOREF_PV(cbWritten);
     2644    }
     2645}
     2646
     2647
     2648/**
     2649 * Called by rtSocketPollStart to make the thread start selecting on the socket.
     2650 *
     2651 * @returns 0 on success, RTPOLL_EVT_ERROR on failure.
     2652 * @param   pThis               The socket handle.
     2653 */
     2654static uint32_t rtSocketPollFallbackStart(RTSOCKETINT *pThis)
     2655{
     2656    /*
     2657     * Reset the event and tell the thread to start selecting on the socket.
     2658     */
     2659    ResetEvent(pThis->hEvent);
     2660    ASMAtomicWriteBool(&pThis->fPollFallbackActive, true);
     2661
     2662    /*
     2663     * Wake up the thread the thread.
     2664     */
     2665    if (pThis->hPollFallbackThread != NIL_RTTHREAD)
     2666        rtSocketPokePollFallbackThread(pThis);
     2667    else
     2668    {
     2669        /*
     2670         * Not running, need to set it up and start it.
     2671         */
     2672        AssertLogRelReturn(pThis->hEvent != NULL && pThis->hEvent != INVALID_HANDLE_VALUE, RTPOLL_EVT_ERROR);
     2673
     2674        /* Create the notification socket pair. */
     2675        int rc;
     2676        if (pThis->hPollFallbackNotifyR == NIL_RTSOCKETNATIVE)
     2677        {
     2678            rc = rtSocketCreateNativeTcpPair(&pThis->hPollFallbackNotifyW, &pThis->hPollFallbackNotifyR);
     2679            AssertLogRelRCReturn(rc, RTPOLL_EVT_ERROR);
     2680
     2681            /* Make the read end non-blocking (not fatal). */
     2682            u_long fNonBlocking = 1;
     2683            rc = g_pfnioctlsocket(pThis->hPollFallbackNotifyR, FIONBIO, &fNonBlocking);
     2684            AssertLogRelMsg(rc == 0,  ("rc=%#x %Rrc\n", rc, rtSocketError()));
     2685        }
     2686
     2687        /* Finally, start the thread.  ASSUME we don't need too much stack. */
     2688        rc = RTThreadCreate(&pThis->hPollFallbackThread, rtSocketPollFallbackThreadProc, pThis,
     2689                            _128K, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "sockpoll");
     2690        AssertLogRelRCReturn(rc, RTPOLL_EVT_ERROR);
     2691    }
     2692    return 0;
     2693}
     2694
     2695
     2696/**
    22902697 * Undos the harm done by WSAEventSelect.
    22912698 *
     
    22982705    if (pThis->fSubscribedEvts)
    22992706    {
    2300         if (g_pfnWSAEventSelect && g_pfnioctlsocket)
    2301         {
    2302             if (g_pfnWSAEventSelect(pThis->hNative, WSA_INVALID_EVENT, 0) == 0)
     2707        if (!pThis->fPollFallback)
     2708        {
     2709            Assert(g_pfnWSAEventSelect && g_pfnioctlsocket);
     2710            if (g_pfnWSAEventSelect && g_pfnioctlsocket)
    23032711            {
    2304                 pThis->fSubscribedEvts = 0;
    2305 
    2306                 /*
    2307                  * Switch back to blocking mode if that was the state before the
    2308                  * operation.
    2309                  */
    2310                 if (pThis->fBlocking)
     2712                if (g_pfnWSAEventSelect(pThis->hNative, WSA_INVALID_EVENT, 0) == 0)
    23112713                {
    2312                     u_long fNonBlocking = 0;
    2313                     int rc2 = g_pfnioctlsocket(pThis->hNative, FIONBIO, &fNonBlocking);
    2314                     if (rc2 != 0)
     2714                    pThis->fSubscribedEvts = 0;
     2715
     2716                    /*
     2717                     * Switch back to blocking mode if that was the state before the
     2718                     * operation.
     2719                     */
     2720                    if (pThis->fBlocking)
    23152721                    {
    2316                         rc = rtSocketError();
    2317                         AssertMsgFailed(("%Rrc; rc2=%d\n", rc, rc2));
     2722                        u_long fNonBlocking = 0;
     2723                        int rc2 = g_pfnioctlsocket(pThis->hNative, FIONBIO, &fNonBlocking);
     2724                        if (rc2 != 0)
     2725                        {
     2726                            rc = rtSocketError();
     2727                            AssertMsgFailed(("%Rrc; rc2=%d\n", rc, rc2));
     2728                        }
    23182729                    }
     2730                }
     2731                else
     2732                {
     2733                    rc = rtSocketError();
     2734                    AssertMsgFailed(("%Rrc\n", rc));
    23192735                }
    23202736            }
    23212737            else
    23222738            {
    2323                 rc = rtSocketError();
    2324                 AssertMsgFailed(("%Rrc\n", rc));
     2739                Assert(pThis->fPollFallback);
     2740                rc = VINF_SUCCESS;
    23252741            }
    23262742        }
     2743        /*
     2744         * Just clear the event mask as we never started waiting if we get here.
     2745         */
    23272746        else
    2328             rc = VERR_NET_NOT_UNSUPPORTED;
     2747            ASMAtomicWriteU32(&pThis->fSubscribedEvts, 0);
    23292748    }
    23302749    return rc;
     
    23412760static int rtSocketPollUpdateEvents(RTSOCKETINT *pThis, uint32_t fEvents)
    23422761{
    2343     LONG fNetworkEvents = 0;
    2344     if (fEvents & RTPOLL_EVT_READ)
    2345         fNetworkEvents |= FD_READ;
    2346     if (fEvents & RTPOLL_EVT_WRITE)
    2347         fNetworkEvents |= FD_WRITE;
    2348     if (fEvents & RTPOLL_EVT_ERROR)
    2349         fNetworkEvents |= FD_CLOSE;
    2350     LogFlowFunc(("fNetworkEvents=%#x\n", fNetworkEvents));
    2351     int rc;
    2352     if (g_pfnWSAEventSelect)
    2353     {
     2762    if (!pThis->fPollFallback)
     2763    {
     2764        LONG fNetworkEvents = 0;
     2765        if (fEvents & RTPOLL_EVT_READ)
     2766            fNetworkEvents |= FD_READ;
     2767        if (fEvents & RTPOLL_EVT_WRITE)
     2768            fNetworkEvents |= FD_WRITE;
     2769        if (fEvents & RTPOLL_EVT_ERROR)
     2770            fNetworkEvents |= FD_CLOSE;
     2771        LogFlowFunc(("fNetworkEvents=%#x\n", fNetworkEvents));
     2772
    23542773        if (g_pfnWSAEventSelect(pThis->hNative, pThis->hEvent, fNetworkEvents) == 0)
    23552774        {
     
    23572776            return VINF_SUCCESS;
    23582777        }
    2359         rc = rtSocketError();
     2778
     2779        int rc = rtSocketError();
    23602780        AssertMsgFailed(("fNetworkEvents=%#x rc=%Rrc\n", fNetworkEvents, rtSocketError()));
    2361     }
    2362     else
    2363         rc = VERR_NET_NOT_UNSUPPORTED;
    2364     return rc;
     2781        return rc;
     2782    }
     2783
     2784    /*
     2785     * Update the events we're waiting for.  Caller will poke/start the thread. later
     2786     */
     2787    ASMAtomicWriteU32(&pThis->fSubscribedEvts, fEvents);
     2788    return VINF_SUCCESS;
    23652789}
    23662790
     
    23892813        rc = rtSocketPollUpdateEvents(pThis, pThis->fSubscribedEvts | fEvents);
    23902814
    2391     /* Get the event mask, ASSUMES that WSAEnumNetworkEvents doesn't clear stuff.  */
    2392     if (g_pfnWSAEnumNetworkEvents)
    2393     {
     2815    if (!pThis->fPollFallback)
     2816    {
     2817        /* Atomically get pending events and reset the event semaphore. */
     2818        Assert(g_pfnWSAEnumNetworkEvents);
    23942819        WSANETWORKEVENTS NetEvts;
    23952820        RT_ZERO(NetEvts);
     
    24202845            rc = rtSocketError();
    24212846    }
    2422     else if (RT_SUCCESS(rc))
    2423         rc = VERR_NET_NOT_UNSUPPORTED;
    2424 
    2425     /* Fall back on select if we hit an error above. */
    2426     if (RT_FAILURE(rc))
    2427     {
    2428         rc = RTSocketSelectOneEx(pThis, fEvents, &fRetEvents, 0);
    2429         if (RT_FAILURE(rc))
     2847
     2848    /* Fall back on select if we hit an error above or is using fallback polling. */
     2849    if (pThis->fPollFallback || RT_FAILURE(rc))
     2850    {
     2851        rc = rtSocketSelectOneEx(pThis, fEvents & RTPOLL_EVT_ERROR ? fEvents | RTPOLL_EVT_READ : fEvents, &fRetEvents, 0);
     2852        if (RT_SUCCESS(rc))
     2853        {
     2854            /* rtSocketSelectOneEx may return RTPOLL_EVT_READ on disconnect.  Use
     2855               getpeername to fix this. */
     2856            if ((fRetEvents & (RTPOLL_EVT_READ | RTPOLL_EVT_ERROR)) == RTPOLL_EVT_READ)
     2857            {
     2858# if 0 /* doens't work */
     2859                rtSocketErrorReset();
     2860                char chIgn;
     2861                rc = g_pfnrecv(pThis->hNative, &chIgn, 0, MSG_NOSIGNAL);
     2862                rc = rtSocketError();
     2863                if (RT_FAILURE(rc))
     2864                    fRetEvents |= RTPOLL_EVT_ERROR;
     2865
     2866                rc = g_pfnsend(pThis->hNative, &chIgn, 0, MSG_NOSIGNAL);
     2867                rc = rtSocketError();
     2868                if (RT_FAILURE(rc))
     2869                    fRetEvents |= RTPOLL_EVT_ERROR;
     2870
     2871                RTSOCKADDRUNION u;
     2872                int cbAddr = sizeof(u);
     2873                if (g_pfngetpeername(pThis->hNative, &u.Addr, &cbAddr) == SOCKET_ERROR)
     2874                    fRetEvents |= RTPOLL_EVT_ERROR;
     2875# endif
     2876                /* If no bytes are available, assume error condition. */
     2877                u_long cbAvail = 0;
     2878                rc = ioctlsocket(pThis->hNative, FIONREAD, &cbAvail);
     2879                if (rc == 0 && cbAvail == 0)
     2880                    fRetEvents |= RTPOLL_EVT_ERROR;
     2881            }
     2882            fRetEvents &= fEvents | RTPOLL_EVT_ERROR;
     2883        }
     2884        else if (rc == VERR_TIMEOUT)
    24302885            fRetEvents = 0;
    2431     }
    2432 
    2433 #else  /* RT_OS_OS2 */
     2886        else
     2887            fRetEvents |= RTPOLL_EVT_ERROR;
     2888    }
     2889
     2890# else  /* RT_OS_OS2 */
    24342891    int aFds[4] = { pThis->hNative, pThis->hNative, pThis->hNative, -1 };
    24352892    int rc = os2_select(aFds, 1, 1, 1, 0);
     
    24442901        fRetEvents &= fEvents;
    24452902    }
    2446 #endif /* RT_OS_OS2 */
     2903# endif /* RT_OS_OS2 */
    24472904
    24482905    LogFlowFunc(("fRetEvents=%#x\n", fRetEvents));
     
    25242981        ASMAtomicDecU32(&pThis->cUsers);
    25252982    }
     2983# ifdef RT_OS_WINDOWS
     2984    /*
     2985     * Kick the poller thread on if this is the final entry and we're in
     2986     * winsock 1.x fallback mode.
     2987     */
     2988    else if (pThis->fPollFallback && fFinalEntry)
     2989        fRetEvents = rtSocketPollFallbackStart(pThis);
     2990# endif
    25262991
    25272992    return fRetEvents;
     
    25543019    RT_NOREF_PV(fFinalEntry);
    25553020
    2556     /* Harvest events and clear the event mask for the next round of polling. */
     3021# ifdef RT_OS_WINDOWS
     3022    /*
     3023     * Deactivate the poll thread if we're in winsock 1.x fallback poll mode.
     3024     */
     3025    if (   pThis->fPollFallback
     3026        && pThis->hPollFallbackThread != NIL_RTTHREAD)
     3027    {
     3028        ASMAtomicWriteU32(&pThis->fSubscribedEvts, 0);
     3029        if (ASMAtomicXchgBool(&pThis->fPollFallbackActive, false))
     3030            rtSocketPokePollFallbackThread(pThis);
     3031    }
     3032# endif
     3033
     3034    /*
     3035     * Harvest events and clear the event mask for the next round of polling.
     3036     */
    25573037    uint32_t fRetEvents = rtSocketPollCheck(pThis, fEvents);
    25583038# ifdef RT_OS_WINDOWS
  • trunk/src/VBox/Runtime/testcase/tstRTPoll.cpp

    r69111 r70481  
    3333#include <iprt/err.h>
    3434#include <iprt/file.h>
     35#include <iprt/log.h>
    3536#include <iprt/mem.h>
    3637#include <iprt/pipe.h>
     38#include <iprt/socket.h>
    3739#include <iprt/string.h>
     40#include <iprt/tcp.h>
    3841#include <iprt/test.h>
     42
     43
     44/*********************************************************************************************************************************
     45*   Global Variables                                                                                                             *
     46*********************************************************************************************************************************/
     47/** What we write from the threads in test 3. */
     48static char g_szHello[] = "hello!";
     49
     50
     51static DECLCALLBACK(int) tstRTPoll3PipeWriteThread(RTTHREAD hSelf, void *pvUser)
     52{
     53    RT_NOREF_PV(hSelf);
     54    RTPIPE hPipe = (RTPIPE)pvUser;
     55    RTThreadSleep(RT_MS_1SEC);
     56    return RTPipeWriteBlocking(hPipe, g_szHello, sizeof(g_szHello) - 1, NULL);
     57}
     58
     59
     60static DECLCALLBACK(int) tstRTPoll3SockWriteThread(RTTHREAD hSelf, void *pvUser)
     61{
     62    RT_NOREF_PV(hSelf);
     63    RTSOCKET hSocket = (RTSOCKET)pvUser;
     64    RTThreadSleep(RT_MS_1SEC);
     65    return RTTcpWrite(hSocket, g_szHello, sizeof(g_szHello) - 1);
     66}
     67
     68
     69static void tstRTPoll3(void)
     70{
     71    RTTestISub("Pipe & Sockets");
     72
     73    /*
     74     * Create a set and a pair of pipes and a pair of sockets.
     75     */
     76    RTPOLLSET hSet = NIL_RTPOLLSET;
     77    RTTESTI_CHECK_RC_RETV(RTPollSetCreate(&hSet), VINF_SUCCESS);
     78    RTTESTI_CHECK_RETV(hSet != NIL_RTPOLLSET);
     79
     80    RTTESTI_CHECK_RETV(RTPollSetGetCount(hSet) == 0);
     81    RTTESTI_CHECK_RC(RTPollSetQueryHandle(hSet, 0, NULL), VERR_POLL_HANDLE_ID_NOT_FOUND);
     82
     83    RTPIPE hPipeR;
     84    RTPIPE hPipeW;
     85    RTTESTI_CHECK_RC_RETV(RTPipeCreate(&hPipeR, &hPipeW, 0/*fFlags*/), VINF_SUCCESS);
     86
     87    RTSOCKET hSocketR;
     88    RTSOCKET hSocketW;
     89    RTTESTI_CHECK_RC_RETV(RTTcpCreatePair(&hSocketR, &hSocketW, 0/*fFlags*/), VINF_SUCCESS);
     90
     91    /*
     92     * Add them for error checking.  These must be added first if want we their IDs
     93     * to show up when disconnecting.
     94     */
     95    RTTESTI_CHECK_RC_RETV(RTPollSetAddPipe(hSet, hPipeR, RTPOLL_EVT_ERROR, 1 /*id*/), VINF_SUCCESS);
     96    RTTESTI_CHECK_RC_RETV(RTPollSetAddSocket(hSet, hSocketR, RTPOLL_EVT_ERROR, 2 /*id*/), VINF_SUCCESS);
     97    RTTESTI_CHECK_RETV(RTPollSetGetCount(hSet) == 2);
     98
     99    /*
     100     * Add the read ends.  Polling should time out.
     101     */
     102    RTTESTI_CHECK_RC_RETV(RTPollSetAddPipe(hSet, hPipeR, RTPOLL_EVT_READ, 11 /*id*/), VINF_SUCCESS);
     103    RTTESTI_CHECK_RC_RETV(RTPollSetAddSocket(hSet, hSocketR, RTPOLL_EVT_READ, 12 /*id*/), VINF_SUCCESS);
     104
     105    RTTESTI_CHECK_RETV(RTPollSetGetCount(hSet) == 4);
     106
     107    RTTESTI_CHECK_RC(RTPollSetQueryHandle(hSet, 11 /*id*/, NULL), VINF_SUCCESS);
     108    RTHANDLE Handle;
     109    RTTESTI_CHECK_RC_RETV(RTPollSetQueryHandle(hSet, 11 /*id*/, &Handle), VINF_SUCCESS);
     110    RTTESTI_CHECK(Handle.enmType == RTHANDLETYPE_PIPE);
     111    RTTESTI_CHECK(Handle.u.hPipe == hPipeR);
     112
     113    RTTESTI_CHECK_RC(RTPollSetQueryHandle(hSet, 12 /*id*/, NULL), VINF_SUCCESS);
     114    RTTESTI_CHECK_RC_RETV(RTPollSetQueryHandle(hSet, 12 /*id*/, &Handle), VINF_SUCCESS);
     115    RTTESTI_CHECK(Handle.enmType == RTHANDLETYPE_SOCKET);
     116    RTTESTI_CHECK(Handle.u.hSocket == hSocketR);
     117
     118    RTTESTI_CHECK_RC(RTPoll(hSet, 0, NULL,  NULL), VERR_TIMEOUT);
     119    RTTESTI_CHECK_RC(RTPoll(hSet, 1, NULL,  NULL), VERR_TIMEOUT);
     120
     121    /*
     122     * Add the write ends.  Should indicate that the first one is ready for writing.
     123     */
     124    RTTESTI_CHECK_RC_RETV(RTPollSetAddPipe(hSet, hPipeW, RTPOLL_EVT_WRITE, 21 /*id*/), VINF_SUCCESS);
     125    RTTESTI_CHECK_RC_RETV(RTPollSetAddSocket(hSet, hSocketW, RTPOLL_EVT_WRITE, 22 /*id*/), VINF_SUCCESS);
     126
     127    uint32_t idReady = UINT32_MAX;
     128    RTTESTI_CHECK_RC(RTPoll(hSet, 0, NULL, &idReady), VINF_SUCCESS);
     129    RTTESTI_CHECK(idReady == 21 || idReady == 22);
     130
     131    /*
     132     * Remove the write ends again.
     133     */
     134    RTTESTI_CHECK_RC(RTPollSetRemove(hSet, 21), VINF_SUCCESS);
     135    RTTESTI_CHECK_RC(RTPollSetRemove(hSet, 22), VINF_SUCCESS);
     136    RTTESTI_CHECK_RC(RTPoll(hSet, 0, NULL,  NULL), VERR_TIMEOUT);
     137
     138    /*
     139     * Kick off a thread that writes to the socket after 1 second.
     140     * This will check that we can wait and wake up.
     141     */
     142    for (uint32_t i = 0; i < 2; i++)
     143    {
     144        RTTHREAD hThread;
     145        RTTESTI_CHECK_RC(RTThreadCreate(&hThread, tstRTPoll3SockWriteThread, hSocketW, 0,
     146                                        RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "test3sock"), VINF_SUCCESS);
     147
     148        uint32_t fEvents = 0;
     149        idReady = 0;
     150        uint64_t msStart = RTTimeSystemMilliTS();
     151        RTTESTI_CHECK_RC(RTPoll(hSet, 5 * RT_MS_1SEC, &fEvents, &idReady), VINF_SUCCESS);
     152        uint32_t msElapsed = RTTimeSystemMilliTS() - msStart;
     153        RTTESTI_CHECK_MSG(msElapsed >= 250 && msElapsed < 4500, ("msElapsed=%RU64\n", msElapsed));
     154        RTTESTI_CHECK(fEvents == RTPOLL_EVT_READ);
     155        RTTESTI_CHECK(idReady == 12);
     156
     157        RTThreadWait(hThread, 5 * RT_MS_1SEC, NULL);
     158
     159        /* Drain the socket. */
     160        char    achBuf[128];
     161        size_t  cbRead = 0;
     162        RTTESTI_CHECK_RC(RTTcpReadNB(hSocketR, achBuf, sizeof(achBuf), &cbRead), VINF_SUCCESS);
     163        RTTESTI_CHECK(cbRead == sizeof(g_szHello) - 1 && memcmp(achBuf, g_szHello, sizeof(g_szHello) - 1) == 0);
     164
     165        RTTESTI_CHECK_RC(RTPoll(hSet, 0, NULL,  NULL), VERR_TIMEOUT);
     166        RTTESTI_CHECK_RC(RTPoll(hSet, 1, NULL,  NULL), VERR_TIMEOUT);
     167    }
     168
     169    /*
     170     * Kick off a thread that writes to the pipe after 1 second.
     171     * This will check that we can wait and wake up.
     172     */
     173    for (uint32_t i = 0; i < 2; i++)
     174    {
     175        RTTHREAD hThread;
     176        RTTESTI_CHECK_RC(RTThreadCreate(&hThread, tstRTPoll3PipeWriteThread, hPipeW, 0,
     177                                        RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "test3pipe"), VINF_SUCCESS);
     178
     179        uint32_t fEvents = 0;
     180        idReady = 0;
     181        uint64_t msStart = RTTimeSystemMilliTS();
     182        RTTESTI_CHECK_RC(RTPoll(hSet, 5 * RT_MS_1SEC, &fEvents, &idReady), VINF_SUCCESS);
     183        uint32_t msElapsed = RTTimeSystemMilliTS() - msStart;
     184        RTTESTI_CHECK_MSG(msElapsed >= 250 && msElapsed < 4500, ("msElapsed=%RU64\n", msElapsed));
     185        RTTESTI_CHECK(fEvents == RTPOLL_EVT_READ);
     186        RTTESTI_CHECK(idReady == 11);
     187
     188        RTThreadWait(hThread, 5 * RT_MS_1SEC, NULL);
     189
     190        /* Drain the socket. */
     191        char    achBuf[128];
     192        size_t  cbRead = 0;
     193        RTTESTI_CHECK_RC(RTPipeRead(hPipeR, achBuf, sizeof(achBuf), &cbRead), VINF_SUCCESS);
     194        RTTESTI_CHECK(cbRead == sizeof(g_szHello) - 1 && memcmp(achBuf, g_szHello, sizeof(g_szHello) - 1) == 0);
     195
     196//        RTTESTI_CHECK_RC(RTPoll(hSet, 0, NULL,  NULL), VERR_TIMEOUT);
     197//        RTTESTI_CHECK_RC(RTPoll(hSet, 1, NULL,  NULL), VERR_TIMEOUT);
     198    }
     199
     200
     201    /*
     202     * Close the write socket, checking that we get error returns.
     203     */
     204    RTSocketShutdown(hSocketW, true, true);
     205    RTSocketClose(hSocketW);
     206
     207    uint32_t fEvents = 0;
     208    idReady = 0;
     209    RTTESTI_CHECK_RC(RTPoll(hSet, 0, &fEvents, &idReady), VINF_SUCCESS);
     210    RTTESTI_CHECK_MSG(idReady == 2 || idReady == 12, ("idReady=%u\n", idReady));
     211    RTTESTI_CHECK_MSG(fEvents & RTPOLL_EVT_ERROR, ("fEvents=%#x\n", fEvents));
     212
     213    RTTESTI_CHECK_RC(RTPollSetRemove(hSet, 2), VINF_SUCCESS);
     214    RTTESTI_CHECK_RC(RTPollSetRemove(hSet, 12), VINF_SUCCESS);
     215
     216    RTSocketClose(hSocketR);
     217
     218    /*
     219     * Ditto for the pipe end.
     220     */
     221    RTPipeClose(hPipeW);
     222
     223    idReady = fEvents = 0;
     224    RTTESTI_CHECK_RC(RTPoll(hSet, 0, &fEvents, &idReady), VINF_SUCCESS);
     225    RTTESTI_CHECK_MSG(idReady == 1 || idReady == 11, ("idReady=%u\n", idReady));
     226    RTTESTI_CHECK_MSG(fEvents & RTPOLL_EVT_ERROR, ("fEvents=%#x\n", fEvents));
     227
     228    RTPipeClose(hPipeR);
     229
     230    RTTESTI_CHECK_RC(RTPollSetDestroy(hSet), VINF_SUCCESS);
     231RTLogFlush(NULL);
     232}
    39233
    40234
     
    99293
    100294    RTTESTI_CHECK_RC_RETV(RTPollSetDestroy(hSet), VINF_SUCCESS);
    101 
    102 
    103 
    104295}
    105296
     
    425616        RTAssertSetQuiet(fQuiet);
    426617        RTAssertSetMayPanic(fMayPanic);
     618
     619        tstRTPoll3();
    427620    }
    428621
Note: See TracChangeset for help on using the changeset viewer.

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