diff options
author | Stuart Henderson <sthen@cvs.openbsd.org> | 2012-05-16 08:57:22 +0000 |
---|---|---|
committer | Stuart Henderson <sthen@cvs.openbsd.org> | 2012-05-16 08:57:22 +0000 |
commit | 096815990943e7237e8fd06a1d29b5f185bb417c (patch) | |
tree | 9d036599d3a64c5afc8ea1e1db77c3e4253e19c5 /usr.sbin/unbound/util/netevent.c | |
parent | 2d0265882a16694c42b396ac0b2598691875b4dc (diff) |
Don't spin accept() when hitting ENFILE/EMFILE. Upstream r2663.
Diffstat (limited to 'usr.sbin/unbound/util/netevent.c')
-rw-r--r-- | usr.sbin/unbound/util/netevent.c | 61 |
1 files changed, 61 insertions, 0 deletions
diff --git a/usr.sbin/unbound/util/netevent.c b/usr.sbin/unbound/util/netevent.c index c6f5279f6a7..cb47352afa9 100644 --- a/usr.sbin/unbound/util/netevent.c +++ b/usr.sbin/unbound/util/netevent.c @@ -115,6 +115,10 @@ struct internal_base { uint32_t secs; /** timeval with current time */ struct timeval now; + /** the event used for slow_accept timeouts */ + struct event slow_accept; + /** true if slow_accept is enabled */ + int slow_accept_enabled; }; /** @@ -225,6 +229,11 @@ comm_base_delete(struct comm_base* b) { if(!b) return; + if(b->eb->slow_accept_enabled) { + if(event_del(&b->eb->slow_accept) != 0) { + log_err("could not event_del slow_accept"); + } + } #ifdef USE_MINI_EVENT event_base_free(b->eb->base); #elif defined(HAVE_EVENT_BASE_FREE) && defined(HAVE_EVENT_BASE_ONCE) @@ -263,6 +272,14 @@ void comm_base_exit(struct comm_base* b) } } +void comm_base_set_slow_accept_handlers(struct comm_base* b, + void (*stop_acc)(void*), void (*start_acc)(void*), void* arg) +{ + b->stop_accept = stop_acc; + b->start_accept = start_acc; + b->cb_arg = arg; +} + struct event_base* comm_base_internal(struct comm_base* b) { return b->eb->base; @@ -646,6 +663,18 @@ setup_tcp_handler(struct comm_point* c, int fd) comm_point_start_listening(c, fd, TCP_QUERY_TIMEOUT); } +void comm_base_handle_slow_accept(int fd, short event, void* arg) +{ + struct comm_base* b = (struct comm_base*)arg; + /* timeout for the slow accept, re-enable accepts again */ + if(b->start_accept) { + verbose(VERB_ALGO, "wait is over, slow accept disabled"); + fptr_ok(fptr_whitelist_start_accept(b->start_accept)); + (*b->start_accept)(b->cb_arg); + b->eb->slow_accept_enabled = 0; + } +} + int comm_point_perform_accept(struct comm_point* c, struct sockaddr_storage* addr, socklen_t* addrlen) { @@ -667,6 +696,38 @@ int comm_point_perform_accept(struct comm_point* c, #endif /* EPROTO */ ) return -1; +#if defined(ENFILE) && defined(EMFILE) + if(errno == ENFILE || errno == EMFILE) { + /* out of file descriptors, likely outside of our + * control. stop accept() calls for some time */ + if(c->ev->base->stop_accept) { + struct comm_base* b = c->ev->base; + struct timeval tv; + verbose(VERB_ALGO, "out of file descriptors: " + "slow accept"); + b->eb->slow_accept_enabled = 1; + fptr_ok(fptr_whitelist_stop_accept( + b->stop_accept)); + (*b->stop_accept)(b->cb_arg); + /* set timeout, no mallocs */ + tv.tv_sec = NETEVENT_SLOW_ACCEPT_TIME/1000; + tv.tv_usec = NETEVENT_SLOW_ACCEPT_TIME%1000; + event_set(&b->eb->slow_accept, -1, EV_TIMEOUT, + comm_base_handle_slow_accept, b); + if(event_base_set(b->eb->base, + &b->eb->slow_accept) != 0) { + /* we do not want to log here, because + * that would spam the logfiles. + * error: "event_base_set failed." */ + } + if(event_add(&b->eb->slow_accept, &tv) != 0) { + /* we do not want to log here, + * error: "event_add failed." */ + } + } + return -1; + } +#endif log_err("accept failed: %s", strerror(errno)); #else /* USE_WINSOCK */ if(WSAGetLastError() == WSAEINPROGRESS || |