VirtualBox

Ignore:
Timestamp:
Apr 1, 2010 12:41:47 PM (15 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
59633
Message:

DrvNamedPipe.cpp: Don't assume we'll get a PowerOff call. Always wait for the thread as we created it with RTTHREADFLAGS_WAITABLE. Use volatile on fShutdown. Must shutdown the server socket or accept() might not abort.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Serial/DrvNamedPipe.cpp

    r27497 r27933  
    11/* $Id$ */
    22/** @file
    3  * VBox stream drivers: Named pipe stream
     3 * Named pipe / local socket stream driver.
    44 */
    55
     
    7676    bool                fIsServer;
    7777#ifdef RT_OS_WINDOWS
    78     /* File handle of the named pipe. */
     78    /** File handle of the named pipe. */
    7979    HANDLE              NamedPipe;
    80     /* Overlapped structure for writes. */
     80    /** Overlapped structure for writes. */
    8181    OVERLAPPED          OverlappedWrite;
    82     /* Overlapped structure for reads. */
     82    /** Overlapped structure for reads. */
    8383    OVERLAPPED          OverlappedRead;
    84     /* Listen thread wakeup semaphore */
    85     RTSEMEVENT          ListenSem;
     84    /** Listen thread wakeup semaphore */
     85    RTSEMEVENTMULTI     ListenSem;
    8686#else /* !RT_OS_WINDOWS */
    8787    /** Socket handle of the local socket for server. */
     
    9393    RTTHREAD            ListenThread;
    9494    /** Flag to signal listening thread to shut down. */
    95     bool                fShutdown;
     95    bool volatile       fShutdown;
    9696} DRVNAMEDPIPE, *PDRVNAMEDPIPE;
    9797
     
    153153                    )
    154154               )
    155 
    156155            {
    157156                FlushFileBuffers(pThis->NamedPipe);
     
    238237        if (RT_FAILURE(rc))
    239238        {
     239            /** @todo WriteFile(pipe) has been observed to return  ERROR_NO_DATA
     240             *        (VERR_NO_DATA) instead of ERROR_BROKEN_PIPE, when the pipe is
     241             *        disconnected. */
    240242            if (    rc == VERR_EOF
    241243                ||  rc == VERR_BROKEN_PIPE)
     
    340342            if (hrc == ERROR_PIPE_CONNECTED)
    341343            {
    342                 RTSemEventWait(pThis->ListenSem, 250);
     344                RTSemEventMultiWait(pThis->ListenSem, 250);
    343345            }
    344346            else if (hrc != ERROR_SUCCESS)
     
    363365            break;
    364366        }
     367        if (pThis->LocalSocket != -1)
     368        {
     369            LogRel(("NamedPipe%d: only single connection supported\n", pThis->pDrvIns->iInstance));
     370            close(s);
     371        }
    365372        else
    366         {
    367             if (pThis->LocalSocket != -1)
    368             {
    369                 LogRel(("NamedPipe%d: only single connection supported\n", pThis->pDrvIns->iInstance));
    370                 close(s);
    371             }
    372             else
    373                 pThis->LocalSocket = s;
    374         }
     373            pThis->LocalSocket = s;
     374
    375375#endif /* !RT_OS_WINDOWS */
    376376    }
     
    379379    CloseHandle(hEvent);
    380380#endif
    381     pThis->ListenThread = NIL_RTTHREAD;
    382381    return VINF_SUCCESS;
    383382}
     
    386385
    387386/**
     387 * Common worker for drvNamedPipePowerOff and drvNamedPipeDestructor.
     388 *
     389 * @param   pThis               The instance data.
     390 */
     391static void drvNamedPipeShutdownListener(PDRVNAMEDPIPE pThis)
     392{
     393    /*
     394     * Signal shutdown of the listener thread.
     395     */
     396    pThis->fShutdown = true;
     397#ifdef RT_OS_WINDOWS
     398    if (    pThis->fIsServer
     399        &&  pThis->NamedPipe != INVALID_HANDLE_VALUE)
     400    {
     401        FlushFileBuffers(pThis->NamedPipe);
     402        DisconnectNamedPipe(pThis->NamedPipe);
     403
     404        BOOL fRc = CloseHandle(pThis->NamedPipe);
     405        Assert(fRc); NOREF(fRc);
     406        pThis->NamedPipe = INVALID_HANDLE_VALUE;
     407
     408        /* Wake up listen thread */
     409        if (pThis->ListenSem != NIL_RTSEMEVENT)
     410            RTSemEventMultiSignal(pThis->ListenSem);
     411    }
     412#else
     413    if (    pThis->fIsServer
     414        &&  pThis->LocalSocketServer != -1)
     415    {
     416        int rc = shutdown(pThis->LocalSocketServer, SHUT_RDWR);
     417        AssertRC(rc == 0); NOREF(rc);
     418
     419        rc = close(pThis->LocalSocketServer);
     420        AssertRC(rc == 0);
     421        pThis->LocalSocketServer = -1;
     422    }
     423#endif
     424}
     425
     426
     427/**
    388428 * Power off a named pipe stream driver instance.
    389429 *
     
    397437    LogFlow(("%s: %s\n", __FUNCTION__, pThis->pszLocation));
    398438
    399     pThis->fShutdown = true;
    400 
    401 #ifdef RT_OS_WINDOWS
    402     if (pThis->NamedPipe != INVALID_HANDLE_VALUE)
    403     {
    404         if (pThis->fIsServer)
    405         {
    406             FlushFileBuffers(pThis->NamedPipe);
    407             DisconnectNamedPipe(pThis->NamedPipe);
    408         }
    409 
    410         CloseHandle(pThis->NamedPipe);
    411         pThis->NamedPipe = INVALID_HANDLE_VALUE;
    412         CloseHandle(pThis->OverlappedRead.hEvent);
    413         CloseHandle(pThis->OverlappedWrite.hEvent);
    414     }
    415     if (pThis->fIsServer)
    416     {
    417         /* Wake up listen thread */
    418         RTSemEventSignal(pThis->ListenSem);
    419         RTSemEventDestroy(pThis->ListenSem);
    420     }
    421 #else /* !RT_OS_WINDOWS */
    422     if (pThis->fIsServer)
    423     {
    424         if (pThis->LocalSocketServer != -1)
    425         {
    426             close(pThis->LocalSocketServer);
    427             pThis->LocalSocketServer = -1;
    428         }
    429         if (pThis->pszLocation)
    430             RTFileDelete(pThis->pszLocation);
    431     }
    432     else
    433     {
    434         if (pThis->LocalSocket != -1)
    435         {
    436             close(pThis->LocalSocket);
    437             pThis->LocalSocket = -1;
    438         }
    439     }
    440 #endif /* !RT_OS_WINDOWS */
     439    drvNamedPipeShutdownListener(pThis);
    441440}
    442441
     
    456455    PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
    457456
    458     if (pThis->ListenThread)
    459     {   RTThreadWait(pThis->ListenThread, 250, NULL);
    460         if (pThis->ListenThread != NIL_RTTHREAD)
    461             LogRel(("NamedPipe%d: listen thread did not terminate\n", pDrvIns->iInstance));
    462     }
    463 
    464     if (pThis->pszLocation)
    465         MMR3HeapFree(pThis->pszLocation);
     457    drvNamedPipeShutdownListener(pThis);
     458
     459    /*
     460     * While the thread exits, clean up as much as we can.
     461     */
     462#ifdef RT_OS_WINDOWS
     463    if (pThis->NamedPipe != INVALID_HANDLE_VALUE)
     464    {
     465        CloseHandle(pThis->NamedPipe);
     466        pThis->NamedPipe = INVALID_HANDLE_VALUE;
     467    }
     468    if (pThis->OverlappedRead.hEvent != NULL)
     469    {
     470        CloseHandle(pThis->OverlappedRead.hEvent);
     471        pThis->OverlappedRead.hEvent = NULL;
     472    }
     473    if (pThis->OverlappedWrite.hEvent != NULL)
     474    {
     475        CloseHandle(pThis->OverlappedWrite.hEvent);
     476        pThis->OverlappedWrite.hEvent = NULL;
     477    }
     478#else /* !RT_OS_WINDOWS */
     479    Assert(pThis->LocalSocketServer == -1);
     480    if (pThis->LocalSocket != -1)
     481    {
     482        int rc = shutdown(pThis->LocalSocket, SHUT_RDWR);
     483        AssertRC(rc == 0); NOREF(rc);
     484
     485        rc = close(pThis->LocalSocket);
     486        Assert(rc == 0);
     487        pThis->LocalSocket = -1;
     488    }
     489    if (   pThis->fIsServer
     490        && pThis->pszLocation)
     491        RTFileDelete(pThis->pszLocation);
     492#endif /* !RT_OS_WINDOWS */
     493
     494    MMR3HeapFree(pThis->pszLocation);
     495    pThis->pszLocation = NULL;
     496
     497    /*
     498     * Wait for the thread.
     499     */
     500    if (pThis->ListenThread != NIL_RTTHREAD)
     501    {
     502        int rc = RTThreadWait(pThis->ListenThread, 30000, NULL);
     503        if (RT_SUCCESS(rc))
     504            pThis->ListenThread = NIL_RTTHREAD;
     505        else
     506            LogRel(("NamedPipe%d: listen thread did not terminate (%Rrc)\n", pDrvIns->iInstance, rc));
     507    }
     508
     509    /*
     510     * The last bits of cleanup.
     511     */
     512#ifdef RT_OS_WINDOWS
     513    if (pThis->ListenSem != NIL_RTSEMEVENT)
     514    {
     515        RTSemEventMultiDestroy(pThis->ListenSem);
     516        pThis->ListenSem = NIL_RTSEMEVENT;
     517    }
     518#endif
    466519}
    467520
     
    474527static DECLCALLBACK(int) drvNamedPipeConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
    475528{
    476     int rc;
    477     char *pszLocation = NULL;
    478529    PDRVNAMEDPIPE pThis = PDMINS_2_DATA(pDrvIns, PDRVNAMEDPIPE);
    479530    PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
     
    487538#ifdef RT_OS_WINDOWS
    488539    pThis->NamedPipe                    = INVALID_HANDLE_VALUE;
     540    pThis->ListenSem                    = NIL_RTSEMEVENTMULTI;
     541    pThis->OverlappedWrite.hEvent       = NULL;
     542    pThis->OverlappedRead.hEvent        = NULL;
    489543#else /* !RT_OS_WINDOWS */
    490544    pThis->LocalSocketServer            = -1;
     
    500554
    501555    /*
    502      * Read the configuration.
     556     * Validate and read the configuration.
    503557     */
    504     if (!CFGMR3AreValuesValid(pCfg, "Location\0IsServer\0"))
    505     {
    506         rc = VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
    507         goto l_out;
    508     }
    509 
    510     rc = CFGMR3QueryStringAlloc(pCfg, "Location", &pszLocation);
     558    PDMDRV_VALIDATE_CONFIG_RETURN(pDrvIns, "Location|IsServer", "");
     559
     560    int rc = CFGMR3QueryStringAlloc(pCfg, "Location", &pThis->pszLocation);
    511561    if (RT_FAILURE(rc))
    512     {
    513         AssertMsgFailed(("Configuration error: query \"Location\" resulted in %Rrc.\n", rc));
    514         goto l_out;
    515     }
    516     pThis->pszLocation = pszLocation;
    517 
    518     bool fIsServer;
    519     rc = CFGMR3QueryBool(pCfg, "IsServer", &fIsServer);
     562        return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
     563                                   N_("Configuration error: querying \"Location\" resulted in %Rrc"), rc);
     564    rc = CFGMR3QueryBool(pCfg, "IsServer", &pThis->fIsServer);
    520565    if (RT_FAILURE(rc))
    521     {
    522         AssertMsgFailed(("Configuration error: query \"IsServer\" resulted in %Rrc.\n", rc));
    523         goto l_out;
    524     }
    525     pThis->fIsServer = fIsServer;
    526 
    527 #ifdef RT_OS_WINDOWS
    528     if (fIsServer)
    529     {
    530         HANDLE hPipe = CreateNamedPipe(pThis->pszLocation, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, 32, 32, 10000, NULL);
    531         if (hPipe == INVALID_HANDLE_VALUE)
     566        return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
     567                                   N_("Configuration error: querying \"IsServer\" resulted in %Rrc"), rc);
     568
     569    /*
     570     * Create/Open the pipe.
     571     */
     572#ifdef RT_OS_WINDOWS
     573    if (pThis->fIsServer)
     574    {
     575        pThis->NamedPipe = CreateNamedPipe(pThis->pszLocation,
     576                                           PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
     577                                           PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
     578                                           1,        /*nMaxInstances*/
     579                                           32,       /*nOutBufferSize*/
     580                                           32,       /*nOutBufferSize*/
     581                                           10000,    /*nDefaultTimeOut*/
     582                                           NULL);    /* lpSecurityAttributes*/
     583        if (pThis->NamedPipe == INVALID_HANDLE_VALUE)
    532584        {
    533585            rc = RTErrConvertFromWin32(GetLastError());
    534586            LogRel(("NamedPipe%d: CreateNamedPipe failed rc=%Rrc\n", pThis->pDrvIns->iInstance));
    535             return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("NamedPipe#%d failed to create named pipe %s"), pDrvIns->iInstance, pszLocation);
    536         }
    537         pThis->NamedPipe = hPipe;
    538 
    539         rc = RTSemEventCreate(&pThis->ListenSem);
    540         AssertRC(rc);
    541 
    542         rc = RTThreadCreate(&pThis->ListenThread, drvNamedPipeListenLoop, (void *)pThis, 0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "SerPipe");
    543         if RT_FAILURE(rc)
    544             return PDMDrvHlpVMSetError(pDrvIns, rc,  RT_SRC_POS, N_("NamedPipe#%d failed to create listening thread"), pDrvIns->iInstance);
     587            return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("NamedPipe#%d failed to create named pipe %s"),
     588                                       pDrvIns->iInstance, pThis->pszLocation);
     589        }
     590
     591        rc = RTSemEventMultiCreate(&pThis->ListenSem);
     592        AssertRCReturn(rc);
     593
     594        rc = RTThreadCreate(&pThis->ListenThread, drvNamedPipeListenLoop, (void *)pThis, 0,
     595                            RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "SerPipe");
     596        if (RT_FAILURE(rc))
     597            return PDMDrvHlpVMSetError(pDrvIns, rc,  RT_SRC_POS, N_("NamedPipe#%d failed to create listening thread"),
     598                                       pDrvIns->iInstance);
    545599
    546600    }
     
    548602    {
    549603        /* Connect to the named pipe. */
    550         HANDLE hPipe = CreateFile(pThis->pszLocation, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
    551         if (hPipe == INVALID_HANDLE_VALUE)
     604        pThis->NamedPipe = CreateFile(pThis->pszLocation, GENERIC_READ | GENERIC_WRITE, 0, NULL,
     605                                      OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
     606        if (pThis->NamedPipe == INVALID_HANDLE_VALUE)
    552607        {
    553608            rc = RTErrConvertFromWin32(GetLastError());
    554609            LogRel(("NamedPipe%d: CreateFile failed rc=%Rrc\n", pThis->pDrvIns->iInstance));
    555             return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("NamedPipe#%d failed to connect to named pipe %s"), pDrvIns->iInstance, pszLocation);
    556         }
    557         pThis->NamedPipe = hPipe;
     610            return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("NamedPipe#%d failed to connect to named pipe %s"),
     611                                       pDrvIns->iInstance, pThis->pszLocation);
     612        }
    558613    }
    559614
    560615    memset(&pThis->OverlappedWrite, 0, sizeof(pThis->OverlappedWrite));
     616    pThis->OverlappedWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
     617    AssertReturn(pThis->OverlappedWrite.hEvent != NULL, VERR_OUT_OF_RESOURCES);
     618
    561619    memset(&pThis->OverlappedRead, 0, sizeof(pThis->OverlappedRead));
    562     pThis->OverlappedWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    563620    pThis->OverlappedRead.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
     621    AssertReturn(pThis->OverlappedRead.hEvent != NULL, VERR_OUT_OF_RESOURCES);
     622
    564623#else /* !RT_OS_WINDOWS */
    565     int s;
     624    int s = socket(PF_UNIX, SOCK_STREAM, 0);
     625    if (s == -1)
     626        return PDMDrvHlpVMSetError(pDrvIns, RTErrConvertFromErrno(errno), RT_SRC_POS,
     627                                   N_("NamedPipe#%d failed to create local socket"), pDrvIns->iInstance);
     628
    566629    struct sockaddr_un addr;
    567 
    568     if ((s = socket(PF_UNIX, SOCK_STREAM, 0)) == -1)
    569         return PDMDrvHlpVMSetError(pDrvIns, RTErrConvertFromErrno(errno), RT_SRC_POS, N_("NamedPipe#%d failed to create local socket"), pDrvIns->iInstance);
    570 
    571630    memset(&addr, 0, sizeof(addr));
    572631    addr.sun_family = AF_UNIX;
    573     strncpy(addr.sun_path, pszLocation, sizeof(addr.sun_path)-1);
    574 
    575     if (fIsServer)
     632    strncpy(addr.sun_path, pThis->pszLocation, sizeof(addr.sun_path) - 1);
     633
     634    if (pThis->fIsServer)
    576635    {
    577636        /* Bind address to the local socket. */
    578         RTFileDelete(pszLocation);
     637        pThis->LocalSocketServer = s;
     638        RTFileDelete(pThis->pszLocation);
    579639        if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) == -1)
    580             return PDMDrvHlpVMSetError(pDrvIns, RTErrConvertFromErrno(errno), RT_SRC_POS, N_("NamedPipe#%d failed to bind to local socket %s"), pDrvIns->iInstance, pszLocation);
    581         pThis->LocalSocketServer = s;
    582         rc = RTThreadCreate(&pThis->ListenThread, drvNamedPipeListenLoop, (void *)pThis, 0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "SerPipe");
    583         if RT_FAILURE(rc)
    584             return PDMDrvHlpVMSetError(pDrvIns, rc,  RT_SRC_POS, N_("NamedPipe#%d failed to create listening thread"), pDrvIns->iInstance);
     640            return PDMDrvHlpVMSetError(pDrvIns, RTErrConvertFromErrno(errno), RT_SRC_POS,
     641                                       N_("NamedPipe#%d failed to bind to local socket %s"),
     642                                       pDrvIns->iInstance, pThis->pszLocation);
     643        rc = RTThreadCreate(&pThis->ListenThread, drvNamedPipeListenLoop, (void *)pThis, 0,
     644                            RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "SerPipe");
     645        if (RT_FAILURE(rc))
     646            return PDMDrvHlpVMSetError(pDrvIns, rc,  RT_SRC_POS,
     647                                       N_("NamedPipe#%d failed to create listening thread"), pDrvIns->iInstance);
    585648    }
    586649    else
    587650    {
    588651        /* Connect to the local socket. */
     652        pThis->LocalSocket = s;
    589653        if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) == -1)
    590             return PDMDrvHlpVMSetError(pDrvIns, RTErrConvertFromErrno(errno), RT_SRC_POS, N_("NamedPipe#%d failed to connect to local socket %s"), pDrvIns->iInstance, pszLocation);
    591         pThis->LocalSocket = s;
     654            return PDMDrvHlpVMSetError(pDrvIns, RTErrConvertFromErrno(errno), RT_SRC_POS,
     655                                       N_("NamedPipe#%d failed to connect to local socket %s"),
     656                                       pDrvIns->iInstance, pThis->pszLocation);
    592657    }
    593658#endif /* !RT_OS_WINDOWS */
    594659
    595 l_out:
    596     if (RT_FAILURE(rc))
    597     {
    598         if (pszLocation)
    599             MMR3HeapFree(pszLocation);
    600         return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("NamedPipe#%d failed to initialize"), pDrvIns->iInstance);
    601     }
    602 
    603     LogFlow(("drvNamedPipeConstruct: location %s isServer %d\n", pszLocation, fIsServer));
    604     LogRel(("NamedPipe: location %s, %s\n", pszLocation, fIsServer ? "server" : "client"));
     660    LogRel(("NamedPipe: location %s, %s\n", pThis->pszLocation, pThis->fIsServer ? "server" : "client"));
    605661    return VINF_SUCCESS;
    606662}
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