dgaudet 97/08/17 04:14:38
Modified: htdocs/manual new_features_1_3.html
src CHANGES Configure
src/core conf.h http_core.c http_main.c httpd.h
Log:
Add new mutexes (sysvsem, solaris pthreads, irix uslocks).
Add SAFE_UNSERIALIZED_ACCEPT support.
Submitted by: Dean Gaudet,
Submitted by: Pierre-Yves Kerembellec <[EMAIL PROTECTED]>,
Submitted by: Martijn Koster <[EMAIL PROTECTED]>
Reviewed by: Paul Sutton
Revision Changes Path
1.15 +2 -2 apachen/htdocs/manual/new_features_1_3.html
Index: new_features_1_3.html
===================================================================
RCS file: /export/home/cvs/apachen/htdocs/manual/new_features_1_3.html,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -r1.14 -r1.15
--- new_features_1_3.html 1997/08/11 10:04:43 1.14
+++ new_features_1_3.html 1997/08/17 11:14:29 1.15
@@ -208,8 +208,8 @@
performed for each hit, now it is performed only once per second.
This should be noticeable on servers running with hundreds of
children and high loads.
- <li><i>XXX Incomplete:</i> New serialization choices improve performance
- on Linux, Solaris, and IRIX.
+ <li>New serialization choices improve performance on Linux, Solaris,
+ and IRIX.
</ul>
</ul>
1.399 +27 -3 apachen/src/CHANGES
Index: CHANGES
===================================================================
RCS file: /export/home/cvs/apachen/src/CHANGES,v
retrieving revision 1.398
retrieving revision 1.399
diff -u -r1.398 -r1.399
--- CHANGES 1997/08/17 02:31:47 1.398
+++ CHANGES 1997/08/17 11:14:31 1.399
@@ -1,5 +1,32 @@
Changes with Apache 1.3a2
+ *) PORT: Apache has need for mutexes to serialize its children around
+ accept. In prior versions either fcntl file locking or flock file
+ locking were used. The method is chosen by the definition of
+ USE_xxx_SERIALIZED_ACCEPT in conf.h. xxx is FCNTL for fcntl(),
+ and FLOCK for flock(). New options have been added:
+ - SYSVSEM to use System V style semaphores
+ - PTHREAD to use Posix threads (appears to work on Solaris only)
+ - USLOCK to use IRIX uslock
+ Based on timing various techniques, the following changes were made
+ to the defaults:
+ - Linux 2.x uses flock instead of fcntl
+ - Solaris 2.x uses pthreads
+ - IRIX uses SysV semaphores -- however multiprocessor IRIX boxes
+ work far faster if you -DUSE_USLOCK_SERIALIZED_ACCEPT
+ [Dean Gaudet, Pierre-Yves Kerembellec <[EMAIL PROTECTED]>,
+ Martijn Koster <[EMAIL PROTECTED]>]
+
+ *) PORT: The semantics of accept/select make it very desirable to use
+ mutexes to serialize accept when multiple Listens are in use. But
+ in the case where only a single socket is open it is sometimes
+ redundant to serialize accept(). Not all unixes do a good job with
+ potentially dozens of children blocked on accept() on the same
+ socket. It's now possible to define SAFE_UNSERIALIZED_ACCEPT and
+ the server will avoid serialization when listening on only one socket,
+ and use serialization when listening on multiple sockets.
+ [Dean Gaudet] PR#467
+
*) 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
@@ -9,9 +36,6 @@
*) mod_browser has been removed, since it's replaced by mod_setenvif.
[Ken Coar]
-
- *) PORT: Timings show that on Linux 2.0.30 flock is slightly cheaper than
- fcntl file locking. So use flock for the mutexes. [Dean Gaudet]
*) Fix another long-standing bug in sub_req_lookup_file where it would
happily skip past access checks on subdirectories looked up with
1.135 +1 -1 apachen/src/Configure
Index: Configure
===================================================================
RCS file: /export/home/cvs/apachen/src/Configure,v
retrieving revision 1.134
retrieving revision 1.135
diff -u -r1.134 -r1.135
--- Configure 1997/08/15 18:12:06 1.134
+++ Configure 1997/08/17 11:14:32 1.135
@@ -358,7 +358,7 @@
SOLVER=`echo $PLAT | sed -e 's/^.*solaris2.//'`
OS="Solaris $SOLVER"
CFLAGS="$CFLAGS -DSOLARIS2=$SOLVER"
- LIBS="$LIBS -lsocket -lnsl"
+ LIBS="$LIBS -lsocket -lnsl -lpthread"
DBM_LIB=""
case "$SOLVER" in
2[0123]*)
1.124 +6 -2 apachen/src/core/conf.h
Index: conf.h
===================================================================
RCS file: /export/home/cvs/apachen/src/core/conf.h,v
retrieving revision 1.123
retrieving revision 1.124
diff -u -r1.123 -r1.124
--- conf.h 1997/08/15 18:12:09 1.123
+++ conf.h 1997/08/17 11:14:34 1.124
@@ -100,7 +100,10 @@
#define HAVE_SYS_RESOURCE_H
#define bzero(a,b) memset(a,0,b)
#define JMP_BUF sigjmp_buf
-#define USE_FCNTL_SERIALIZED_ACCEPT
+/*#define USE_FCNTL_SERIALIZED_ACCEPT*/
+/*#define USE_SYSVSEM_SERIALIZED_ACCEPT*/
+#define USE_PTHREAD_SERIALIZED_ACCEPT
+#define NEED_UNION_SEMUN
#define HAVE_MMAP
#define HAVE_CRYPT_H
int gethostname(char *name, int namelen);
@@ -112,7 +115,8 @@
#define NO_KILLPG
#undef NO_SETSID
#define JMP_BUF sigjmp_buf
-#define USE_FCNTL_SERIALIZED_ACCEPT
+/*#define USE_FCNTL_SERIALIZED_ACCEPT*/
+#define USE_SYSVSEM_SERIALIZED_ACCEPT
#define HAVE_SHMGET
#define HAVE_CRYPT_H
#define NO_LONG_DOUBLE
1.110 +1 -1 apachen/src/core/http_core.c
Index: http_core.c
===================================================================
RCS file: /export/home/cvs/apachen/src/core/http_core.c,v
retrieving revision 1.109
retrieving revision 1.110
diff -u -r1.109 -r1.110
--- http_core.c 1997/08/06 20:21:24 1.109
+++ http_core.c 1997/08/17 11:14:34 1.110
@@ -352,7 +352,7 @@
core_dir_config *conf =
(core_dir_config *)get_module_config(r->per_dir_config, &core_module);
- return conf->default_type ? conf->default_type : DEFAULT_TYPE;
+ return conf->default_type ? conf->default_type : DEFAULT_CONTENT_TYPE;
}
API_EXPORT(char *) document_root (request_rec *r) /* Don't use this!!! */
1.201 +261 -12 apachen/src/core/http_main.c
Index: http_main.c
===================================================================
RCS file: /export/home/cvs/apachen/src/core/http_main.c,v
retrieving revision 1.200
retrieving revision 1.201
diff -u -r1.200 -r1.201
--- http_main.c 1997/08/15 18:12:11 1.200
+++ http_main.c 1997/08/17 11:14:35 1.201
@@ -261,18 +261,248 @@
}
#endif
-#if defined(USE_FCNTL_SERIALIZED_ACCEPT)
+#if defined (USE_USLOCK_SERIALIZED_ACCEPT)
+
+#include <ulocks.h>
+
+static ulock_t uslock = NULL;
+
+#define accept_mutex_cleanup()
+
+static void accept_mutex_init(pool *p)
+{
+ ptrdiff_t old;
+ usptr_t *us;
+
+
+ /* default is 8, allocate enough for all the children plus the parent */
+ if ((old = usconfig(CONF_INITUSERS, HARD_SERVER_LIMIT+1)) == -1) {
+ perror("usconfig(CONF_INITUSERS)");
+ exit(-1);
+ }
+
+ if ((old = usconfig(CONF_LOCKTYPE, US_NODEBUG)) == -1) {
+ perror("usconfig(CONF_LOCKTYPE)");
+ exit(-1);
+ }
+ if ((old = usconfig(CONF_ARENATYPE, US_SHAREDONLY)) == -1) {
+ perror("usconfig(CONF_ARENATYPE)");
+ exit(-1);
+ }
+ if ((us = usinit("/dev/zero")) == NULL) {
+ perror("usinit");
+ exit(-1);
+ }
+
+ if ((uslock = usnewlock(us)) == NULL) {
+ perror("usnewlock");
+ exit(-1);
+ }
+}
+
+static void accept_mutex_on()
+{
+ switch(ussetlock(uslock)) {
+ case 1:
+ /* got lock */
+ break;
+ case 0:
+ fprintf(stderr, "didn't get lock\n");
+ exit(-1);
+ case -1:
+ perror("ussetlock");
+ exit(-1);
+ }
+}
+
+static void accept_mutex_off()
+{
+ if (usunsetlock(uslock) == -1) {
+ perror("usunsetlock");
+ exit(-1);
+ }
+}
+
+#elif defined (USE_PTHREAD_SERIALIZED_ACCEPT)
+
+/* This code probably only works on Solaris ... but it works really fast
+ * on Solaris
+ */
+
+#include <pthread.h>
+
+static pthread_mutex_t *accept_mutex;
+
+static void accept_mutex_cleanup(void)
+{
+ if (munmap ((caddr_t)accept_mutex, sizeof (*accept_mutex))) {
+ perror ("munmap");
+ }
+}
+
+static void accept_mutex_init(pool *p)
+{
+ pthread_mutexattr_t mattr;
+ int fd;
+
+ fd = open ("/dev/zero", O_RDWR);
+ if (fd == -1) {
+ perror ("open(/dev/zero)");
+ exit (1);
+ }
+ accept_mutex = (pthread_mutex_t *)mmap ((caddr_t)0, sizeof
(*accept_mutex),
+ PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+ if (accept_mutex == (void *)(caddr_t)-1) {
+ perror ("mmap");
+ exit (1);
+ }
+ close (fd);
+ if (pthread_mutexattr_init(&mattr)) {
+ perror ("pthread_mutexattr_init");
+ exit (1);
+ }
+ if (pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED)) {
+ perror ("pthread_mutexattr_setpshared");
+ exit (1);
+ }
+ if (pthread_mutex_init(accept_mutex, &mattr)) {
+ perror ("pthread_mutex_init");
+ exit (1);
+ }
+}
+
+static void accept_mutex_on()
+{
+ if (pthread_mutex_lock (accept_mutex)) {
+ perror ("pthread_mutex_lock");
+ exit (1);
+ }
+}
+
+static void accept_mutex_off()
+{
+ if (pthread_mutex_unlock (accept_mutex)) {
+ perror ("pthread_mutex_unlock");
+ exit (1);
+ }
+}
+
+#elif defined (USE_SYSVSEM_SERIALIZED_ACCEPT)
+
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/sem.h>
+
+#ifdef NEED_UNION_SEMUN
+/* it makes no sense, but this isn't defined on solaris */
+union semun {
+ int val;
+ struct semid_ds *buf;
+ ushort *array;
+};
+#endif
+
+static int sem_cleanup_registered;
+static pid_t sem_cleanup_pid;
+static int sem_id = -1;
+static struct sembuf op_on;
+static struct sembuf op_off;
+
+/* We get a random semaphore ... the lame sysv semaphore interface
+ * means we have to be sure to clean this up or else we'll leak
+ * semaphores. Note that this is registered via atexit, so we can't
+ * do many things in here... especially nothing that would allocate
+ * memory or use a FILE *.
+ */
+static void accept_mutex_cleanup (void)
+{
+ union semun ick;
+
+ if (sem_id < 0) return;
+ if (getpid() != sem_cleanup_pid) return;
+ /* this is ignored anyhow */
+ ick.val = 0;
+ semctl (sem_id, 0, IPC_RMID, ick);
+}
+
+
+static void accept_mutex_init(pool *p)
+{
+ union semun ick;
+ struct semid_ds buf;
+
+ if (!sem_cleanup_registered) {
+ /* only the parent will try to do cleanup */
+ sem_cleanup_pid = getpid();
+ if (atexit (accept_mutex_cleanup)) {
+ perror ("atexit");
+ exit (1);
+ }
+ sem_cleanup_registered = 1;
+ }
+ /* acquire the semaphore */
+ sem_id = semget(IPC_PRIVATE, 1, IPC_CREAT | 0600);
+ if (sem_id < 0) {
+ perror ("semget");
+ exit (1);
+ }
+ ick.val = 1;
+ if (semctl(sem_id, 0, SETVAL, ick) < 0) {
+ perror ("semctl(SETVAL)");
+ exit (1);
+ }
+ if (!getuid()) {
+ /* restrict it to use only by the appropriate user_id ... not that this
+ * stops CGIs from acquiring it and dinking around with it.
+ */
+ buf.sem_perm.uid = user_id;
+ buf.sem_perm.gid = group_id;
+ buf.sem_perm.mode = 0600;
+ ick.buf = &buf;
+ if (semctl(sem_id, 0, IPC_SET, ick) < 0) {
+ perror ("semctl(IPC_SET)");
+ exit (1);
+ }
+ }
+
+ /* pre-initialize these */
+ op_on.sem_num = 0;
+ op_on.sem_op = -1;
+ op_on.sem_flg = SEM_UNDO;
+ op_off.sem_num = 0;
+ op_off.sem_op = 1;
+ op_off.sem_flg = SEM_UNDO;
+}
+
+static void accept_mutex_on()
+{
+ if (semop(sem_id, &op_on, 1) < 0) {
+ perror ("accept_mutex_on");
+ exit (1);
+ }
+}
+
+static void accept_mutex_off()
+{
+ if (semop(sem_id, &op_off, 1) < 0) {
+ perror ("accept_mutex_off");
+ exit (1);
+ }
+}
+
+#elif defined(USE_FCNTL_SERIALIZED_ACCEPT)
static struct flock lock_it;
static struct flock unlock_it;
static int lock_fd=-1;
+#define accept_mutex_cleanup()
+
/*
* Initialize mutex lock.
* Must be safe to call this on a restart.
*/
-void
-accept_mutex_init(pool *p)
+static void accept_mutex_init(pool *p)
{
lock_it.l_whence = SEEK_SET; /* from current point */
@@ -297,7 +527,7 @@
unlink(lock_fname);
}
-void accept_mutex_on(void)
+static void accept_mutex_on(void)
{
int ret;
@@ -311,7 +541,7 @@
}
}
-void accept_mutex_off(void)
+static void accept_mutex_off(void)
{
if (fcntl (lock_fd, F_SETLKW, &unlock_it) < 0)
{
@@ -320,16 +550,18 @@
exit(1);
}
}
+
#elif defined(USE_FLOCK_SERIALIZED_ACCEPT)
static int lock_fd=-1;
+#define accept_mutex_cleanup()
+
/*
* Initialize mutex lock.
* Must be safe to call this on a restart.
*/
-void
-accept_mutex_init(pool *p)
+static void accept_mutex_init(pool *p)
{
expand_lock_fname (p);
@@ -343,7 +575,7 @@
unlink(lock_fname);
}
-void accept_mutex_on(void)
+static void accept_mutex_on(void)
{
int ret;
@@ -357,7 +589,7 @@
}
}
-void accept_mutex_off(void)
+static void accept_mutex_off(void)
{
if (flock (lock_fd, LOCK_UN) < 0)
{
@@ -366,15 +598,28 @@
exit(1);
}
}
+
#else
/* Default --- no serialization. Other methods *could* go here,
* as #elifs...
*/
+#define accept_mutex_cleanup()
#define accept_mutex_init(x)
#define accept_mutex_on()
#define accept_mutex_off()
#endif
+/* On some architectures it's safe to do unserialized accept()s in the
+ * single Listen case. But it's never safe to do it in the case where
+ * there's multiple Listen statements. Define SAFE_UNSERIALIZED_ACCEPT
+ * when it's safe in the single Listen case.
+ */
+#ifdef SAFE_UNSERIALIZED_ACCEPT
+#define SAFE_ACCEPT(stmt) do {if(listeners->next != listeners) {stmt;}}
while(0)
+#else
+#define SAFE_ACCEPT(stmt) do {stmt;} while(0)
+#endif
+
void usage(char *bin)
{
fprintf(stderr,"Usage: %s [-d directory] [-f file] [-v] [-h]
[-l]\n",bin);
@@ -1490,6 +1735,7 @@
void sig_term(int sig) {
log_error("httpd: caught SIGTERM, shutting down", server_conf);
cleanup_scoreboard();
+ accept_mutex_cleanup();
#ifdef SIGKILL
ap_killpg (pgrp, SIGKILL);
#endif /* SIGKILL */
@@ -2399,7 +2645,8 @@
* Wait for an acceptable connection to arrive.
*/
- accept_mutex_on(); /* Lock around "accept", if necessary */
+ /* Lock around "accept", if necessary */
+ SAFE_ACCEPT(accept_mutex_on());
for (;;) {
if (listeners->next != listeners) {
@@ -2464,7 +2711,7 @@
child_exit_modules(pconf, server_conf);
}
- accept_mutex_off(); /* unlock after "accept" */
+ SAFE_ACCEPT(accept_mutex_off()); /* unlock after "accept" */
/* We've got a socket, let's at least process one request off the
* socket before we accept a graceful restart request.
@@ -2806,7 +3053,7 @@
init_modules (pconf, server_conf);
open_logs (server_conf, pconf);
set_group_privs ();
- accept_mutex_init (pconf);
+ SAFE_ACCEPT(accept_mutex_init (pconf));
if (!is_graceful) {
reinit_scoreboard(pconf);
}
@@ -2947,6 +3194,8 @@
log_error ("SIGHUP received. Attempting to restart", server_conf);
}
++generation;
+
+ SAFE_ACCEPT(accept_mutex_cleanup());
} while (restart_pending);
1.138 +2 -2 apachen/src/core/httpd.h
Index: httpd.h
===================================================================
RCS file: /export/home/cvs/apachen/src/core/httpd.h,v
retrieving revision 1.137
retrieving revision 1.138
diff -u -r1.137 -r1.138
--- httpd.h 1997/08/05 06:02:43 1.137
+++ httpd.h 1997/08/17 11:14:36 1.138
@@ -157,8 +157,8 @@
/* Define this to be what type you'd like returned for files with unknown */
/* suffixes */
-#ifndef DEFAULT_TYPE
-#define DEFAULT_TYPE "text/plain"
+#ifndef DEFAULT_CONTENT_TYPE
+#define DEFAULT_CONTENT_TYPE "text/plain"
#endif
/* Define this to be what your per-directory security files are called */