VirtualBox

Ignore:
Timestamp:
Dec 3, 2017 8:54:16 AM (7 years ago)
Author:
vboxsync
Message:

Runtime/serialport-posix: Updates

File:
1 edited

Legend:

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

    r69897 r69907  
    3939#include <iprt/string.h>
    4040#include <iprt/thread.h>
     41#include <iprt/time.h>
    4142#include "internal/magics.h"
    4243
     
    101102    /** Writing end of wakeup pipe. */
    102103    int                 iFdPipeW;
     104    /** Event pending mask. */
     105    volatile uint32_t   fEvtsPending;
    103106    /** The current active config (we assume no one changes this behind our back). */
    104107    struct termios      PortCfg;
     
    216219    cfsetospeed(&pThis->PortCfg, B9600);
    217220    pThis->PortCfg.c_cflag = CS8 | CLOCAL; /* 8 data bits, ignore modem control lines. */
    218     if (pThis->fOpenFlags & RT_SERIALPORT_OPEN_F_READ)
     221    if (pThis->fOpenFlags & RTSERIALPORT_OPEN_F_READ)
    219222        pThis->PortCfg.c_cflag |= CREAD;   /* Enable receiver. */
    220223
     
    235238        {
    236239#ifdef RT_OS_LINUX
    237             if (pThis->fOpenFlags & RT_SERIALPORT_OPEN_F_ENABLE_LOOPBACK)
     240            if (pThis->fOpenFlags & RTSERIALPORT_OPEN_F_ENABLE_LOOPBACK)
    238241            {
    239242                int fTiocmSet = TIOCM_LOOP;
     
    251254            }
    252255#else
    253             if (pThis->fOpenFlags & RT_SERIALPORT_OPEN_F_ENABLE_LOOPBACK)
     256            if (pThis->fOpenFlags & RTSERIALPORT_OPEN_F_ENABLE_LOOPBACK)
    254257                return VERR_NOT_SUPPORTED;
    255258#endif
     
    558561static int rtSerialPortMonitorThreadCreate(PRTSERIALPORTINTERNAL pThis)
    559562{
    560     pThis->fMonThrdShutdown = false;
    561     int rc = RTThreadCreate(&pThis->hMonThrd, rtSerialPortStsLineMonitorThrd, pThis, 0 /*cbStack*/,
     563    int rc = VINF_SUCCESS;
     564
     565    /*
     566     * Check whether querying the status lines is supported at all, pseudo terminals
     567     * don't support it so an error returned in that case.
     568     */
     569    uint32_t fStsLines = 0;
     570    int rcPsx = ioctl(pThis->iFd, TIOCMGET, &fStsLines);
     571    if (!rcPsx)
     572    {
     573        pThis->fMonThrdShutdown = false;
     574        rc = RTThreadCreate(&pThis->hMonThrd, rtSerialPortStsLineMonitorThrd, pThis, 0 /*cbStack*/,
    562575                            RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "IPRT-SerPortMon");
    563     if (RT_SUCCESS(rc))
    564     {
    565         /* Wait for the thread to start up. */
    566         rc = RTThreadUserWait(pThis->hMonThrd, 20*RT_MS_1SEC);
    567         if (   rc == VERR_TIMEOUT
    568             || pThis->fMonThrdShutdown)
    569         {
    570             /* Startup failed, try to reap the thread. */
    571             int rcThrd;
    572             rc = RTThreadWait(pThis->hMonThrd, 20*RT_MS_1SEC, &rcThrd);
    573             if (RT_SUCCESS(rc))
    574                 rc = rcThrd;
    575             else
    576                 rc = VERR_INTERNAL_ERROR;
    577             /* The thread is lost otherwise. */
    578         }
    579     }
     576        if (RT_SUCCESS(rc))
     577        {
     578            /* Wait for the thread to start up. */
     579            rc = RTThreadUserWait(pThis->hMonThrd, 20*RT_MS_1SEC);
     580            if (   rc == VERR_TIMEOUT
     581                || pThis->fMonThrdShutdown)
     582            {
     583                /* Startup failed, try to reap the thread. */
     584                int rcThrd;
     585                rc = RTThreadWait(pThis->hMonThrd, 20*RT_MS_1SEC, &rcThrd);
     586                if (RT_SUCCESS(rc))
     587                    rc = rcThrd;
     588                else
     589                    rc = VERR_INTERNAL_ERROR;
     590                /* The thread is lost otherwise. */
     591            }
     592        }
     593    }
     594    else if (errno == ENOTTY)
     595        rc = VERR_NOT_SUPPORTED;
     596    else
     597        rc = RTErrConvertFromErrno(errno);
    580598
    581599    return rc;
     
    609627    AssertPtrReturn(phSerialPort, VERR_INVALID_POINTER);
    610628    AssertReturn(VALID_PTR(pszPortAddress) && *pszPortAddress != '\0', VERR_INVALID_PARAMETER);
    611     AssertReturn(!(fFlags & ~RT_SERIALPORT_OPEN_F_VALID_MASK), VERR_INVALID_PARAMETER);
    612     AssertReturn((fFlags & RT_SERIALPORT_OPEN_F_READ) || (fFlags & RT_SERIALPORT_OPEN_F_WRITE),
     629    AssertReturn(!(fFlags & ~RTSERIALPORT_OPEN_F_VALID_MASK), VERR_INVALID_PARAMETER);
     630    AssertReturn((fFlags & RTSERIALPORT_OPEN_F_READ) || (fFlags & RTSERIALPORT_OPEN_F_WRITE),
    613631                 VERR_INVALID_PARAMETER);
    614632
     
    619637        int fPsxFlags = O_NOCTTY;
    620638
    621         if ((fFlags & RT_SERIALPORT_OPEN_F_READ) && !(fFlags & RT_SERIALPORT_OPEN_F_WRITE))
     639        if ((fFlags & RTSERIALPORT_OPEN_F_READ) && !(fFlags & RTSERIALPORT_OPEN_F_WRITE))
    622640            fPsxFlags |= O_RDONLY;
    623         else if (!(fFlags & RT_SERIALPORT_OPEN_F_READ) && (fFlags & RT_SERIALPORT_OPEN_F_WRITE))
     641        else if (!(fFlags & RTSERIALPORT_OPEN_F_READ) && (fFlags & RTSERIALPORT_OPEN_F_WRITE))
    624642            fPsxFlags |= O_WRONLY;
    625643        else
    626644            fPsxFlags |= O_RDWR;
    627645
    628         pThis->fOpenFlags = fFlags;
    629         pThis->iFd        = open(pszPortAddress, fPsxFlags);
     646        pThis->fOpenFlags   = fFlags;
     647        pThis->fEvtsPending = 0;
     648        pThis->iFd          = open(pszPortAddress, fPsxFlags);
    630649        if (pThis->iFd != -1)
    631650        {
     
    650669                    rc = rtSerialPortSetDefaultCfg(pThis);
    651670                    if (   RT_SUCCESS(rc)
    652                         && (fFlags & RT_SERIALPORT_OPEN_F_SUPPORT_STATUS_LINE_MONITORING))
     671                        && (fFlags & RTSERIALPORT_OPEN_F_SUPPORT_STATUS_LINE_MONITORING))
    653672                        rc = rtSerialPortMonitorThreadCreate(pThis);
    654673
     
    693712    AssertReturn(ASMAtomicCmpXchgU32(&pThis->u32Magic, RTSERIALPORT_MAGIC_DEAD, RTSERIALPORT_MAGIC), VERR_INVALID_HANDLE);
    694713
    695     if (pThis->fOpenFlags & RT_SERIALPORT_OPEN_F_SUPPORT_STATUS_LINE_MONITORING)
     714    if (pThis->fOpenFlags & RTSERIALPORT_OPEN_F_SUPPORT_STATUS_LINE_MONITORING)
    696715        rtSerialPortMonitorThreadShutdown(pThis);
    697716
     
    740759         * if break detection was enabled during open.
    741760         */
    742         if (pThis->fOpenFlags & RT_SERIALPORT_OPEN_F_DETECT_BREAK_CONDITION)
     761        if (pThis->fOpenFlags & RTSERIALPORT_OPEN_F_DETECT_BREAK_CONDITION)
    743762        { /** @todo */ }
    744763
     
    818837         * is to send a signal after each tcsetattr.
    819838         */
    820         if (pThis->fOpenFlags & RT_SERIALPORT_OPEN_F_SUPPORT_STATUS_LINE_MONITORING)
     839        if (pThis->fOpenFlags & RTSERIALPORT_OPEN_F_SUPPORT_STATUS_LINE_MONITORING)
    821840            RTThreadPoke(pThis->hMonThrd);
    822841#endif
     
    827846
    828847
    829 RTDECL(int) RTSerialPortEvtPoll(RTSERIALPORT hSerialPort, RTSERIALPORTEVT *penmEvt, RTMSINTERVAL msTimeout)
    830 {
    831     RT_NOREF(hSerialPort, penmEvt, msTimeout);
    832     return VERR_NOT_IMPLEMENTED;
     848RTDECL(int) RTSerialPortEvtPoll(RTSERIALPORT hSerialPort, uint32_t fEvtMask, uint32_t *pfEvtsRecv,
     849                                RTMSINTERVAL msTimeout)
     850{
     851    PRTSERIALPORTINTERNAL pThis = hSerialPort;
     852    AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
     853    AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
     854    AssertReturn(!(fEvtMask & ~RTSERIALPORT_EVT_F_VALID_MASK), VERR_INVALID_PARAMETER);
     855    AssertPtrReturn(pfEvtsRecv, VERR_INVALID_POINTER);
     856
     857    *pfEvtsRecv = 0;
     858
     859    fEvtMask |= RTSERIALPORT_EVT_F_STATUS_LINE_MONITOR_FAILED; /* This will be reported always, no matter what the caller wants. */
     860
     861    /* Return early if there are events pending from previous calls which weren't fetched yet. */
     862    for (;;)
     863    {
     864        uint32_t fEvtsPending = ASMAtomicReadU32(&pThis->fEvtsPending);
     865        if (fEvtsPending & fEvtMask)
     866        {
     867            *pfEvtsRecv = fEvtsPending & fEvtMask;
     868            /* Write back, repeat the whole procedure if someone else raced us. */
     869            if (ASMAtomicCmpXchgU32(&pThis->fEvtsPending, fEvtsPending & ~fEvtMask, fEvtsPending))
     870                return VINF_SUCCESS;
     871        }
     872        else
     873            break;
     874    }
     875
     876    struct pollfd aPollFds[2]; RT_ZERO(aPollFds);
     877    aPollFds[0].fd = pThis->iFd;
     878    aPollFds[0].events = POLLERR | POLLHUP;
     879    aPollFds[0].revents = 0;
     880    if (   (pThis->fOpenFlags & RTSERIALPORT_OPEN_F_READ)
     881        && (fEvtMask & RTSERIALPORT_EVT_F_DATA_RX))
     882        aPollFds[0].events |= POLLIN;
     883    if (   (pThis->fOpenFlags & RTSERIALPORT_OPEN_F_WRITE)
     884        && (fEvtMask & RTSERIALPORT_EVT_F_DATA_TX))
     885        aPollFds[0].events |= POLLOUT;
     886
     887    aPollFds[1].fd      = pThis->iFdPipeR;
     888    aPollFds[1].events  = POLLIN | POLLERR | POLLHUP;
     889    aPollFds[1].revents = 0;
     890
     891    int rcPsx = 0;
     892    int msTimeoutLeft = msTimeout == RT_INDEFINITE_WAIT ? -1 : msTimeout;
     893    while (msTimeoutLeft != 0)
     894    {
     895        uint64_t tsPollStart = RTTimeMilliTS();
     896
     897        rcPsx = poll(&aPollFds[0], RT_ELEMENTS(aPollFds), msTimeoutLeft);
     898        if (rcPsx != -1 || errno != EINTR)
     899            break;
     900        /* Restart when getting interrupted. */
     901        if (msTimeoutLeft > -1)
     902        {
     903            uint64_t tsPollEnd = RTTimeMilliTS();
     904            uint64_t tsPollSpan = tsPollEnd - tsPollStart;
     905            msTimeoutLeft -= RT_MIN(tsPollSpan, (uint32_t)msTimeoutLeft);
     906        }
     907    }
     908
     909    int rc = VINF_SUCCESS;
     910    uint32_t fEvtsPending = 0;
     911    if (rcPsx < 0 && errno != EINTR)
     912        rc = RTErrConvertFromErrno(errno);
     913    else if (rcPsx > 0)
     914    {
     915        if (aPollFds[0].revents != 0)
     916        {
     917            fEvtsPending |= (aPollFds[0].revents & POLLIN) ? RTSERIALPORT_EVT_F_DATA_RX : 0;
     918            fEvtsPending |= (aPollFds[0].revents & POLLIN) ? RTSERIALPORT_EVT_F_DATA_TX : 0;
     919            /** @todo BREAK condition detection. */
     920        }
     921
     922        if (aPollFds[1].revents != 0)
     923        {
     924            AssertReturn(!(aPollFds[1].revents & (POLLHUP | POLLERR | POLLNVAL)), VERR_INTERNAL_ERROR);
     925            Assert(aPollFds[1].revents & POLLIN);
     926
     927            uint8_t bWakeupReason = 0;
     928            ssize_t cbRead = read(pThis->iFdPipeR, &bWakeupReason, 1);
     929            if (cbRead == 1)
     930            {
     931                switch (bWakeupReason)
     932                {
     933                    case RTSERIALPORT_WAKEUP_PIPE_REASON_INTERRUPT:
     934                        rc = VERR_INTERRUPTED;
     935                        break;
     936                    case RTSERIALPORT_WAKEUP_PIPE_REASON_STS_LINE_CHANGED:
     937                        fEvtsPending |= RTSERIALPORT_EVT_F_STATUS_LINE_CHANGED;
     938                        break;
     939                    case RTSERIALPORT_WAKEUP_PIPE_REASON_STS_LINE_MONITOR_FAILED:
     940                        fEvtsPending |= RTSERIALPORT_EVT_F_STATUS_LINE_MONITOR_FAILED;
     941                        break;
     942                    default:
     943                        AssertFailed();
     944                        rc = VERR_INTERNAL_ERROR;
     945                }
     946            }
     947            else
     948                rc = VERR_INTERNAL_ERROR;
     949        }
     950    }
     951    else
     952        rc = VERR_TIMEOUT;
     953
     954    *pfEvtsRecv = fEvtsPending & fEvtMask;
     955    fEvtsPending &= ~fEvtMask;
     956    ASMAtomicOrU32(&pThis->fEvtsPending, fEvtsPending);
     957
     958    return rc;
    833959}
    834960
     
    869995    int fTiocmClear = 0;
    870996
    871     if (fClear & RT_SERIALPORT_CHG_STS_LINES_F_RTS)
     997    if (fClear & RTSERIALPORT_CHG_STS_LINES_F_RTS)
    872998        fTiocmClear |= TIOCM_RTS;
    873     if (fClear & RT_SERIALPORT_CHG_STS_LINES_F_DTR)
     999    if (fClear & RTSERIALPORT_CHG_STS_LINES_F_DTR)
    8741000        fTiocmClear |= TIOCM_DTR;
    8751001
    876     if (fSet & RT_SERIALPORT_CHG_STS_LINES_F_RTS)
     1002    if (fSet & RTSERIALPORT_CHG_STS_LINES_F_RTS)
    8771003        fTiocmSet |= TIOCM_RTS;
    878     if (fSet & RT_SERIALPORT_CHG_STS_LINES_F_DTR)
     1004    if (fSet & RTSERIALPORT_CHG_STS_LINES_F_DTR)
    8791005        fTiocmSet |= TIOCM_DTR;
    8801006
     
    9041030    if (!rcPsx)
    9051031    {
    906         *pfStsLines |= (fStsLines & TIOCM_CAR) ? RT_SERIALPORT_STS_LINE_DCD : 0;
    907         *pfStsLines |= (fStsLines & TIOCM_RNG) ? RT_SERIALPORT_STS_LINE_RI  : 0;
    908         *pfStsLines |= (fStsLines & TIOCM_DSR) ? RT_SERIALPORT_STS_LINE_DSR : 0;
    909         *pfStsLines |= (fStsLines & TIOCM_CTS) ? RT_SERIALPORT_STS_LINE_CTS : 0;
     1032        /* This resets the status line event pending flag. */
     1033        for (;;)
     1034        {
     1035            uint32_t fEvtsPending = ASMAtomicReadU32(&pThis->fEvtsPending);
     1036            if (ASMAtomicCmpXchgU32(&pThis->fEvtsPending, fEvtsPending & ~RTSERIALPORT_EVT_F_STATUS_LINE_CHANGED, fEvtsPending))
     1037                break;
     1038        }
     1039
     1040        *pfStsLines |= (fStsLines & TIOCM_CAR) ? RTSERIALPORT_STS_LINE_DCD : 0;
     1041        *pfStsLines |= (fStsLines & TIOCM_RNG) ? RTSERIALPORT_STS_LINE_RI  : 0;
     1042        *pfStsLines |= (fStsLines & TIOCM_DSR) ? RTSERIALPORT_STS_LINE_DSR : 0;
     1043        *pfStsLines |= (fStsLines & TIOCM_CTS) ? RTSERIALPORT_STS_LINE_CTS : 0;
    9101044    }
    9111045    else
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