performance: use Linux extended syscalls and flags

reduce syscalls on Linux using extended syscalls and flags,
e.g. accept4(), pipe2(), O_CLOEXEC, SOCK_CLOEXEC, SOCK_NONBLOCK

github: closes #2
This commit is contained in:
Glenn Strauss 2013-12-23 23:28:44 -05:00
parent 8047c2f448
commit 93afda9c8e
12 changed files with 129 additions and 43 deletions

View File

@ -140,14 +140,11 @@ static int connection_close(server *srv, connection *con) {
"(warning) close:", con->fd, strerror(errno));
}
#endif
else {
srv->cur_fds--;
}
con->fd = -1;
srv->cur_fds--;
#if 0
log_error_write(srv, __FILE__, __LINE__, "sd",
"closed()", con->fd);
#endif
connection_del(srv, con);
connection_set_state(srv, con, CON_STATE_CONNECT);
@ -1027,7 +1024,12 @@ connection *connection_accept(server *srv, server_socket *srv_socket) {
cnt_len = sizeof(cnt_addr);
if (-1 == (cnt = accept(srv_socket->fd, (struct sockaddr *) &cnt_addr, &cnt_len))) {
#if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK)
cnt = accept4(srv_socket->fd, (struct sockaddr *) &cnt_addr, &cnt_len, SOCK_CLOEXEC | SOCK_NONBLOCK);
#else
cnt = accept(srv_socket->fd, (struct sockaddr *) &cnt_addr, &cnt_len);
#endif
if (-1 == cnt) {
switch (errno) {
case EAGAIN:
#if EWOULDBLOCK != EAGAIN
@ -1078,8 +1080,9 @@ connection *connection_accepted(server *srv, server_socket *srv_socket, sock_add
buffer_copy_string(con->dst_addr_buf, inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
con->srv_socket = srv_socket;
if (-1 == (fdevent_fcntl_set(srv->ev, con->fd))) {
if (-1 == fdevent_fcntl_set_nb_cloexec_sock(srv->ev, con->fd)) {
log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno));
connection_close(srv, con);
return NULL;
}
#ifdef USE_OPENSSL
@ -1089,6 +1092,7 @@ connection *connection_accepted(server *srv, server_socket *srv_socket, sock_add
log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
ERR_error_string(ERR_get_error(), NULL));
connection_close(srv, con);
return NULL;
}
@ -1099,6 +1103,7 @@ connection *connection_accepted(server *srv, server_socket *srv_socket, sock_add
if (1 != (SSL_set_fd(con->ssl, cnt))) {
log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
ERR_error_string(ERR_get_error(), NULL));
connection_close(srv, con);
return NULL;
}
}

View File

@ -270,7 +270,10 @@ void fd_close_on_exec(int fd) {
}
int fdevent_fcntl_set(fdevents *ev, int fd) {
fd_close_on_exec(fd);
return ((ev) && (ev->fcntl_set)) ? ev->fcntl_set(ev, fd) : 0;
}
int fdevent_fcntl_set_nb(fdevents *ev, int fd) {
if ((ev) && (ev->fcntl_set)) return ev->fcntl_set(ev, fd);
#ifdef O_NONBLOCK
return fcntl(fd, F_SETFL, O_NONBLOCK | O_RDWR);
@ -279,6 +282,67 @@ int fdevent_fcntl_set(fdevents *ev, int fd) {
#endif
}
int fdevent_fcntl_set_nb_cloexec(fdevents *ev, int fd) {
fd_close_on_exec(fd);
return fdevent_fcntl_set_nb(ev, fd);
}
int fdevent_fcntl_set_nb_cloexec_sock(fdevents *ev, int fd) {
#if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK)
return ((ev) && (ev->fcntl_set)) ? ev->fcntl_set(ev, fd) : 0;
#else
return fdevent_fcntl_set_nb_cloexec(ev, fd);
#endif
}
int fdevent_socket_cloexec(int domain, int type, int protocol) {
#ifdef SOCK_CLOEXEC
return socket(domain, type | SOCK_CLOEXEC, protocol);
#else
int fd;
if (-1 != (fd = socket(domain, type, protocol))) {
#ifdef FD_CLOEXEC
fcntl(fd, F_SETFD, FD_CLOEXEC);
#endif
}
return fd;
#endif
}
int fdevent_socket_nb_cloexec(int domain, int type, int protocol) {
#ifdef SOCK_CLOEXEC
return socket(domain, type | SOCK_CLOEXEC | SOCK_NONBLOCK, protocol);
#else
int fd;
if (-1 != (fd = socket(domain, type, protocol))) {
#ifdef FD_CLOEXEC
fcntl(fd, F_SETFD, FD_CLOEXEC);
#endif
#ifdef O_NONBLOCK
fcntl(fd, F_SETFL, O_NONBLOCK | O_RDWR);
#endif
}
return fd;
#endif
}
#ifndef O_NOCTTY
#define O_NOCTTY 0
#endif
int fdevent_open_cloexec(const char *pathname, int flags, mode_t mode) {
#ifdef O_CLOEXEC
return open(pathname, flags | O_CLOEXEC | O_NOCTTY, mode);
#else
int fd = open(pathname, flags | O_NOCTTY, mode);
#ifdef FD_CLOEXEC
if (fd != -1)
fcntl(fd, F_SETFD, FD_CLOEXEC);
#endif
return fd;
#endif
}
int fdevent_event_next_fdndx(fdevents *ev, int ndx) {
if (ev->event_next_fdndx) return ev->event_next_fdndx(ev, ndx);

View File

@ -208,6 +208,12 @@ void fdevent_sched_run(struct server *srv, fdevents *ev);
void fd_close_on_exec(int fd);
int fdevent_fcntl_set(fdevents *ev, int fd);
int fdevent_fcntl_set_nb(fdevents *ev, int fd);
int fdevent_fcntl_set_nb_cloexec(fdevents *ev, int fd);
int fdevent_fcntl_set_nb_cloexec_sock(fdevents *ev, int fd);
int fdevent_socket_cloexec(int domain, int type, int protocol);
int fdevent_socket_nb_cloexec(int domain, int type, int protocol);
int fdevent_open_cloexec(const char *pathname, int flags, mode_t mode);
int fdevent_select_init(fdevents *ev);
int fdevent_poll_init(fdevents *ev);

View File

@ -663,13 +663,12 @@ SIGHUP_FUNC(log_access_cycle) {
if (-1 != s->log_access_fd) close(s->log_access_fd);
if (-1 == (s->log_access_fd =
open(s->access_logfile->ptr, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
fdevent_open_cloexec(s->access_logfile->ptr, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
log_error_write(srv, __FILE__, __LINE__, "ss", "cycling access-log failed:", strerror(errno));
return HANDLER_ERROR;
}
fd_close_on_exec(s->log_access_fd);
}
}

View File

@ -36,6 +36,14 @@
#include <stdio.h>
#include <fcntl.h>
#ifdef O_CLOEXEC
#define pipe_cloexec(pipefd) pipe2((pipefd), O_CLOEXEC)
#elif defined FD_CLOEXEC
#define pipe_cloexec(pipefd) (0 == pipe(pipefd) ? fcntl(fd, F_SETFD, FD_CLOEXEC) : -1)
#else
#define pipe_cloexec(pipefd) pipe(pipefd)
#endif
enum {EOL_UNSET, EOL_N, EOL_RN};
typedef struct {
@ -1072,12 +1080,12 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, handler_
}
}
if (pipe(to_cgi_fds)) {
if (pipe_cloexec(to_cgi_fds)) {
log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed:", strerror(errno));
return -1;
}
if (pipe(from_cgi_fds)) {
if (pipe_cloexec(from_cgi_fds)) {
close(to_cgi_fds[0]);
close(to_cgi_fds[1]);
log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed:", strerror(errno));
@ -1099,18 +1107,20 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, handler_
server_socket *srv_sock = con->srv_socket;
/* move stdout to from_cgi_fd[1] */
close(STDOUT_FILENO);
dup2(from_cgi_fds[1], STDOUT_FILENO);
#ifndef FD_CLOEXEC
close(from_cgi_fds[1]);
/* not needed */
close(from_cgi_fds[0]);
#endif
/* move the stdin to to_cgi_fd[0] */
close(STDIN_FILENO);
dup2(to_cgi_fds[0], STDIN_FILENO);
#ifndef FD_CLOEXEC
close(to_cgi_fds[0]);
/* not needed */
close(to_cgi_fds[1]);
#endif
/* create environment */
env.ptr = NULL;
@ -1372,7 +1382,7 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, handler_
close(to_cgi_fds[1]);
} else {
/* there is content to send */
if (-1 == fdevent_fcntl_set(srv->ev, to_cgi_fds[1])) {
if (-1 == fdevent_fcntl_set_nb(srv->ev, to_cgi_fds[1])) {
log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno));
close(to_cgi_fds[1]);
cgi_connection_close(srv, hctx);
@ -1389,13 +1399,12 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, handler_
}
fdevent_register(srv->ev, hctx->fd, cgi_handle_fdevent, hctx);
fdevent_event_set(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
if (-1 == fdevent_fcntl_set(srv->ev, hctx->fd)) {
if (-1 == fdevent_fcntl_set_nb(srv->ev, hctx->fd)) {
log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno));
cgi_connection_close(srv, hctx);
return -1;
}
fdevent_event_set(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
break;
}

View File

@ -679,12 +679,11 @@ static int mod_deflate_file_chunk(server *srv, connection *con, handler_ctx *hct
#endif
if (-1 == c->file.fd) { /* open the file if not already open */
if (-1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
if (-1 == (c->file.fd = fdevent_open_cloexec(c->file.name->ptr, O_RDONLY, 0))) {
log_error_write(srv, __FILE__, __LINE__, "sbs", "open failed for:", c->file.name, strerror(errno));
return -1;
}
fd_close_on_exec(c->file.fd);
}
abs_offset = c->file.start + c->offset;

View File

@ -993,7 +993,7 @@ static int fcgi_spawn_connection(server *srv,
buffer_append_int(proc->connection_name, proc->port);
}
if (-1 == (fcgi_fd = socket(fcgi_addr->sa_family, SOCK_STREAM, 0))) {
if (-1 == (fcgi_fd = fdevent_socket_cloexec(fcgi_addr->sa_family, SOCK_STREAM, 0))) {
log_error_write(srv, __FILE__, __LINE__, "ss",
"failed:", strerror(errno));
return -1;
@ -1012,7 +1012,7 @@ static int fcgi_spawn_connection(server *srv,
close(fcgi_fd);
/* reopen socket */
if (-1 == (fcgi_fd = socket(fcgi_addr->sa_family, SOCK_STREAM, 0))) {
if (-1 == (fcgi_fd = fdevent_socket_cloexec(fcgi_addr->sa_family, SOCK_STREAM, 0))) {
log_error_write(srv, __FILE__, __LINE__, "ss",
"socket failed:", strerror(errno));
return -1;
@ -1060,10 +1060,13 @@ static int fcgi_spawn_connection(server *srv,
arg.used = 0;
if(fcgi_fd != FCGI_LISTENSOCK_FILENO) {
close(FCGI_LISTENSOCK_FILENO);
dup2(fcgi_fd, FCGI_LISTENSOCK_FILENO);
close(fcgi_fd);
}
#ifdef SOCK_CLOEXEC
else
fcntl(fcgi_fd, F_SETFD, 0); /* clear cloexec */
#endif
/* we don't need the client socket */
for (i = 3; i < 256; i++) {
@ -2996,7 +2999,7 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) {
if (proc->load < hctx->proc->load) hctx->proc = proc;
}
if (-1 == (hctx->fd = socket(host->family, SOCK_STREAM, 0))) {
if (-1 == (hctx->fd = fdevent_socket_nb_cloexec(host->family, SOCK_STREAM, 0))) {
if (errno == EMFILE ||
errno == EINTR) {
log_error_write(srv, __FILE__, __LINE__, "sd",

View File

@ -783,14 +783,14 @@ static handler_t proxy_write_request(server *srv, handler_ctx *hctx) {
#endif
#if defined(HAVE_IPV6) && defined(HAVE_INET_PTON)
if (strstr(host->host->ptr,":")) {
if (-1 == (hctx->fd = socket(AF_INET6, SOCK_STREAM, 0))) {
if (-1 == (hctx->fd = fdevent_socket_nb_cloexec(AF_INET6, SOCK_STREAM, 0))) {
log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed: ", strerror(errno));
return HANDLER_ERROR;
}
} else
#endif
{
if (-1 == (hctx->fd = socket(AF_INET, SOCK_STREAM, 0))) {
if (-1 == (hctx->fd = fdevent_socket_nb_cloexec(AF_INET, SOCK_STREAM, 0))) {
log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed: ", strerror(errno));
return HANDLER_ERROR;
}
@ -817,7 +817,7 @@ static handler_t proxy_write_request(server *srv, handler_ctx *hctx) {
return HANDLER_WAIT_FOR_EVENT;
case -1:
/* if ECONNREFUSED choose another connection -> FIXME */
/* if ECONNREFUSED choose another connection */
hctx->fde_ndx = -1;
return HANDLER_ERROR;

View File

@ -757,7 +757,7 @@ static int scgi_spawn_connection(server *srv,
scgi_addr = (struct sockaddr *) &scgi_addr_in;
}
if (-1 == (scgi_fd = socket(scgi_addr->sa_family, SOCK_STREAM, 0))) {
if (-1 == (scgi_fd = fdevent_socket_cloexec(scgi_addr->sa_family, SOCK_STREAM, 0))) {
log_error_write(srv, __FILE__, __LINE__, "ss",
"failed:", strerror(errno));
return -1;
@ -775,7 +775,7 @@ static int scgi_spawn_connection(server *srv,
close(scgi_fd);
/* reopen socket */
if (-1 == (scgi_fd = socket(scgi_addr->sa_family, SOCK_STREAM, 0))) {
if (-1 == (scgi_fd = fdevent_socket_cloexec(scgi_addr->sa_family, SOCK_STREAM, 0))) {
log_error_write(srv, __FILE__, __LINE__, "ss",
"socket failed:", strerror(errno));
return -1;
@ -824,6 +824,10 @@ static int scgi_spawn_connection(server *srv,
dup2(scgi_fd, 0);
close(scgi_fd);
}
#ifdef SOCK_CLOEXEC
else
fcntl(scgi_fd, F_SETFD, 0); /* clear cloexec */
#endif
/* we don't need the client socket */
for (fd = 3; fd < 256; fd++) {
@ -2270,7 +2274,7 @@ static handler_t scgi_write_request(server *srv, handler_ctx *hctx) {
switch(hctx->state) {
case FCGI_STATE_INIT:
if (-1 == (hctx->fd = socket(host->family, SOCK_STREAM, 0))) {
if (-1 == (hctx->fd = fdevent_socket_nb_cloexec(host->family, SOCK_STREAM, 0))) {
if (errno == EMFILE ||
errno == EINTR) {
log_error_write(srv, __FILE__, __LINE__, "sd",
@ -2292,7 +2296,6 @@ static handler_t scgi_write_request(server *srv, handler_ctx *hctx) {
if (-1 == fdevent_fcntl_set(srv->ev, hctx->fd)) {
log_error_write(srv, __FILE__, __LINE__, "ss",
"fcntl failed: ", strerror(errno));
return HANDLER_ERROR;
}

View File

@ -382,7 +382,7 @@ static int network_server_init(server *srv, buffer *host_token, specific_config
if (AF_UNIX == srv_socket->addr.plain.sa_family) {
/* check if the socket exists and try to connect to it. */
force_assert(host); /*(static analysis hint)*/
if (-1 == (srv_socket->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, 0))) {
if (-1 == (srv_socket->fd = fdevent_socket_cloexec(srv_socket->addr.plain.sa_family, SOCK_STREAM, 0))) {
log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno));
goto error_free_socket;
}
@ -409,10 +409,12 @@ static int network_server_init(server *srv, buffer *host_token, specific_config
goto error_free_socket;
}
fdevent_fcntl_set_nb(srv->ev, srv_socket->fd);
} else
#endif
{
if (-1 == (srv_socket->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, IPPROTO_TCP))) {
if (-1 == (srv_socket->fd = fdevent_socket_nb_cloexec(srv_socket->addr.plain.sa_family, SOCK_STREAM, IPPROTO_TCP))) {
log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno));
goto error_free_socket;
}
@ -433,9 +435,6 @@ static int network_server_init(server *srv, buffer *host_token, specific_config
#endif
}
/* set FD_CLOEXEC now, fdevent_fcntl_set is called later; needed for pipe-logger forks */
fd_close_on_exec(srv_socket->fd);
/* */
srv->cur_fds = srv_socket->fd;

View File

@ -38,11 +38,10 @@ int network_open_file_chunk(server *srv, connection *con, chunkqueue *cq) {
return -1;
}
if (-1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY|O_NOCTTY))) {
if (-1 == (c->file.fd = fdevent_open_cloexec(c->file.name->ptr, O_RDONLY, 0))) {
log_error_write(srv, __FILE__, __LINE__, "ssb", "open failed:", strerror(errno), c->file.name);
return -1;
}
fd_close_on_exec(c->file.fd);
file_size = sce->st.st_size;
} else {

View File

@ -931,7 +931,7 @@ int main (int argc, char **argv) {
/* open pid file BEFORE chroot */
if (!buffer_string_is_empty(srv->srvconf.pid_file)) {
if (-1 == (pid_fd = open(srv->srvconf.pid_file->ptr, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) {
if (-1 == (pid_fd = fdevent_open_cloexec(srv->srvconf.pid_file->ptr, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) {
struct stat st;
if (errno != EEXIST) {
log_error_write(srv, __FILE__, __LINE__, "sbs",
@ -956,7 +956,6 @@ int main (int argc, char **argv) {
return -1;
}
}
fd_close_on_exec(pid_fd);
}
if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
@ -1489,6 +1488,7 @@ int main (int argc, char **argv) {
FAMNoExists(&srv->stat_cache->fam);
#endif
fd_close_on_exec(FAMCONNECTION_GETFD(&srv->stat_cache->fam));
fdevent_register(srv->ev, FAMCONNECTION_GETFD(&srv->stat_cache->fam), stat_cache_handle_fdevent, NULL);
fdevent_event_set(srv->ev, &(srv->stat_cache->fam_fcce_ndx), FAMCONNECTION_GETFD(&srv->stat_cache->fam), FDEVENT_IN);
}
@ -1502,7 +1502,7 @@ int main (int argc, char **argv) {
for (i = 0; i < srv->srv_sockets.used; i++) {
server_socket *srv_socket = srv->srv_sockets.ptr[i];
if (srv->sockets_disabled) continue; /* lighttpd -1 (one-shot mode) */
if (-1 == fdevent_fcntl_set(srv->ev, srv_socket->fd)) {
if (-1 == fdevent_fcntl_set_nb_cloexec_sock(srv->ev, srv_socket->fd)) {
log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed:", strerror(errno));
return -1;
}