You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by Dean Gaudet <dg...@arctic.org> on 1997/08/17 04:49:44 UTC
[PATCH] USE_MMAP_FILES
Here is mmap integrated into the core. Pretty much everything that
defined HAVE_MMAP I also defined USE_MMAP_FILES. I also added
USE_MMAP_FILES for Linux 2.x and IRIX.
Tested on Linux 2.0.30 and IRIX 5.3.
Dean
Index: htdocs/manual/new_features_1_3.html
===================================================================
RCS file: /export/home/cvs/apachen/htdocs/manual/new_features_1_3.html,v
retrieving revision 1.14
diff -u -r1.14 new_features_1_3.html
--- new_features_1_3.html 1997/08/11 10:04:43 1.14
+++ new_features_1_3.html 1997/08/17 02:34:58
@@ -193,7 +193,7 @@
to issue multiple writes with a single system call. They also avoid
copying memory into buffers as much as possible. The result is
less CPU time spent on transferring large files.
- <li><i>XXX Incomplete:</i> Static requests are served using
+ <li>Static requests are served using
<code>mmap</code>, which means bytes are only copied from the
disk buffer to the network buffer directly by the kernel. The
program never copies bytes around, which reduces CPU time.
Index: src/CHANGES
===================================================================
RCS file: /export/home/cvs/apachen/src/CHANGES,v
retrieving revision 1.398
diff -u -r1.398 CHANGES
--- CHANGES 1997/08/17 02:31:47 1.398
+++ CHANGES 1997/08/17 02:35:08
@@ -1,5 +1,12 @@
Changes with Apache 1.3a2
+ *) Various architectures now define USE_MMAP_FILES which causes
+ the server to use mmap() for static files. There are two
+ compile-time tunables MMAP_THRESHOLD (minimum number of bytes
+ required to use mmap(), default is 0), and MMAP_SEGMENT_SIZE (maximum
+ number of bytes written in one cycle from a single mmap()d object,
+ default 32768). [Dean Gaudet]
+
*) Configure changes: TestLib replaced by TestCompile, which has
some additional capability (such as doing a sanity check of
the compiler and flags selected); the version of Solaris is now
Index: src/PORTING
===================================================================
RCS file: /export/home/cvs/apachen/src/PORTING,v
retrieving revision 1.9
diff -u -r1.9 PORTING
--- PORTING 1997/08/09 00:55:53 1.9
+++ PORTING 1997/08/17 02:35:08
@@ -171,7 +171,8 @@
HAVE_MMAP:
Define if the OS supports the BSD mmap() call. This is used by various
OSs to allow the scoreboard file to be held in shared mmapped-memory
- instead of a real file.
+ instead of a real file. Note that this is only used to determine
+ if mmap should be used for shared memory.
HAVE_SHMGET:
Define if the OS has the SysV-based shmget() family of shared-memory
@@ -213,6 +214,9 @@
USE_LONGJMP:
use the longjmp() call instead of siglongjmp()
(as well as setjmp() instead of sigsetjmp())
+
+ USE_MMAP_FILES:
+ Enable the use of mmap() for sending static files.
--
Index: src/core/conf.h
===================================================================
RCS file: /export/home/cvs/apachen/src/core/conf.h,v
retrieving revision 1.123
diff -u -r1.123 conf.h
--- conf.h 1997/08/15 18:12:09 1.123
+++ conf.h 1997/08/17 02:35:10
@@ -85,6 +85,7 @@
char *mktemp(char *template);
#define JMP_BUF sigjmp_buf
#define HAVE_MMAP
+#define USE_MMAP_FILES
#include <sys/time.h>
#define NEED_STRERROR
typedef int rlim_t;
@@ -102,6 +103,7 @@
#define JMP_BUF sigjmp_buf
#define USE_FCNTL_SERIALIZED_ACCEPT
#define HAVE_MMAP
+#define USE_MMAP_FILES
#define HAVE_CRYPT_H
int gethostname(char *name, int namelen);
@@ -114,6 +116,7 @@
#define JMP_BUF sigjmp_buf
#define USE_FCNTL_SERIALIZED_ACCEPT
#define HAVE_SHMGET
+#define USE_MMAP_FILES
#define HAVE_CRYPT_H
#define NO_LONG_DOUBLE
#define HAVE_BSTRING_H
@@ -154,6 +157,7 @@
#define JMP_BUF sigjmp_buf
#ifndef __ps2__
#define HAVE_MMAP
+#define USE_MMAP_FILES
#define DEFAULT_GROUP "nobody"
#endif
#define DEFAULT_USER "nobody"
@@ -179,6 +183,7 @@
#undef NO_SETSID
#define JMP_BUF sigjmp_buf
#define HAVE_MMAP
+#define USE_MMAP_FILES
#define HAVE_CRYPT_H
#define NO_LONG_DOUBLE
@@ -188,6 +193,7 @@
#undef NO_SETSID
#define JMP_BUF sigjmp_buf
#define HAVE_MMAP
+#define USE_MMAP_FILES
#define HAVE_CRYPT_H
#define NO_LONG_DOUBLE
typedef int rlim_t;
@@ -267,6 +273,7 @@
#define NET_SIZE_T size_t
#endif
#define HAVE_SHMGET
+#define USE_MMAP_FILES
#define HAVE_SYS_RESOURCE_H
typedef int rlim_t;
/* flock is faster ... but hasn't been tested on 1.x systems */
@@ -298,6 +305,7 @@
#define HAVE_SYS_SELECT_H
#define USE_FCNTL_SERIALIZED_ACCEPT
#define HAVE_MMAP
+#define USE_MMAP_FILES
#define HAVE_SYS_RESOURCE_H
#define SecureWare
@@ -362,6 +370,7 @@
#define JMP_BUF sigjmp_buf
#define HAVE_RESOURCE
#define HAVE_MMAP
+#define USE_MMAP_FILES
#define HAVE_SHMGET
#define HAVE_CRYPT_H
#define HAVE_SYS_SELECT_H
@@ -417,6 +426,7 @@
#undef NO_SETSID
#define JMP_BUF sigjmp_buf
#define HAVE_MMAP
+#define USE_MMAP_FILES
#define DEFAULT_USER "nobody"
#define DEFAULT_GROUP "nogroup"
#if defined(__bsdi__) || \
@@ -465,6 +475,7 @@
#define JMP_BUF sigjmp_buf
#define USE_FCNTL_SERIALIZED_ACCEPT
#define HAVE_MMAP
+#define USE_MMAP_FILES
#define HAVE_CRYPT_H
#elif defined(__EMX__)
@@ -506,6 +517,7 @@
#undef NO_SETSID
#undef NEED_STRDUP
#define HAVE_MMAP
+#define USE_MMAP_FILES
#define NO_TIMEZONE
#include <stdio.h>
Index: src/core/http_core.c
===================================================================
RCS file: /export/home/cvs/apachen/src/core/http_core.c,v
retrieving revision 1.109
diff -u -r1.109 http_core.c
--- http_core.c 1997/08/06 20:21:24 1.109
+++ http_core.c 1997/08/17 02:35:15
@@ -64,6 +64,28 @@
#include "scoreboard.h"
#include "fnmatch.h"
+#ifdef USE_MMAP_FILES
+#include <unistd.h>
+#include <sys/mman.h>
+
+/* mmap support for static files based on ideas from John Heidemann's
+ * patch against 1.0.5. See
+ * <http://www.isi.edu/~johnh/SOFTWARE/APACHE/index.html>.
+ */
+
+/* Files have to be at least this big before they're mmap()d. This is to
+ * deal with systems where the expense of doing an mmap() and an munmap()
+ * outweighs the benefit for small files.
+ */
+#ifndef MMAP_THRESHOLD
+#ifdef SUNOS4
+#define MMAP_THRESHOLD (8*1024)
+#else
+#define MMAP_THRESHOLD 0
+#endif
+#endif
+#endif
+
/* Server core module... This module provides support for really basic
* server operations, including options and commands which control the
* operation of other modules. Consider this the bureaucracy module.
@@ -1484,6 +1506,20 @@
int do_nothing (request_rec *r) { return OK; }
+#ifdef USE_MMAP_FILES
+struct mmap {
+ void *mm;
+ size_t length;
+};
+
+static void mmap_cleanup (void *mmv)
+{
+ struct mmap *mmd = mmv;
+
+ munmap(mmd->mm, mmd->length);
+}
+#endif
+
/*
* Default handler for MIME types without other handlers. Only GET
* and OPTIONS at this point... anyone who wants to write a generic
@@ -1498,6 +1534,9 @@
(core_dir_config *)get_module_config(r->per_dir_config, &core_module);
int rangestatus, errstatus;
FILE *f;
+#ifdef USE_MMAP_FILES
+ caddr_t mm;
+#endif
/* This handler has no use for a request body (yet), but we still
* need to read and discard it if the client sent one.
@@ -1539,24 +1578,76 @@
|| (errstatus = set_content_length (r, r->finfo.st_size)))
return errstatus;
- if (d->content_md5 & 1) {
- table_set (r->headers_out, "Content-MD5", md5digest(r->pool, f));
+#ifdef USE_MMAP_FILES
+ block_alarms();
+ if (r->finfo.st_size >= MMAP_THRESHOLD) {
+ /* we need to protect ourselves in case we die while we've got the
+ * file mmapped */
+ mm = mmap (NULL, r->finfo.st_size, PROT_READ, MAP_PRIVATE,
+ fileno(f), 0);
+ } else {
+ mm = (caddr_t)-1;
}
- rangestatus = set_byterange(r);
- send_http_header (r);
-
- if (!r->header_only) {
- if (!rangestatus)
- send_fd (f, r);
- else {
- long offset, length;
- while (each_byterange(r, &offset, &length)) {
- fseek(f, offset, SEEK_SET);
- send_fd_length(f, r, length);
+ if (mm == (caddr_t)-1) {
+ unblock_alarms();
+
+ log_unixerr ("mmap_handler", r->filename, "mmap failed", r->server);
+#endif
+
+ if (d->content_md5 & 1) {
+ table_set (r->headers_out, "Content-MD5", md5digest(r->pool, f));
+ }
+
+ rangestatus = set_byterange(r);
+ send_http_header (r);
+
+ if (!r->header_only) {
+ if (!rangestatus)
+ send_fd (f, r);
+ else {
+ long offset, length;
+ while (each_byterange(r, &offset, &length)) {
+ fseek(f, offset, SEEK_SET);
+ send_fd_length(f, r, length);
+ }
+ }
+ }
+
+#ifdef USE_MMAP_FILES
+ } else {
+ struct mmap *mmd;
+
+ mmd = palloc (r->pool, sizeof (*mmd));
+ mmd->mm = mm;
+ mmd->length = r->finfo.st_size;
+ register_cleanup (r->pool, (void *)mmd, mmap_cleanup, mmap_cleanup);
+ unblock_alarms();
+
+ if (d->content_md5 & 1) {
+ MD5_CTX context;
+
+ MD5Init(&context);
+ MD5Update(&context, (void *)mm, r->finfo.st_size);
+ table_set (r->headers_out, "Content-MD5",
+ md5contextTo64(r->pool, &context));
+ }
+
+ rangestatus = set_byterange(r);
+ send_http_header (r);
+
+ if (!r->header_only) {
+ if (!rangestatus)
+ send_mmap (mm, r, 0, r->finfo.st_size);
+ else {
+ long offset, length;
+ while (each_byterange(r, &offset, &length)) {
+ send_mmap(mm, r, offset, length);
+ }
}
}
}
+#endif
pfclose(r->pool, f);
return OK;
Index: src/core/http_protocol.c
===================================================================
RCS file: /export/home/cvs/apachen/src/core/http_protocol.c,v
retrieving revision 1.152
diff -u -r1.152 http_protocol.c
--- http_protocol.c 1997/08/15 17:59:50 1.152
+++ http_protocol.c 1997/08/17 02:35:20
@@ -1754,6 +1754,68 @@
return total_bytes_sent;
}
+
+
+/* The code writes MMAP_SEGMENT_SIZE bytes at a time. This is due to Apache's
+ * timeout model, which is a timeout per-write rather than a time for the
+ * entire transaction to complete. Essentially this should be small enough
+ * so that in one Timeout period, your slowest clients should be reasonably
+ * able to receive this many bytes.
+ */
+#ifndef MMAP_SEGMENT_SIZE
+#define MMAP_SEGMENT_SIZE 32768
+#endif
+
+/* send data from an in-memory buffer */
+API_EXPORT(size_t) send_mmap(void * mm, request_rec *r, size_t offset,
+ size_t length)
+{
+ size_t total_bytes_sent = 0;
+ int n, w;
+
+ if (length == 0) return 0;
+
+ soft_timeout("send mmap", r);
+
+ length += offset;
+ while (!r->connection->aborted && offset < length) {
+ if (length - offset > MMAP_SEGMENT_SIZE) {
+ n = MMAP_SEGMENT_SIZE;
+ } else {
+ n = length - offset;
+ }
+
+ while (n && !r->connection->aborted) {
+ w = bwrite(r->connection->client, (char *)mm + offset, n);
+ if (w > 0) {
+ reset_timeout(r); /* reset timeout after successful write */
+ total_bytes_sent += w;
+ n -= w;
+ offset += w;
+ }
+ else if (w < 0) {
+ if (r->connection->aborted)
+ break;
+ else if (errno == EAGAIN)
+ continue;
+ else {
+ log_unixerr("send mmap lost connection to",
+ get_remote_host(r->connection,
+ r->per_dir_config, REMOTE_NAME),
+ NULL, r->server);
+ bsetflag(r->connection->client, B_EOUT, 1);
+ r->connection->aborted = 1;
+ break;
+ }
+ }
+ }
+ }
+
+ kill_timeout(r);
+ SET_BYTES_SENT(r);
+ return total_bytes_sent;
+}
+
API_EXPORT(int) rputc (int c, request_rec *r)
{
if (r->connection->aborted) return EOF;
Index: src/core/http_protocol.h
===================================================================
RCS file: /export/home/cvs/apachen/src/core/http_protocol.h,v
retrieving revision 1.25
diff -u -r1.25 http_protocol.h
--- http_protocol.h 1997/07/24 04:23:59 1.25
+++ http_protocol.h 1997/08/17 02:35:21
@@ -113,6 +113,9 @@
API_EXPORT(long) send_fb(BUFF *f, request_rec *r);
API_EXPORT(long) send_fb_length(BUFF *f, request_rec *r, long length);
+
+API_EXPORT(size_t) send_mmap(void *mm, request_rec *r, size_t offset,
+ size_t length);
/* Hmmm... could macrofy these for now, and maybe forever, though the
* definitions of the macros would get a whole lot hairier.