Skip to content

Commit 6dbe0d5

Browse files
committed
Merge branch 'linux-optimizations'
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2 parents cd3bfb8 + 7fab8fd commit 6dbe0d5

File tree

5 files changed

+212
-13
lines changed

5 files changed

+212
-13
lines changed

configure.ac

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,15 @@ AC_CHECK_LIB(crypt, crypt)
4343
AC_CHECK_LIB(resolv, hstrerror)
4444

4545
# Checks for header files.
46-
AC_CHECK_HEADERS([grp.h osreldate.h poll.h sys/devpoll.h sys/event.h sys/poll.h sys/time.h])
46+
AC_CHECK_HEADERS([grp.h osreldate.h poll.h sys/devpoll.h sys/epoll.h sys/event.h sys/poll.h sys/sendfile.h sys/time.h])
4747
AC_HEADER_DIRENT
4848

4949
# Check for missing/broken API's, which we can replace, e.g. lib/lstat.c
5050
AC_REPLACE_FUNCS([strlcpy strlcat tempfile])
5151
AC_CONFIG_LIBOBJ_DIR([lib])
5252

5353
# Checks for library functions actually conditioned on in the source.
54-
AC_CHECK_FUNCS([atoll backtrace clock_gettime daemon hstrerror kqueue poll select setlogin setsid waitpid])
54+
AC_CHECK_FUNCS([accept4 atoll backtrace clock_gettime daemon epoll_create1 hstrerror kqueue poll select sendfile setlogin setsid waitpid])
5555

5656
# Check for command line options
5757
AC_ARG_ENABLE(builtin-icons,
@@ -215,6 +215,8 @@ Optional features:
215215
.htpasswd.............: ${enable_htpasswd:-no}
216216
MSIE padding..........: ${enable_msie_padding:-no}
217217
Symlinks..............: $with_symlinks
218+
epoll.................: ${ac_cv_func_epoll_create1:-no}
219+
sendfile..............: ${ac_cv_func_sendfile:-no}
218220

219221
------------- Compiler version --------------
220222
$($CC --version || true)

src/fdwatch.c

Lines changed: 146 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,11 @@
5555
#endif /* !HAVE_DEVPOLL */
5656
#endif /* HAVE_SYS_DEVPOLL_H */
5757

58+
#ifdef HAVE_SYS_EPOLL_H
59+
#include <sys/epoll.h>
60+
#include <errno.h>
61+
#endif
62+
5863
#ifdef HAVE_SYS_EVENT_H
5964
#include <sys/event.h>
6065
#endif /* HAVE_SYS_EVENT_H */
@@ -98,7 +103,28 @@ static int kqueue_check_fd(int fd);
98103
static int kqueue_get_fd(int ridx);
99104

100105
#else /* HAVE_KQUEUE */
101-
# ifdef HAVE_DEVPOLL
106+
107+
# ifdef HAVE_EPOLL_CREATE1
108+
109+
#define WHICH "epoll"
110+
#define INIT(nfiles) epoll_init(nfiles)
111+
#define EXIT() epoll_exit()
112+
#define ADD_FD(fd, rw) epoll_add_fd(fd, rw)
113+
#define DEL_FD(fd) epoll_del_fd(fd)
114+
#define WATCH(timeout_msecs) epoll_watch(timeout_msecs)
115+
#define CHECK_FD(fd) epoll_check_fd(fd)
116+
#define GET_FD(ridx) epoll_get_fd(ridx)
117+
118+
static int epoll_init(int nfiles);
119+
static void epoll_exit(void);
120+
static void epoll_add_fd(int fd, int rw);
121+
static void epoll_del_fd(int fd);
122+
static int epoll_watch(long timeout_msecs);
123+
static int epoll_check_fd(int fd);
124+
static int epoll_get_fd(int ridx);
125+
126+
# else /* HAVE_EPOLL_CREATE1 */
127+
# ifdef HAVE_DEVPOLL
102128

103129
#define WHICH "devpoll"
104130
#define INIT(nfiles) devpoll_init(nfiles)
@@ -117,8 +143,8 @@ static int devpoll_watch(long timeout_msecs);
117143
static int devpoll_check_fd(int fd);
118144
static int devpoll_get_fd(int ridx);
119145

120-
# else /* HAVE_DEVPOLL */
121-
# ifdef HAVE_POLL
146+
# else /* HAVE_DEVPOLL */
147+
# ifdef HAVE_POLL
122148

123149
#define WHICH "poll"
124150
#define INIT(nfiles) poll_init(nfiles)
@@ -137,8 +163,8 @@ static int poll_watch(long timeout_msecs);
137163
static int poll_check_fd(int fd);
138164
static int poll_get_fd(int ridx);
139165

140-
# else /* HAVE_POLL */
141-
# ifdef HAVE_SELECT
166+
# else /* HAVE_POLL */
167+
# ifdef HAVE_SELECT
142168

143169
#define WHICH "select"
144170
#define INIT(nfiles) select_init(nfiles)
@@ -157,9 +183,10 @@ static int select_watch(long timeout_msecs);
157183
static int select_check_fd(int fd);
158184
static int select_get_fd(int ridx);
159185

160-
# endif /* HAVE_SELECT */
161-
# endif /* HAVE_POLL */
162-
# endif /* HAVE_DEVPOLL */
186+
# endif /* HAVE_SELECT */
187+
# endif /* HAVE_POLL */
188+
# endif /* HAVE_DEVPOLL */
189+
# endif /* HAVE_EPOLL_CREATE1 */
163190
#endif /* HAVE_KQUEUE */
164191

165192

@@ -194,7 +221,7 @@ int fdwatch_get_nfiles(void)
194221
}
195222
#endif
196223

