X-Git-Url: http://sigrok.org/gitweb/?a=blobdiff_plain;f=serialport.c;h=fb7adf65eb0aa7efb4f9b9260d96d81d74bd2722;hb=0188a545c75b1012054efef41b8fb465ca90a37a;hp=35b6ac54fe20b067701be9d212f4d864de2e2df8;hpb=772c586133ec5e069233bac08a0bb0e86b36a6e8;p=libserialport.git diff --git a/serialport.c b/serialport.c index 35b6ac5..fb7adf6 100644 --- a/serialport.c +++ b/serialport.c @@ -774,6 +774,7 @@ SP_API enum sp_return sp_blocking_write(struct sp_port *port, const void *buf, size_t bytes_written = 0; unsigned char *ptr = (unsigned char *) buf; struct timeval start, delta, now, end = {0, 0}; + int started = 0; fd_set fds; int result; @@ -792,16 +793,20 @@ SP_API enum sp_return sp_blocking_write(struct sp_port *port, const void *buf, /* Loop until we have written the requested number of bytes. */ while (bytes_written < count) { - /* Wait until space is available. */ - if (timeout_ms) { + /* + * Check timeout only if we have run select() at least once, + * to avoid any issues if a short timeout is reached before + * select() is even run. + */ + if (timeout_ms && started) { gettimeofday(&now, NULL); - if (timercmp(&now, &end, >)) { - DEBUG("Write timed out"); - RETURN_INT(bytes_written); - } + if (timercmp(&now, &end, >)) + /* Timeout has expired. */ + break; timersub(&end, &now, &delta); } result = select(port->fd + 1, NULL, &fds, NULL, timeout_ms ? &delta : NULL); + started = 1; if (result < 0) { if (errno == EINTR) { DEBUG("select() call was interrupted, repeating"); @@ -810,8 +815,8 @@ SP_API enum sp_return sp_blocking_write(struct sp_port *port, const void *buf, RETURN_FAIL("select() failed"); } } else if (result == 0) { - DEBUG("Write timed out"); - RETURN_INT(bytes_written); + /* Timeout has expired. */ + break; } /* Do write. */ @@ -830,6 +835,9 @@ SP_API enum sp_return sp_blocking_write(struct sp_port *port, const void *buf, ptr += result; } + if (bytes_written < count) + DEBUG("Write timed out"); + RETURN_INT(bytes_written); #endif } @@ -962,8 +970,10 @@ SP_API enum sp_return sp_blocking_read(struct sp_port *port, void *buf, /* Set timeout. */ if (port->timeouts.ReadIntervalTimeout != 0 || + port->timeouts.ReadTotalTimeoutMultiplier != 0 || port->timeouts.ReadTotalTimeoutConstant != timeout_ms) { port->timeouts.ReadIntervalTimeout = 0; + port->timeouts.ReadTotalTimeoutMultiplier = 0; port->timeouts.ReadTotalTimeoutConstant = timeout_ms; if (SetCommTimeouts(port->hdl, &port->timeouts) == 0) RETURN_FAIL("SetCommTimeouts() failed"); @@ -990,6 +1000,7 @@ SP_API enum sp_return sp_blocking_read(struct sp_port *port, void *buf, size_t bytes_read = 0; unsigned char *ptr = (unsigned char *) buf; struct timeval start, delta, now, end = {0, 0}; + int started = 0; fd_set fds; int result; @@ -1008,15 +1019,20 @@ SP_API enum sp_return sp_blocking_read(struct sp_port *port, void *buf, /* Loop until we have the requested number of bytes. */ while (bytes_read < count) { - /* Wait until data is available. */ - if (timeout_ms) { + /* + * Check timeout only if we have run select() at least once, + * to avoid any issues if a short timeout is reached before + * select() is even run. + */ + if (timeout_ms && started) { gettimeofday(&now, NULL); if (timercmp(&now, &end, >)) /* Timeout has expired. */ - RETURN_INT(bytes_read); + break; timersub(&end, &now, &delta); } result = select(port->fd + 1, &fds, NULL, NULL, timeout_ms ? &delta : NULL); + started = 1; if (result < 0) { if (errno == EINTR) { DEBUG("select() call was interrupted, repeating"); @@ -1025,8 +1041,8 @@ SP_API enum sp_return sp_blocking_read(struct sp_port *port, void *buf, RETURN_FAIL("select() failed"); } } else if (result == 0) { - DEBUG("Read timed out"); - RETURN_INT(bytes_read); + /* Timeout has expired. */ + break; } /* Do read. */ @@ -1034,7 +1050,10 @@ SP_API enum sp_return sp_blocking_read(struct sp_port *port, void *buf, if (result < 0) { if (errno == EAGAIN) - /* This shouldn't happen because we did a select() first, but handle anyway. */ + /* + * This shouldn't happen because we did a + * select() first, but handle anyway. + */ continue; else /* This is an actual failure. */ @@ -1045,6 +1064,9 @@ SP_API enum sp_return sp_blocking_read(struct sp_port *port, void *buf, ptr += result; } + if (bytes_read < count) + DEBUG("Read timed out"); + RETURN_INT(bytes_read); #endif } @@ -1066,8 +1088,10 @@ SP_API enum sp_return sp_nonblocking_read(struct sp_port *port, void *buf, /* Set timeout. */ if (port->timeouts.ReadIntervalTimeout != MAXDWORD || + port->timeouts.ReadTotalTimeoutMultiplier != 0 || port->timeouts.ReadTotalTimeoutConstant != 0) { port->timeouts.ReadIntervalTimeout = MAXDWORD; + port->timeouts.ReadTotalTimeoutMultiplier = 0; port->timeouts.ReadTotalTimeoutConstant = 0; if (SetCommTimeouts(port->hdl, &port->timeouts) == 0) RETURN_FAIL("SetCommTimeouts() failed"); @@ -1262,6 +1286,7 @@ SP_API enum sp_return sp_wait(struct sp_event_set *event_set, RETURN_OK(); #else struct timeval start, delta, now, end = {0, 0}; + int started = 0; int result, timeout_remaining_ms; struct pollfd *pollfds; unsigned int i; @@ -1293,7 +1318,12 @@ SP_API enum sp_return sp_wait(struct sp_event_set *event_set, /* Loop until an event occurs. */ while (1) { - if (timeout_ms) { + /* + * Check timeout only if we have run poll() at least once, + * to avoid any issues if a short timeout is reached before + * poll() is even run. + */ + if (timeout_ms && started) { gettimeofday(&now, NULL); if (timercmp(&now, &end, >)) { DEBUG("Wait timed out"); @@ -1304,6 +1334,7 @@ SP_API enum sp_return sp_wait(struct sp_event_set *event_set, } result = poll(pollfds, event_set->count, timeout_ms ? timeout_remaining_ms : -1); + started = 1; if (result < 0) { if (errno == EINTR) {