nginx-0.0.2-2004-02-23-23:57:12 import
diff --git a/auto/configure b/auto/configure
index f9ad319..a944573 100755
--- a/auto/configure
+++ b/auto/configure
@@ -16,6 +16,10 @@
. auto/cc
. auto/lib/conf
+if [ "$PLATFORM" != win32 ]; then
+ . auto/threads
+fi
+
. auto/make
. auto/lib/make
@@ -23,4 +27,6 @@
. auto/unix
fi
+#have NGX_SMP . auto/have
+
. auto/summary
diff --git a/auto/lib/make b/auto/lib/make
index d4cba34..fcf67a0 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
+ ;;
- *)
- echo " cd $MD5 && \$(MAKE) x86-elf" >> $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
+ ;;
+
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 4f6a636..06006e4 100644
--- a/auto/lib/md5/conf
+++ b/auto/lib/md5/conf
@@ -27,11 +27,12 @@
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 @@
else
# FreeBSD
+
ngx_lib="rsaref md"
ngx_lib_test="MD5_CTX md5; MD5Init(&md5)"
ngx_libs=-lmd
@@ -56,8 +58,9 @@
ngx_found=no
else
- ngx_lib_inc="#include <sys/types.h>
-#include <openssl/md5.h>"
+ # OpenSSL crypto library
+
+ ngx_inc="#include <openssl/md5.h>"
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 c912119..f153e94 100644
--- a/auto/options
+++ b/auto/options
@@ -15,6 +15,8 @@
EVENT_POLL=NO
EVENT_AIO=NO
+USE_THREADS=NO
+
HTTP_REWRITE=YES
HTTP_GZIP=YES
HTTP_SSI=YES
@@ -51,6 +53,9 @@
--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 81ba968..17e6a4a 100644
--- a/auto/sources
+++ b/auto/sources
@@ -5,6 +5,7 @@
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 @@
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 @@
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 0000000..71fbcb6
--- /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 005417c..a941899 100644
--- a/src/core/nginx.c
+++ b/src/core/nginx.c
@@ -27,6 +27,9 @@
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_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 @@
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 @@
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 @@
}
+#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 eb7fe93..6680de1 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 b6bd17f..f5edd19 100644
--- a/src/core/ngx_atomic.h
+++ b/src/core/ngx_atomic.h
@@ -6,9 +6,78 @@
#include <ngx_core.h>
+#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 83f410a..67e17d0 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 @@
/* 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 6bfefcc..f8803c8 100644
--- a/src/core/ngx_core.h
+++ b/src/core/ngx_core.h
@@ -20,6 +20,7 @@
#include <ngx_socket.h>
#include <ngx_errno.h>
#include <ngx_process.h>
+#include <ngx_thread.h>
#include <ngx_string.h>
#include <ngx_parse.h>
#include <ngx_log.h>
diff --git a/src/core/ngx_log.c b/src/core/ngx_log.c
index 7fdd898..349fe6b 100644
--- a/src/core/ngx_log.c
+++ b/src/core/ngx_log.c
@@ -79,7 +79,7 @@
/* 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 9326d2b..43c8c20 100644
--- a/src/core/ngx_times.c
+++ b/src/core/ngx_times.c
@@ -3,6 +3,11 @@
#include <ngx_core.h>
+#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 @@
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 @@
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 @@
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 e737410..779fdad 100644
--- a/src/event/ngx_event_accept.c
+++ b/src/event/ngx_event_accept.c
@@ -254,17 +254,17 @@
/*
* 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 @@
accepted++;
} while (ev->available);
-
- return;
}
diff --git a/src/event/ngx_event_timer.c b/src/event/ngx_event_timer.c
index 5e866a4..e002cb7 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 8013ee3..823f74d 100644
--- a/src/http/ngx_http_cache.h
+++ b/src/http/ngx_http_cache.h
@@ -61,6 +61,9 @@
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 66e11b9..ae01851 100644
--- a/src/os/unix/ngx_freebsd_rfork_thread.c
+++ b/src/os/unix/ngx_freebsd_rfork_thread.c
@@ -2,31 +2,44 @@
#include <ngx_config.h>
#include <ngx_core.h>
-
-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 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 @@
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 @@
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 @@
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 66b9d7d..bc68a05 100644
--- a/src/os/unix/ngx_process.h
+++ b/src/os/unix/ngx_process.h
@@ -40,7 +40,8 @@
#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 0000000..ce305de
--- /dev/null
+++ b/src/os/unix/ngx_thread.h
@@ -0,0 +1,74 @@
+#ifndef _NGX_THREAD_H_INCLUDED_
+#define _NGX_THREAD_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+#if (NGX_THREADS)
+
+#if (USE_RFORK)
+
+#include <sys/ipc.h>
+#include <sys/sem.h>
+#include <sched.h>
+
+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 <pthread.h>
+
+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_ */