Replace termios VMIN=0 and VTIME=0 with O_NONBLOCK.

Enable O_NONBLOCK to be able to detect the difference between a timeout 
and a modem disconnect (EOF). With this change, it's also possible to 
implement write timeouts.
This commit is contained in:
Jef Driesen 2007-10-29 09:37:26 +00:00
parent 3f33f82bc2
commit a3ae610b2e

View File

@ -80,16 +80,6 @@ serial_open (serial** out, const char* name)
return -1; // Error during open call. return -1; // Error during open call.
} }
// Restore blocking mode after opening the device. The CLOCAL bit
// of the termios struct will be set to ignore modem control lines.
int flags = fcntl (device->fd, F_GETFL, 0);
if (fcntl (device->fd, F_SETFL, flags & ~O_NONBLOCK) != 0) {
TRACE ("fcntl");
close (device->fd);
free (device);
return -1; // Failed to restore blocking mode.
}
// Retrieve the current terminal attributes, to // Retrieve the current terminal attributes, to
// be able to restore them when closing the device. // be able to restore them when closing the device.
// It is also used to check if the obtained // It is also used to check if the obtained
@ -166,8 +156,12 @@ serial_configure (serial *device, int baudrate, int databits, int parity, int st
// and VTIME is the timeout in deciseconds for non-canonical read. // and VTIME is the timeout in deciseconds for non-canonical read.
// Setting both of these parameters to zero implies that a read // Setting both of these parameters to zero implies that a read
// will return immediately, only giving the currently available // will return immediately, only giving the currently available
// characters (non-blocking read behaviour). // characters (non-blocking read behaviour). However, a non-blocking
tty.c_cc[VMIN] = 0; // read (or write) can also be achieved by using O_NONBLOCK.
// But together with VMIN = 1, it becomes possible to recognize
// the difference between a timeout and modem disconnect (EOF)
// when read() returns zero.
tty.c_cc[VMIN] = 1;
tty.c_cc[VTIME] = 0; tty.c_cc[VTIME] = 0;
// Set the baud rate. // Set the baud rate.
@ -473,6 +467,7 @@ serial_read (serial* device, void* data, unsigned int size)
// Attempt to read data from the file descriptor. // Attempt to read data from the file descriptor.
int n = posix_read (device->fd, data + nbytes, size - nbytes); int n = posix_read (device->fd, data + nbytes, size - nbytes);
if (n < 0) { if (n < 0) {
if (errno == EAGAIN) continue; // Retry.
TRACE ("posix_read"); TRACE ("posix_read");
return -1; // Error during read call. return -1; // Error during read call.
} else if (n == 0) { } else if (n == 0) {
@ -492,16 +487,29 @@ serial_write (serial* device, const void* data, unsigned int size)
if (device == NULL) if (device == NULL)
return -1; // EINVAL (Invalid argument) return -1; // EINVAL (Invalid argument)
// Initialize the timeout calculation.
struct timeouts_t timeouts = {0};
timeouts_init_write (device, &timeouts, size);
unsigned int nbytes = 0; unsigned int nbytes = 0;
while (nbytes < size) { while (nbytes < size) {
// Wait until the file descriptor is ready for writing, or the timeout expires.
int rc = posix_wait (device->fd, &timeouts, 0, nbytes);
if (rc < 0) {
TRACE ("posix_wait");
return -1; // Error during select/poll call.
} else if (rc == 0)
break; // Timeout.
// Attempt to write data to the file descriptor. // Attempt to write data to the file descriptor.
int n = posix_write (device->fd, data + nbytes, size - nbytes); int n = posix_write (device->fd, data + nbytes, size - nbytes);
if (n < 0) { if (n < 0) {
if (errno == EAGAIN) continue; // Retry.
TRACE ("posix_write"); TRACE ("posix_write");
return -1; // Error during write call. return -1; // Error during write call.
} else {
nbytes += n; // Success.
} }
nbytes += n;
} }
return nbytes; return nbytes;