Fix WSAPoll (#1265)

* Fix calling WSAPoll.

* fast_reload: explicitly set tcp_wouldblock on Windows when there is no
  command to read from the fast_reload thread.

* For poll(), also check for ENOMEM (Linux).

* Remove ifdefs for ENOMEM.
* Some systems return EAGAIN for poll.
This commit is contained in:
Yorgos Thessalonikefs 2025-04-11 15:05:52 +02:00 committed by GitHub
parent 4f06e658d1
commit 75e8fd7539
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 64 additions and 41 deletions

View file

@ -3899,6 +3899,7 @@ sock_poll_timeout(int fd, int timeout, int pollin, int pollout, int* event)
{
int loopcount = 0;
/* Loop if the system call returns an errno to do so, like EINTR. */
log_assert(pollin || pollout);
while(1) {
struct pollfd p, *fds;
int nfds, ret;
@ -3916,11 +3917,11 @@ sock_poll_timeout(int fd, int timeout, int pollin, int pollout, int* event)
nfds = 1;
memset(&p, 0, sizeof(p));
p.fd = fd;
p.events = POLLERR
#ifndef USE_WINSOCK
p.events = POLLERR
| POLLHUP
#endif
;
#endif
if(pollin)
p.events |= POLLIN;
if(pollout)
@ -3937,19 +3938,20 @@ sock_poll_timeout(int fd, int timeout, int pollin, int pollout, int* event)
}
#endif
if(ret == -1) {
if(
#ifndef USE_WINSOCK
if(
errno == EINTR || errno == EAGAIN
# ifdef EWOULDBLOCK
|| errno == EWOULDBLOCK
# endif
#else
WSAGetLastError() == WSAEINTR ||
WSAGetLastError() == WSAEINPROGRESS ||
WSAGetLastError() == WSAEWOULDBLOCK
) continue; /* Try again. */
#endif
)
continue; /* Try again. */
/* For WSAPoll we only get errors here:
* o WSAENETDOWN
* o WSAEFAULT
* o WSAEINVAL
* o WSAENOBUFS
*/
log_err("poll: %s", sock_strerror(errno));
if(event)
*event = 0;
@ -7392,11 +7394,17 @@ fr_main_handle_cmd(struct fast_reload_thread* fr)
# endif
#else
WSAGetLastError() == WSAEINTR ||
WSAGetLastError() == WSAEINPROGRESS ||
WSAGetLastError() == WSAEWOULDBLOCK
WSAGetLastError() == WSAEINPROGRESS
#endif
)
return; /* Continue later. */
#ifdef USE_WINSOCK
if(WSAGetLastError() == WSAEWOULDBLOCK) {
ub_winsock_tcp_wouldblock(fr->service_event,
UB_EV_READ);
return; /* Continue later. */
}
#endif
log_err("read cmd from fast reload thread, recv: %s",
sock_strerror(errno));
return;
@ -7428,10 +7436,23 @@ fr_check_cmd_from_thread(struct fast_reload_thread* fr)
if(!sock_poll_timeout(fr->commpair[0], 0, 1, 0, &inevent)) {
log_err("check for cmd from fast reload thread: "
"poll failed");
#ifdef USE_WINSOCK
if(worker->daemon->fast_reload_thread)
ub_winsock_tcp_wouldblock(worker->daemon->
fast_reload_thread->service_event,
UB_EV_READ);
#endif
return;
}
if(!inevent)
if(!inevent) {
#ifdef USE_WINSOCK
if(worker->daemon->fast_reload_thread)
ub_winsock_tcp_wouldblock(worker->daemon->
fast_reload_thread->service_event,
UB_EV_READ);
#endif
return;
}
fr_main_handle_cmd(fr);
}
}

View file

