Index: shlib_version =================================================================== RCS file: /cvs/src/lib/libc/shlib_version,v retrieving revision 1.183 diff -u -p -r1.183 shlib_version --- shlib_version 7 May 2016 19:05:21 -0000 1.183 +++ shlib_version 19 May 2016 03:54:10 -0000 @@ -1,4 +1,4 @@ major=87 -minor=0 +minor=1 # note: If changes were made to include/thread_private.h or if system # calls were added/changed then librthread/shlib_version also be updated. Index: asr/asr.c =================================================================== RCS file: /cvs/src/lib/libc/asr/asr.c,v retrieving revision 1.51 diff -u -p -r1.51 asr.c --- asr/asr.c 24 Feb 2016 20:52:53 -0000 1.51 +++ asr/asr.c 19 May 2016 03:54:10 -0000 @@ -174,13 +174,12 @@ asr_run_sync(struct asr_query *as, struc while ((r = asr_run(as, ar)) == ASYNC_COND) { fds[0].fd = ar->ar_fd; fds[0].events = (ar->ar_cond == ASR_WANT_READ) ? POLLIN:POLLOUT; - again: + r = poll(fds, 1, ar->ar_timeout); - if (r == -1 && errno == EINTR) - goto again; + /* - * Otherwise, just ignore the error and let asr_run() - * catch the failure. + * ignore any error and let asr_run() + * determine the state. */ } Index: asr/asr_private.h =================================================================== RCS file: /cvs/src/lib/libc/asr/asr_private.h,v retrieving revision 1.38 diff -u -p -r1.38 asr_private.h --- asr/asr_private.h 16 Dec 2015 16:32:30 -0000 1.38 +++ asr/asr_private.h 19 May 2016 03:54:10 -0000 @@ -168,6 +168,7 @@ struct asr_query { int as_state; /* cond */ + long long as_expiry; int as_timeout; int as_fd; Index: asr/res_send_async.c =================================================================== RCS file: /cvs/src/lib/libc/asr/res_send_async.c,v retrieving revision 1.29 diff -u -p -r1.29 res_send_async.c --- asr/res_send_async.c 23 Oct 2015 00:52:09 -0000 1.29 +++ asr/res_send_async.c 19 May 2016 03:54:10 -0000 @@ -45,9 +45,41 @@ static int validate_packet(struct asr_qu static int setup_query(struct asr_query *, const char *, const char *, int, int); static int ensure_ibuf(struct asr_query *, size_t); static int iter_ns(struct asr_query *); +static int res_now(long long *); +static int res_timedout(struct asr_query *); #define AS_NS_SA(p) ((p)->as_ctx->ac_ns[(p)->as.dns.nsidx - 1]) +static int +res_now(long long *e) +{ + struct timespec ts; + + if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) + return (-1); + + *e = ts.tv_sec * 1000 + (ts.tv_nsec + 999999) / 1000000; +} + +static int +res_timedout(struct asr_query *as) +{ + long long now, timeout; + + if (res_now(&now) == -1) + return (-1); + + timeout = as->as_expiry - now; + + /* there's time remaining */ + if (timeout > 0) { + as->as_timeout = timeout; + return (0); + } + + /* we're past the expiry */ + return (1); +} struct asr_query * res_send_async(const unsigned char *buf, int buflen, void *asr) @@ -146,6 +178,8 @@ _res_query_async_ctx(const char *name, i static int res_send_async_run(struct asr_query *as, struct asr_result *ar) { + long long timeout; + next: switch (as->as_state) { @@ -176,7 +210,6 @@ res_send_async_run(struct asr_query *as, break; case ASR_STATE_UDP_SEND: - if (udp_send(as) == -1) { async_set_state(as, ASR_STATE_NEXT_NS); break; @@ -189,22 +222,37 @@ res_send_async_run(struct asr_query *as, break; case ASR_STATE_UDP_RECV: - - if (udp_recv(as) == -1) { - if (errno == ENOMEM) { + if (udp_recv(as) != -1) { + switch (errno) { + case ENOMEM: ar->ar_errno = errno; async_set_state(as, ASR_STATE_HALT); break; - } - if (errno != EOVERFLOW) { - /* Fail or timeout */ + + case EAGAIN: + switch (res_timedout(as)) { + case -1: + ar->ar_errno = errno; + async_set_state(as, ASR_STATE_HALT); + break; + case 1: /* timed out, next ns */ + async_set_state(as, + ASR_STATE_NEXT_NS); + break; + case 0: /* spurious run, try again */ + return (ASYNC_COND); + } + break; + + case EOVERFLOW: + async_set_state(as, + (as->as_ctx->ac_options & RES_IGNTC) ? + ASR_STATE_PACKET : ASR_STATE_TCP_WRITE); + break; + default: async_set_state(as, ASR_STATE_NEXT_NS); break; } - if (as->as_ctx->ac_options & RES_IGNTC) - async_set_state(as, ASR_STATE_PACKET); - else - async_set_state(as, ASR_STATE_TCP_WRITE); } else async_set_state(as, ASR_STATE_PACKET); break; @@ -212,8 +260,22 @@ res_send_async_run(struct asr_query *as, case ASR_STATE_TCP_WRITE: switch (tcp_write(as)) { - case -1: /* fail or timeout */ - async_set_state(as, ASR_STATE_NEXT_NS); + case -1: + if (errno == EAGAIN) { + switch (res_timedout(as)) { + case -1: + ar->ar_errno = errno; + async_set_state(as, ASR_STATE_HALT); + break; + case 1: /* timed out, next ns */ + async_set_state(as, + ASR_STATE_NEXT_NS); + break; + case 0: /* spurious run, try again */ + return (ASYNC_COND); + } + } else + async_set_state(as, ASR_STATE_NEXT_NS); break; case 0: async_set_state(as, ASR_STATE_TCP_READ); @@ -232,10 +294,20 @@ res_send_async_run(struct asr_query *as, case ASR_STATE_TCP_READ: switch (tcp_read(as)) { - case -1: /* Fail or timeout */ - if (errno == ENOMEM) { - ar->ar_errno = errno; - async_set_state(as, ASR_STATE_HALT); + case -1: + if (errno == EAGAIN) { + switch (res_timedout(as)) { + case -1: + ar->ar_errno = errno; + async_set_state(as, ASR_STATE_HALT); + break; + case 1: /* timed out, next ns */ + async_set_state(as, + ASR_STATE_NEXT_NS); + break; + case 0: /* spurious run, try again */ + return (ASYNC_COND); + } } else async_set_state(as, ASR_STATE_NEXT_NS); break; @@ -738,6 +810,11 @@ validate_packet(struct asr_query *as) static int iter_ns(struct asr_query *as) { + long long expiry; + + if (res_now(&expiry) == -1) + return (-1); + for (;;) { if (as->as.dns.nsloop >= as->as_ctx->ac_nsretries) return (-1); @@ -755,6 +832,8 @@ iter_ns(struct asr_query *as) as->as_timeout /= as->as_ctx->ac_nscount; if (as->as_timeout < 1000) as->as_timeout = 1000; + + as->as_expiry = expiry + as->as_timeout; return (0); }