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:
Paul Saab 2000-09-12 11:37:20 +00:00
parent 6004db96ae
commit 0c893d623c

View File

@ -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 */