From b54698b5798b7f1a54226274347ce1faee5a92a4 Mon Sep 17 00:00:00 2001 From: Igor Sysoev Date: Mon, 23 Feb 2004 20:57:12 +0000 Subject: [PATCH] nginx-0.0.2-2004-02-23-23:57:12 import --- auto/configure | 6 + auto/lib/make | 56 +++- auto/lib/md5/conf | 17 +- auto/options | 5 + auto/sources | 4 +- auto/threads | 7 + src/core/nginx.c | 73 ++++- src/core/nginx.h | 2 +- src/core/ngx_atomic.h | 69 +++++ src/core/ngx_config.h | 7 +- src/core/ngx_core.h | 1 + src/core/ngx_log.c | 2 +- src/core/ngx_times.c | 23 ++ src/event/ngx_event_accept.c | 10 +- src/event/ngx_event_timer.c | 4 + src/http/ngx_http_cache.h | 3 + src/os/unix/ngx_freebsd_rfork_thread.c | 410 +++++++++++++++++++++---- src/os/unix/ngx_process.h | 3 +- src/os/unix/ngx_thread.h | 74 +++++ 19 files changed, 661 insertions(+), 115 deletions(-) create mode 100644 auto/threads create mode 100644 src/os/unix/ngx_thread.h diff --git a/auto/configure b/auto/configure index f9ad3191c..a944573a5 100755 --- a/auto/configure +++ b/auto/configure @@ -16,6 +16,10 @@ fi . auto/cc . auto/lib/conf +if [ "$PLATFORM" != win32 ]; then + . auto/threads +fi + . auto/make . auto/lib/make @@ -23,4 +27,6 @@ if [ "$PLATFORM" != win32 ]; then . auto/unix fi +#have NGX_SMP . auto/have + . auto/summary diff --git a/auto/lib/make b/auto/lib/make index d4cba34f5..fcf67a0c6 100644 --- a/auto/lib/make +++ b/auto/lib/make @@ -2,36 +2,60 @@ if [ "$PLATFORM" != "win32" ]; then if [ $PCRE != NO ]; then - echo "$PCRE/.libs/libpcre.a:" >> $MAKEFILE - echo " cd $PCRE \\" >> $MAKEFILE - echo " && ./configure --disable-shared \\" >> $MAKEFILE - echo " && \$(MAKE)" >> $MAKEFILE - echo >> $MAKEFILE + echo "$PCRE/.libs/libpcre.a:" >> $MAKEFILE + echo " cd $PCRE \\" >> $MAKEFILE + echo " && ./configure --disable-shared \\" >> $MAKEFILE + echo " && \$(MAKE)" >> $MAKEFILE + echo >> $MAKEFILE fi if [ $MD5 != NO ]; then - echo "$MD5/libmd5.a:" >> $MAKEFILE + echo "$MD5/libmd5.a:" >> $MAKEFILE case $PLATFORM in - SunOS:*) - echo " cd $MD5 && \$(MAKE) x86-solaris" >> $MAKEFILE - ;; + SunOS:*:i386) + echo " cd $MD5 && \$(MAKE) x86-solaris" >> $MAKEFILE + ;; + + *:i386) + echo " cd $MD5 && \$(MAKE) x86-elf" >> $MAKEFILE + ;; + + *) + if [ $CC = gcc ]; then + echo " cd $MD5 && \$(MAKE) gcc" >> $MAKEFILE + else + echo " cd $MD5 && \$(MAKE) cc" >> $MAKEFILE + fi + ;; - *) - echo " cd $MD5 && \$(MAKE) x86-elf" >> $MAKEFILE - ;; esac - echo >> $MAKEFILE + echo >> $MAKEFILE fi if [ $ZLIB != NO ]; then - echo "$ZLIB/libz.a:" >> $MAKEFILE - echo " cd $ZLIB && ./configure && \$(MAKE)" >> $MAKEFILE - echo >> $MAKEFILE + echo "$ZLIB/libz.a:" >> $MAKEFILE + + case $PLATFORM in + + *:i386) + echo " cd $ZLIB \\" >> $MAKEFILE + echo " && cp contrib/asm686/match.S . \\" >> $MAKEFILE + echo " && CFLAGS=\"-O3 -DASMV\" ./configure \\" >> $MAKEFILE + echo " && \$(MAKE) OBJA=match.o" >> $MAKEFILE + ;; + + *) + echo " cd $ZLIB && ./configure && \$(MAKE)" >> $MAKEFILE + ;; + + esac + + echo >> $MAKEFILE fi fi diff --git a/auto/lib/md5/conf b/auto/lib/md5/conf index 4f6a6364b..06006e456 100644 --- a/auto/lib/md5/conf +++ b/auto/lib/md5/conf @@ -27,11 +27,12 @@ ngx_lib_inc="#include MD5=NO - # Solaris 8/9 - ngx_lib="rsaref md5" - ngx_lib_test="MD5_CTX md5; MD5Init(&md5)" - ngx_libs=-lmd5 - . auto/lib/test + # Solaris 8/9 + + ngx_lib="rsaref md5" + ngx_lib_test="MD5_CTX md5; MD5Init(&md5)" + ngx_libs=-lmd5 + . auto/lib/test if [ $ngx_found = yes ]; then @@ -42,6 +43,7 @@ ngx_lib_inc="#include else # FreeBSD + ngx_lib="rsaref md" ngx_lib_test="MD5_CTX md5; MD5Init(&md5)" ngx_libs=-lmd @@ -56,8 +58,9 @@ ngx_lib_inc="#include ngx_found=no else - ngx_lib_inc="#include -#include " + # OpenSSL crypto library + + ngx_inc="#include " ngx_lib="OpenSSL md5 crypto" ngx_lib_test="MD5_CTX md5; MD5_Init(&md5)" ngx_libs=-lcrypto diff --git a/auto/options b/auto/options index c912119c6..f153e944a 100644 --- a/auto/options +++ b/auto/options @@ -15,6 +15,8 @@ EVENT_SELECT=NO EVENT_POLL=NO EVENT_AIO=NO +USE_THREADS=NO + HTTP_REWRITE=YES HTTP_GZIP=YES HTTP_SSI=YES @@ -51,6 +53,9 @@ do --without-poll_module) EVENT_POLL=NONE ;; --with-aio_module) EVENT_AIO=YES ;; + --with-threads=*) USE_THREADS="$value" ;; + --with-threads) USE_THREADS="pthreads" ;; + --without-http_rewrite_module) HTTP_REWRITE=NO ;; --without-http_ssi_module) HTTP_SSI=NO ;; --without-http_gzip_module) HTTP_GZIP=NO ;; diff --git a/auto/sources b/auto/sources index 81ba968f2..17e6a4abb 100644 --- a/auto/sources +++ b/auto/sources @@ -5,6 +5,7 @@ CORE_INCS="-I src/core" CORE_DEPS="src/core/nginx.h \ src/core/ngx_config.h \ + src/core/ngx_core.h \ src/core/ngx_atomic.h \ src/core/ngx_log.h \ src/core/ngx_alloc.h \ @@ -98,6 +99,7 @@ UNIX_DEPS="$CORE_DEPS $EVENT_DEPS \ src/os/unix/ngx_errno.h \ src/os/unix/ngx_files.h \ src/os/unix/ngx_process.h \ + src/os/unix/ngx_thread.h \ src/os/unix/ngx_socket.h \ src/os/unix/ngx_os.h" @@ -117,7 +119,7 @@ UNIX_SRCS="$CORE_SRCS $EVENT_SRCS \ FREEBSD_DEPS=src/os/unix/ngx_freebsd_config.h FREEBSD_SRCS=src/os/unix/ngx_freebsd_init.c FREEBSD_SENDFILE_SRCS=src/os/unix/ngx_freebsd_sendfile_chain.c - +FREEBSD_RFORK_SRCS="src/os/unix/ngx_freebsd_rfork_thread.c" LINUX_DEPS=src/os/unix/ngx_linux_config.h LINUX_SRCS=src/os/unix/ngx_linux_init.c diff --git a/auto/threads b/auto/threads new file mode 100644 index 000000000..71fbcb6ef --- /dev/null +++ b/auto/threads @@ -0,0 +1,7 @@ + +if [ $USE_THREADS = "rfork" ]; then + have=NGX_THREADS . auto/have + have=USE_RFORK . auto/have + CORE_DEPS="$CORE_DEPS $UNIX_THREADS_DEPS" + CORE_SRCS="$CORE_SRCS $FREEBSD_RFORK_SRCS" +fi diff --git a/src/core/nginx.c b/src/core/nginx.c index 005417ced..a9418992e 100644 --- a/src/core/nginx.c +++ b/src/core/nginx.c @@ -27,6 +27,9 @@ typedef struct { static void ngx_master_process_cycle(ngx_cycle_t *cycle, ngx_master_ctx_t *ctx); static void ngx_master_exit(ngx_cycle_t *cycle, ngx_master_ctx_t *ctx); static void ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data); +#if (NGX_THREADS) +static int ngx_worker_thread_cycle(void *data); +#endif static ngx_int_t ngx_add_inherited_sockets(ngx_cycle_t *cycle, char **envp); static ngx_pid_t ngx_exec_new_binary(ngx_cycle_t *cycle, char *const *argv); static ngx_int_t ngx_getopt(ngx_master_ctx_t *ctx, ngx_cycle_t *cycle); @@ -87,22 +90,22 @@ ngx_module_t ngx_core_module = { }; -ngx_int_t ngx_max_module; -ngx_uint_t ngx_connection_counter; +ngx_int_t ngx_max_module; +ngx_atomic_t ngx_connection_counter; -ngx_int_t ngx_process; -ngx_pid_t ngx_pid; -ngx_pid_t ngx_new_binary; +ngx_int_t ngx_process; +ngx_pid_t ngx_pid; +ngx_pid_t ngx_new_binary; -ngx_int_t ngx_inherited; -ngx_int_t ngx_reap; -ngx_int_t ngx_timer; -ngx_int_t ngx_terminate; -ngx_int_t ngx_quit; -ngx_int_t ngx_noaccept; -ngx_int_t ngx_reconfigure; -ngx_int_t ngx_reopen; -ngx_int_t ngx_change_binary; +ngx_int_t ngx_inherited; +ngx_int_t ngx_reap; +ngx_int_t ngx_timer; +ngx_int_t ngx_terminate; +ngx_int_t ngx_quit; +ngx_int_t ngx_noaccept; +ngx_int_t ngx_reconfigure; +ngx_int_t ngx_reopen; +ngx_int_t ngx_change_binary; int main(int argc, char *const *argv, char **envp) @@ -577,6 +580,9 @@ static void ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data) ngx_int_t i; ngx_listening_t *ls; ngx_core_conf_t *ccf; +#if (NGX_THREADS) + ngx_tid_t tid; +#endif ngx_process = NGX_PROCESS_WORKER; ngx_last_process = 0; @@ -641,7 +647,15 @@ static void ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data) ngx_setproctitle("worker process"); - /* TODO: threads: start ngx_worker_thread_cycle() */ +#if (NGX_THREADS) + + ngx_init_threads(5, 128 * 1024 * 1024, cycle->log); + + for (i = 0; i < 1; i++) { + ngx_create_thread(&tid, ngx_worker_thread_cycle, cycle, cycle->log); + } + +#endif for ( ;; ) { ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "worker cycle"); @@ -688,6 +702,35 @@ static void ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data) } +#if (NGX_THREADS) + +int ngx_worker_thread_cycle(void *data) +{ + ngx_cycle_t *cycle = data; + + struct timeval tv; + + /* STUB */ + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, ngx_cycle->log, ngx_errno, + "thread %d started", ngx_thread_self()); + + ngx_setproctitle("worker thread"); + + sleep(5); + + ngx_gettimeofday(&tv); + ngx_time_update(tv.tv_sec); + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, ngx_cycle->log, ngx_errno, + "thread %d done", ngx_thread_self()); + + return 1; +} + +#endif + + static ngx_int_t ngx_add_inherited_sockets(ngx_cycle_t *cycle, char **envp) { char *p, *v; diff --git a/src/core/nginx.h b/src/core/nginx.h index eb7fe93ad..6680de165 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -13,7 +13,7 @@ extern ngx_module_t ngx_core_module; -extern ngx_uint_t ngx_connection_counter; +extern ngx_atomic_t ngx_connection_counter; extern ngx_int_t ngx_process; diff --git a/src/core/ngx_atomic.h b/src/core/ngx_atomic.h index b6bd17fb3..f5edd1966 100644 --- a/src/core/ngx_atomic.h +++ b/src/core/ngx_atomic.h @@ -6,9 +6,78 @@ #include +#ifdef __i386__ + +typedef uint32_t ngx_atomic_t; + +#if (NGX_SMP) +#define NGX_SMP_LOCK "lock" +#else +#define NGX_SMP_LOCK +#endif + + +static ngx_inline uint32_t ngx_atomic_inc(ngx_atomic_t *value) +{ + uint32_t old; + + __asm__ __volatile (" + + movl $1, %0 + " NGX_SMP_LOCK + " xaddl %0, %1 + + ": "=a" (old) : "m" (*value)); + + return old; +} + + +static ngx_inline uint32_t ngx_atomic_dec(ngx_atomic_t *value) +{ + uint32_t old; + + __asm__ __volatile (" + + movl $-1, %0 + " NGX_SMP_LOCK + " xaddl %0, %1 + + ": "=a" (old) : "m" (*value)); + + return old; +} + + +static ngx_inline uint32_t ngx_atomic_cmp_set(ngx_atomic_t *lock, + ngx_atomic_t old, + ngx_atomic_t set) +{ + uint32_t res; + + __asm__ __volatile (" + + " NGX_SMP_LOCK + " cmpxchgl %3, %1 + setzb %%al + movzbl %%al, %0 + + ": "=a" (res) : "m" (*lock), "a" (old), "q" (set)); + + return res; +} + +#else + +typedef uint32_t ngx_atomic_t; + /* STUB */ #define ngx_atomic_inc(x) x++; #define ngx_atomic_dec(x) x--; +#define ngx_atomic_cmp_set(lock, old, set) 1; +/**/ + +#endif #endif /* _NGX_ATOMIC_H_INCLUDED_ */ diff --git a/src/core/ngx_config.h b/src/core/ngx_config.h index 83f410a61..67e17d0a3 100644 --- a/src/core/ngx_config.h +++ b/src/core/ngx_config.h @@ -38,11 +38,6 @@ #endif -/* STUB: ngx_mutex.h */ -#define ngx_mutex_lock(m) -#define ngx_mutex_unlock(m) - - /* STUB: autoconf */ typedef int ngx_int_t; typedef u_int ngx_uint_t; @@ -71,7 +66,7 @@ typedef int ngx_flag_t; /* TODO: #ifndef */ #define NGX_SHUTDOWN_SIGNAL QUIT #define NGX_TERMINATE_SIGNAL TERM -#define NGX_NOACCEPT_SIGNAL ABRT +#define NGX_NOACCEPT_SIGNAL WINCH #define NGX_RECONFIGURE_SIGNAL HUP #define NGX_REOPEN_SIGNAL USR1 #define NGX_CHANGEBIN_SIGNAL USR2 diff --git a/src/core/ngx_core.h b/src/core/ngx_core.h index 6bfefcc49..f8803c8ff 100644 --- a/src/core/ngx_core.h +++ b/src/core/ngx_core.h @@ -20,6 +20,7 @@ typedef struct ngx_connection_s ngx_connection_t; #include #include #include +#include #include #include #include diff --git a/src/core/ngx_log.c b/src/core/ngx_log.c index 7fdd8984c..349fe6bb1 100644 --- a/src/core/ngx_log.c +++ b/src/core/ngx_log.c @@ -79,7 +79,7 @@ void ngx_log_error_core(int level, ngx_log_t *log, ngx_err_t err, /* pid#tid */ len += ngx_snprintf(errstr + len, max - len, - PID_T_FMT "#%d: ", ngx_pid, /* STUB */ 0); + PID_T_FMT "#" TID_T_FMT ": ", ngx_log_pid, ngx_log_tid); if (log->data && *(int *) log->data != -1) { len += ngx_snprintf(errstr + len, max - len, diff --git a/src/core/ngx_times.c b/src/core/ngx_times.c index 9326d2bd5..43c8c204a 100644 --- a/src/core/ngx_times.c +++ b/src/core/ngx_times.c @@ -3,6 +3,11 @@ #include +#if (NGX_THREADS) +static ngx_mutex_t *ngx_time_mutex; +#endif + + time_t ngx_cached_time; ngx_epoch_msec_t ngx_elapsed_msec; ngx_epoch_msec_t ngx_old_elapsed_msec; @@ -46,6 +51,13 @@ void ngx_time_init() ngx_elapsed_msec = 0; ngx_time_update(tv.tv_sec); + +#if (NGX_THREADS0) + if (!(ngx_time_mutex = ngx_mutex_init(log, NGX_MUTEX_LIGHT); + return 0; + } +#endif + } @@ -57,6 +69,12 @@ void ngx_time_update(time_t s) return; } +#if (NGX_THREADS0) + if (ngx_mutex_trylock(ngx_time_mutex) != NGX_OK) { + return; + } +#endif + ngx_cached_time = s; ngx_gmtime(ngx_cached_time, &ngx_cached_gmtime); @@ -90,6 +108,11 @@ void ngx_time_update(time_t s) tm.ngx_tm_hour, tm.ngx_tm_min, tm.ngx_tm_sec); + +#if (NGX_THREADS0) + ngx_mutex_unlock(ngx_time_mutex); +#endif + } diff --git a/src/event/ngx_event_accept.c b/src/event/ngx_event_accept.c index e73741011..779fdadcc 100644 --- a/src/event/ngx_event_accept.c +++ b/src/event/ngx_event_accept.c @@ -254,17 +254,17 @@ void ngx_event_accept(ngx_event_t *ev) /* * TODO: MT: - atomic increment (x86: lock xadd) - * or protection by critical section or mutex + * or protection by critical section or light mutex * * TODO: MP: - allocated in a shared memory * - atomic increment (x86: lock xadd) - * or protection by critical section or mutex + * or protection by critical section or light mutex */ - c->number = ngx_connection_counter++; + c->number = ngx_atomic_inc(&ngx_connection_counter); ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0, - "accept: %d, %d", s, c->number); + "accept: fd:%d c:%d", s, c->number); if (ngx_add_conn) { if (ngx_add_conn(c) == NGX_ERROR) { @@ -292,8 +292,6 @@ void ngx_event_accept(ngx_event_t *ev) accepted++; } while (ev->available); - - return; } diff --git a/src/event/ngx_event_timer.c b/src/event/ngx_event_timer.c index 5e866a491..e002cb7eb 100644 --- a/src/event/ngx_event_timer.c +++ b/src/event/ngx_event_timer.c @@ -9,6 +9,10 @@ * protected by the single mutex */ +#if (NGX_THREADS) +static ngx_mutex_t *ngx_event_timer_mutex; +#endif + ngx_rbtree_t *ngx_event_timer_rbtree; ngx_rbtree_t ngx_event_timer_sentinel; diff --git a/src/http/ngx_http_cache.h b/src/http/ngx_http_cache.h index 8013ee3ac..823f74d87 100644 --- a/src/http/ngx_http_cache.h +++ b/src/http/ngx_http_cache.h @@ -61,6 +61,9 @@ typedef struct { size_t nelts; time_t life; time_t update; +#if (NGX_THREADS) + ngx_mutex_t mutex; +#endif ngx_pool_t *pool; } ngx_http_cache_hash_t; diff --git a/src/os/unix/ngx_freebsd_rfork_thread.c b/src/os/unix/ngx_freebsd_rfork_thread.c index 66e11b939..ae01851a2 100644 --- a/src/os/unix/ngx_freebsd_rfork_thread.c +++ b/src/os/unix/ngx_freebsd_rfork_thread.c @@ -2,31 +2,44 @@ #include #include - -extern int __isthreaded; +/* + * The threads implementation uses the rfork(RFPROC|RFTHREAD|RFMEM) + * to create threads. All threads use the stacks of the same size mmap()ed + * below the main stack. Thus the stack pointer is used to determine + * the current thread id. + * + * The mutex implementation uses the ngx_atomic_cmp_set() operation + * to acquire mutex and the SysV semaphore to wait on a mutex or to wake up + * the waiting threads. + * + * The condition variable implementation uses the SysV semaphore set of two + * semaphores. The first is used by the CV mutex, and the second is used + * by CV itself. + */ -typedef int ngx_tid_t; +extern int __isthreaded; static inline int ngx_gettid(); static char *usrstack; -static int red_zone = 4096; +static size_t rz_size = /* STUB: PAGE_SIZE */ 4096; static size_t stack_size; static size_t usable_stack_size; static char *last_stack; -static int threads; -static int nthreads; -static ngx_tid_t *tids; +static ngx_uint_t nthreads; +static ngx_uint_t max_threads; +static ngx_tid_t *tids; /* the threads tids array */ + /* the thread-safe errno */ static int errno0; /* the main thread's errno */ -static int *errnos; +static int *errnos; /* the threads errno's array */ int *__error() { @@ -41,20 +54,22 @@ int *__error() int ngx_create_thread(ngx_tid_t *tid, int (*func)(void *arg), void *arg, ngx_log_t *log) { - int id, err; - char *stack, *stack_top; + int id, err; + char *stack, *stack_top; - if (threads >= nthreads) { + if (nthreads >= max_threads) { ngx_log_error(NGX_LOG_CRIT, log, 0, - "no more than %d threads can be created", nthreads); + "no more than %d threads can be created", max_threads); return NGX_ERROR; } last_stack -= stack_size; + stack = mmap(last_stack, usable_stack_size, PROT_READ|PROT_WRITE, MAP_STACK, -1, 0); + if (stack == MAP_FAILED) { - ngx_log_error(NGX_LOG_ALERT, log, errno, + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, "mmap(%08X:%d, MAP_STACK) thread stack failed", last_stack, usable_stack_size); return NGX_ERROR; @@ -66,7 +81,8 @@ int ngx_create_thread(ngx_tid_t *tid, int (*func)(void *arg), void *arg, stack_top = stack + usable_stack_size; -printf("stack: %08X-%08X\n", stack, stack_top); + ngx_log_debug2(NGX_LOG_DEBUG_CORE, log, 0, + "thread stack: %08X-%08X", stack, stack_top); #if 1 id = rfork_thread(RFPROC|RFTHREAD|RFMEM, stack_top, func, arg); @@ -78,89 +94,78 @@ printf("stack: %08X-%08X\n", stack, stack_top); id = rfork(RFFDG|RFCFDG); #endif - err = errno; + err = ngx_errno; if (id == -1) { ngx_log_error(NGX_LOG_ALERT, log, err, "rfork() failed"); } else { *tid = id; - threads = (usrstack - stack_top) / stack_size; - tids[threads] = id; + nthreads = (usrstack - stack_top) / stack_size; + tids[nthreads] = id; - /* allow the spinlock in libc malloc() */ - __isthreaded = 1; + ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0, "rfork()ed thread: %d", id); } return err; } -int ngx_init_thread_env(int n, size_t size, ngx_log_t *log) +ngx_int_t ngx_init_threads(int n, size_t size, ngx_log_t *log) { int len; - char *rz, *zone; + char *red_zone, *zone; - nthreads = n; + max_threads = n; len = 4; if (sysctlbyname("kern.usrstack", &usrstack, &len, NULL, 0) == -1) { - ngx_log_error(NGX_LOG_ALERT, log, errno, + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, "sysctlbyname(kern.usrstack) failed"); return NGX_ERROR; } -printf("usrstack: %08X\n", usrstack); + /* the main thread stack red zone */ + red_zone = usrstack - (size + rz_size); - /* red zone */ - rz = usrstack - (size + red_zone); + ngx_log_debug2(NGX_LOG_DEBUG_CORE, log, 0, + "usrstack: %08X, red zone: %08X", usrstack, red_zone); -printf("red zone: %08X\n", rz); - - zone = mmap(rz, red_zone, PROT_NONE, MAP_ANON, -1, 0); + zone = mmap(red_zone, rz_size, PROT_NONE, MAP_ANON, -1, 0); if (zone == MAP_FAILED) { - ngx_log_error(NGX_LOG_ALERT, log, errno, + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, "mmap(%08X:%d, PROT_NONE, MAP_ANON) red zone failed", - rz, red_zone); + red_zone, rz_size); return NGX_ERROR; } - if (zone != rz) { + if (zone != red_zone) { ngx_log_error(NGX_LOG_ALERT, log, 0, "red zone address was changed"); } - /* create the thread errno array */ - ngx_test_null(errnos, ngx_calloc(n * sizeof(int), log), NGX_ERROR); + /* create the threads errno array */ - /* create the thread tid array */ - ngx_test_null(tids, ngx_calloc((n + 1) * sizeof(ngx_tid_t), log), - NGX_ERROR); - - tids[0] = ngx_getpid(); - threads = 1; - - last_stack = zone + red_zone; - usable_stack_size = size; - stack_size = size + red_zone; - - return NGX_OK; -} - - -ngx_tid_t ngx_thread_self() -{ - int tid; - ngx_tid_t pid; - - tid = ngx_gettid(); - - if (tids[tid] == 0) { - pid = ngx_getpid(); - tids[tid] = pid; - return pid; + if (!(errnos = ngx_calloc(n * sizeof(int), log))) { + return NGX_ERROR; } - return tids[tid]; + /* create the threads tid array */ + + if (!(tids = ngx_calloc((n + 1) * sizeof(ngx_tid_t), log))) { + return NGX_ERROR; + } + + tids[0] = ngx_pid; + nthreads = 1; + + last_stack = zone + rz_size; + usable_stack_size = size; + stack_size = size + rz_size; + + /* allow the spinlock in libc malloc() */ + __isthreaded = 1; + + return NGX_OK; } @@ -176,3 +181,286 @@ static inline int ngx_gettid() return (usrstack - sp) / stack_size; } + + +ngx_tid_t ngx_thread_self() +{ + int tid; + ngx_tid_t pid; + + tid = ngx_gettid(); + + if (tids == NULL) { + return ngx_pid; + } + +#if 0 + if (tids[tid] == 0) { + pid = ngx_pid; + tids[tid] = pid; + return pid; + } +#endif + + return tids[tid]; +} + + +ngx_mutex_t *ngx_mutex_init(ngx_log_t *log, uint flags) +{ + int nsem, i; + ngx_mutex_t *m; + union semun op; + + if (!(m = ngx_alloc(sizeof(ngx_mutex_t), log))) { + return NULL; + } + + m->lock = 0; + m->log = log; + + if (flags & NGX_MUTEX_LIGHT) { + m->semid = -1; + return m; + } + + nsem = flags & NGX_MUTEX_CV ? 2 : 1; + + m->semid = semget(IPC_PRIVATE, nsem, SEM_R|SEM_A); + if (m->semid == -1) { + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, "semget() failed"); + return NULL; + } + + op.val = 0; + for (i = 0; i < nsem; i++) { + if (semctl(m->semid, i, SETVAL, op) == -1) { + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + "semctl(SETVAL) failed"); + + if (semctl(m->semid, 0, IPC_RMID) == -1) { + ngx_log_error(NGX_LOG_ALERT, m->log, ngx_errno, + "semctl(IPC_RMID) failed"); + } + + return NULL; + } + } + + return m; +} + + +void ngx_mutex_done(ngx_mutex_t *m) +{ + if (semctl(m->semid, 0, IPC_RMID) == -1) { + ngx_log_error(NGX_LOG_ALERT, m->log, ngx_errno, + "semctl(IPC_RMID) failed"); + } + + ngx_free(m); +} + + +ngx_int_t ngx_mutex_do_lock(ngx_mutex_t *m, ngx_int_t try) +{ + uint32_t lock, new, old; + ngx_uint_t tries; + struct sembuf op; + +#if (NGX_DEBUG) + if (try) { + ngx_log_debug2(NGX_LOG_DEBUG_CORE, m->log, 0, + "try lock mutex %08X lock:%X", m, m->lock); + } else { + ngx_log_debug2(NGX_LOG_DEBUG_CORE, m->log, 0, + "lock mutex %08X lock:%X", m, m->lock); + } +#endif + + old = m->lock; + tries = 0; + + for ( ;; ) { + if (old & NGX_MUTEX_LOCK_BUSY) { + + if (try) { + return NGX_AGAIN; + } + + if (ngx_freebsd_hw_ncpu > 1 && tries++ < 1000) { + + /* the spinlock is used only on the SMP system */ + + old = m->lock; + continue; + } + + if (m->semid == -1) { + sched_yield(); + + tries = 0; + old = m->lock; + continue; + } + + ngx_log_debug2(NGX_LOG_DEBUG_CORE, m->log, 0, + "mutex %08X lock:%X", m, m->lock); + + /* + * The mutex is locked so we increase a number + * of the threads that are waiting on the mutex + */ + + lock = old + 1; + + if ((lock & ~NGX_MUTEX_LOCK_BUSY) > nthreads) { + ngx_log_error(NGX_LOG_ALERT, m->log, ngx_errno, + "%d threads wait for mutex %0X, " + "while only %d threads are available", + lock & ~NGX_MUTEX_LOCK_BUSY, m, nthreads); + return NGX_ERROR; + } + + if (ngx_atomic_cmp_set(&m->lock, old, lock)) { + + ngx_log_debug2(NGX_LOG_DEBUG_CORE, m->log, 0, + "wait mutex %08X lock:%X", m, m->lock); + + /* + * The number of the waiting threads has been increased + * and we would wait on the SysV semaphore. + * A semaphore should wake up us more efficiently than + * a simple usleep(). + */ + + op.sem_num = 0; + op.sem_op = -1; + op.sem_flg = SEM_UNDO; + + if (semop(m->semid, &op, 1) == -1) { + ngx_log_error(NGX_LOG_ALERT, m->log, ngx_errno, + "semop() failed while waiting " + "on mutex %08X", m); + return NGX_ERROR; + } + + tries = 0; + old = m->lock; + continue; + } + + old = m->lock; + + } else { + lock = old | NGX_MUTEX_LOCK_BUSY; + + if (ngx_atomic_cmp_set(&m->lock, old, lock)) { + + /* we locked the mutex */ + + break; + } + + old = m->lock; + } + + if (tries++ > 1000) { + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, m->log, 0, + "mutex %08X is contested", m); + + /* the mutex is probably contested so we are giving up now */ + + sched_yield(); + + tries = 0; + old = m->lock; + } + } + + ngx_log_debug2(NGX_LOG_DEBUG_CORE, m->log, 0, + "mutex %08X is locked, lock:%X", m, m->lock); + + return NGX_OK; +} + + +ngx_int_t ngx_mutex_unlock(ngx_mutex_t *m) +{ + uint32_t lock, new, old; + struct sembuf op; + + old = m->lock; + + if (!(old & NGX_MUTEX_LOCK_BUSY)) { + ngx_log_error(NGX_LOG_ALERT, m->log, ngx_errno, + "tring to unlock the free mutex %0X", m); + return NGX_ERROR; + } + + /* free the mutex */ + + for ( ;; ) { + lock = old & ~NGX_MUTEX_LOCK_BUSY; + + if (ngx_atomic_cmp_set(&m->lock, old, lock)) { + break; + } + + old = m->lock; + } + + if (m->semid == -1) { + ngx_log_debug1(NGX_LOG_DEBUG_CORE, m->log, 0, + "mutex %08X is unlocked", m); + + return NGX_OK; + } + + /* check weather we need to wake up a waiting thread */ + + old = m->lock; + + for ( ;; ) { + if (old & NGX_MUTEX_LOCK_BUSY) { + + /* the mutex is just locked by another thread */ + + break; + } + + if (old == 0) { + break; + } + + /* there are the waiting threads */ + + lock = old - 1; + + if (ngx_atomic_cmp_set(&m->lock, old, lock)) { + + /* wake up the thread that waits on semaphore */ + + op.sem_num = 0; + op.sem_op = 1; + op.sem_flg = SEM_UNDO; + + if (semop(m->semid, &op, 1) == -1) { + ngx_log_error(NGX_LOG_ALERT, m->log, ngx_errno, + "semop() failed while waking up on mutex %08X", + m); + return NGX_ERROR; + } + + break; + } + + old = m->lock; + } + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, m->log, 0, + "mutex %08X is unlocked", m); + + return NGX_OK; +} diff --git a/src/os/unix/ngx_process.h b/src/os/unix/ngx_process.h index 66b9d7d45..bc68a054b 100644 --- a/src/os/unix/ngx_process.h +++ b/src/os/unix/ngx_process.h @@ -40,7 +40,8 @@ typedef struct { #define NGX_PROCESS_DETACHED -3 -#define ngx_getpid getpid +#define ngx_getpid getpid +#define ngx_log_pid ngx_pid ngx_pid_t ngx_spawn_process(ngx_cycle_t *cycle, ngx_spawn_proc_pt proc, void *data, diff --git a/src/os/unix/ngx_thread.h b/src/os/unix/ngx_thread.h new file mode 100644 index 000000000..ce305deb7 --- /dev/null +++ b/src/os/unix/ngx_thread.h @@ -0,0 +1,74 @@ +#ifndef _NGX_THREAD_H_INCLUDED_ +#define _NGX_THREAD_H_INCLUDED_ + + +#include +#include + +#if (NGX_THREADS) + +#if (USE_RFORK) + +#include +#include +#include + +typedef pid_t ngx_tid_t; + +#define TID_T_FMT PID_T_FMT + +#define ngx_log_tid 0 + +#undef ngx_log_pid +#define ngx_log_pid ngx_thread_self() + + +#define NGX_MUTEX_LIGHT 1 +#define NGX_MUTEX_CV 2 + +#define NGX_MUTEX_LOCK_BUSY 0x80000000 + +typedef struct { + ngx_atomic_t lock; + ngx_log_t *log; + int semid; +} ngx_mutex_t; + + +#else /* use pthreads */ + +#include + +typedef pthread_t ngx_tid_t; + +#define ngx_log_tid ngx_thread_self() + +#endif + + +ngx_int_t ngx_init_threads(int n, size_t size, ngx_log_t *log); +int ngx_create_thread(ngx_tid_t *tid, int (*func)(void *arg), void *arg, + ngx_log_t *log); +ngx_tid_t ngx_thread_self(); + +ngx_mutex_t *ngx_mutex_init(ngx_log_t *log, uint flags); +void ngx_mutex_done(ngx_mutex_t *m); + +#define ngx_mutex_trylock(m) ngx_mutex_do_lock(m, 1) +#define ngx_mutex_lock(m) ngx_mutex_do_lock(m, 0) +ngx_int_t ngx_mutex_do_lock(ngx_mutex_t *m, ngx_int_t try); +ngx_int_t ngx_mutex_unlock(ngx_mutex_t *m); + + +#else /* !NGX_THREADS */ + +#define ngx_log_tid 0 +#define TID_T_FMT "%d" + +#define ngx_mutex_lock(m) +#define ngx_mutex_unlock(m) + +#endif + + +#endif /* _NGX_THREAD_H_INCLUDED_ */