VirtualBox

Changeset 71028 in vbox for trunk/src/VBox/Runtime/r3


Ignore:
Timestamp:
Feb 15, 2018 3:28:14 PM (7 years ago)
Author:
vboxsync
Message:

Runtime/RTSerialPort: Implement synchronous read/write methods for POSIX and Windows, allows the serial transport layer in TestExecService to work

Location:
trunk/src/VBox/Runtime/r3
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/r3/posix/serialport-posix.cpp

    r70760 r71028  
    104104    /** Event pending mask. */
    105105    volatile uint32_t   fEvtsPending;
     106    /** Flag whether we are in blocking or non blocking mode. */
     107    bool                fBlocking;
    106108    /** The current active config (we assume no one changes this behind our back). */
    107109    struct termios      PortCfg;
     
    634636
    635637
     638/**
     639 * The slow path of rtSerialPortSwitchBlockingMode that does the actual switching.
     640 *
     641 * @returns IPRT status code.
     642 * @param   pThis                   The internal serial port instance data.
     643 * @param   fBlocking               The desired mode of operation.
     644 * @remarks Do not call directly.
     645 */
     646static int rtSerialPortSwitchBlockingModeSlow(PRTSERIALPORTINTERNAL pThis, bool fBlocking)
     647{
     648    int fFlags = fcntl(pThis->iFd, F_GETFL, 0);
     649    if (fFlags == -1)
     650       return RTErrConvertFromErrno(errno);
     651
     652    if (fBlocking)
     653        fFlags &= ~O_NONBLOCK;
     654    else
     655        fFlags |= O_NONBLOCK;
     656    if (fcntl(pThis->iFd, F_SETFL, fFlags) == -1)
     657       return RTErrConvertFromErrno(errno);
     658
     659    pThis->fBlocking = fBlocking;
     660    return VINF_SUCCESS;
     661}
     662
     663
     664/**
     665 * Switches the serial port to the desired blocking mode if necessary.
     666 *
     667 * @returns IPRT status code.
     668 * @param   pThis                   The internal serial port instance data.
     669 * @param   fBlocking               The desired mode of operation.
     670 */
     671DECLINLINE(int) rtSerialPortSwitchBlockingMode(PRTSERIALPORTINTERNAL pThis, bool fBlocking)
     672{
     673    if (pThis->fBlocking != fBlocking)
     674        return rtSerialPortSwitchBlockingModeSlow(pThis, fBlocking);
     675    return VINF_SUCCESS;
     676}
     677
     678
    636679RTDECL(int)  RTSerialPortOpen(PRTSERIALPORT phSerialPort, const char *pszPortAddress, uint32_t fFlags)
    637680{
     
    659702        pThis->fEvtsPending = 0;
    660703        pThis->iFd          = open(pszPortAddress, fPsxFlags);
     704        pThis->fBlocking    = false;
    661705        if (pThis->iFd != -1)
    662706        {
     
    747791RTDECL(int) RTSerialPortRead(RTSERIALPORT hSerialPort, void *pvBuf, size_t cbToRead, size_t *pcbRead)
    748792{
    749     RT_NOREF(hSerialPort, pvBuf, cbToRead, pcbRead);
    750     return VERR_NOT_IMPLEMENTED;
     793    PRTSERIALPORTINTERNAL pThis = hSerialPort;
     794    AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
     795    AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
     796    AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
     797    AssertReturn(cbToRead > 0, VERR_INVALID_PARAMETER);
     798
     799    int rc = rtSerialPortSwitchBlockingMode(pThis, true);
     800    if (RT_SUCCESS(rc))
     801    {
     802        /*
     803         * Attempt read.
     804         */
     805        ssize_t cbRead = read(pThis->iFd, pvBuf, cbToRead);
     806        if (cbRead >= 0)
     807        {
     808            if (pcbRead)
     809                /* caller can handle partial read. */
     810                *pcbRead = cbRead;
     811            else
     812            {
     813                /* Caller expects all to be read. */
     814                while ((ssize_t)cbToRead > cbRead)
     815                {
     816                    ssize_t cbReadPart = read(pThis->iFd, (uint8_t *)pvBuf + cbRead, cbToRead - cbRead);
     817                    if (cbReadPart < 0)
     818                        return RTErrConvertFromErrno(errno);
     819
     820                    cbRead += cbReadPart;
     821                }
     822            }
     823        }
     824        else
     825            rc = RTErrConvertFromErrno(errno);
     826    }
     827
     828    return rc;
    751829}
    752830
     
    763841    *pcbRead = 0;
    764842
    765     int rc = VINF_SUCCESS;
    766     ssize_t cbThisRead = read(pThis->iFd, pvBuf, cbToRead);
    767     if (cbThisRead > 0)
     843    int rc = rtSerialPortSwitchBlockingMode(pThis, false);
     844    if (RT_SUCCESS(rc))
     845    {
     846        ssize_t cbThisRead = read(pThis->iFd, pvBuf, cbToRead);
     847        if (cbThisRead > 0)
     848        {
     849            /*
     850             * The read data needs to be scanned for the BREAK condition marker encoded in the data stream,
     851             * if break detection was enabled during open.
     852             */
     853            if (pThis->fOpenFlags & RTSERIALPORT_OPEN_F_DETECT_BREAK_CONDITION)
     854            { /** @todo */ }
     855
     856            *pcbRead = cbThisRead;
     857        }
     858        else if (cbThisRead == 0 || errno == EAGAIN || errno == EWOULDBLOCK)
     859            rc = VINF_TRY_AGAIN;
     860        else
     861            rc = RTErrConvertFromErrno(errno);
     862    }
     863
     864    return rc;
     865}
     866
     867
     868RTDECL(int) RTSerialPortWrite(RTSERIALPORT hSerialPort, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
     869{
     870    PRTSERIALPORTINTERNAL pThis = hSerialPort;
     871    AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
     872    AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
     873    AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
     874    AssertReturn(cbToWrite > 0, VERR_INVALID_PARAMETER);
     875
     876    int rc = rtSerialPortSwitchBlockingMode(pThis, true);
     877    if (RT_SUCCESS(rc))
    768878    {
    769879        /*
    770          * The read data needs to be scanned for the BREAK condition marker encoded in the data stream,
    771          * if break detection was enabled during open.
     880         * Attempt write.
    772881         */
    773         if (pThis->fOpenFlags & RTSERIALPORT_OPEN_F_DETECT_BREAK_CONDITION)
    774         { /** @todo */ }
    775 
    776         *pcbRead = cbThisRead;
    777     }
    778     else if (cbThisRead == 0 || errno == EAGAIN || errno == EWOULDBLOCK)
    779         rc = VINF_TRY_AGAIN;
    780     else
    781         rc = RTErrConvertFromErrno(errno);
    782 
    783     return rc;
    784 }
    785 
    786 
    787 RTDECL(int) RTSerialPortWrite(RTSERIALPORT hSerialPort, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
    788 {
    789     RT_NOREF(hSerialPort, pvBuf, cbToWrite, pcbWritten);
    790     return VERR_NOT_IMPLEMENTED;
     882        ssize_t cbWritten = write(pThis->iFd, pvBuf, cbToWrite);
     883        if (cbWritten >= 0)
     884        {
     885            if (pcbWritten)
     886                /* caller can handle partial write. */
     887                *pcbWritten = cbWritten;
     888            else
     889            {
     890                /* Caller expects all to be written. */
     891                while ((ssize_t)cbToWrite > cbWritten)
     892                {
     893                    ssize_t cbWrittenPart = write(pThis->iFd, (const uint8_t *)pvBuf + cbWritten, cbToWrite - cbWritten);
     894                    if (cbWrittenPart < 0)
     895                        return RTErrConvertFromErrno(errno);
     896                    cbWritten += cbWrittenPart;
     897                }
     898            }
     899        }
     900    }
     901
     902    return rc;
    791903}
    792904
     
    803915    *pcbWritten = 0;
    804916
    805     int rc = VINF_SUCCESS;
    806     ssize_t cbThisWrite = write(pThis->iFd, pvBuf, cbToWrite);
    807     if (cbThisWrite > 0)
    808         *pcbWritten = cbThisWrite;
    809     else if (cbThisWrite == 0 || errno == EAGAIN || errno == EWOULDBLOCK)
    810         rc = VINF_TRY_AGAIN;
    811     else
    812         rc = RTErrConvertFromErrno(errno);
     917    int rc = rtSerialPortSwitchBlockingMode(pThis, false);
     918    if (RT_SUCCESS(rc))
     919    {
     920        ssize_t cbThisWrite = write(pThis->iFd, pvBuf, cbToWrite);
     921        if (cbThisWrite > 0)
     922            *pcbWritten = cbThisWrite;
     923        else if (cbThisWrite == 0 || errno == EAGAIN || errno == EWOULDBLOCK)
     924            rc = VINF_TRY_AGAIN;
     925        else
     926            rc = RTErrConvertFromErrno(errno);
     927    }
    813928
    814929    return rc;
     
    8921007    }
    8931008
    894     struct pollfd aPollFds[2]; RT_ZERO(aPollFds);
    895     aPollFds[0].fd = pThis->iFd;
    896     aPollFds[0].events = POLLERR | POLLHUP;
    897     aPollFds[0].revents = 0;
    898     if (   (pThis->fOpenFlags & RTSERIALPORT_OPEN_F_READ)
    899         && (fEvtMask & RTSERIALPORT_EVT_F_DATA_RX))
    900         aPollFds[0].events |= POLLIN;
    901     if (   (pThis->fOpenFlags & RTSERIALPORT_OPEN_F_WRITE)
    902         && (fEvtMask & RTSERIALPORT_EVT_F_DATA_TX))
    903         aPollFds[0].events |= POLLOUT;
    904 
    905     aPollFds[1].fd      = pThis->iFdPipeR;
    906     aPollFds[1].events  = POLLIN | POLLERR | POLLHUP;
    907     aPollFds[1].revents = 0;
    908 
    909     int rcPsx = 0;
    910     int msTimeoutLeft = msTimeout == RT_INDEFINITE_WAIT ? -1 : msTimeout;
    911     while (msTimeoutLeft != 0)
    912     {
    913         uint64_t tsPollStart = RTTimeMilliTS();
    914 
    915         rcPsx = poll(&aPollFds[0], RT_ELEMENTS(aPollFds), msTimeoutLeft);
    916         if (rcPsx != -1 || errno != EINTR)
    917             break;
    918         /* Restart when getting interrupted. */
    919         if (msTimeoutLeft > -1)
    920         {
    921             uint64_t tsPollEnd = RTTimeMilliTS();
    922             uint64_t tsPollSpan = tsPollEnd - tsPollStart;
    923             msTimeoutLeft -= RT_MIN(tsPollSpan, (uint32_t)msTimeoutLeft);
    924         }
    925     }
    926 
    927     int rc = VINF_SUCCESS;
    928     uint32_t fEvtsPending = 0;
    929     if (rcPsx < 0 && errno != EINTR)
    930         rc = RTErrConvertFromErrno(errno);
    931     else if (rcPsx > 0)
    932     {
    933         if (aPollFds[0].revents != 0)
    934         {
    935             fEvtsPending |= (aPollFds[0].revents & POLLIN) ? RTSERIALPORT_EVT_F_DATA_RX : 0;
    936             fEvtsPending |= (aPollFds[0].revents & POLLOUT) ? RTSERIALPORT_EVT_F_DATA_TX : 0;
    937             /** @todo BREAK condition detection. */
    938         }
    939 
    940         if (aPollFds[1].revents != 0)
    941         {
    942             AssertReturn(!(aPollFds[1].revents & (POLLHUP | POLLERR | POLLNVAL)), VERR_INTERNAL_ERROR);
    943             Assert(aPollFds[1].revents & POLLIN);
    944 
    945             uint8_t bWakeupReason = 0;
    946             ssize_t cbRead = read(pThis->iFdPipeR, &bWakeupReason, 1);
    947             if (cbRead == 1)
     1009    int rc = rtSerialPortSwitchBlockingMode(pThis, false);
     1010    if (RT_SUCCESS(rc))
     1011    {
     1012        struct pollfd aPollFds[2]; RT_ZERO(aPollFds);
     1013        aPollFds[0].fd = pThis->iFd;
     1014        aPollFds[0].events = POLLERR | POLLHUP;
     1015        aPollFds[0].revents = 0;
     1016        if (   (pThis->fOpenFlags & RTSERIALPORT_OPEN_F_READ)
     1017            && (fEvtMask & RTSERIALPORT_EVT_F_DATA_RX))
     1018            aPollFds[0].events |= POLLIN;
     1019        if (   (pThis->fOpenFlags & RTSERIALPORT_OPEN_F_WRITE)
     1020            && (fEvtMask & RTSERIALPORT_EVT_F_DATA_TX))
     1021            aPollFds[0].events |= POLLOUT;
     1022
     1023        aPollFds[1].fd      = pThis->iFdPipeR;
     1024        aPollFds[1].events  = POLLIN | POLLERR | POLLHUP;
     1025        aPollFds[1].revents = 0;
     1026
     1027        int rcPsx = 0;
     1028        int msTimeoutLeft = msTimeout == RT_INDEFINITE_WAIT ? -1 : msTimeout;
     1029        while (msTimeoutLeft != 0)
     1030        {
     1031            uint64_t tsPollStart = RTTimeMilliTS();
     1032
     1033            rcPsx = poll(&aPollFds[0], RT_ELEMENTS(aPollFds), msTimeoutLeft);
     1034            if (rcPsx != -1 || errno != EINTR)
     1035                break;
     1036            /* Restart when getting interrupted. */
     1037            if (msTimeoutLeft > -1)
    9481038            {
    949                 switch (bWakeupReason)
     1039                uint64_t tsPollEnd = RTTimeMilliTS();
     1040                uint64_t tsPollSpan = tsPollEnd - tsPollStart;
     1041                msTimeoutLeft -= RT_MIN(tsPollSpan, (uint32_t)msTimeoutLeft);
     1042            }
     1043        }
     1044
     1045        uint32_t fEvtsPending = 0;
     1046        if (rcPsx < 0 && errno != EINTR)
     1047            rc = RTErrConvertFromErrno(errno);
     1048        else if (rcPsx > 0)
     1049        {
     1050            if (aPollFds[0].revents != 0)
     1051            {
     1052                fEvtsPending |= (aPollFds[0].revents & POLLIN) ? RTSERIALPORT_EVT_F_DATA_RX : 0;
     1053                fEvtsPending |= (aPollFds[0].revents & POLLOUT) ? RTSERIALPORT_EVT_F_DATA_TX : 0;
     1054                /** @todo BREAK condition detection. */
     1055            }
     1056
     1057            if (aPollFds[1].revents != 0)
     1058            {
     1059                AssertReturn(!(aPollFds[1].revents & (POLLHUP | POLLERR | POLLNVAL)), VERR_INTERNAL_ERROR);
     1060                Assert(aPollFds[1].revents & POLLIN);
     1061
     1062                uint8_t bWakeupReason = 0;
     1063                ssize_t cbRead = read(pThis->iFdPipeR, &bWakeupReason, 1);
     1064                if (cbRead == 1)
    9501065                {
    951                     case RTSERIALPORT_WAKEUP_PIPE_REASON_INTERRUPT:
    952                         rc = VERR_INTERRUPTED;
    953                         break;
    954                     case RTSERIALPORT_WAKEUP_PIPE_REASON_STS_LINE_CHANGED:
    955                         fEvtsPending |= RTSERIALPORT_EVT_F_STATUS_LINE_CHANGED;
    956                         break;
    957                     case RTSERIALPORT_WAKEUP_PIPE_REASON_STS_LINE_MONITOR_FAILED:
    958                         fEvtsPending |= RTSERIALPORT_EVT_F_STATUS_LINE_MONITOR_FAILED;
    959                         break;
    960                     default:
    961                         AssertFailed();
    962                         rc = VERR_INTERNAL_ERROR;
     1066                    switch (bWakeupReason)
     1067                    {
     1068                        case RTSERIALPORT_WAKEUP_PIPE_REASON_INTERRUPT:
     1069                            rc = VERR_INTERRUPTED;
     1070                            break;
     1071                        case RTSERIALPORT_WAKEUP_PIPE_REASON_STS_LINE_CHANGED:
     1072                            fEvtsPending |= RTSERIALPORT_EVT_F_STATUS_LINE_CHANGED;
     1073                            break;
     1074                        case RTSERIALPORT_WAKEUP_PIPE_REASON_STS_LINE_MONITOR_FAILED:
     1075                            fEvtsPending |= RTSERIALPORT_EVT_F_STATUS_LINE_MONITOR_FAILED;
     1076                            break;
     1077                        default:
     1078                            AssertFailed();
     1079                            rc = VERR_INTERNAL_ERROR;
     1080                    }
    9631081                }
     1082                else
     1083                    rc = VERR_INTERNAL_ERROR;
    9641084            }
    965             else
    966                 rc = VERR_INTERNAL_ERROR;
    967         }
    968     }
    969     else
    970         rc = VERR_TIMEOUT;
    971 
    972     *pfEvtsRecv = fEvtsPending & fEvtMask;
    973     fEvtsPending &= ~fEvtMask;
    974     ASMAtomicOrU32(&pThis->fEvtsPending, fEvtsPending);
     1085        }
     1086        else
     1087            rc = VERR_TIMEOUT;
     1088
     1089        *pfEvtsRecv = fEvtsPending & fEvtMask;
     1090        fEvtsPending &= ~fEvtMask;
     1091        ASMAtomicOrU32(&pThis->fEvtsPending, fEvtsPending);
     1092    }
    9751093
    9761094    return rc;
  • trunk/src/VBox/Runtime/r3/win/serialport-win.cpp

    r69986 r71028  
    335335    AssertReturn(cbToRead > 0, VERR_INVALID_PARAMETER);
    336336
    337     RT_NOREF(pcbRead);
    338     int rc = VERR_NOT_IMPLEMENTED;
     337    /*
     338     * Kick of an overlapped read.
     339     */
     340    int rc = VINF_SUCCESS;
     341    uint8_t *pbBuf = (uint8_t *)pvBuf;
     342
     343    while (   cbToRead > 0
     344           && RT_SUCCESS(rc))
     345    {
     346        BOOL fSucc = ResetEvent(pThis->Overlapped.hEvent); Assert(fSucc == TRUE); RT_NOREF(fSucc);
     347        DWORD cbRead = 0;
     348        if (ReadFile(pThis->hDev, pbBuf,
     349                     cbToRead <= ~(DWORD)0 ? (DWORD)cbToRead : ~(DWORD)0,
     350                     &cbRead, &pThis->Overlapped))
     351        {
     352            if (pcbRead)
     353            {
     354                *pcbRead = cbRead;
     355                break;
     356            }
     357            rc = VINF_SUCCESS;
     358        }
     359        else if (GetLastError() == ERROR_IO_PENDING)
     360        {
     361            DWORD dwWait = WaitForSingleObject(pThis->Overlapped.hEvent, INFINITE);
     362            if (dwWait == WAIT_OBJECT_0)
     363            {
     364                if (GetOverlappedResult(pThis->hDev, &pThis->Overlapped, &cbRead, TRUE /*fWait*/))
     365                {
     366                    if (pcbRead)
     367                    {
     368                        *pcbRead = cbRead;
     369                        break;
     370                    }
     371                    rc = VINF_SUCCESS;
     372                }
     373                else
     374                    rc = RTErrConvertFromWin32(GetLastError());
     375            }
     376            else
     377            {
     378                Assert(dwWait == WAIT_FAILED);
     379                rc = RTErrConvertFromWin32(GetLastError());
     380            }
     381        }
     382        else
     383            rc = RTErrConvertFromWin32(GetLastError());
     384
     385        if (RT_SUCCESS(rc))
     386        {
     387            cbToRead -= cbRead;
     388            pbBuf    += cbRead;
     389        }
     390    }
     391
    339392    return rc;
    340393}
     
    394447RTDECL(int) RTSerialPortWrite(RTSERIALPORT hSerialPort, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
    395448{
    396     RT_NOREF(hSerialPort, pvBuf, cbToWrite, pcbWritten);
    397     return VERR_NOT_IMPLEMENTED;
     449    PRTSERIALPORTINTERNAL pThis = hSerialPort;
     450    AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
     451    AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
     452    AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
     453    AssertReturn(cbToWrite > 0, VERR_INVALID_PARAMETER);
     454
     455    /* If I/O is pending, check if it has completed. */
     456    int rc = VINF_SUCCESS;
     457    if (pThis->fWritePending)
     458        rc = rtSerialPortWriteCheckCompletion(pThis);
     459    if (rc == VINF_SUCCESS)
     460    {
     461        const uint8_t *pbBuf = (const uint8_t *)pvBuf;
     462
     463        while (   cbToWrite > 0
     464               && RT_SUCCESS(rc))
     465        {
     466            BOOL fSucc = ResetEvent(pThis->Overlapped.hEvent); Assert(fSucc == TRUE); RT_NOREF(fSucc);
     467            DWORD cbWritten = 0;
     468            if (WriteFile(pThis->hDev, pbBuf,
     469                          cbToWrite <= ~(DWORD)0 ? (DWORD)cbToWrite : ~(DWORD)0,
     470                          &cbWritten, &pThis->Overlapped))
     471            {
     472                if (pcbWritten)
     473                {
     474                    *pcbWritten = cbWritten;
     475                    break;
     476                }
     477                rc = VINF_SUCCESS;
     478            }
     479            else if (GetLastError() == ERROR_IO_PENDING)
     480            {
     481                DWORD dwWait = WaitForSingleObject(pThis->Overlapped.hEvent, INFINITE);
     482                if (dwWait == WAIT_OBJECT_0)
     483                {
     484                    if (GetOverlappedResult(pThis->hDev, &pThis->Overlapped, &cbWritten, TRUE /*fWait*/))
     485                    {
     486                        if (pcbWritten)
     487                        {
     488                            *pcbWritten = cbWritten;
     489                            break;
     490                        }
     491                        rc = VINF_SUCCESS;
     492                    }
     493                    else
     494                        rc = RTErrConvertFromWin32(GetLastError());
     495                }
     496                else
     497                {
     498                    Assert(dwWait == WAIT_FAILED);
     499                    rc = RTErrConvertFromWin32(GetLastError());
     500                }
     501            }
     502            else
     503                rc = RTErrConvertFromWin32(GetLastError());
     504
     505            if (RT_SUCCESS(rc))
     506            {
     507                cbToWrite -= cbWritten;
     508                pbBuf     += cbWritten;
     509            }
     510        }
     511    }
     512
     513    return rc;
    398514}
    399515
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