[core] isolate fdevent subsystem

fdevent.c no longer directly uses struct server *srv
srv->srvconf.max_fds (if set) is used to set rlimits
set max_conns in server.c after fdevent_init(), which sets srv->max_fds
  using srv->srvconf.max_fds (if set) as input hint
This commit is contained in:
Glenn Strauss 2019-12-24 23:15:02 -05:00
parent 6dfe0b9a16
commit 8588772caa
7 changed files with 74 additions and 76 deletions

View File

@ -355,7 +355,6 @@ struct server {
server_socket_array srv_sockets_inherited;
buffer_plugin plugins;
int event_handler;
time_t startup_ts;
uid_t uid;

View File

@ -2064,7 +2064,8 @@ int config_set_defaults(server *srv) {
specific_config *s = &((config_data_base *)srv->config_data_base)->defaults;
struct stat st1, st2;
if (0 != fdevent_config(srv)) return -1;
if (fdevent_config(&srv->srvconf.event_handler, srv->errh) <= 0)
return -1;
if (!buffer_string_is_empty(srv->srvconf.changeroot)) {
if (-1 == stat(srv->srvconf.changeroot->ptr, &st1)) {

View File

@ -2,7 +2,6 @@
#include "fdevent_impl.h"
#include "fdevent.h"
#include "base.h"
#include "buffer.h"
#include "log.h"
@ -24,7 +23,7 @@ static int use_sock_cloexec;
static int use_sock_nonblock;
#endif
int fdevent_config(server *srv) {
int fdevent_config(const char **event_handler_name, log_error_st *errh) {
static const struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] =
{
/* - epoll is most reliable
@ -56,57 +55,45 @@ int fdevent_config(server *srv) {
{ FDEVENT_HANDLER_UNSET, NULL }
};
if (NULL == srv->srvconf.event_handler) {
const char * event_handler = *event_handler_name;
fdevent_handler_t et = FDEVENT_HANDLER_UNSET;
if (NULL == event_handler) {
/* choose a good default
*
* the event_handler list is sorted by 'goodness'
* taking the first available should be the best solution
*/
srv->event_handler = event_handlers[0].et;
et = event_handlers[0].et;
*event_handler_name = event_handlers[0].name;
if (FDEVENT_HANDLER_UNSET == srv->event_handler) {
log_error(srv->errh, __FILE__, __LINE__,
if (FDEVENT_HANDLER_UNSET == et) {
log_error(errh, __FILE__, __LINE__,
"sorry, there is no event handler for this system");
return -1;
}
srv->srvconf.event_handler = event_handlers[0].name;
} else {
/*
* User override
*/
for (uint32_t i = 0; event_handlers[i].name; ++i) {
if (0 == strcmp(event_handlers[i].name, srv->srvconf.event_handler)) {
srv->event_handler = event_handlers[i].et;
if (0 == strcmp(event_handlers[i].name, event_handler)) {
et = event_handlers[i].et;
break;
}
}
if (FDEVENT_HANDLER_UNSET == srv->event_handler) {
log_error(srv->errh, __FILE__, __LINE__,
if (FDEVENT_HANDLER_UNSET == et) {
log_error(errh, __FILE__, __LINE__,
"the selected event-handler in unknown or not supported: %s",
srv->srvconf.event_handler);
event_handler);
return -1;
}
}
#ifdef FDEVENT_USE_SELECT
if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
/* select limits itself
*
* as it is a hard limit and will lead to a segfault we add some safety
* */
srv->max_fds = FD_SETSIZE - 200;
}
else
#endif
{
srv->max_fds = 4096;
}
return 0;
return et;
}
const char * fdevent_show_event_handlers(void) {
@ -150,10 +137,13 @@ const char * fdevent_show_event_handlers(void) {
;
}
fdevents *fdevent_init(server *srv) {
fdevents * fdevent_init(const char *event_handler, int *max_fds, int *cur_fds, log_error_st *errh) {
fdevents *ev;
int type = srv->event_handler;
uint32_t maxfds;
uint32_t maxfds = (0 != *max_fds)
? (uint32_t)*max_fds
: 4096;
int type = fdevent_config(&event_handler, errh);
if (type <= 0) return NULL;
#ifdef SOCK_CLOEXEC
/* Test if SOCK_CLOEXEC is supported by kernel.
@ -180,20 +170,25 @@ fdevents *fdevent_init(server *srv) {
#endif
#ifdef FDEVENT_USE_SELECT
/* select limits itself
* as it is a hard limit and will lead to a segfault we add some safety
* */
if (type == FDEVENT_HANDLER_SELECT) {
if (srv->max_fds > (int)FD_SETSIZE - 200) {
srv->max_fds = (int)FD_SETSIZE - 200;
}
if (maxfds > (uint32_t)FD_SETSIZE - 200)
maxfds = (uint32_t)FD_SETSIZE - 200;
}
#endif
maxfds = srv->max_fds + 1; /*(+1 for event-handler fd)*/
*max_fds = (int)maxfds;
++maxfds; /*(+1 for event-handler fd)*/
ev = calloc(1, sizeof(*ev));
force_assert(NULL != ev);
ev->srv = srv;
ev->errh = errh;
ev->cur_fds = cur_fds;
ev->event_handler = event_handler;
ev->fdarray = calloc(maxfds, sizeof(*ev->fdarray));
if (NULL == ev->fdarray) {
log_error(srv->errh, __FILE__, __LINE__,
log_error(ev->errh, __FILE__, __LINE__,
"server.max-fds too large? (%u)", maxfds-1);
free(ev);
return NULL;
@ -244,10 +239,10 @@ fdevents *fdevent_init(server *srv) {
free(ev->fdarray);
free(ev);
log_error(srv->errh, __FILE__, __LINE__,
log_error(errh, __FILE__, __LINE__,
"event-handler failed: %s; "
"try to set server.event-handler = \"poll\" or \"select\"",
srv->srvconf.event_handler);
event_handler);
return NULL;
}
@ -270,11 +265,10 @@ void fdevent_free(fdevents *ev) {
int fdevent_reset(fdevents *ev) {
int rc = (NULL != ev->reset) ? ev->reset(ev) : 0;
if (-1 == rc) {
const char *event_handler = ev->srv->srvconf.event_handler;
log_error(ev->srv->errh, __FILE__, __LINE__,
log_error(ev->errh, __FILE__, __LINE__,
"event-handler failed: %s; "
"try to set server.event-handler = \"poll\" or \"select\"",
event_handler ? event_handler : "");
ev->event_handler ? ev->event_handler : "");
}
return rc;
}
@ -318,7 +312,6 @@ void fdevent_sched_close(fdevents *ev, int fd, int issock) {
}
static void fdevent_sched_run(fdevents *ev) {
server *srv = ev->srv;
for (fdnode *fdn = ev->pendclose; fdn; ) {
int fd, rc;
fdnode *fdn_tmp;
@ -339,10 +332,10 @@ static void fdevent_sched_run(fdevents *ev) {
#endif
if (0 != rc) {
log_perror(srv->errh, __FILE__, __LINE__, "close failed %d", fd);
log_perror(ev->errh, __FILE__, __LINE__, "close failed %d", fd);
}
else {
--srv->cur_fds;
--(*ev->cur_fds);
}
fdn_tmp = fdn;
@ -371,7 +364,7 @@ static int fdevent_fdnode_event_unsetter_retry(fdevents *ev, fdnode *fdn) {
/*case ENOMEM:*/
default:
/* unrecoverable error; might leak fd */
log_perror(ev->srv->errh, __FILE__, __LINE__,
log_perror(ev->errh, __FILE__, __LINE__,
"fdevent event_del failed on fd %d", fdn->fd);
return 0;
}
@ -404,7 +397,7 @@ static int fdevent_fdnode_event_setter_retry(fdevents *ev, fdnode *fdn, int even
/*case ENOMEM:*/
default:
/* unrecoverable error */
log_perror(ev->srv->errh, __FILE__, __LINE__,
log_perror(ev->errh, __FILE__, __LINE__,
"fdevent event_set failed on fd %d", fdn->fd);
return 0;
}
@ -445,7 +438,7 @@ int fdevent_poll(fdevents *ev, int timeout_ms) {
if (n >= 0)
fdevent_sched_run(ev);
else if (errno != EINTR)
log_perror(ev->srv->errh, __FILE__, __LINE__, "fdevent_poll failed");
log_perror(ev->errh, __FILE__, __LINE__, "fdevent_poll failed");
return n;
}

View File

@ -2,8 +2,9 @@
#define _FDEVENT_H_
#include "first.h"
#include "base_decls.h"
#include "base_decls.h" /* handler_t */
struct log_error_st; /* declaration */
struct fdevents; /* declaration */
typedef struct fdevents fdevents;
@ -46,13 +47,13 @@ struct fdnode_st {
#define FDEVENT_STREAM_RESPONSE_POLLRDHUP BV(15)
__attribute_cold__
int fdevent_config(server *srv);
int fdevent_config(const char **event_handler_name, struct log_error_st *errh);
__attribute_cold__
const char * fdevent_show_event_handlers(void);
__attribute_cold__
fdevents *fdevent_init(struct server *srv);
fdevents * fdevent_init(const char *event_handler, int *max_fds, int *cur_fds, struct log_error_st *errh);
__attribute_cold__
int fdevent_reset(fdevents *ev); /* "init" after fork() */

View File

@ -82,7 +82,8 @@ struct fdevents {
int (*event_del)(struct fdevents *ev, fdnode *fdn);
int (*poll)(struct fdevents *ev, int timeout_ms);
struct server *srv;
log_error_st *errh;
int *cur_fds;
uint32_t maxfds;
#ifdef FDEVENT_USE_LINUX_EPOLL
int epoll_fd;
@ -125,6 +126,7 @@ struct fdevents {
int (*reset)(struct fdevents *ev);
void (*free)(struct fdevents *ev);
const char *event_handler;
fdevent_handler_t type;
};

View File

@ -64,8 +64,7 @@ static int fdevent_solaris_port_poll(fdevents *ev, int timeout_ms) {
int revents = ev->port_events[i].portev_events;
if (0 == ((uintptr_t)fdn & 0x3)) {
if (port_associate(pfd,PORT_SOURCE_FD,fd,(int)ud,(void*)ud) < 0) {
log_error(ev->srv->errh, __FILE__, __LINE__,
"port_associate failed");
log_error(ev->errh,__FILE__,__LINE__,"port_associate failed");
}
(*fdn->handler)(fdn->ctx, revents);
}

View File

@ -935,10 +935,11 @@ static int server_main_setup (server * const srv, int argc, char **argv) {
}
}
srv->max_fds = rlim.rlim_cur;
/*(default upper limit of 4k if server.max-fds not specified)*/
if (i_am_root && 0 == srv->srvconf.max_fds && rlim.rlim_cur > 4096)
srv->max_fds = 4096;
/*(default upper limit of 4k if server.max-fds not specified)*/
if (0 == srv->srvconf.max_fds)
srv->srvconf.max_fds = (rlim.rlim_cur <= 4096)
? (unsigned short)rlim.rlim_cur
: 4096;
/* set core file rlimit, if enable_cores is set */
if (use_rlimit && srv->srvconf.enable_cores && getrlimit(RLIMIT_CORE, &rlim) == 0) {
@ -1046,21 +1047,6 @@ static int server_main_setup (server * const srv, int argc, char **argv) {
#endif
}
/* set max-conns */
if (srv->srvconf.max_conns > srv->max_fds/2) {
/* we can't have more connections than max-fds/2 */
log_error(srv->errh, __FILE__, __LINE__,
"can't have more connections than fds/2: %hu %d",
srv->srvconf.max_conns, srv->max_fds);
srv->max_conns = srv->max_fds/2;
} else if (srv->srvconf.max_conns) {
/* otherwise respect the wishes of the user */
srv->max_conns = srv->srvconf.max_conns;
} else {
/* or use the default: we really don't want to hit max-fds */
srv->max_conns = srv->max_fds/3;
}
#ifdef HAVE_FORK
/* network is up, let's daemonize ourself */
if (0 == srv->srvconf.dont_daemonize && 0 == graceful_restart) {
@ -1301,7 +1287,9 @@ static int server_main_setup (server * const srv, int argc, char **argv) {
}
#endif
if (NULL == (srv->ev = fdevent_init(srv))) {
srv->max_fds = (int)srv->srvconf.max_fds;
srv->ev = fdevent_init(srv->srvconf.event_handler, &srv->max_fds, &srv->cur_fds, srv->errh);
if (NULL == srv->ev) {
log_error(srv->errh, __FILE__, __LINE__, "fdevent_init failed");
return -1;
}
@ -1309,6 +1297,21 @@ static int server_main_setup (server * const srv, int argc, char **argv) {
srv->max_fds_lowat = srv->max_fds * 8 / 10;
srv->max_fds_hiwat = srv->max_fds * 9 / 10;
/* set max-conns */
if (srv->srvconf.max_conns > srv->max_fds/2) {
/* we can't have more connections than max-fds/2 */
log_error(srv->errh, __FILE__, __LINE__,
"can't have more connections than fds/2: %hu %d",
srv->srvconf.max_conns, srv->max_fds);
srv->max_conns = srv->max_fds/2;
} else if (srv->srvconf.max_conns) {
/* otherwise respect the wishes of the user */
srv->max_conns = srv->srvconf.max_conns;
} else {
/* or use the default: we really don't want to hit max-fds */
srv->max_conns = srv->max_fds/3;
}
/* libev backend overwrites our SIGCHLD handler and calls waitpid on SIGCHLD; we want our own SIGCHLD handling. */
#ifdef HAVE_SIGACTION
sigaction(SIGCHLD, &act, NULL);