Received: (from majordom@localhost) by hyperreal.org (8.8.5/8.8.5) id EAA07611; Sun, 17 Aug 1997 04:14:42 -0700 (PDT) Received: (from dgaudet@localhost) by hyperreal.org (8.8.5/8.8.5) id EAA07606 for apache-cvs; Sun, 17 Aug 1997 04:14:39 -0700 (PDT) Date: Sun, 17 Aug 1997 04:14:39 -0700 (PDT) From: Dean Gaudet Message-Id: <199708171114.EAA07606@hyperreal.org> To: apache-cvs@hyperreal.org Subject: cvs commit: apachen/src/core conf.h http_core.c http_main.c httpd.h Sender: apache-cvs-owner@apache.org Precedence: bulk Reply-To: new-httpd@apache.org 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 , Submitted by: Martijn Koster 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. -
  • XXX Incomplete: New serialization choices improve performance - on Linux, Solaris, and IRIX. +
  • New serialization choices improve performance on Linux, Solaris, + and IRIX. 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 , + Martijn Koster ] + + *) 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 + +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 + +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 +#include +#include + +#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 */