@ -456,9 +456,9 @@ comm_point_send_udp_msg(struct comm_point *c, sldns_buffer* packet,
int pret;
memset(&p, 0, sizeof(p));
p.fd = c->fd;
p.events = POLLOUT | POLLERR
p.events = POLLOUT
#ifndef USE_WINSOCK
| POLLHUP
| POLLERR | POLLHUP
#endif
;
# ifndef USE_WINSOCK
@ -483,7 +483,7 @@ comm_point_send_udp_msg(struct comm_point *c, sldns_buffer* packet,
# ifdef EWOULDBLOCK
errno != EWOULDBLOCK &&
# endif
errno != ENOBUFS
errno != ENOMEM && errno != ENOBUFS
#else
WSAGetLastError() != WSAEINPROGRESS &&
WSAGetLastError() != WSAEINTR &&
@ -496,15 +496,19 @@ comm_point_send_udp_msg(struct comm_point *c, sldns_buffer* packet,
return 0;
} else if((pret < 0 &&
#ifndef USE_WINSOCK
errno == ENOBUFS
( errno == ENOBUFS /* Maybe some systems */
|| errno == ENOMEM /* Linux */
|| errno == EAGAIN) /* Macos, solaris, openbsd */
#else
WSAGetLastError() == WSAENOBUFS
#endif
) || (send_nobufs && retries > 0)) {
/* ENOBUFS, and poll returned without
/* ENOBUFS/ENOMEM/EAGAIN, and poll
* returned without
* a timeout. Or the retried send call
* returned ENOBUFS. It is good to
* wait a bit for the error to clear. */
* returned ENOBUFS/ENOMEM/EAGAIN.
* It is good to wait a bit for the
* error to clear. */
/* The timeout is 20*(2^(retries+1)),
* it increases exponentially, starting
* at 40 msec. After 5 tries, 1240 msec
@ -517,18 +521,15 @@ comm_point_send_udp_msg(struct comm_point *c, sldns_buffer* packet,
Sleep((SEND_BLOCKED_WAIT_TIMEOUT/10)<<(retries+1));
pret = 0;
#endif
if(pret < 0 &&
if(pret < 0
#ifndef USE_WINSOCK
errno != EAGAIN && errno != EINTR &&
&& errno != EAGAIN && errno != EINTR &&
# ifdef EWOULDBLOCK
errno != EWOULDBLOCK &&
# endif
errno != ENOBUFS
errno != ENOMEM && errno != ENOBUFS
#else
WSAGetLastError() != WSAEINPROGRESS &&
WSAGetLastError() != WSAEINTR &&
WSAGetLastError() != WSAENOBUFS &&
WSAGetLastError() != WSAEWOULDBLOCK
/* Sleep does not error */
#endif
) {
log_err("poll udp out timer failed: %s",
@ -770,9 +771,9 @@ comm_point_send_udp_msg_if(struct comm_point *c, sldns_buffer* packet,
int pret;
memset(&p, 0, sizeof(p));
p.fd = c->fd;
p.events = POLLOUT | POLLERR
p.events = POLLOUT
#ifndef USE_WINSOCK
| POLLHUP
| POLLERR | POLLHUP
#endif
;
# ifndef USE_WINSOCK
@ -797,7 +798,7 @@ comm_point_send_udp_msg_if(struct comm_point *c, sldns_buffer* packet,
# ifdef EWOULDBLOCK
errno != EWOULDBLOCK &&
# endif
errno != ENOBUFS
errno != ENOMEM && errno != ENOBUFS
#else
WSAGetLastError() != WSAEINPROGRESS &&
WSAGetLastError() != WSAEINTR &&
@ -810,15 +811,19 @@ comm_point_send_udp_msg_if(struct comm_point *c, sldns_buffer* packet,
return 0;
} else if((pret < 0 &&
#ifndef USE_WINSOCK
errno == ENOBUFS
( errno == ENOBUFS /* Maybe some systems */
|| errno == ENOMEM /* Linux */
|| errno == EAGAIN) /* Macos, solaris, openbsd */
#else
WSAGetLastError() == WSAENOBUFS
#endif
) || (send_nobufs && retries > 0)) {
/* ENOBUFS, and poll returned without
/* ENOBUFS/ENOMEM/EAGAIN, and poll
* returned without
* a timeout. Or the retried send call
* returned ENOBUFS. It is good to
* wait a bit for the error to clear. */
* returned ENOBUFS/ENOMEM/EAGAIN.
* It is good to wait a bit for the
* error to clear. */
/* The timeout is 20*(2^(retries+1)),
* it increases exponentially, starting
* at 40 msec. After 5 tries, 1240 msec
@ -831,18 +836,15 @@ comm_point_send_udp_msg_if(struct comm_point *c, sldns_buffer* packet,
Sleep((SEND_BLOCKED_WAIT_TIMEOUT/10)<<(retries+1));
pret = 0;
#endif
if(pret < 0 &&
if(pret < 0
#ifndef USE_WINSOCK
errno != EAGAIN && errno != EINTR &&
&& errno != EAGAIN && errno != EINTR &&
# ifdef EWOULDBLOCK
errno != EWOULDBLOCK &&
# endif
errno != ENOBUFS
#else
WSAGetLastError() != WSAEINPROGRESS &&
WSAGetLastError() != WSAEINTR &&
WSAGetLastError() != WSAENOBUFS &&
WSAGetLastError() != WSAEWOULDBLOCK
errno != ENOMEM && errno != ENOBUFS
#else /* USE_WINSOCK */
/* Sleep does not error */
#endif
) {
log_err("poll udp out timer failed: %s",