diff options
-rw-r--r-- | iolooper-select.c | 19 | ||||
-rw-r--r-- | iolooper.h | 35 |
2 files changed, 54 insertions, 0 deletions
diff --git a/iolooper-select.c b/iolooper-select.c index 000fa5d..62cce08 100644 --- a/iolooper-select.c +++ b/iolooper-select.c @@ -166,6 +166,10 @@ iolooper_wait( IoLooper* iol, int64_t duration ) iol->writes_result[0] = iol->writes[0]; ret = select( count, iol->reads_result, iol->writes_result, &errs, tm); + if (ret == 0) { + // Indicates timeout + errno = ETIMEDOUT; + } } while (ret < 0 && errno == EINTR); return ret; @@ -189,3 +193,18 @@ iolooper_has_operations( IoLooper* iol ) { return iolooper_fd_count(iol) > 0; } + +int64_t +iolooper_now(void) +{ + struct timeval time_now; + return gettimeofday(&time_now, NULL) ? -1 : (int64_t)time_now.tv_sec * 1000LL + + time_now.tv_usec / 1000; +} + +int +iolooper_wait_absolute(IoLooper* iol, int64_t deadline) +{ + int64_t timeout = deadline - iolooper_now(); + return (timeout >= 0) ? iolooper_wait(iol, timeout) : 0; +} @@ -17,11 +17,46 @@ void iolooper_del_read( IoLooper* iol, int fd ); void iolooper_del_write( IoLooper* iol, int fd ); int iolooper_poll( IoLooper* iol ); +/* Wrapper around select() + * Return: + * > 0 in case an I/O has occurred, or < 0 on error, or 0 on timeout with + * errno set to ETIMEDOUT. + */ int iolooper_wait( IoLooper* iol, int64_t duration ); int iolooper_is_read( IoLooper* iol, int fd ); int iolooper_is_write( IoLooper* iol, int fd ); /* Returns 1 if this IoLooper has one or more file descriptor to interact with */ int iolooper_has_operations( IoLooper* iol ); +/* Gets current time in milliseconds. + * Return: + * Number of milliseconds corresponded to the current time on success, or -1 + * on failure. + */ +int64_t iolooper_now(void); +/* Waits for an I/O to occur before specific absolute time. + * This routine should be used (instead of iolooper_wait) in cases when multiple + * sequential I/O should be completed within given time interval. For instance, + * consider the scenario, when "server" does two sequential writes, and "client" + * now has to read data transferred with these two distinct writes. It might be + * wasteful to do two reads, each with the same (large) timeout. Instead, it + * would be better to assign a deadline for both reads before the first read, + * and call iolooper_wait_absoulte with the same deadline value: + * int64_t deadline = iolooper_now() + TIMEOUT; + * if (iolooper_wait_absoulte(iol, deadline)) { + * // Process first buffer. + * (iolooper_wait_absoulte(iol, deadline)) { + * // Process second read + * } + * } + * Param: + * iol IoLooper instance for an I/O. + * deadline Deadline (absoulte time in milliseconds) before which an I/O should + * occur. + * Return: + * Number of I/O descriptors set in iol, if an I/O has occurred, 0 if no I/O + * occurred before the deadline, or -1 on error. + */ +int iolooper_wait_absolute(IoLooper* iol, int64_t deadline); #endif /* IOLOOPER_H */ |