<div id="path">
<a href="http://www.apache.org/">Apache</a> > <a href="http://httpd.apache.org/">HTTP Server</a> > <a href="http://httpd.apache.org/docs-project/">Documentation</a> > <a href="../">Version 2.1</a> > <a href="./">Miscellaneous Documentation</a></div><div id="page-content"><div id="preamble"><h1>Apache Performance Notes</h1>
- <div class="warning"><strong>Warning:</strong>
- This document has not been fully updated
- to take into account changes made in the 2.0 version of the
- Apache HTTP Server. Some of the information may still be
- relevant, but please use it with care.</div>
+ <div class="warning"><h3>Warning:</h3>
+ <p>This document has not been fully updated
+ to take into account changes made in the 2.0 version of the
+ Apache HTTP Server. Some of the information may still be
+ relevant, but please use it with care.</p>
+ </div>
<p>Orignally written by Dean Gaudet.</p>
<table class="related"><tr><th>Related Modules</th><th>Related Directives</th></tr><tr><td><ul><li><code class="module"><a href="../mod/mod_dir.html">mod_dir</a></code></li><li><code class="module"><a href="../mod/mpm_common.html">mpm_common</a></code></li><li><code class="module"><a href="../mod/mod_status.html">mod_status</a></code></li></ul></td><td><ul><li><code class="directive"><a href="../mod/core.html#allowoverride">AllowOverride</a></code></li><li><code class="directive"><a href="../mod/mod_dir.html#directoryindex">DirectoryIndex</a></code></li><li><code class="directive"><a href="../mod/core.html#hostnamelookups">HostnameLookups</a></code></li><li><code class="directive"><a href="../mod/core.html#enablemmap">EnableMMAP</a></code></li><li><code class="directive"><a href="../mod/core.html#enablesendfile">EnableSendfile</a></code></li><li><code class="directive"><a href="../mod/core.html#keepalivetimeout">KeepAliveTimeout</a></code></li><li><code class="directive"><a href="../mod/prefork.html#maxspareservers">MaxSpareServers</a></code></li><li><code class="directive"><a href="../mod/prefork.html#minspareservers">MinSpareServers</a></code></li><li><code class="directive"><a href="../mod/core.html#options">Options</a></code></li><li><code class="directive"><a href="../mod/mpm_common.html#startservers">StartServers</a></code></li></ul></td></tr></table>
- <h3><code>HostnameLookups</code></h3>
+ <h3>HostnameLookups</h3>
matching the criteria. Here's an example which disables lookups
except for <code>.html</code> and <code>.cgi</code> files:</p>
-<div class="example"><pre>
-HostnameLookups off
-<Files ~ "\.(html|cgi)$">
- HostnameLookups on
-</Files>
-</pre></div>
+ <div class="example"><p><code>
+ HostnameLookups off<br />
+ <Files ~ "\.(html|cgi)$"><br />
+ <span class="indent">
+ HostnameLookups on<br />
+ </span>
+ </Files>
+ </code></p></div>
<p>But even still, if you just need DNS names in some CGIs you
could consider doing the <code>gethostbyname</code> call in the
- <h3><code>FollowSymLinks</code> and <code>SymLinksIfOwnerMatch</code></h3>
+ <h3>FollowSymLinks and SymLinksIfOwnerMatch</h3>
system calls to check up on symlinks. One extra call per
filename component. For example, if you had:</p>
-<div class="example"><pre>
-DocumentRoot /www/htdocs
-<Directory />
- Options SymLinksIfOwnerMatch
-</Directory>
-</pre></div>
+ <div class="example"><p><code>
+ DocumentRoot /www/htdocs<br />
+ <Directory /><br />
+ <span class="indent">
+ Options SymLinksIfOwnerMatch<br />
+ </span>
+ </Directory>
+ </code></p></div>
<p>and a request is made for the URI <code>/index.html</code>.
Then Apache will perform <code>lstat(2)</code> on
every single request. If you really desire the symlinks
security checking you can do something like this:</p>
-<div class="example"><pre>
-DocumentRoot /www/htdocs
-<Directory />
- Options FollowSymLinks
-</Directory>
-<Directory /www/htdocs>
- Options -FollowSymLinks +SymLinksIfOwnerMatch
-</Directory>
-</pre></div>
+ <div class="example"><p><code>
+ DocumentRoot /www/htdocs<br />
+ <Directory /><br />
+ <span class="indent">
+ Options FollowSymLinks<br />
+ </span>
+ </Directory><br />
+ <br />
+ <Directory /www/htdocs><br />
+ <span class="indent">
+ Options -FollowSymLinks +SymLinksIfOwnerMatch<br />
+ </span>
+ </Directory>
+ </code></p></div>
<p>This at least avoids the extra checks for the
<code class="directive"><a href="../mod/core.html#documentroot">DocumentRoot</a></code> path.
- <h3><code>AllowOverride</code></h3>
+ <h3>AllowOverride</h3>
<code>.htaccess</code> for each filename component. For
example,</p>
-<div class="example"><pre>
-DocumentRoot /www/htdocs
-<Directory />
- AllowOverride all
-</Directory>
-</pre></div>
+ <div class="example"><p><code>
+ DocumentRoot /www/htdocs<br />
+ <Directory /><br />
+ <span class="indent">
+ AllowOverride all<br />
+ </span>
+ </Directory>
+ </code></p></div>
<p>and a request is made for the URI <code>/index.html</code>.
Then Apache will attempt to open <code>/.htaccess</code>,
penalties. There's one case where you can speed up the server.
Instead of using a wildcard such as:</p>
-<div class="example"><pre>
-DirectoryIndex index
-</pre></div>
+ <div class="example"><p><code>
+ DirectoryIndex index
+ </code></p></div>
- <p>Use a complete list of options:</p>
+ <p>Use a complete list of options:</p>
-<div class="example"><pre>
-DirectoryIndex index.cgi index.pl index.shtml index.html
-</pre></div>
+ <div class="example"><p><code>
+ DirectoryIndex index.cgi index.pl index.shtml index.html
+ </code></p></div>
<p>where you list the most common choice first.</p>
do not match the code, they're contrived for pedagogical
purposes):</p>
-<div class="example"><pre>
- for (;;) {
- for (;;) {
- fd_set accept_fds;
-
- FD_ZERO (&accept_fds);
- for (i = first_socket; i <= last_socket; ++i) {
- FD_SET (i, &accept_fds);
- }
- rc = select (last_socket+1, &accept_fds, NULL, NULL, NULL);
- if (rc < 1) continue;
- new_connection = -1;
- for (i = first_socket; i <= last_socket; ++i) {
- if (FD_ISSET (i, &accept_fds)) {
- new_connection = accept (i, NULL, NULL);
- if (new_connection != -1) break;
- }
+ <div class="example"><p><code>
+ for (;;) {<br />
+ <span class="indent">
+ for (;;) {<br />
+ <span class="indent">
+ fd_set accept_fds;<br />
+ <br />
+ FD_ZERO (&accept_fds);<br />
+ for (i = first_socket; i <= last_socket; ++i) {<br />
+ <span class="indent">
+ FD_SET (i, &accept_fds);<br />
+ </span>
+ }<br />
+ rc = select (last_socket+1, &accept_fds, NULL, NULL, NULL);<br />
+ if (rc < 1) continue;<br />
+ new_connection = -1;<br />
+ for (i = first_socket; i <= last_socket; ++i) {<br />
+ <span class="indent">
+ if (FD_ISSET (i, &accept_fds)) {<br />
+ <span class="indent">
+ new_connection = accept (i, NULL, NULL);<br />
+ if (new_connection != -1) break;<br />
+ </span>
+ }<br />
+ </span>
+ }<br />
+ if (new_connection != -1) break;<br />
+ </span>
+ }<br />
+ process the new_connection;<br />
+ </span>
}
- if (new_connection != -1) break;
- }
- process the new_connection;
- }
-</pre></div>
+ </code></p></div>
<p>But this naive implementation has a serious starvation problem.
Recall that multiple children execute this loop at the same
entry into the inner loop. The loop looks like this
(differences highlighted):</p>
-<div class="example"><pre>
- for (;;) {
- <strong>accept_mutex_on ();</strong>
- for (;;) {
- fd_set accept_fds;
-
- FD_ZERO (&accept_fds);
- for (i = first_socket; i <= last_socket; ++i) {
- FD_SET (i, &accept_fds);
- }
- rc = select (last_socket+1, &accept_fds, NULL, NULL, NULL);
- if (rc < 1) continue;
- new_connection = -1;
- for (i = first_socket; i <= last_socket; ++i) {
- if (FD_ISSET (i, &accept_fds)) {
- new_connection = accept (i, NULL, NULL);
- if (new_connection != -1) break;
- }
+ <div class="example"><p><code>
+ for (;;) {<br />
+ <span class="indent">
+ <strong>accept_mutex_on ();</strong><br />
+ for (;;) {<br />
+ <span class="indent">
+ fd_set accept_fds;<br />
+ <br />
+ FD_ZERO (&accept_fds);<br />
+ for (i = first_socket; i <= last_socket; ++i) {<br />
+ <span class="indent">
+ FD_SET (i, &accept_fds);<br />
+ </span>
+ }<br />
+ rc = select (last_socket+1, &accept_fds, NULL, NULL, NULL);<br />
+ if (rc < 1) continue;<br />
+ new_connection = -1;<br />
+ for (i = first_socket; i <= last_socket; ++i) {<br />
+ <span class="indent">
+ if (FD_ISSET (i, &accept_fds)) {<br />
+ <span class="indent">
+ new_connection = accept (i, NULL, NULL);<br />
+ if (new_connection != -1) break;<br />
+ </span>
+ }<br />
+ </span>
+ }<br />
+ if (new_connection != -1) break;<br />
+ </span>
+ }<br />
+ <strong>accept_mutex_off ();</strong><br />
+ process the new_connection;<br />
+ </span>
}
- if (new_connection != -1) break;
- }
- <strong>accept_mutex_off ();</strong>
- process the new_connection;
- }
-</pre></div>
+ </code></p></div>
<p><a id="serialize" name="serialize">The functions</a>
<code>accept_mutex_on</code> and <code>accept_mutex_off</code>
<code>http_main.c</code>). The function looks roughly like
this:</p>
-<div class="example"><pre>
- void lingering_close (int s)
- {
- char junk_buffer[2048];
-
- /* shutdown the sending side */
- shutdown (s, 1);
-
- signal (SIGALRM, lingering_death);
- alarm (30);
-
- for (;;) {
- select (s for reading, 2 second timeout);
- if (error) break;
- if (s is ready for reading) {
- if (read (s, junk_buffer, sizeof (junk_buffer)) <= 0) {
- break;
+ <div class="example"><p><code>
+ void lingering_close (int s)<br />
+ {<br />
+ <span class="indent">
+ char junk_buffer[2048];<br />
+ <br />
+ /* shutdown the sending side */<br />
+ shutdown (s, 1);<br />
+ <br />
+ signal (SIGALRM, lingering_death);<br />
+ alarm (30);<br />
+ <br />
+ for (;;) {<br />
+ <span class="indent">
+ select (s for reading, 2 second timeout);<br />
+ if (error) break;<br />
+ if (s is ready for reading) {<br />
+ <span class="indent">
+ if (read (s, junk_buffer, sizeof (junk_buffer)) <= 0) {<br />
+ <span class="indent">
+ break;<br />
+ </span>
+ }<br />
+ /* just toss away whatever is here */<br />
+ </span>
+ }<br />
+ </span>
+ }<br />
+ <br />
+ close (s);<br />
+ </span>
}
- /* just toss away whatever is here */
- }
- }
-
- close (s);
- }
-</pre></div>
+ </code></p></div>
<p>This naturally adds some expense at the end of a connection,
but it is required for a reliable implementation. As HTTP/1.1
- <h3><code>DYNAMIC_MODULE_LIMIT</code></h3>
+ <h3>DYNAMIC_MODULE_LIMIT</h3>
on Solaris 8. This trace was collected using:</p>
<div class="example"><p><code>
- truss -l -p <em>httpd_child_pid</em>.
+ truss -l -p <var>httpd_child_pid</var>.
</code></p></div>
<p>The <code>-l</code> option tells truss to log the ID of the
with content negotiation look wildly different (and quite ugly
in some cases).</p>
-<div class="example"><pre>
-/67: accept(3, 0x00200BEC, 0x00200C0C, 1) (sleeping...)
-/67: accept(3, 0x00200BEC, 0x00200C0C, 1) = 9
-</pre></div>
+ <div class="example"><pre>/67: accept(3, 0x00200BEC, 0x00200C0C, 1) (sleeping...)
+/67: accept(3, 0x00200BEC, 0x00200C0C, 1) = 9</pre></div>
<p>In this trace, the listener thread is running within LWP #67.</p>
particular platform, the worker MPM uses an unserialized accept by
default unless it is listening on multiple ports.</div>
-<div class="example"><pre>
-/65: lwp_park(0x00000000, 0) = 0
-/67: lwp_unpark(65, 1) = 0
-</pre></div>
+ <div class="example"><pre>/65: lwp_park(0x00000000, 0) = 0
+/67: lwp_unpark(65, 1) = 0</pre></div>
<p>Upon accepting the connection, the listener thread wakes up
a worker thread to do the request processing. In this trace,
the worker thread that handles the request is mapped to LWP #65.</p>
-<div class="example"><pre>
-/65: getsockname(9, 0x00200BA4, 0x00200BC4, 1) = 0
-</pre></div>
+ <div class="example"><pre>/65: getsockname(9, 0x00200BA4, 0x00200BC4, 1) = 0</pre></div>
<p>In order to implement virtual hosts, Apache needs to know
the local socket address used to accept the connection. It
are used which do not have wildcard addresses). But
no effort has yet been made to do these optimizations. </p>
-<div class="example"><pre>
-/65: brk(0x002170E8) = 0
-/65: brk(0x002190E8) = 0
-</pre></div>
+ <div class="example"><pre>/65: brk(0x002170E8) = 0
+/65: brk(0x002190E8) = 0</pre></div>
<p>The <code>brk(2)</code> calls allocate memory from the heap.
It is rare to see these in a system call trace, because the httpd
call <code>malloc(3)</code> to get the blocks of raw memory
with which to create the custom memory allocators.</p>
-<div class="example"><pre>
-/65: fcntl(9, F_GETFL, 0x00000000) = 2
+ <div class="example"><pre>/65: fcntl(9, F_GETFL, 0x00000000) = 2
/65: fstat64(9, 0xFAF7B818) = 0
/65: getsockopt(9, 65535, 8192, 0xFAF7B918, 0xFAF7B910, 2190656) = 0
/65: fstat64(9, 0xFAF7B818) = 0
/65: getsockopt(9, 65535, 8192, 0xFAF7B918, 0xFAF7B914, 2190656) = 0
/65: setsockopt(9, 65535, 8192, 0xFAF7B918, 4, 2190656) = 0
-/65: fcntl(9, F_SETFL, 0x00000082) = 0
-</pre></div>
+/65: fcntl(9, F_SETFL, 0x00000082) = 0</pre></div>
<p>Next, the worker thread puts the connection to the client (file
descriptor 9) in non-blocking mode. The <code>setsockopt(2)</code>
and <code>getsockopt(2)</code> calls are a side-effect of how
Solaris's libc handles <code>fcntl(2)</code> on sockets.</p>
-<div class="example"><pre>
-/65: read(9, " G E T / 1 0 k . h t m".., 8000) = 97
-</pre></div>
+ <div class="example"><pre>/65: read(9, " G E T / 1 0 k . h t m".., 8000) = 97</pre></div>
<p>The worker thread reads the request from the client.</p>
-<div class="example"><pre>
-/65: stat("/var/httpd/apache/httpd-8999/htdocs/10k.html", 0xFAF7B978) = 0
-/65: open("/var/httpd/apache/httpd-8999/htdocs/10k.html", O_RDONLY) = 10
-</pre></div>
+ <div class="example"><pre>/65: stat("/var/httpd/apache/httpd-8999/htdocs/10k.html", 0xFAF7B978) = 0
+/65: open("/var/httpd/apache/httpd-8999/htdocs/10k.html", O_RDONLY) = 10</pre></div>
<p>This httpd has been configured with <code>Options FollowSymLinks</code>
and <code>AllowOverride None</code>. Thus it doesn't need to
It simply calls <code>stat(2)</code> to verify that the file:
1) exists, and 2) is a regular file, not a directory.</p>
-<div class="example"><pre>
-/65: sendfilev(0, 9, 0x00200F90, 2, 0xFAF7B53C) = 10269
-</pre></div>
+ <div class="example"><pre>/65: sendfilev(0, 9, 0x00200F90, 2, 0xFAF7B53C) = 10269</pre></div>
<p>In this example, the httpd is able to send the HTTP response
header and the requested file with a single <code>sendfilev(2)</code>
<code>writev(2)</code> call to send the headers before calling
<code>sendfile(2)</code>.</p>
-<div class="example"><pre>
-/65: write(4, " 1 2 7 . 0 . 0 . 1 - ".., 78) = 78
-</pre></div>
+ <div class="example"><pre>/65: write(4, " 1 2 7 . 0 . 0 . 1 - ".., 78) = 78</pre></div>
<p>This <code>write(2)</code> call records the request in the
access log. Note that one thing missing from this trace is a
optimized implementation that doesn't require as much overhead
as a typical system call.</p>
-<div class="example"><pre>
-/65: shutdown(9, 1, 1) = 0
+ <div class="example"><pre>/65: shutdown(9, 1, 1) = 0
/65: poll(0xFAF7B980, 1, 2000) = 1
/65: read(9, 0xFAF7BC20, 512) = 0
-/65: close(9) = 0
-</pre></div>
+/65: close(9) = 0</pre></div>
<p>The worker thread does a lingering close of the connection.</p>
-<div class="example"><pre>
-/65: close(10) = 0
-/65: lwp_park(0x00000000, 0) (sleeping...)
-</pre></div>
+ <div class="example"><pre>/65: close(10) = 0
+/65: lwp_park(0x00000000, 0) (sleeping...)</pre></div>
<p>Finally the worker thread closes the file that it has just delivered
and blocks until the listener assigns it another connection.</p>
-<div class="example"><pre>
-/67: accept(3, 0x001FEB74, 0x001FEB94, 1) (sleeping...)
-</pre></div>
+ <div class="example"><pre>/67: accept(3, 0x001FEB74, 0x001FEB94, 1) (sleeping...)</pre></div>
<p>Meanwhile, the listener thread is able to accept another connection
as soon as it has dispatched this connection to a worker thread (subject
<summary>
- <note type="warning"><strong>Warning:</strong>
- This document has not been fully updated
- to take into account changes made in the 2.0 version of the
- Apache HTTP Server. Some of the information may still be
- relevant, but please use it with care.</note>
+ <note type="warning"><title>Warning:</title>
+ <p>This document has not been fully updated
+ to take into account changes made in the 2.0 version of the
+ Apache HTTP Server. Some of the information may still be
+ relevant, but please use it with care.</p>
+ </note>
<p>Orignally written by Dean Gaudet.</p>
<section>
- <title><code>HostnameLookups</code></title>
+ <title>HostnameLookups</title>
<p>Prior to Apache 1.3, <directive module="core"
>HostnameLookups</directive> defaulted to <code>On</code>.
matching the criteria. Here's an example which disables lookups
except for <code>.html</code> and <code>.cgi</code> files:</p>
-<example><pre>
-HostnameLookups off
-<Files ~ "\.(html|cgi)$">
- HostnameLookups on
-</Files>
-</pre></example>
+ <example>
+ HostnameLookups off<br />
+ <Files ~ "\.(html|cgi)$"><br />
+ <indent>
+ HostnameLookups on<br />
+ </indent>
+ </Files>
+ </example>
<p>But even still, if you just need DNS names in some CGIs you
could consider doing the <code>gethostbyname</code> call in the
<section>
- <title><code>FollowSymLinks</code> and <code>SymLinksIfOwnerMatch</code></title>
+ <title>FollowSymLinks and SymLinksIfOwnerMatch</title>
<p>Wherever in your URL-space you do not have an <code>Options
FollowSymLinks</code>, or you do have an <code>Options
system calls to check up on symlinks. One extra call per
filename component. For example, if you had:</p>
-<example><pre>
-DocumentRoot /www/htdocs
-<Directory />
- Options SymLinksIfOwnerMatch
-</Directory>
-</pre></example>
+ <example>
+ DocumentRoot /www/htdocs<br />
+ <Directory /><br />
+ <indent>
+ Options SymLinksIfOwnerMatch<br />
+ </indent>
+ </Directory>
+ </example>
<p>and a request is made for the URI <code>/index.html</code>.
Then Apache will perform <code>lstat(2)</code> on
every single request. If you really desire the symlinks
security checking you can do something like this:</p>
-<example><pre>
-DocumentRoot /www/htdocs
-<Directory />
- Options FollowSymLinks
-</Directory>
-<Directory /www/htdocs>
- Options -FollowSymLinks +SymLinksIfOwnerMatch
-</Directory>
-</pre></example>
+ <example>
+ DocumentRoot /www/htdocs<br />
+ <Directory /><br />
+ <indent>
+ Options FollowSymLinks<br />
+ </indent>
+ </Directory><br />
+ <br />
+ <Directory /www/htdocs><br />
+ <indent>
+ Options -FollowSymLinks +SymLinksIfOwnerMatch<br />
+ </indent>
+ </Directory>
+ </example>
<p>This at least avoids the extra checks for the
<directive module="core">DocumentRoot</directive> path.
<section>
- <title><code>AllowOverride</code></title>
+ <title>AllowOverride</title>
<p>Wherever in your URL-space you allow overrides (typically
<code>.htaccess</code> files) Apache will attempt to open
<code>.htaccess</code> for each filename component. For
example,</p>
-<example><pre>
-DocumentRoot /www/htdocs
-<Directory />
- AllowOverride all
-</Directory>
-</pre></example>
+ <example>
+ DocumentRoot /www/htdocs<br />
+ <Directory /><br />
+ <indent>
+ AllowOverride all<br />
+ </indent>
+ </Directory>
+ </example>
<p>and a request is made for the URI <code>/index.html</code>.
Then Apache will attempt to open <code>/.htaccess</code>,
penalties. There's one case where you can speed up the server.
Instead of using a wildcard such as:</p>
-<example><pre>
-DirectoryIndex index
-</pre></example>
+ <example>
+ DirectoryIndex index
+ </example>
- <p>Use a complete list of options:</p>
+ <p>Use a complete list of options:</p>
-<example><pre>
-DirectoryIndex index.cgi index.pl index.shtml index.html
-</pre></example>
+ <example>
+ DirectoryIndex index.cgi index.pl index.shtml index.html
+ </example>
<p>where you list the most common choice first.</p>
do not match the code, they're contrived for pedagogical
purposes):</p>
-<example><pre>
- for (;;) {
- for (;;) {
- fd_set accept_fds;
-
- FD_ZERO (&accept_fds);
- for (i = first_socket; i <= last_socket; ++i) {
- FD_SET (i, &accept_fds);
- }
- rc = select (last_socket+1, &accept_fds, NULL, NULL, NULL);
- if (rc < 1) continue;
- new_connection = -1;
- for (i = first_socket; i <= last_socket; ++i) {
- if (FD_ISSET (i, &accept_fds)) {
- new_connection = accept (i, NULL, NULL);
- if (new_connection != -1) break;
- }
+ <example>
+ for (;;) {<br />
+ <indent>
+ for (;;) {<br />
+ <indent>
+ fd_set accept_fds;<br />
+ <br />
+ FD_ZERO (&accept_fds);<br />
+ for (i = first_socket; i <= last_socket; ++i) {<br />
+ <indent>
+ FD_SET (i, &accept_fds);<br />
+ </indent>
+ }<br />
+ rc = select (last_socket+1, &accept_fds, NULL, NULL, NULL);<br />
+ if (rc < 1) continue;<br />
+ new_connection = -1;<br />
+ for (i = first_socket; i <= last_socket; ++i) {<br />
+ <indent>
+ if (FD_ISSET (i, &accept_fds)) {<br />
+ <indent>
+ new_connection = accept (i, NULL, NULL);<br />
+ if (new_connection != -1) break;<br />
+ </indent>
+ }<br />
+ </indent>
+ }<br />
+ if (new_connection != -1) break;<br />
+ </indent>
+ }<br />
+ process the new_connection;<br />
+ </indent>
}
- if (new_connection != -1) break;
- }
- process the new_connection;
- }
-</pre></example>
+ </example>
<p>But this naive implementation has a serious starvation problem.
Recall that multiple children execute this loop at the same
entry into the inner loop. The loop looks like this
(differences highlighted):</p>
-<example><pre>
- for (;;) {
- <strong>accept_mutex_on ();</strong>
- for (;;) {
- fd_set accept_fds;
-
- FD_ZERO (&accept_fds);
- for (i = first_socket; i <= last_socket; ++i) {
- FD_SET (i, &accept_fds);
- }
- rc = select (last_socket+1, &accept_fds, NULL, NULL, NULL);
- if (rc < 1) continue;
- new_connection = -1;
- for (i = first_socket; i <= last_socket; ++i) {
- if (FD_ISSET (i, &accept_fds)) {
- new_connection = accept (i, NULL, NULL);
- if (new_connection != -1) break;
+ <example>
+ for (;;) {<br />
+ <indent>
+ <strong>accept_mutex_on ();</strong><br />
+ for (;;) {<br />
+ <indent>
+ fd_set accept_fds;<br />
+ <br />
+ FD_ZERO (&accept_fds);<br />
+ for (i = first_socket; i <= last_socket; ++i) {<br />
+ <indent>
+ FD_SET (i, &accept_fds);<br />
+ </indent>
+ }<br />
+ rc = select (last_socket+1, &accept_fds, NULL, NULL, NULL);<br />
+ if (rc < 1) continue;<br />
+ new_connection = -1;<br />
+ for (i = first_socket; i <= last_socket; ++i) {<br />
+ <indent>
+ if (FD_ISSET (i, &accept_fds)) {<br />
+ <indent>
+ new_connection = accept (i, NULL, NULL);<br />
+ if (new_connection != -1) break;<br />
+ </indent>
+ }<br />
+ </indent>
+ }<br />
+ if (new_connection != -1) break;<br />
+ </indent>
+ }<br />
+ <strong>accept_mutex_off ();</strong><br />
+ process the new_connection;<br />
+ </indent>
}
- }
- if (new_connection != -1) break;
- }
- <strong>accept_mutex_off ();</strong>
- process the new_connection;
- }
-</pre></example>
+ </example>
<p><a id="serialize" name="serialize">The functions</a>
<code>accept_mutex_on</code> and <code>accept_mutex_off</code>
<code>http_main.c</code>). The function looks roughly like
this:</p>
-<example><pre>
- void lingering_close (int s)
- {
- char junk_buffer[2048];
-
- /* shutdown the sending side */
- shutdown (s, 1);
-
- signal (SIGALRM, lingering_death);
- alarm (30);
-
- for (;;) {
- select (s for reading, 2 second timeout);
- if (error) break;
- if (s is ready for reading) {
- if (read (s, junk_buffer, sizeof (junk_buffer)) <= 0) {
- break;
+ <example>
+ void lingering_close (int s)<br />
+ {<br />
+ <indent>
+ char junk_buffer[2048];<br />
+ <br />
+ /* shutdown the sending side */<br />
+ shutdown (s, 1);<br />
+ <br />
+ signal (SIGALRM, lingering_death);<br />
+ alarm (30);<br />
+ <br />
+ for (;;) {<br />
+ <indent>
+ select (s for reading, 2 second timeout);<br />
+ if (error) break;<br />
+ if (s is ready for reading) {<br />
+ <indent>
+ if (read (s, junk_buffer, sizeof (junk_buffer)) <= 0) {<br />
+ <indent>
+ break;<br />
+ </indent>
+ }<br />
+ /* just toss away whatever is here */<br />
+ </indent>
+ }<br />
+ </indent>
+ }<br />
+ <br />
+ close (s);<br />
+ </indent>
}
- /* just toss away whatever is here */
- }
- }
-
- close (s);
- }
-</pre></example>
+ </example>
<p>This naturally adds some expense at the end of a connection,
but it is required for a reliable implementation. As HTTP/1.1
<section>
- <title><code>DYNAMIC_MODULE_LIMIT</code></title>
+ <title>DYNAMIC_MODULE_LIMIT</title>
<p>If you have no intention of using dynamically loaded modules
(you probably don't if you're reading this and tuning your
on Solaris 8. This trace was collected using:</p>
<example>
- truss -l -p <em>httpd_child_pid</em>.
+ truss -l -p <var>httpd_child_pid</var>.
</example>
<p>The <code>-l</code> option tells truss to log the ID of the
with content negotiation look wildly different (and quite ugly
in some cases).</p>
-<example><pre>
-/67: accept(3, 0x00200BEC, 0x00200C0C, 1) (sleeping...)
-/67: accept(3, 0x00200BEC, 0x00200C0C, 1) = 9
-</pre></example>
+ <example>
+<pre>/67: accept(3, 0x00200BEC, 0x00200C0C, 1) (sleeping...)
+/67: accept(3, 0x00200BEC, 0x00200C0C, 1) = 9</pre>
+ </example>
<p>In this trace, the listener thread is running within LWP #67.</p>
particular platform, the worker MPM uses an unserialized accept by
default unless it is listening on multiple ports.</note>
-<example><pre>
-/65: lwp_park(0x00000000, 0) = 0
-/67: lwp_unpark(65, 1) = 0
-</pre></example>
+ <example>
+<pre>/65: lwp_park(0x00000000, 0) = 0
+/67: lwp_unpark(65, 1) = 0</pre>
+ </example>
<p>Upon accepting the connection, the listener thread wakes up
a worker thread to do the request processing. In this trace,
the worker thread that handles the request is mapped to LWP #65.</p>
-<example><pre>
-/65: getsockname(9, 0x00200BA4, 0x00200BC4, 1) = 0
-</pre></example>
+ <example>
+<pre>/65: getsockname(9, 0x00200BA4, 0x00200BC4, 1) = 0</pre>
+ </example>
<p>In order to implement virtual hosts, Apache needs to know
the local socket address used to accept the connection. It
are used which do not have wildcard addresses). But
no effort has yet been made to do these optimizations. </p>
-<example><pre>
-/65: brk(0x002170E8) = 0
-/65: brk(0x002190E8) = 0
-</pre></example>
+ <example>
+<pre>/65: brk(0x002170E8) = 0
+/65: brk(0x002190E8) = 0</pre>
+ </example>
<p>The <code>brk(2)</code> calls allocate memory from the heap.
It is rare to see these in a system call trace, because the httpd
call <code>malloc(3)</code> to get the blocks of raw memory
with which to create the custom memory allocators.</p>
-<example><pre>
-/65: fcntl(9, F_GETFL, 0x00000000) = 2
+ <example>
+<pre>/65: fcntl(9, F_GETFL, 0x00000000) = 2
/65: fstat64(9, 0xFAF7B818) = 0
/65: getsockopt(9, 65535, 8192, 0xFAF7B918, 0xFAF7B910, 2190656) = 0
/65: fstat64(9, 0xFAF7B818) = 0
/65: getsockopt(9, 65535, 8192, 0xFAF7B918, 0xFAF7B914, 2190656) = 0
/65: setsockopt(9, 65535, 8192, 0xFAF7B918, 4, 2190656) = 0
-/65: fcntl(9, F_SETFL, 0x00000082) = 0
-</pre></example>
+/65: fcntl(9, F_SETFL, 0x00000082) = 0</pre>
+ </example>
<p>Next, the worker thread puts the connection to the client (file
descriptor 9) in non-blocking mode. The <code>setsockopt(2)</code>
and <code>getsockopt(2)</code> calls are a side-effect of how
Solaris's libc handles <code>fcntl(2)</code> on sockets.</p>
-<example><pre>
-/65: read(9, " G E T / 1 0 k . h t m".., 8000) = 97
-</pre></example>
+ <example>
+<pre>/65: read(9, " G E T / 1 0 k . h t m".., 8000) = 97</pre>
+ </example>
<p>The worker thread reads the request from the client.</p>
-<example><pre>
-/65: stat("/var/httpd/apache/httpd-8999/htdocs/10k.html", 0xFAF7B978) = 0
-/65: open("/var/httpd/apache/httpd-8999/htdocs/10k.html", O_RDONLY) = 10
-</pre></example>
+ <example>
+<pre>/65: stat("/var/httpd/apache/httpd-8999/htdocs/10k.html", 0xFAF7B978) = 0
+/65: open("/var/httpd/apache/httpd-8999/htdocs/10k.html", O_RDONLY) = 10</pre>
+ </example>
<p>This httpd has been configured with <code>Options FollowSymLinks</code>
and <code>AllowOverride None</code>. Thus it doesn't need to
It simply calls <code>stat(2)</code> to verify that the file:
1) exists, and 2) is a regular file, not a directory.</p>
-<example><pre>
-/65: sendfilev(0, 9, 0x00200F90, 2, 0xFAF7B53C) = 10269
-</pre></example>
+ <example>
+<pre>/65: sendfilev(0, 9, 0x00200F90, 2, 0xFAF7B53C) = 10269</pre>
+ </example>
<p>In this example, the httpd is able to send the HTTP response
header and the requested file with a single <code>sendfilev(2)</code>
<code>writev(2)</code> call to send the headers before calling
<code>sendfile(2)</code>.</p>
-<example><pre>
-/65: write(4, " 1 2 7 . 0 . 0 . 1 - ".., 78) = 78
-</pre></example>
+ <example>
+<pre>/65: write(4, " 1 2 7 . 0 . 0 . 1 - ".., 78) = 78</pre>
+ </example>
<p>This <code>write(2)</code> call records the request in the
access log. Note that one thing missing from this trace is a
optimized implementation that doesn't require as much overhead
as a typical system call.</p>
-<example><pre>
-/65: shutdown(9, 1, 1) = 0
+ <example>
+<pre>/65: shutdown(9, 1, 1) = 0
/65: poll(0xFAF7B980, 1, 2000) = 1
/65: read(9, 0xFAF7BC20, 512) = 0
-/65: close(9) = 0
-</pre></example>
+/65: close(9) = 0</pre>
+ </example>
<p>The worker thread does a lingering close of the connection.</p>
-<example><pre>
-/65: close(10) = 0
-/65: lwp_park(0x00000000, 0) (sleeping...)
-</pre></example>
+ <example>
+<pre>/65: close(10) = 0
+/65: lwp_park(0x00000000, 0) (sleeping...)</pre>
+ </example>
<p>Finally the worker thread closes the file that it has just delivered
and blocks until the listener assigns it another connection.</p>
-<example><pre>
-/67: accept(3, 0x001FEB74, 0x001FEB94, 1) (sleeping...)
-</pre></example>
+ <example>
+<pre>/67: accept(3, 0x001FEB74, 0x001FEB94, 1) (sleeping...)</pre>
+ </example>
<p>Meanwhile, the listener thread is able to accept another connection
as soon as it has dispatched this connection to a worker thread (subject