nginx-0.0.1-2003-05-12-19:52:24 import
diff --git a/src/os/unix/ngx_daemon.c b/src/os/unix/ngx_daemon.c
new file mode 100644
index 0000000..6faf85b
--- /dev/null
+++ b/src/os/unix/ngx_daemon.c
@@ -0,0 +1,80 @@
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_log.h>
+
+/* daemon in Linux */
+
+int ngx_daemon(ngx_log_t *log)
+{
+    int  fd;
+
+    switch (fork()) {
+    case -1:
+        ngx_log_error(NGX_LOG_ALERT, log, errno, "fork() failed");
+        return NGX_ERROR;
+
+    case 0:
+        break;
+
+    default:
+        exit(0);
+    }
+
+    if (setsid() == -1) {
+        ngx_log_error(NGX_LOG_ALERT, log, errno, "setsid() failed");
+        return NGX_ERROR;
+    }
+
+#if (__SVR4 || linux)
+
+    /* need HUP IGN ? check in Solaris and Linux */
+
+    switch (fork()) {
+    case -1:
+        ngx_log_error(NGX_LOG_ALERT, log, errno, "fork() failed");
+        return NGX_ERROR;
+
+    case 0:
+        break;
+
+    default:
+        exit(0);
+    }
+
+#endif
+
+    umask(0);
+
+#if 0
+    fd = open("/dev/null", O_RDWR);
+    if (fd == -1) {
+        ngx_log_error(NGX_LOG_ALERT, log, errno, "open(\"/dev/null\") failed");
+        return NGX_ERROR;
+    }
+
+    if (dup2(fd, STDIN_FILENO) == -1) {
+        ngx_log_error(NGX_LOG_ALERT, log, errno, "dup2(STDIN) failed");
+        return NGX_ERROR;
+    }
+
+    if (dup2(fd, STDOUT_FILENO) == -1) {
+        ngx_log_error(NGX_LOG_ALERT, log, errno, "dup2(STDOUT) failed");
+        return NGX_ERROR;
+    }
+
+    if (dup2(fd, STDERR_FILENO) == -1) {
+        ngx_log_error(NGX_LOG_ALERT, log, errno, "dup2(STDERR) failed");
+        return NGX_ERROR;
+    }
+
+    if (fd > STDERR_FILENO) {
+        if (close(fd) == -1) {
+            ngx_log_error(NGX_LOG_ALERT, log, errno, "close() failed");
+            return NGX_ERROR;
+        }
+    }
+#endif
+
+    return NGX_OK;
+}
diff --git a/src/os/unix/ngx_freebsd_init.c b/src/os/unix/ngx_freebsd_init.c
new file mode 100644
index 0000000..a24fc41
--- /dev/null
+++ b/src/os/unix/ngx_freebsd_init.c
@@ -0,0 +1,67 @@
+
+#include <ngx_freebsd_init.h>
+
+
+int freebsd_kern_osreldate;
+int freebsd_hw_ncpu;
+
+int freebsd_sendfile_nbytes_bug;
+
+
+int ngx_os_init(ngx_log_t *log)
+{
+    size_t  size;
+
+    size = 4;
+    if (sysctlbyname("kern.osreldate",
+                     &freebsd_kern_osreldate, &size, NULL, 0) == -1) {
+        ngx_log_error(NGX_LOG_ALERT, log, errno,
+                      "sysctlbyname(kern.osreldate) failed");
+        return NGX_ERROR;
+    }
+
+    ngx_log_error(NGX_LOG_INFO, log, 0,
+                  "kern.osreldate: %d, built on %d",
+                  freebsd_kern_osreldate, __FreeBSD_version);
+
+
+#if HAVE_FREEBSD_SENDFILE
+
+    /* The determination of the sendfile() nbytes bug is complex enough.
+       There're two sendfile() syscalls: a new 393 has no bug while
+       an old 336 has the bug in some versions and has not in others.
+       libc_r wrapper also emulates the bug in some versions.
+       There's no way to say exactly if a given FreeBSD version has bug.
+       Here is the algorithm that work at least for RELEASEs
+       and for syscalls only (not libc_r wrapper). */
+
+    /* detect was the new sendfile() version available at the compile time
+       to allow an old binary to run correctly on an updated FreeBSD system. */
+
+#if (__FreeBSD__ == 4 && __FreeBSD_version >= 460102) \
+    || __FreeBSD_version == 460002 || __FreeBSD_version >= 500039
+
+    /* a new syscall without the bug */
+    freebsd_sendfile_nbytes_bug = 0;
+
+#else
+
+    /* an old syscall that can have the bug */
+    freebsd_sendfile_nbytes_bug = 1;
+
+#endif
+
+#endif /* HAVE_FREEBSD_SENDFILE */
+
+
+    size = 4;
+    if (sysctlbyname("hw.ncpu", &freebsd_hw_ncpu, &size, NULL, 0) == -1) {
+        ngx_log_error(NGX_LOG_ALERT, log, errno,
+                      "sysctlbyname(hw.ncpu) failed");
+        return NGX_ERROR;
+    }
+
+    ngx_log_error(NGX_LOG_INFO, log, 0, "hw.ncpu: %d", freebsd_hw_ncpu);
+
+    return NGX_OK;
+}
diff --git a/src/os/unix/ngx_freebsd_init.h b/src/os/unix/ngx_freebsd_init.h
new file mode 100644
index 0000000..d0af10b
--- /dev/null
+++ b/src/os/unix/ngx_freebsd_init.h
@@ -0,0 +1,18 @@
+#ifndef _NGX_OS_INIT_H_INCLUDED_
+#define _NGX_OS_INIT_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_log.h>
+#include <sys/sysctl.h>
+
+
+int ngx_os_init(ngx_log_t *log);
+
+
+extern int freebsd_kern_osreldate;
+extern int freebsd_hw_ncpu;
+
+
+#endif /* _NGX_OS_INIT_H_INCLUDED_ */
diff --git a/src/os/unix/ngx_freebsd_rfork_thread.c b/src/os/unix/ngx_freebsd_rfork_thread.c
index 6cbb078..88ceced 100644
--- a/src/os/unix/ngx_freebsd_rfork_thread.c
+++ b/src/os/unix/ngx_freebsd_rfork_thread.c
@@ -11,57 +11,76 @@
 
 typedef int  ngx_tid_t;
 
