changeset 272:d4e65d74db9f

nginx-0.0.2-2004-03-01-00:03:02 import
author Igor Sysoev <igor@sysoev.ru>
date Sun, 29 Feb 2004 21:03:02 +0000
parents e16dfb9b9afa
children 34329e143004
files auto/cc auto/lib/make auto/os/freebsd auto/sources src/core/ngx_atomic.h src/event/modules/ngx_kqueue_module.c src/event/ngx_event.c src/event/ngx_event.h src/event/ngx_event_mutex.c src/event/ngx_event_timer.c src/event/ngx_event_timer.h src/http/ngx_http_busy_lock.c src/http/ngx_http_busy_lock.h src/os/unix/ngx_freebsd_rfork_thread.c src/os/unix/ngx_freebsd_sendfile_chain.c src/os/unix/ngx_linux_sendfile_chain.c src/os/unix/ngx_process.c src/os/unix/ngx_solaris_sendfilev_chain.c src/os/unix/ngx_thread.h
diffstat 19 files changed, 240 insertions(+), 114 deletions(-) [+]
line wrap: on
line diff
--- a/auto/cc
+++ b/auto/cc
@@ -5,6 +5,10 @@ case $CC in
 
          # optimization
          #CFLAGS="$CFLAGS -O2 -fomit-frame-pointer"
+         # optimize for Pentium Pro, Pentium II and Pentium III
+         CFLAGS="$CFLAGS -mcpu=pentiumpro"
+         # optimize for Pentium 4, gcc 3.x
+         #CFLAGS="$CFLAGS -mcpu=pentium4"
 
          # warnings
          CFLAGS="$CFLAGS -O -W"
@@ -40,7 +44,7 @@ case $CC in
          # optimization
          CFLAGS="$CFLAGS -O"
          # optimize for Pentium Pro, Pentium II and Pentium III
-         #CFLAGS="$CFLAGS -mcpu=pentiumpro"
+         CFLAGS="$CFLAGS -mcpu=pentiumpro"
          # optimize for Pentium 4, default
          #CFLAGS="$CFLAGS -mcpu=pentium4"
 
--- a/auto/lib/make
+++ b/auto/lib/make
@@ -11,29 +11,7 @@ if [ "$PLATFORM" != "win32" ]; then
 
 
     if [ $MD5 != NO ]; then
-        echo "$MD5/libmd5.a:"                                    >> $MAKEFILE
-
-        case $PLATFORM in
-
-            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
-            ;;
-
-        esac
-
-        echo                                                     >> $MAKEFILE
+        . auto/lib/md5/make
     fi
 
 
--- a/auto/os/freebsd
+++ b/auto/os/freebsd
@@ -24,7 +24,7 @@ fi
 # sendfile
 
 if [ $version -gt 300007 ]; then
-    echo " + sendfile() found"
+    echo " + using sendfile()"
 
     have=HAVE_SENDFILE . auto/have
     CORE_SRCS="$CORE_SRCS $FREEBSD_SENDFILE_SRCS"
@@ -36,7 +36,7 @@ fi
 if [ \( $version -lt 500000 -a $version -ge 410000 \) \
      -o $version -ge 500011 ]
 then
-    echo " + kqueue found"
+    echo " + using kqueue"
 
     have=HAVE_KQUEUE . auto/have
     have=HAVE_CLEAR_EVENT . auto/have
@@ -51,7 +51,7 @@ fi
 if [ \( $version -lt 500000 -a $version -ge 430000 \) \
      -o $version -ge 500018 ]
 then
-    echo " + kqueue's NOTE_LAWAT found"
+    echo " + using kqueue's NOTE_LAWAT"
 
     have=HAVE_LOWAT_EVENT . auto/have
 fi
