Change from using poll(2) to kqueue/kevent when waiting for a DNS
response to return. This will stop processes waiting on DNS requests from being woken up when a select collision occurs. This was tested on mx1.FreeBSD.org (outgoing mail for the FreeBSD.org mailing lists.) Reviewed by: jlemon, peter
This commit is contained in:
parent
6004db96ae
commit
0c893d623c
@ -79,6 +79,7 @@ static char rcsid[] = "$FreeBSD$";
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/event.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
@ -95,7 +96,6 @@ static char rcsid[] = "$FreeBSD$";
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <poll.h>
|
||||
|
||||
#include "res_config.h"
|
||||
|
||||
@ -356,6 +356,7 @@ res_send(buf, buflen, ans, anssiz)
|
||||
HEADER *hp = (HEADER *) buf;
|
||||
HEADER *anhp = (HEADER *) ans;
|
||||
int gotsomewhere, connreset, terrno, try, v_circuit, resplen, ns, n;
|
||||
int kq;
|
||||
u_int badns; /* XXX NSMAX can't exceed #/bits in this variable */
|
||||
|
||||
if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
|
||||
@ -374,6 +375,11 @@ res_send(buf, buflen, ans, anssiz)
|
||||
terrno = ETIMEDOUT;
|
||||
badns = 0;
|
||||
|
||||
if ((kq = kqueue()) < 0) {
|
||||
Perror(stderr, "kqueue", errno);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Send request, RETRY times, or until successful
|
||||
*/
|
||||
@ -414,6 +420,7 @@ res_send(buf, buflen, ans, anssiz)
|
||||
res_close();
|
||||
goto next_ns;
|
||||
case res_done:
|
||||
close(kq);
|
||||
return (resplen);
|
||||
case res_modified:
|
||||
/* give the hook another try */
|
||||
@ -423,6 +430,7 @@ res_send(buf, buflen, ans, anssiz)
|
||||
case res_error:
|
||||
/*FALLTHROUGH*/
|
||||
default:
|
||||
close(kq);
|
||||
return (-1);
|
||||
}
|
||||
} while (!done);
|
||||
@ -587,9 +595,8 @@ res_send(buf, buflen, ans, anssiz)
|
||||
/*
|
||||
* Use datagrams.
|
||||
*/
|
||||
struct pollfd pfd;
|
||||
int msec;
|
||||
struct timeval timeout, itv;
|
||||
struct kevent kv;
|
||||
struct timespec timeout;
|
||||
struct sockaddr_storage from;
|
||||
int fromlen;
|
||||
|
||||
@ -693,42 +700,30 @@ res_send(buf, buflen, ans, anssiz)
|
||||
* Wait for reply
|
||||
*/
|
||||
|
||||
msec = (_res.retrans << try) * 1000;
|
||||
timeout.tv_sec = (_res.retrans << try);
|
||||
if (try > 0)
|
||||
msec /= _res.nscount;
|
||||
if (msec <= 0)
|
||||
msec = 1000;
|
||||
gettimeofday(&timeout, NULL);
|
||||
itv.tv_sec = msec / 1000;
|
||||
itv.tv_usec = (msec % 1000) * 1000;
|
||||
timeradd(&timeout, &itv, &timeout);
|
||||
|
||||
timeout.tv_sec /= _res.nscount;
|
||||
if ((long) timeout.tv_sec <= 0)
|
||||
timeout.tv_sec = 1;
|
||||
timeout.tv_nsec = 0;
|
||||
wait:
|
||||
if (s < 0) {
|
||||
Perror(stderr, "s out-of-bounds", EMFILE);
|
||||
res_close();
|
||||
goto next_ns;
|
||||
}
|
||||
pfd.fd = s;
|
||||
pfd.events = POLLIN;
|
||||
n = poll(&pfd, 1, msec);
|
||||
|
||||
kv.ident = s;
|
||||
kv.flags = EV_ADD | EV_ONESHOT;
|
||||
kv.filter = EVFILT_READ;
|
||||
|
||||
n = kevent(kq, &kv, 1, &kv, 1, &timeout);
|
||||
if (n < 0) {
|
||||
if (errno == EINTR) {
|
||||
struct timeval ctv;
|
||||
|
||||
gettimeofday(&ctv, NULL);
|
||||
if (timercmp(&ctv, &timeout, <)) {
|
||||
timersub(&timeout,
|
||||
&ctv, &ctv);
|
||||
msec = ctv.tv_sec * 1000;
|
||||
msec += ctv.tv_usec / 1000;
|
||||
goto wait;
|
||||
}
|
||||
} else {
|
||||
Perror(stderr, "poll", errno);
|
||||
res_close();
|
||||
goto next_ns;
|
||||
}
|
||||
if (errno == EINTR)
|
||||
goto wait;
|
||||
Perror(stderr, "kevent", errno);
|
||||
res_close();
|
||||
goto next_ns;
|
||||
}
|
||||
|
||||
if (n == 0) {
|
||||
@ -873,16 +868,19 @@ res_send(buf, buflen, ans, anssiz)
|
||||
case res_error:
|
||||
/*FALLTHROUGH*/
|
||||
default:
|
||||
close(kq);
|
||||
return (-1);
|
||||
}
|
||||
} while (!done);
|
||||
|
||||
}
|
||||
close(kq);
|
||||
return (resplen);
|
||||
next_ns: ;
|
||||
} /*foreach ns*/
|
||||
} /*foreach retry*/
|
||||
res_close();
|
||||
close(kq);
|
||||
if (!v_circuit) {
|
||||
if (!gotsomewhere)
|
||||
errno = ECONNREFUSED; /* no nameservers found */
|
||||
|
Loading…
Reference in New Issue
Block a user