1
0
mirror of git://sigrok.org/libserialport synced 2023-08-10 21:13:24 +03:00

Move repetitive timeout code into helper functions.

This commit is contained in:
Martin Ling 2020-01-03 22:42:00 +00:00
parent 9a7945af84
commit 32dbe2d298

View File

@ -63,9 +63,18 @@ struct time {
struct timeval tv; struct timeval tv;
}; };
struct timeout {
unsigned int ms;
struct time start, delta, now, end;
struct timeval delta_tv;
bool overflow;
};
#define TIME_ZERO {.tv = {0, 0}} #define TIME_ZERO {.tv = {0, 0}}
#define TIME_MS(ms) {.tv = {ms / 1000, (ms % 1000) * 1000}} #define TIME_MS(ms) {.tv = {ms / 1000, (ms % 1000) * 1000}}
const struct time max_delta = TIME_MS(INT_MAX);
static void time_get(struct time *time) static void time_get(struct time *time)
{ {
#ifdef HAVE_CLOCK_GETTIME #ifdef HAVE_CLOCK_GETTIME
@ -119,6 +128,53 @@ static unsigned int time_as_ms(const struct time *time)
return time->tv.tv_sec * 1000 + time->tv.tv_usec / 1000; return time->tv.tv_sec * 1000 + time->tv.tv_usec / 1000;
} }
static void timeout_start(struct timeout *timeout, unsigned int timeout_ms)
{
timeout->ms = timeout_ms;
timeout->overflow = (timeout->ms > INT_MAX);
/* Get time at start of operation. */
time_get(&timeout->start);
/* Define duration of timeout. */
time_set_ms(&timeout->delta, timeout_ms);
/* Calculate time at which we should give up. */
time_add(&timeout->start, &timeout->delta, &timeout->end);
}
static bool timeout_check(struct timeout *timeout)
{
if (timeout->ms == 0)
return false;
time_get(&timeout->now);
time_sub(&timeout->end, &timeout->now, &timeout->delta);
if ((timeout->overflow = time_greater(&timeout->delta, &max_delta)))
timeout->delta = max_delta;
return time_greater(&timeout->now, &timeout->end);
}
static struct timeval *timeout_timeval(struct timeout *timeout)
{
if (timeout->ms == 0)
return NULL;
time_as_timeval(&timeout->delta, &timeout->delta_tv);
return &timeout->delta_tv;
}
static unsigned int timeout_remaining_ms(struct timeout *timeout)
{
if (timeout->ms == 0)
return -1;
else if (timeout->overflow)
return INT_MAX;
else
return time_as_ms(&timeout->delta);
}
#endif #endif
SP_API enum sp_return sp_get_port_by_name(const char *portname, struct sp_port **port_ptr) SP_API enum sp_return sp_get_port_by_name(const char *portname, struct sp_port **port_ptr)
@ -887,19 +943,12 @@ SP_API enum sp_return sp_blocking_write(struct sp_port *port, const void *buf,
#else #else
size_t bytes_written = 0; size_t bytes_written = 0;
unsigned char *ptr = (unsigned char *) buf; unsigned char *ptr = (unsigned char *) buf;
struct time start, delta, now, end = TIME_ZERO; struct timeout timeout;
int started = 0; int started = 0;
fd_set fds; fd_set fds;
int result; int result;
if (timeout_ms) { timeout_start(&timeout, timeout_ms);
/* Get time at start of operation. */
time_get(&start);
/* Define duration of timeout. */
time_set_ms(&delta, timeout_ms);
/* Calculate time at which we should give up. */
time_add(&start, &delta, &end);
}
FD_ZERO(&fds); FD_ZERO(&fds);
FD_SET(port->fd, &fds); FD_SET(port->fd, &fds);
@ -911,16 +960,10 @@ SP_API enum sp_return sp_blocking_write(struct sp_port *port, const void *buf,
* to avoid any issues if a short timeout is reached before * to avoid any issues if a short timeout is reached before
* select() is even run. * select() is even run.
*/ */
struct timeval tv; if (started && timeout_check(&timeout))
if (timeout_ms && started) { break;
time_get(&now);
if (time_greater(&now, &end)) result = select(port->fd + 1, NULL, &fds, NULL, timeout_timeval(&timeout));
/* Timeout has expired. */
break;
time_sub(&end, &now, &delta);
time_as_timeval(&delta, &tv);
}
result = select(port->fd + 1, NULL, &fds, NULL, timeout_ms ? &tv : NULL);
started = 1; started = 1;
if (result < 0) { if (result < 0) {
if (errno == EINTR) { if (errno == EINTR) {
@ -1108,19 +1151,12 @@ SP_API enum sp_return sp_blocking_read(struct sp_port *port, void *buf,
#else #else
size_t bytes_read = 0; size_t bytes_read = 0;
unsigned char *ptr = (unsigned char *) buf; unsigned char *ptr = (unsigned char *) buf;
struct time start, delta, now, end = TIME_ZERO; struct timeout timeout;
int started = 0; int started = 0;
fd_set fds; fd_set fds;
int result; int result;
if (timeout_ms) { timeout_start(&timeout, timeout_ms);
/* Get time at start of operation. */
time_get(&start);
/* Define duration of timeout. */
time_set_ms(&delta, timeout_ms);
/* Calculate time at which we should give up. */
time_add(&start, &delta, &end);
}
FD_ZERO(&fds); FD_ZERO(&fds);
FD_SET(port->fd, &fds); FD_SET(port->fd, &fds);
@ -1132,16 +1168,11 @@ SP_API enum sp_return sp_blocking_read(struct sp_port *port, void *buf,
* to avoid any issues if a short timeout is reached before * to avoid any issues if a short timeout is reached before
* select() is even run. * select() is even run.
*/ */
struct timeval tv; if (started && timeout_check(&timeout))
if (timeout_ms && started) { /* Timeout has expired. */
time_get(&now); break;
if (time_greater(&now, &end))
/* Timeout has expired. */ result = select(port->fd + 1, &fds, NULL, NULL, timeout_timeval(&timeout));
break;
time_sub(&end, &now, &delta);
time_as_timeval(&delta, &tv);
}
result = select(port->fd + 1, &fds, NULL, NULL, timeout_ms ? &tv : NULL);
started = 1; started = 1;
if (result < 0) { if (result < 0) {
if (errno == EINTR) { if (errno == EINTR) {
@ -1246,19 +1277,12 @@ SP_API enum sp_return sp_blocking_read_next(struct sp_port *port, void *buf,
#else #else
size_t bytes_read = 0; size_t bytes_read = 0;
struct time start, delta, now, end = TIME_ZERO; struct timeout timeout;
int started = 0; int started = 0;
fd_set fds; fd_set fds;
int result; int result;
if (timeout_ms) { timeout_start(&timeout, timeout_ms);
/* Get time at start of operation. */
time_get(&start);
/* Define duration of timeout. */
time_set_ms(&delta, timeout_ms);
/* Calculate time at which we should give up. */
time_add(&start, &delta, &end);
}
FD_ZERO(&fds); FD_ZERO(&fds);
FD_SET(port->fd, &fds); FD_SET(port->fd, &fds);
@ -1270,16 +1294,11 @@ SP_API enum sp_return sp_blocking_read_next(struct sp_port *port, void *buf,
* to avoid any issues if a short timeout is reached before * to avoid any issues if a short timeout is reached before
* select() is even run. * select() is even run.
*/ */
struct timeval tv; if (started && timeout_check(&timeout))
if (timeout_ms && started) { /* Timeout has expired. */
time_get(&now); break;
if (time_greater(&now, &end))
/* Timeout has expired. */ result = select(port->fd + 1, &fds, NULL, NULL, timeout_timeval(&timeout));
break;
time_sub(&end, &now, &delta);
time_as_timeval(&delta, &tv);
}
result = select(port->fd + 1, &fds, NULL, NULL, timeout_ms ? &tv : NULL);
started = 1; started = 1;
if (result < 0) { if (result < 0) {
if (errno == EINTR) { if (errno == EINTR) {
@ -1530,10 +1549,8 @@ SP_API enum sp_return sp_wait(struct sp_event_set *event_set,
RETURN_OK(); RETURN_OK();
#else #else
struct time start, delta, now, end = TIME_ZERO; struct timeout timeout;
const struct time max_delta = TIME_MS(INT_MAX); int started = 0, result;
int started = 0, timeout_overflow = 0;
int result, timeout_remaining_ms;
struct pollfd *pollfds; struct pollfd *pollfds;
unsigned int i; unsigned int i;
@ -1552,14 +1569,7 @@ SP_API enum sp_return sp_wait(struct sp_event_set *event_set,
pollfds[i].events |= POLLERR; pollfds[i].events |= POLLERR;
} }
if (timeout_ms) { timeout_start(&timeout, timeout_ms);
/* Get time at start of operation. */
time_get(&start);
/* Define duration of timeout. */
time_set_ms(&delta, timeout_ms);
/* Calculate time at which we should give up. */
time_add(&start, &delta, &end);
}
/* Loop until an event occurs. */ /* Loop until an event occurs. */
while (1) { while (1) {
@ -1568,24 +1578,12 @@ SP_API enum sp_return sp_wait(struct sp_event_set *event_set,
* to avoid any issues if a short timeout is reached before * to avoid any issues if a short timeout is reached before
* poll() is even run. * poll() is even run.
*/ */
if (!timeout_ms) { if (started && timeout_check(&timeout)) {
timeout_remaining_ms = -1; DEBUG("Wait timed out");
} else if (!started) { break;
timeout_overflow = (timeout_ms > INT_MAX);
timeout_remaining_ms = timeout_overflow ? INT_MAX : timeout_ms;
} else {
time_get(&now);
if (time_greater(&now, &end)) {
DEBUG("Wait timed out");
break;
}
time_sub(&end, &now, &delta);
if ((timeout_overflow = time_greater(&delta, &max_delta)))
delta = max_delta;
timeout_remaining_ms = time_as_ms(&delta);
} }
result = poll(pollfds, event_set->count, timeout_remaining_ms); result = poll(pollfds, event_set->count, timeout_remaining_ms(&timeout));
started = 1; started = 1;
if (result < 0) { if (result < 0) {
@ -1598,7 +1596,7 @@ SP_API enum sp_return sp_wait(struct sp_event_set *event_set,
} }
} else if (result == 0) { } else if (result == 0) {
DEBUG("poll() timed out"); DEBUG("poll() timed out");
if (!timeout_overflow) if (!timeout.overflow)
break; break;
} else { } else {
DEBUG("poll() completed"); DEBUG("poll() completed");