VirtualBox

Changeset 32277 in vbox


Ignore:
Timestamp:
Sep 7, 2010 11:34:55 AM (14 years ago)
Author:
vboxsync
Message:

DrvVD: Implement alternate select interface for Windows XP to avoid the 15ms delay when waiting for the socket to become writable

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/VBoxHDD.h

    r31776 r32277  
    10311031/** Error condition, hangup, exception or similar. */
    10321032#define VD_INTERFACETCPNET_EVT_ERROR        RT_BIT_32(2)
     1033/** Hint for the select that getting interrupted while waiting is more likely.
     1034 * The interface implementation can optimize the waiting strategy based on this.
     1035 * It is assumed that it is more likely to get one of the above socket events
     1036 * instead of being interrupted if the flag is not set. */
     1037#define VD_INTERFACETCPNET_HINT_INTERRUPT   RT_BIT_32(3)
    10331038/** Mask of the valid bits. */
    1034 #define VD_INTERFACETCPNET_EVT_VALID_MASK   UINT32_C(0x00000007)
     1039#define VD_INTERFACETCPNET_EVT_VALID_MASK   UINT32_C(0x0000000f)
    10351040/** @} */
    10361041
  • trunk/src/VBox/Devices/Storage/DrvVD.cpp

    r31578 r32277  
    3535#include <iprt/poll.h>
    3636#include <iprt/pipe.h>
     37#include <iprt/system.h>
    3738
    3839#ifdef VBOX_WITH_INIP
     
    10021003        }
    10031004    }
     1005    else
     1006    {
     1007        *pSock = pSockInt;
     1008        return VINF_SUCCESS;
     1009    }
    10041010
    10051011    RTMemFree(pSockInt);
     
    10201026        {
    10211027            rc = RTPollSetRemove(pSockInt->hPollSet, VDSOCKET_POLL_ID_SOCKET);
    1022             AssertRC(rc);
     1028            Assert(RT_SUCCESS(rc) || rc == VERR_POLL_HANDLE_ID_NOT_FOUND);
    10231029        }
    10241030        rc = RTPollSetRemove(pSockInt->hPollSet, VDSOCKET_POLL_ID_PIPE);
     
    10561062            rc = RTPollSetAddSocket(pSockInt->hPollSet, pSockInt->hSocket,
    10571063                                    pSockInt->fEventsOld, VDSOCKET_POLL_ID_SOCKET);
    1058 
    1059             if (RT_SUCCESS(rc))
    1060                 return VINF_SUCCESS;
    1061         }
     1064        }
     1065
     1066        if (RT_SUCCESS(rc))
     1067            return VINF_SUCCESS;
    10621068
    10631069        rc = RTTcpClientClose(pSockInt->hSocket);
     
    11811187}
    11821188
    1183 /** @copydoc VDINTERFACETCPNET::pfnSelectOneEx */
    1184 static DECLCALLBACK(int) drvvdTcpSelectOneEx(VDSOCKET Sock, uint32_t fEvents,
    1185                                              uint32_t *pfEvents, RTMSINTERVAL cMillies)
     1189static int drvvdTcpSelectOneExPoll(VDSOCKET Sock, uint32_t fEvents,
     1190                                   uint32_t *pfEvents, RTMSINTERVAL cMillies)
    11861191{
    11871192    int rc = VINF_SUCCESS;
     
    12521257        }
    12531258    }
     1259
     1260    return rc;
     1261}
     1262
     1263/** @copydoc VDINTERFACETCPNET::pfnSelectOneEx */
     1264static DECLCALLBACK(int) drvvdTcpSelectOneExNoPoll(VDSOCKET Sock, uint32_t fEvents,
     1265                                                   uint32_t *pfEvents, RTMSINTERVAL cMillies)
     1266{
     1267    int rc = VINF_SUCCESS;
     1268    PVDSOCKETINT pSockInt = (PVDSOCKETINT)Sock;
     1269
     1270    *pfEvents = 0;
     1271
     1272    ASMAtomicXchgBool(&pSockInt->fWaiting, true);
     1273    if (ASMAtomicXchgBool(&pSockInt->fWokenUp, false))
     1274    {
     1275        ASMAtomicXchgBool(&pSockInt->fWaiting, false);
     1276        return VERR_INTERRUPTED;
     1277    }
     1278
     1279    if (   pSockInt->hSocket == NIL_RTSOCKET
     1280        || !fEvents)
     1281    {
     1282        /*
     1283         * Only the pipe is configured or the caller doesn't wait for a socket event,
     1284         * wait until there is something to read from the pipe.
     1285         */
     1286        size_t cbRead = 0;
     1287        char ch = 0;
     1288        rc = RTPipeReadBlocking(pSockInt->hPipeR, &ch, 1, &cbRead);
     1289        if (RT_SUCCESS(rc))
     1290        {
     1291            Assert(cbRead == 1);
     1292            rc = VERR_INTERRUPTED;
     1293            ASMAtomicXchgBool(&pSockInt->fWokenUp, false);
     1294        }
     1295    }
     1296    else
     1297    {
     1298        uint32_t fSelectEvents = 0;
     1299
     1300        if (fEvents & VD_INTERFACETCPNET_EVT_READ)
     1301            fSelectEvents |= RTSOCKET_EVT_READ;
     1302        if (fEvents & VD_INTERFACETCPNET_EVT_WRITE)
     1303            fSelectEvents |= RTSOCKET_EVT_WRITE;
     1304        if (fEvents & VD_INTERFACETCPNET_EVT_ERROR)
     1305            fSelectEvents |= RTSOCKET_EVT_ERROR;
     1306
     1307        if (fEvents & VD_INTERFACETCPNET_HINT_INTERRUPT)
     1308        {
     1309            uint32_t fEventsRecv = 0;
     1310
     1311            /* Make sure the socket is not in the pollset. */
     1312            rc = RTPollSetRemove(pSockInt->hPollSet, VDSOCKET_POLL_ID_SOCKET);
     1313            Assert(RT_SUCCESS(rc) || rc == VERR_POLL_HANDLE_ID_NOT_FOUND);
     1314
     1315            for (;;)
     1316            {
     1317                uint32_t id = 0;
     1318                rc = RTPoll(pSockInt->hPollSet, 5, &fEvents, &id);
     1319                if (rc == VERR_TIMEOUT)
     1320                {
     1321                    /* Check the socket. */
     1322                    rc = RTTcpSelectOneEx(pSockInt->hSocket, fSelectEvents, &fEventsRecv, 0);
     1323                    if (RT_SUCCESS(rc))
     1324                    {
     1325                        if (fEventsRecv & RTSOCKET_EVT_READ)
     1326                            *pfEvents |= VD_INTERFACETCPNET_EVT_READ;
     1327                        if (fEventsRecv & RTSOCKET_EVT_WRITE)
     1328                            *pfEvents |= VD_INTERFACETCPNET_EVT_WRITE;
     1329                        if (fEventsRecv & RTSOCKET_EVT_ERROR)
     1330                            *pfEvents |= VD_INTERFACETCPNET_EVT_ERROR;
     1331                        break; /* Quit */
     1332                    }
     1333                    else if (rc != VERR_TIMEOUT)
     1334                        break;
     1335                }
     1336                else if (RT_SUCCESS(rc))
     1337                {
     1338                    size_t cbRead = 0;
     1339                    uint8_t abBuf[10];
     1340                    Assert(id == VDSOCKET_POLL_ID_PIPE);
     1341                    Assert((fEventsRecv & RTPOLL_EVT_VALID_MASK) == RTPOLL_EVT_READ);
     1342
     1343                    /* We got interrupted, drain the pipe. */
     1344                    rc = RTPipeRead(pSockInt->hPipeR, abBuf, sizeof(abBuf), &cbRead);
     1345                    AssertRC(rc);
     1346
     1347                    ASMAtomicXchgBool(&pSockInt->fWokenUp, false);
     1348
     1349                    rc = VERR_INTERRUPTED;
     1350                    break;
     1351                }
     1352                else
     1353                    break;
     1354            }
     1355        }
     1356        else /* The caller waits for a socket event. */
     1357        {
     1358            uint32_t fEventsRecv = 0;
     1359
     1360            /* Loop until we got woken up or a socket event occurred. */
     1361            for (;;)
     1362            {
     1363                /** @todo find an adaptive wait algorithm based on the
     1364                 * number of wakeups in the past. */
     1365                rc = RTTcpSelectOneEx(pSockInt->hSocket, fSelectEvents, &fEventsRecv, 5);
     1366                if (rc == VERR_TIMEOUT)
     1367                {
     1368                    /* Check if there is an event pending. */
     1369                    size_t cbRead = 0;
     1370                    char ch = 0;
     1371                    rc = RTPipeRead(pSockInt->hPipeR, &ch, 1, &cbRead);
     1372                    if (RT_SUCCESS(rc) && rc != VINF_TRY_AGAIN)
     1373                    {
     1374                        Assert(cbRead == 1);
     1375                        rc = VERR_INTERRUPTED;
     1376                        ASMAtomicXchgBool(&pSockInt->fWokenUp, false);
     1377                        break; /* Quit */
     1378                    }
     1379                    else
     1380                        Assert(rc == VINF_TRY_AGAIN);
     1381                }
     1382                else if (RT_SUCCESS(rc))
     1383                {
     1384                    if (fEventsRecv & RTSOCKET_EVT_READ)
     1385                        *pfEvents |= VD_INTERFACETCPNET_EVT_READ;
     1386                    if (fEventsRecv & RTSOCKET_EVT_WRITE)
     1387                        *pfEvents |= VD_INTERFACETCPNET_EVT_WRITE;
     1388                    if (fEventsRecv & RTSOCKET_EVT_ERROR)
     1389                        *pfEvents |= VD_INTERFACETCPNET_EVT_ERROR;
     1390                    break; /* Quit */
     1391                }
     1392                else
     1393                    break;
     1394            }
     1395        }
     1396    }
     1397
     1398    ASMAtomicXchgBool(&pSockInt->fWaiting, false);
    12541399
    12551400    return rc;
     
    18922037            pThis->VDITcpNetCallbacks.pfnGetLocalAddress = drvvdTcpGetLocalAddress;
    18932038            pThis->VDITcpNetCallbacks.pfnGetPeerAddress = drvvdTcpGetPeerAddress;
    1894             pThis->VDITcpNetCallbacks.pfnSelectOneEx = drvvdTcpSelectOneEx;
     2039
     2040            /*
     2041             * There is a 15ms delay between receiving the data and marking the socket
     2042             * as readable on Windows XP which hurts async I/O performance of
     2043             * TCP backends badly. Provide a different select method without
     2044             * using poll on XP.
     2045             * This is only used on XP because it is not as efficient as the one using poll
     2046             * and all other Windows versions are working fine.
     2047             */
     2048            char szOS[64];
     2049            memset(szOS, 0, sizeof(szOS));
     2050            rc = RTSystemQueryOSInfo(RTSYSOSINFO_PRODUCT, &szOS[0], sizeof(szOS));
     2051
     2052            if (RT_SUCCESS(rc) && !strncmp(szOS, "Windows XP", 10))
     2053            {
     2054                LogRel(("VD: Detected Windows XP, disabled poll based waiting for TCP\n"));
     2055                pThis->VDITcpNetCallbacks.pfnSelectOneEx = drvvdTcpSelectOneExNoPoll;
     2056            }
     2057            else
     2058                pThis->VDITcpNetCallbacks.pfnSelectOneEx = drvvdTcpSelectOneExPoll;
     2059
    18952060            pThis->VDITcpNetCallbacks.pfnPoke = drvvdTcpPoke;
    18962061        }
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