Changeset 69907 in vbox for trunk/src/VBox/Runtime/r3/posix/serialport-posix.cpp
- Timestamp:
- Dec 3, 2017 8:54:16 AM (7 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/r3/posix/serialport-posix.cpp
r69897 r69907 39 39 #include <iprt/string.h> 40 40 #include <iprt/thread.h> 41 #include <iprt/time.h> 41 42 #include "internal/magics.h" 42 43 … … 101 102 /** Writing end of wakeup pipe. */ 102 103 int iFdPipeW; 104 /** Event pending mask. */ 105 volatile uint32_t fEvtsPending; 103 106 /** The current active config (we assume no one changes this behind our back). */ 104 107 struct termios PortCfg; … … 216 219 cfsetospeed(&pThis->PortCfg, B9600); 217 220 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) 219 222 pThis->PortCfg.c_cflag |= CREAD; /* Enable receiver. */ 220 223 … … 235 238 { 236 239 #ifdef RT_OS_LINUX 237 if (pThis->fOpenFlags & RT _SERIALPORT_OPEN_F_ENABLE_LOOPBACK)240 if (pThis->fOpenFlags & RTSERIALPORT_OPEN_F_ENABLE_LOOPBACK) 238 241 { 239 242 int fTiocmSet = TIOCM_LOOP; … … 251 254 } 252 255 #else 253 if (pThis->fOpenFlags & RT _SERIALPORT_OPEN_F_ENABLE_LOOPBACK)256 if (pThis->fOpenFlags & RTSERIALPORT_OPEN_F_ENABLE_LOOPBACK) 254 257 return VERR_NOT_SUPPORTED; 255 258 #endif … … 558 561 static int rtSerialPortMonitorThreadCreate(PRTSERIALPORTINTERNAL pThis) 559 562 { 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*/, 562 575 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); 580 598 581 599 return rc; … … 609 627 AssertPtrReturn(phSerialPort, VERR_INVALID_POINTER); 610 628 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), 613 631 VERR_INVALID_PARAMETER); 614 632 … … 619 637 int fPsxFlags = O_NOCTTY; 620 638 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)) 622 640 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)) 624 642 fPsxFlags |= O_WRONLY; 625 643 else 626 644 fPsxFlags |= O_RDWR; 627 645 628 pThis->fOpenFlags = fFlags; 629 pThis->iFd = open(pszPortAddress, fPsxFlags); 646 pThis->fOpenFlags = fFlags; 647 pThis->fEvtsPending = 0; 648 pThis->iFd = open(pszPortAddress, fPsxFlags); 630 649 if (pThis->iFd != -1) 631 650 { … … 650 669 rc = rtSerialPortSetDefaultCfg(pThis); 651 670 if ( RT_SUCCESS(rc) 652 && (fFlags & RT _SERIALPORT_OPEN_F_SUPPORT_STATUS_LINE_MONITORING))671 && (fFlags & RTSERIALPORT_OPEN_F_SUPPORT_STATUS_LINE_MONITORING)) 653 672 rc = rtSerialPortMonitorThreadCreate(pThis); 654 673 … … 693 712 AssertReturn(ASMAtomicCmpXchgU32(&pThis->u32Magic, RTSERIALPORT_MAGIC_DEAD, RTSERIALPORT_MAGIC), VERR_INVALID_HANDLE); 694 713 695 if (pThis->fOpenFlags & RT _SERIALPORT_OPEN_F_SUPPORT_STATUS_LINE_MONITORING)714 if (pThis->fOpenFlags & RTSERIALPORT_OPEN_F_SUPPORT_STATUS_LINE_MONITORING) 696 715 rtSerialPortMonitorThreadShutdown(pThis); 697 716 … … 740 759 * if break detection was enabled during open. 741 760 */ 742 if (pThis->fOpenFlags & RT _SERIALPORT_OPEN_F_DETECT_BREAK_CONDITION)761 if (pThis->fOpenFlags & RTSERIALPORT_OPEN_F_DETECT_BREAK_CONDITION) 743 762 { /** @todo */ } 744 763 … … 818 837 * is to send a signal after each tcsetattr. 819 838 */ 820 if (pThis->fOpenFlags & RT _SERIALPORT_OPEN_F_SUPPORT_STATUS_LINE_MONITORING)839 if (pThis->fOpenFlags & RTSERIALPORT_OPEN_F_SUPPORT_STATUS_LINE_MONITORING) 821 840 RTThreadPoke(pThis->hMonThrd); 822 841 #endif … … 827 846 828 847 829 RTDECL(int) RTSerialPortEvtPoll(RTSERIALPORT hSerialPort, RTSERIALPORTEVT *penmEvt, RTMSINTERVAL msTimeout) 830 { 831 RT_NOREF(hSerialPort, penmEvt, msTimeout); 832 return VERR_NOT_IMPLEMENTED; 848 RTDECL(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; 833 959 } 834 960 … … 869 995 int fTiocmClear = 0; 870 996 871 if (fClear & RT _SERIALPORT_CHG_STS_LINES_F_RTS)997 if (fClear & RTSERIALPORT_CHG_STS_LINES_F_RTS) 872 998 fTiocmClear |= TIOCM_RTS; 873 if (fClear & RT _SERIALPORT_CHG_STS_LINES_F_DTR)999 if (fClear & RTSERIALPORT_CHG_STS_LINES_F_DTR) 874 1000 fTiocmClear |= TIOCM_DTR; 875 1001 876 if (fSet & RT _SERIALPORT_CHG_STS_LINES_F_RTS)1002 if (fSet & RTSERIALPORT_CHG_STS_LINES_F_RTS) 877 1003 fTiocmSet |= TIOCM_RTS; 878 if (fSet & RT _SERIALPORT_CHG_STS_LINES_F_DTR)1004 if (fSet & RTSERIALPORT_CHG_STS_LINES_F_DTR) 879 1005 fTiocmSet |= TIOCM_DTR; 880 1006 … … 904 1030 if (!rcPsx) 905 1031 { 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; 910 1044 } 911 1045 else
Note:
See TracChangeset
for help on using the changeset viewer.