197-
#if defined(HAVE_SELECT) && ! ( defined(HAVE_POLL) || defined(HAVE_DEVPOLL) || defined(HAVE_KQUEUE) )
224+
#if defined(HAVE_SELECT) && ! ( defined(HAVE_POLL) || defined(HAVE_DEVPOLL) || defined(HAVE_EPOLL_CREATE1) || defined(HAVE_KQUEUE) )
198225
/* If we use select(), then we must limit ourselves to FD_SETSIZE. */
199226
nfiles = MIN(nfiles, FD_SETSIZE);
200227
#endif
@@ -471,7 +498,113 @@ static int kqueue_get_fd(int ridx)
471498
#else /* HAVE_KQUEUE */
472499

473500

474-
# ifdef HAVE_DEVPOLL
501+
# ifdef HAVE_EPOLL_CREATE1
502+
503+
static int epollfd;
504+
static struct epoll_event *epoll_revents;
505+
static int *epoll_rfdidx;
506+
507+
static int epoll_init(int nfiles)
508+
{
509+
int i;
510+
511+
epollfd = epoll_create1(EPOLL_CLOEXEC);
512+
if (epollfd == -1)
513+
return -1;
514+
515+
epoll_revents = calloc(nfiles, sizeof(struct epoll_event));
516+
if (!epoll_revents) {
517+
close(epollfd);
518+
return -1;
519+
}
520+
521+
epoll_rfdidx = malloc(nfiles * sizeof(int));
522+
if (!epoll_rfdidx) {
523+
free(epoll_revents);
524+
close(epollfd);
525+
return -1;
526+
}
527+
528+
for (i = 0; i < nfiles; i++)
529+
epoll_rfdidx[i] = -1;
530+
531+
return 0;
532+
}
533+
534+
static void epoll_exit(void)
535+
{
536+
free(epoll_revents);
537+
free(epoll_rfdidx);
538+
close(epollfd);
539+
}
540+
541+
static void epoll_add_fd(int fd, int rw)
542+
{
543+
struct epoll_event ev;
544+
545+
ev.data.fd = fd;
546+
ev.events = (rw == FDW_READ) ? EPOLLIN : EPOLLOUT;
547+
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) < 0)
548+
syslog(LOG_ERR, "epoll_ctl(ADD, %d): %s", fd, strerror(errno));
549+
}
550+
551+
static void epoll_del_fd(int fd)
552+
{
553+
if (epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, NULL) < 0)
554+
syslog(LOG_ERR, "epoll_ctl(DEL, %d): %s", fd, strerror(errno));
555+
epoll_rfdidx[fd] = -1;
556+
}
557+
558+
static int epoll_watch(long timeout_msecs)
559+
{
560+
int i, r;
561+
562+
r = epoll_wait(epollfd, epoll_revents, nfiles, (int)timeout_msecs);
563+
if (r <= 0)
564+
return r;
565+
566+
for (i = 0; i < r; i++)
567+
epoll_rfdidx[epoll_revents[i].data.fd] = i;
568+
569+
return r;
570+
}
571+
572+
static int epoll_check_fd(int fd)
573+
{
574+
int ridx = epoll_rfdidx[fd];
575+
576+
if (ridx < 0 || ridx >= nreturned)
577+
return 0;
578+
579+
if (epoll_revents[ridx].data.fd != fd)
580+
return 0;
581+
582+
if (epoll_revents[ridx].events & EPOLLERR)
583+
return 0;
584+
585+
switch (fd_rw[fd]) {
586+
case FDW_READ:
587+
return epoll_revents[ridx].events & (EPOLLIN | EPOLLHUP | EPOLLRDHUP);
588+
589+
case FDW_WRITE:
590+
return epoll_revents[ridx].events & (EPOLLOUT | EPOLLHUP);
591+
}
592+
593+
return 0;
594+
}
595+
596+
static int epoll_get_fd(int ridx)
597+
{
598+
if (ridx < 0 || ridx >= nreturned) {
599+
syslog(LOG_ERR, "bad ridx (%d) in epoll_get_fd!", ridx);
600+
return -1;
601+
}
602+
603+
return epoll_revents[ridx].data.fd;
604+
}
605+
606+
# else /* HAVE_EPOLL_CREATE1 */
607+
# ifdef HAVE_DEVPOLL
475608