--- a/auto/sources
+++ b/auto/sources
@@ -57,6 +57,7 @@ EVENT_DEPS="src/event/ngx_event.h \
 
 EVENT_SRCS="src/event/ngx_event.c \
             src/event/ngx_event_timer.c \
+            src/event/ngx_event_mutex.c \
             src/event/ngx_event_accept.c \
             src/event/ngx_event_connect.c \
             src/event/ngx_event_pipe.c"
--- a/src/core/ngx_atomic.h
+++ b/src/core/ngx_atomic.h
@@ -59,7 +59,7 @@ static ngx_inline uint32_t ngx_atomic_cm
 
         NGX_SMP_LOCK
     "   cmpxchgl  %3, %1;   "
-    "   setzb     %%al;     "
+    "   setz      %%al;     "
     "   movzbl    %%al, %0; "
 
     : "=a" (res) : "m" (*lock), "a" (old), "q" (set));
--- a/src/event/modules/ngx_kqueue_module.c
+++ b/src/event/modules/ngx_kqueue_module.c
@@ -22,6 +22,9 @@ static int ngx_kqueue_add_event(ngx_even
 static int ngx_kqueue_del_event(ngx_event_t *ev, int event, u_int flags);
 static int ngx_kqueue_set_event(ngx_event_t *ev, int filter, u_int flags);
 static int ngx_kqueue_process_events(ngx_log_t *log);
+#if (NGX_THREADS)
+static void ngx_kqueue_thread_handler(ngx_event_t *ev);
+#endif
 
 static void *ngx_kqueue_create_conf(ngx_cycle_t *cycle);
 static char *ngx_kqueue_init_conf(ngx_cycle_t *cycle, void *conf);
@@ -68,6 +71,9 @@ ngx_event_module_t  ngx_kqueue_module_ct
         NULL,                              /* add an connection */
         NULL,                              /* delete an connection */
         ngx_kqueue_process_events,         /* process the events */
+#if (NGX_THREADS0)
+        ngx_kqueue_thread_handler,         /* process an event by thread */
+#endif
         ngx_kqueue_init,                   /* init the events */
         ngx_kqueue_done                    /* done the events */
     }