-#define NGX_MAX_THREADS  10
-
 
 static inline int ngx_gettid();
 
 
-static char        *stacks_start;
-static char        *stacks_end;
-static size_t       stack_size;
-static char        *last_stack;
-static int          last_thread;
-
-static ngx_log_t   *log;
-
-static ngx_tid_t    tids[NGX_MAX_THREADS];
-
+static char        *usrstack;
 static int          red_zone = 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;
 
 /* the thread-safe errno */
 
-static int   errnos[NGX_MAX_THREADS];
+static int   errno0;   /* the main thread's errno */
+static int  *errnos;
 
 int *__error()
 {
-    return &errnos[ngx_gettid()];
+    int  tid;
+
+    tid = ngx_gettid();
+
+    return tid ? &errnos[tid - 1] : &errno0;
 }
 
 
-int ngx_create_thread(ngx_tid_t *tid, int (*func)(void *arg), void *arg)
+int ngx_create_thread(ngx_tid_t *tid, int (*func)(void *arg), void *arg,
+                      ngx_log_t *log)
 {
     int         id, err;
-    char       *stack_top;
+    char       *stack, *stack_top;
 
-    last_stack += stack_size;
-    stack_top = last_stack - red_zone;
-
-    if (stack_top > stacks_end) {
-        ngx_log_error(NGX_LOG_CRIT, log, 0, "no more threads allocated");
+    if (threads >= nthreads) {
+        ngx_log_error(NGX_LOG_CRIT, log, 0,
+                      "no more than %d threads can be created", nthreads);
         return NGX_ERROR;
     }
 
-#if 0
-    id = rfork(RFFDG|RFCFDG);
-#elif 0
-    id = rfork_thread(RFFDG|RFCFDG, stack_top, func, arg);
-#elif 0
-    id = rfork_thread(RFPROC|RFMEM, stack_top, func, arg);
-#else
+    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,
+                      "mmap(%08X:%d, MAP_STACK) thread stack failed",
+                      last_stack, usable_stack_size);
+        return NGX_ERROR;
+    }
+
+    if (stack != last_stack) {
+        ngx_log_error(NGX_LOG_ALERT, log, 0, "stack address was changed");
+    }
+
+    stack_top = stack + usable_stack_size;
+
+printf("stack: %08X-%08X\n", stack, stack_top);
+
+#if 1
     id = rfork_thread(RFPROC|RFTHREAD|RFMEM, stack_top, func, arg);
+#elif 1
+    id = rfork_thread(RFPROC|RFMEM, stack_top, func, arg);
+#elif 1
+    id = rfork_thread(RFFDG|RFCFDG, stack_top, func, arg);
+#else
+    id = rfork(RFFDG|RFCFDG);
 #endif
+
     err = errno;
 
     if (id == -1) {
@@ -69,7 +88,8 @@
 
     } else {
         *tid = id;
-        tids[last_thread++] = id;
+        threads = (usrstack - stack_top) / stack_size;
+        tids[threads] = id;
 
         /* allow the spinlock in libc malloc() */
         __isthreaded = 1;
@@ -79,14 +99,12 @@
 }
 
 