476609
static int maxdpevents;
477610
static struct pollfd *dpevents;
@@ -958,6 +1091,8 @@ static int select_get_fd(int ridx)
9581091

9591092
# endif /* HAVE_POLL */
9601093

961-
# endif /* HAVE_DEVPOLL */
1094+
# endif /* HAVE_DEVPOLL */
1095+
1096+
# endif /* HAVE_EPOLL_CREATE1 */
9621097

9631098
#endif /* HAVE_KQUEUE */

src/libhttpd.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@
5353
#include <osreldate.h>
5454
#endif
5555

56+
#ifdef HAVE_SYS_SENDFILE_H
57+
#include <sys/sendfile.h>
58+
#endif
59+
5660
#include <wordexp.h>
5761

5862
#ifdef HAVE_DIRENT_H
@@ -762,6 +766,14 @@ static int initialize_listen_socket(sockaddr_t *sa)
762766
return -1;
763767
}
764768

769+
/* Defer accept until data arrives (HTTP request), saving a wakeup. */
770+
#ifdef TCP_DEFER_ACCEPT
771+
{
772+
int timeout = 1;
773+
setsockopt(listen_fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &timeout, sizeof(timeout));
774+
}
775+
#endif
776+
765777
/* Use accept filtering, if available. */
766778
#ifdef SO_ACCEPTFILTER
767779
{
@@ -2378,6 +2390,12 @@ static char *expand_symlinks(char *path, char **trailer, int no_symlink_check, i
23782390
void httpd_close_conn(struct http_conn *hc, struct timeval *now)
23792391
{
23802392
if (hc->file_address) {
2393+
#ifdef HAVE_SENDFILE
2394+
if (hc->file_fd >= 0) {
2395+
close(hc->file_fd);
2396+
hc->file_fd = -1;
2397+
}
2398+
#endif
23812399
mmc_unmap(hc->file_address, &(hc->sb), now);
23822400
hc->file_address = NULL;
23832401
}
@@ -2523,6 +2541,7 @@ void httpd_init_conn_content(struct http_conn *hc)
25232541
hc->do_keep_alive = 0;
25242542
hc->should_linger = 0;
25252543
hc->file_address = NULL;
2544+
hc->file_fd = -1;
25262545
hc->compression_type = COMPRESSION_NONE;
25272546
}
25282547

@@ -2537,7 +2556,11 @@ int httpd_get_conn(struct httpd *hs, int listen_fd, struct http_conn *hc)
25372556

25382557
/* Accept the new connection. */
25392558
sz = sizeof(sa);
2559+
#ifdef HAVE_ACCEPT4
2560+
hc->conn_fd = accept4(listen_fd, &sa.sa, &sz, SOCK_CLOEXEC);
2561+
#else
25402562
hc->conn_fd = accept(listen_fd, &sa.sa, &sz);
2563+
#endif
25412564
if (hc->conn_fd < 0) {
25422565
if (errno == EWOULDBLOCK)
25432566
return GC_NO_MORE;
@@ -2551,9 +2574,11 @@ int httpd_get_conn(struct httpd *hs, int listen_fd, struct http_conn *hc)
25512574
goto error;
25522575
}
25532576

2577+
#ifndef HAVE_ACCEPT4
25542578
if (-1 == set_cloexec(hc->conn_fd))
25552579
syslog(LOG_ERR, "failed setting CLOEXEC on client socket: %s",
25562580
strerror(errno));
2581+
#endif
25572582

25582583
SETSOCKOPT(hc->conn_fd, IPPROTO_TCP, TCP_NODELAY);
25592584

@@ -5031,6 +5056,9 @@ int httpd_start_request(struct http_conn *hc, struct timeval *now)
50315056
char *extra = mod_headers(hc);
50325057

50335058
hc->file_address = mmc_map(hc->expnfilename, &(hc->sb), now);
5059+
#ifdef HAVE_SENDFILE
5060+
hc->file_fd = open(hc->expnfilename, O_RDONLY | O_CLOEXEC);
5061+
#endif
50345062
if (!hc->file_address) {
50355063
syslog(LOG_ERR, "mmc_map(%s): cannot find %s", hc->expnfilename, is_icon ? "icon" : "file");
50365064
if (is_icon)

src/libhttpd.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,7 @@ struct http_conn {
256256
int has_deflate; /* Built with zlib:deflate() and enabled */
257257
int compression_type;
258258
char *file_address;
259+
int file_fd;
259260

260261
void *ssl; /* Opaque SSL* */
261262
int skip_redirect; /* On location match, skip redirect */

src/merecat.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828

2929
#include <config.h>
3030

31+
#include <errno.h>
3132
#include <getopt.h>
3233
#include <pwd.h>
3334
#ifdef HAVE_GRP_H
@@ -49,6 +50,10 @@
4950
#include <zlib.h>
5051
#endif
5152

53+
#ifdef HAVE_SYS_SENDFILE_H
54+
#include <sys/sendfile.h>
55+
#endif
56+
5257
#include "conf.h"
5358
#include "fdwatch.h"
5459
#include "libhttpd.h"
@@ -565,6 +570,12 @@ static void clear_connection(connecttab *c, struct timeval *tv)
565570

566571
/* release file memory */
567572
if (c->hc->file_address) {
573+
#ifdef HAVE_SENDFILE
574+
if (c->hc->file_fd >= 0) {
575+
close(c->hc->file_fd);
576+
c->hc->file_fd = -1;
577+
}
578+
#endif
568579
mmc_unmap(c->hc->file_address, &c->hc->sb, tv);
569580
c->hc->file_address = NULL;
570581
}
@@ -1424,6 +1435,28 @@ static void handle_send(connecttab *c, struct timeval *tv)
14241435
/* Do we need to write the headers first? */
14251436
if (hc->responselen == 0) {
14261437
/* No, just write the file. */
1438+
#ifdef HAVE_SENDFILE
1439+
if (hc->file_fd >= 0
1440+
# ifdef ENABLE_SSL
1441+
&& !hc->ssl
1442+
# endif
1443+
) {
1444+
off_t offset = (off_t)c->next_byte_index;
1445+
size_t nbytes = (size_t)MIN(c->end_byte_index - c->next_byte_index, (off_t)max_bytes);
1446+
# ifdef HAVE_SYS_SENDFILE_H
1447+
/* Linux: sendfile(out, in, &offset, count) */
1448+
sz = sendfile(hc->conn_fd, hc->file_fd, &offset, nbytes);
1449+
# else
1450+
/* BSD: sendfile(in, out, offset, nbytes, hdtr, &sbytes, flags) */
1451+
{
1452+
off_t sent = 0;
1453+
int rc = sendfile(hc->file_fd, hc->conn_fd, offset, nbytes, NULL, &sent, 0);
1454+
1455+
sz = (rc == 0 || (rc < 0 && errno == EAGAIN)) ? (ssize_t)sent : -1;
1456+
}
1457+
# endif
1458+
} else
1459+
#endif /* HAVE_SENDFILE */
14271460
sz = httpd_write(hc, &(hc->file_address[c->next_byte_index]),
14281461
MIN(c->end_byte_index - c->next_byte_index, (off_t)max_bytes));
14291462
} else {

0 commit comments

Comments
 (0)