@@ -500,7 +506,12 @@ static ngx_int_t ngx_kqueue_process_even
 
             if (ev->light) {
 
-                /* the accept event */
+                /*
+                 * The light events are the accept event,
+                 * or the event that waits in the mutex queue - we need to
+                 * remove it from the mutex queue before the inserting into
+                 * the posted events queue.
+                 */
 
                 ngx_mutex_unlock(ngx_posted_events_mutex);
 
@@ -538,12 +549,17 @@ static ngx_int_t ngx_kqueue_process_even
 
     /* TODO: non-thread mode only */
 
-    ev = ngx_posted_events;
-    ngx_posted_events = NULL;
+    for ( ;; ) {
+
+        ev = (ngx_event_t *) ngx_posted_events;
 
-    while (ev) {
+        if (ev == NULL) {
+            break;
+        }
+
+        ngx_posted_events = ev->next;
+
         ev->event_handler(ev);
-        ev = ev->next;
     }
 
     return NGX_OK;
--- a/src/event/ngx_event.c
+++ b/src/event/ngx_event.c
@@ -39,13 +39,13 @@ static void *ngx_event_create_conf(ngx_c
 static char *ngx_event_init_conf(ngx_cycle_t *cycle, void *conf);
 
 
-int                  ngx_event_flags;
-ngx_event_actions_t  ngx_event_actions;
+int                    ngx_event_flags;
+ngx_event_actions_t    ngx_event_actions;
 
 
-static int           ngx_event_max_module;
+static int             ngx_event_max_module;
 
-ngx_event_t         *ngx_posted_events;
+volatile ngx_event_t  *ngx_posted_events;
 
 
 static ngx_str_t  events_name = ngx_string("events");
--- a/src/event/ngx_event.h
+++ b/src/event/ngx_event.h
@@ -20,6 +20,14 @@ typedef struct {
 #endif
 
 
+typedef struct {
+    ngx_uint_t       lock;
+
+    ngx_event_t     *events;
+    ngx_event_t     *last;
+} ngx_event_mutex_t;
+
+
 struct ngx_event_s {
     void            *data;
     /* TODO rename to handler */
@@ -373,11 +381,11 @@ typedef struct {
 
 
 
-extern ngx_event_t          *ngx_posted_events;
+extern volatile ngx_event_t  *ngx_posted_events;
 
-extern int                   ngx_event_flags;
-extern ngx_module_t          ngx_events_module;
-extern ngx_module_t          ngx_event_core_module;
+extern int                    ngx_event_flags;
+extern ngx_module_t           ngx_events_module;
+extern ngx_module_t           ngx_event_core_module;
 
 
 #define ngx_event_get_conf(conf_ctx, module)                                  \
--- a/src/event/ngx_event_mutex.c
+++ b/src/event/ngx_event_mutex.c
@@ -1,14 +1,65 @@
 
-spinlock_max depend on CPU number and mutex type.
-    1 CPU               1
-    ngx_malloc_mutex    1000 ?
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
 
 
-int ngx_event_mutex_trylock(ngx_mutex_t *mtx)
+ngx_int_t ngx_event_mutex_timedlock(ngx_event_mutex_t *m, ngx_msec_t timer,
+                                    ngx_event_t *ev)
 {
-    for(i = mtx->spinlock_max; i; i--)
-        if (trylock(mtx->lock))
-            return 1;
+    ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
+                   "lock event mutex " PTR_FMT " lock:%X", m, m->lock);
+
+    if (m->lock) {
+
+        if (m->events == NULL) {
+            m->events = ev;
+
+        } else {
+            m->last->next = ev;
+        }
+
+        m->last = ev;
+        ev->next = NULL;
+
+#if (NGX_THREADS)
+        ev->light = 1;
+#endif
+
+        ngx_add_timer(ev, timer);
+
+        return NGX_AGAIN;
+    }
+
+    m->lock = 1;
 
-    return 0;
+    return NGX_OK;
 }
+
+
+ngx_int_t ngx_event_mutex_unlock(ngx_event_mutex_t *m, ngx_log_t *log)
+{
+    ngx_event_t  *ev;
+
+    if (m->lock == 0) {
+        ngx_log_error(NGX_LOG_ALERT, log, 0,
+                      "tring to unlock the free event mutex " PTR_FMT, m);
+        return NGX_ERROR;
+    }
+
+    ngx_log_debug2(NGX_LOG_DEBUG_EVENT, log, 0,
+                   "unlock event mutex " PTR_FMT ", next event: " PTR_FMT,
+                   m, m->events);
+
+    m->lock = 0;
+
+    if (m->events) {
+        ev = m->events;
+        m->events = ev->next;
+
+        ev->next = (ngx_event_t *) ngx_posted_events;
+        ngx_posted_events = ev;
+    }
+
+    return NGX_OK;
+}
--- a/src/event/ngx_event_timer.c
+++ b/src/event/ngx_event_timer.c
@@ -9,22 +9,26 @@ ngx_mutex_t  *ngx_event_timer_mutex;
 #endif
 
 
-ngx_rbtree_t  *ngx_event_timer_rbtree;
-ngx_rbtree_t   ngx_event_timer_sentinel;
+volatile ngx_rbtree_t  *ngx_event_timer_rbtree;
+ngx_rbtree_t            ngx_event_timer_sentinel;
 
 
 ngx_int_t ngx_event_timer_init(ngx_log_t *log)
 {
     if (ngx_event_timer_rbtree) {
+#if (NGX_THREADS)
         ngx_event_timer_mutex->log = log;
+#endif
         return NGX_OK;
     }
 
     ngx_event_timer_rbtree = &ngx_event_timer_sentinel;
 
+#if (NGX_THREADS)
     if (!(ngx_event_timer_mutex = ngx_mutex_init(log, 0))) {
         return NGX_ERROR;
     }
+#endif
 
     return NGX_OK;
 }
@@ -44,7 +48,8 @@ ngx_msec_t ngx_event_find_timer(void)
     }
 #endif
 
-    node = ngx_rbtree_min(ngx_event_timer_rbtree, &ngx_event_timer_sentinel);
+    node = ngx_rbtree_min((ngx_rbtree_t *) ngx_event_timer_rbtree,
+                          &ngx_event_timer_sentinel);
 
 #if (NGX_THREADS)
     ngx_mutex_unlock(ngx_event_timer_mutex);
@@ -76,7 +81,7 @@ void ngx_event_expire_timers(ngx_msec_t 
         }
 #endif
 
-        node = ngx_rbtree_min(ngx_event_timer_rbtree,
+        node = ngx_rbtree_min((ngx_rbtree_t *) ngx_event_timer_rbtree,
                               &ngx_event_timer_sentinel);
 
 #if (NGX_THREADS)
--- a/src/event/ngx_event_timer.h
+++ b/src/event/ngx_event_timer.h
@@ -31,8 +31,8 @@ extern ngx_mutex_t  *ngx_event_timer_mut
 #endif
 
 
-extern ngx_rbtree_t  *ngx_event_timer_rbtree;
-extern ngx_rbtree_t   ngx_event_timer_sentinel;
+extern volatile ngx_rbtree_t  *ngx_event_timer_rbtree;
+extern ngx_rbtree_t            ngx_event_timer_sentinel;
 
 
 ngx_inline static void ngx_event_del_timer(ngx_event_t *ev)
@@ -47,7 +47,8 @@ ngx_inline static void ngx_event_del_tim
     }
 #endif
 
-    ngx_rbtree_delete(&ngx_event_timer_rbtree, &ngx_event_timer_sentinel,
+    ngx_rbtree_delete((ngx_rbtree_t **) &ngx_event_timer_rbtree,
+                      &ngx_event_timer_sentinel,
                       (ngx_rbtree_t *) &ev->rbtree_key);
 
 #if (NGX_THREADS)
@@ -87,7 +88,8 @@ ngx_inline static void ngx_event_add_tim
     }
 #endif
 
-    ngx_rbtree_insert(&ngx_event_timer_rbtree, &ngx_event_timer_sentinel,
+    ngx_rbtree_insert((ngx_rbtree_t **) &ngx_event_timer_rbtree,
+                      &ngx_event_timer_sentinel,
                       (ngx_rbtree_t *) &ev->rbtree_key);
 
 #if (NGX_THREADS)
--- a/src/http/ngx_http_busy_lock.c
+++ b/src/http/ngx_http_busy_lock.c
@@ -40,6 +40,7 @@ int ngx_http_busy_lock(ngx_http_busy_loc
 
     if (bl->waiting < bl->max_waiting) {
         bl->waiting++;
+
         ngx_add_timer(bc->event, 1000);
         bc->event->event_handler = bc->event_handler;
 
@@ -204,6 +205,11 @@ char *ngx_http_set_busy_lock_slot(ngx_co
     }
     *blp = bl;
 
+    /* ngx_calloc_shared() */
+    if (!(bl->mutex = ngx_pcalloc(cf->pool, sizeof(ngx_event_mutex_t)))) {
+        return NGX_CONF_ERROR;
+    }
+
     dup = 0;
     invalid = 0;
     value = cf->args->elts;
--- a/src/http/ngx_http_busy_lock.h
+++ b/src/http/ngx_http_busy_lock.h
@@ -9,20 +9,19 @@
 
 
 typedef struct {
-    u_char  *md5_mask;
-    char    *md5;
-    int      cachable;
+    u_char             *md5_mask;
+    char               *md5;
+    int                 cachable;
 
-    int      busy;
-    int      max_busy;
+    int                 busy;
+    int                 max_busy;
 
-    int      waiting;
-    int      max_waiting;
+    int                 waiting;
+    int                 max_waiting;
 
-    time_t   timeout;
+    time_t              timeout;
 
- /* ngx_mutex_t  mutex; */
-
+    ngx_event_mutex_t  *mutex;
 } ngx_http_busy_lock_t;
 
 
--- a/src/os/unix/ngx_freebsd_rfork_thread.c
+++ b/src/os/unix/ngx_freebsd_rfork_thread.c
@@ -1,3 +1,8 @@
+
+/*
+ * Copyright (C) 2002-2004 Igor Sysoev, http://sysoev.ru/en/
+ */
+
 
 #include <ngx_config.h>
 #include <ngx_core.h>
@@ -21,15 +26,12 @@
  */
 
 
-ngx_int_t  ngx_threaded;
-
-static inline int ngx_gettid();
+ngx_int_t   ngx_threaded;
+char       *ngx_freebsd_kern_usrstack;
+size_t      ngx_thread_stack_size;
 
 
-static char        *usrstack;
 static size_t       rz_size = /* STUB: PAGE_SIZE */ 4096;
-
-static size_t       stack_size;
 static size_t       usable_stack_size;
 static char        *last_stack;
 
@@ -54,12 +56,12 @@ int *__error()
 
 
 /*
- * __isthreaded enables spinlock() in some libc functions, i.e. in malloc()
+ * __isthreaded enables the spinlocks in some libc functions, i.e. in malloc()
  * and some other places.  Nevertheless we protect our malloc()/free() calls
  * by own mutex that is more efficient than the spinlock.
  *
- * We define own _spinlock() because a weak referenced _spinlock() stub in
- * src/lib/libc/gen/_spinlock_stub.c does nothing.
+ * _spinlock() is a weak referenced stub in src/lib/libc/gen/_spinlock_stub.c
+ * that does nothing.
  */
 
 extern int  __isthreaded;
@@ -69,6 +71,7 @@ void _spinlock(ngx_atomic_t *lock)
     ngx_int_t  tries;
 
     tries = 0;
+
     for ( ;; ) {
 
         if (*lock) {
@@ -88,6 +91,24 @@ void _spinlock(ngx_atomic_t *lock)
 }
 
 
+/*
+ * Before FreeBSD 5.1 _spinunlock() is a simple #define in
+ * src/lib/libc/include/spinlock.h that zeroes lock.
+ *
+ * Since FreeBSD 5.1 _spinunlock() is a weak referenced stub in
+ * src/lib/libc/gen/_spinlock_stub.c that does nothing.
+ */
+
+#ifndef _spinunlock
+
+void _spinunlock(ngx_atomic_t *lock)
+{
+    *lock = 0;
+}
+
+#endif
+
+
 int ngx_create_thread(ngx_tid_t *tid, int (*func)(void *arg), void *arg,
                       ngx_log_t *log)
 {
@@ -100,7 +121,7 @@ int ngx_create_thread(ngx_tid_t *tid, in
         return NGX_ERROR;
     }
 
-    last_stack -= stack_size;
+    last_stack -= ngx_thread_stack_size;
 
     stack = mmap(last_stack, usable_stack_size, PROT_READ|PROT_WRITE,
                  MAP_STACK, -1, 0);
@@ -139,7 +160,8 @@ int ngx_create_thread(ngx_tid_t *tid, in
 
     } else {
         *tid = id;
-        nthreads = (usrstack - stack_top) / stack_size;
+        nthreads = (ngx_freebsd_kern_usrstack - stack_top)
+                                                       / ngx_thread_stack_size;
         tids[nthreads] = id;
 
         ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0, "rfork()ed thread: %d", id);
@@ -156,19 +178,21 @@ ngx_int_t ngx_init_threads(int n, size_t
 
     max_threads = n;
 
-    len = sizeof(usrstack);
-    if (sysctlbyname("kern.usrstack", &usrstack, &len, NULL, 0) == -1) {
+    len = sizeof(ngx_freebsd_kern_usrstack);
+    if (sysctlbyname("kern.usrstack", &ngx_freebsd_kern_usrstack, &len,
+                                                                NULL, 0) == -1)
+    {
         ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                       "sysctlbyname(kern.usrstack) failed");
         return NGX_ERROR;
     }
 
     /* the main thread stack red zone */
-    red_zone = usrstack - (size + rz_size);
+    red_zone = ngx_freebsd_kern_usrstack - (size + rz_size);
 
     ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0,
                    "usrstack: " PTR_FMT " red zone: " PTR_FMT,
-                   usrstack, red_zone);
+                   ngx_freebsd_kern_usrstack, red_zone);
 
     zone = mmap(red_zone, rz_size, PROT_NONE, MAP_ANON, -1, 0);
     if (zone == MAP_FAILED) {
@@ -201,7 +225,7 @@ ngx_int_t ngx_init_threads(int n, size_t
 
     last_stack = zone + rz_size;
     usable_stack_size = size;
-    stack_size = size + rz_size;
+    ngx_thread_stack_size = size + rz_size;
 
     /* allow the spinlock in libc malloc() */
     __isthreaded = 1;
@@ -212,28 +236,6 @@ ngx_int_t ngx_init_threads(int n, size_t
 }
 
 
-static inline int ngx_gettid()
-{
-    char  *sp;
-
-    if (stack_size == 0) {
-        return 0;
-    }
-
-#if ( __i386__ )
-
-    __asm__ volatile ("mov %%esp, %0" : "=q" (sp));
-
-#elif ( __amd64__ )
-
-    __asm__ volatile ("mov %%rsp, %0" : "=q" (sp));
-
-#endif
-
-    return (usrstack - sp) / stack_size;
-}
-
-
 ngx_tid_t ngx_thread_self()
 {
     int        tid;
@@ -313,7 +315,7 @@ void ngx_mutex_done(ngx_mutex_t *m)
 }
 
 
-ngx_int_t ngx_mutex_do_lock(ngx_mutex_t *m, ngx_int_t try)
+ngx_int_t ngx_mutex_dolock(ngx_mutex_t *m, ngx_int_t try)
 {
     uint32_t       lock, new, old;
     ngx_uint_t     tries;
@@ -453,7 +455,7 @@ ngx_int_t ngx_mutex_unlock(ngx_mutex_t *
     old = m->lock;
 
     if (!(old & NGX_MUTEX_LOCK_BUSY)) {
-        ngx_log_error(NGX_LOG_ALERT, m->log, ngx_errno,
+        ngx_log_error(NGX_LOG_ALERT, m->log, 0,
                       "tring to unlock the free mutex " PTR_FMT, m);
         return NGX_ERROR;
     }
--- a/src/os/unix/ngx_freebsd_sendfile_chain.c
+++ b/src/os/unix/ngx_freebsd_sendfile_chain.c
@@ -1,3 +1,8 @@
+
+/*
+ * Copyright (C) 2002-2004 Igor Sysoev, http://sysoev.ru/en/
+ */
+
 
 #include <ngx_config.h>
 #include <ngx_core.h>
--- a/src/os/unix/ngx_linux_sendfile_chain.c
+++ b/src/os/unix/ngx_linux_sendfile_chain.c
@@ -1,3 +1,8 @@
+
+/*
+ * Copyright (C) 2002-2004 Igor Sysoev, http://sysoev.ru/en/
+ */
+
 
 #include <ngx_config.h>
 #include <ngx_core.h>
--- a/src/os/unix/ngx_process.c
+++ b/src/os/unix/ngx_process.c
@@ -13,9 +13,12 @@ ngx_pid_t ngx_spawn_process(ngx_cycle_t 
                             ngx_spawn_proc_pt proc, void *data,
                             char *name, ngx_int_t respawn)
 {
+#if 0
     sigset_t   set, oset;
+#endif
     ngx_pid_t  pid;
 
+#if 0
     if (respawn < 0) {
         sigemptyset(&set);
         sigaddset(&set, SIGCHLD);
@@ -25,6 +28,7 @@ ngx_pid_t ngx_spawn_process(ngx_cycle_t 
             return NGX_ERROR;
         }
     }
+#endif
 
     pid = fork();
 
@@ -34,11 +38,13 @@ ngx_pid_t ngx_spawn_process(ngx_cycle_t 
     }
 
     if (pid == -1 || pid == 0) {
+#if 0
         if (sigprocmask(SIG_SETMASK, &oset, &set) == -1) {
             ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                           "sigprocmask() failed while spawning %s", name);
             return NGX_ERROR;
         }
+#endif
     }
 
     switch (pid) {
@@ -75,11 +81,13 @@ ngx_pid_t ngx_spawn_process(ngx_cycle_t 
     ngx_processes[ngx_last_process].exiting = 0;
     ngx_last_process++;
 
+#if 0
     if (sigprocmask(SIG_SETMASK, &oset, &set) == -1) {
         ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                       "sigprocmask() failed while spawning %s", name);
         return NGX_ERROR;
     }
+#endif
 
     return pid;
 }
--- a/src/os/unix/ngx_solaris_sendfilev_chain.c
+++ b/src/os/unix/ngx_solaris_sendfilev_chain.c
@@ -1,3 +1,8 @@
+
+/*
+ * Copyright (C) 2002-2004 Igor Sysoev, http://sysoev.ru/en/
+ */
+
 
 #include <ngx_config.h>
 #include <ngx_core.h>
--- a/src/os/unix/ngx_thread.h
+++ b/src/os/unix/ngx_thread.h
@@ -15,12 +15,11 @@
 
 typedef pid_t  ngx_tid_t;
 
-#define TID_T_FMT      PID_T_FMT
-
+#undef ngx_log_pid
+#define ngx_log_pid    ngx_thread_self()
 #define ngx_log_tid    0
 
-#undef ngx_log_pid
-#define ngx_log_pid    ngx_thread_self()
+#define TID_T_FMT      PID_T_FMT
 
 
 #define NGX_MUTEX_LIGHT      1
@@ -35,12 +34,43 @@ typedef volatile struct {
 } ngx_mutex_t;
 
 
+extern char    *ngx_freebsd_kern_usrstack;
+extern size_t   ngx_thread_stack_size;
+
+static inline int ngx_gettid()
+{
+    char  *sp;
+
+    if (ngx_thread_stack_size == 0) {
+        return 0;
+    }
+
+#if ( __i386__ )
+
+    __asm__ volatile ("mov %%esp, %0" : "=q" (sp));
+
+#elif ( __amd64__ )
+
+    __asm__ volatile ("mov %%rsp, %0" : "=q" (sp));
+
+#else
+
+#error "rfork()ed threads are not supported on this platform"
+
+#endif
+
+    return (ngx_freebsd_kern_usrstack - sp) / ngx_thread_stack_size;
+}
+
+
+
 #else /* use pthreads */
 
 #include <pthread.h>
 
 typedef pthread_t  ngx_tid_t;
 
+#define ngx_gettid()   ((ngx_int_t) pthread_getspecific(0))
 #define ngx_log_tid    ngx_thread_self()
 
 #endif
@@ -51,12 +81,13 @@ int ngx_create_thread(ngx_tid_t *tid, in
                       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);
+#define ngx_mutex_trylock(m)  ngx_mutex_dolock(m, 1)
+#define ngx_mutex_lock(m)     ngx_mutex_dolock(m, 0)
+ngx_int_t ngx_mutex_dolock(ngx_mutex_t *m, ngx_int_t try);
 ngx_int_t ngx_mutex_unlock(ngx_mutex_t *m);