Menu

#608 PSerialChannel::Read() disregarding SetReadTimeout() on Linux

Stable_Branch
open
None
5
2022-06-02
2022-06-02
d153859
No

PTLib 2.18.8 release bundle on Linux arm, kernel 3.18.20, glibc 2.21.

In src/ptlib/unix/channel.cxx, PChannel::Read() method, which PSerialChannel::Read() inherits unchanged, contains the following code:

...
    PPROFILE_SYSTEM(
      int result = ::read(os_handle, buf, len);
    );
    if (result >= 0)
      return ConvertOSError(SetLastReadCount(result), LastReadError) && result > 0;

    switch (errno) {
...
      case EWOULDBLOCK :
        if (readTimeout > 0) {
          if (PXSetIOBlock(PXReadBlock, readTimeout))
            break;
          return false;
        }
...

Serial devices in PTLib are opened with O_NONBLOCK flag, so the expected behaviour is when there's no data from the serial port yet, read() call would return (-1) and set errno to EWOULDBLOCK.
But, in fact, there are serial devices (I wouldn't state this for the whole world) returning 0 from read() and errno is also 0 despite of O_NONBLOCK set, so in case when no data to read, PSerialChannel::Read() returns immediately disregarding SetReadTimeout() value, and it breaks existing application functionality.

In old PWLib 1.10.0, for example (I didn't dive deep into the revision history), PXSetIOBlock() was called before read():

...
  if (!PXSetIOBlock(PXReadBlock, readTimeout)) 
    return FALSE;

  if (ConvertOSError(lastReadCount = ::read(os_handle, buf, len), LastReadError))
    return lastReadCount > 0;
...

... and it worked properly.

Suggested solution:
Revert this peace of code to call PXSetIOBlock() before read().

Discussion


Log in to post a comment.