-int ngx_init_thread_env(int n, size_t size, ngx_log_t *lg)
+int ngx_init_thread_env(int n, size_t size, ngx_log_t *log)
 {
-    int    len, i;
-    char  *usrstack, *zone;
+    int    len;
+    char  *rz, *zone;
 
-    log = lg;
-
-    /* create the thread stacks */
+    nthreads = n;
 
     len = 4;
     if (sysctlbyname("kern.usrstack", &usrstack, &len, NULL, 0) == -1) {
@@ -96,41 +114,37 @@
     }
 
 printf("usrstack: %08X\n", usrstack);
-printf("red zone: %08X\n", usrstack - (size + red_zone));
 
-#if 1
     /* red zone */
-    zone = mmap(usrstack - (size + red_zone), red_zone,
-                PROT_NONE, MAP_ANON, -1, 0);
+    rz = usrstack - (size + red_zone);
+
+printf("red zone: %08X\n", rz);
+
+    zone = mmap(rz, red_zone, PROT_NONE, MAP_ANON, -1, 0);
     if (zone == MAP_FAILED) {
         ngx_log_error(NGX_LOG_ALERT, log, errno,
-                      "mmap(%d, PROT_NONE, MAP_ANON) failed", red_zone);
+                      "mmap(%08X:%d, PROT_NONE, MAP_ANON) red zone failed",
+                      rz, red_zone);
         return NGX_ERROR;
     }
-#else
-    zone = usrstack - (size + red_zone);
-#endif
 
-    last_stack = zone + red_zone;
-
-    for (i = 0; i < n; i++) {
-        last_stack -= size + red_zone;
-printf("stack: %08X\n", last_stack);
-        last_stack = mmap(last_stack, size, PROT_READ|PROT_WRITE,
-                          MAP_STACK, -1, 0);
-        if (last_stack == MAP_FAILED) {
-            ngx_log_error(NGX_LOG_ALERT, log, errno,
-                          "mmap(%d, MAP_STACK) failed", size);
-            return NGX_ERROR;
-        }
+    if (zone != rz) {
+        ngx_log_error(NGX_LOG_ALERT, log, 0, "red zone address was changed");
     }
 
-    stacks_start = last_stack;
-    stack_size = size + red_zone;
-    stacks_end = stacks_start + n * stack_size;
+    /* create the thread errno array */
+    ngx_test_null(errnos, ngx_calloc(n * sizeof(int), log), NGX_ERROR);
+
+    /* create the thread tid array */
+    ngx_test_null(tids, ngx_calloc((n + 1) * sizeof(ngx_tid_t), log),
+                  NGX_ERROR);
 
     tids[0] = ngx_getpid();
-    last_thread = 1;
+    threads = 1;
+
+    last_stack = zone + red_zone;
+    usable_stack_size = size;
+    stack_size = size + red_zone;
 
     return NGX_OK;
 }
@@ -138,7 +152,18 @@
 
 ngx_tid_t ngx_thread_self()
 {
-    return tids[ngx_gettid()];
+    int        tid;
+    ngx_tid_t  pid;
+
+    tid = ngx_gettid();
+
+    if (tids[tid] == 0) {
+        pid = ngx_getpid();
+        tids[tid] = pid;
+        return pid;
+    }
+
+    return tids[tid];
 }
 
 
@@ -146,7 +171,11 @@
 {   
     char  *sp;
 
+    if (stack_size == 0) {
+        return 0;
+    }
+
     __asm__ ("mov %%esp, %0" : "=q" (sp));
 
-    return (sp > stacks_end) ? 0 : ((sp - stacks_start) / stack_size  + 1);
+    return (usrstack - sp) / stack_size;
 }
diff --git a/src/os/unix/ngx_init.c b/src/os/unix/ngx_init.c
new file mode 100644
index 0000000..28af128
--- /dev/null
+++ b/src/os/unix/ngx_init.c
@@ -0,0 +1,20 @@
+
+
+int ngx_unix_init(ngx_log_t *log)
+{
+    struct rlimit  rlmt;
+
+    if (getrlimit(RLIMIT_NOFILE, &rlmt) == -1) {
+        ngx_log_error(NGX_LOG_ALERT, log, errno,
+                      "getrlimit(RLIMIT_NOFILE) failed)");
+        return NGX_ERROR;
+    }
+
+    ngx_log_error(NGX_LOG_INFO, log, 0,
+                  "getrlimit(RLIMIT_NOFILE): %d", rlmt.rlim_cur);
+
+    RLIM_INFINITY
+    max_connections =< rlmt.rlim_cur;
+
+    return NGX_OK;
+}