aboutsummaryrefslogtreecommitdiff
path: root/src/os/unix/ngx_freebsd_rfork_thread.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/os/unix/ngx_freebsd_rfork_thread.c')
-rw-r--r--src/os/unix/ngx_freebsd_rfork_thread.c158
1 files changed, 158 insertions, 0 deletions
diff --git a/src/os/unix/ngx_freebsd_rfork_thread.c b/src/os/unix/ngx_freebsd_rfork_thread.c
new file mode 100644
index 000000000..d74b7ba9b
--- /dev/null
+++ b/src/os/unix/ngx_freebsd_rfork_thread.c
@@ -0,0 +1,158 @@
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_process.h>
+#include <ngx_log.h>
+#include <ngx_alloc.h>
+
+
+extern int __isthreaded;
+
+
+typedef int ngx_tid_t;
+
+
+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;
+
+static int red_zone = 4096;
+
+
+/* the thread-safe errno */
+
+static int errno0; /* the main thread's errno */
+static int *errnos;
+
+int *__error()
+{
+ int tid;
+
+ tid = ngx_gettid();
+ return tid ? &errnos[tid] : &errno0;
+}
+
+
+int ngx_create_thread(ngx_tid_t *tid, int (*func)(void *arg), void *arg)
+{
+ int id, err;
+ char *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");
+ return NGX_ERROR;
+ }
+
+#if 0
+ id = rfork_thread(RFPROC|RFMEM|RFFDG|RFCFDG, stack_top, func, arg);
+#elif 1
+ id = rfork_thread(RFPROC|RFMEM, stack_top, func, arg);
+#else
+ id = rfork_thread(RFPROC|RFTHREAD|RFMEM, stack_top, func, arg);
+#endif
+ err = errno;
+
+ if (id == -1) {
+ ngx_log_error(NGX_LOG_ALERT, log, err, "rfork() failed");
+
+ } else {
+ *tid = id;
+ tids[last_thread++] = id;
+
+ /* allow the spinlock in libc malloc() */
+ __isthreaded = 1;
+ }
+
+ return err;
+}
+
+
+int ngx_init_thread_env(int n, size_t size, ngx_log_t *lg)
+{
+ int len, i;
+ char *usrstack, *zone;
+
+ log = lg;
+
+ /* create the thread stacks */
+
+ len = 4;
+ if (sysctlbyname("kern.usrstack", &usrstack, &len, NULL, 0) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, log, errno,
+ "sysctlbyname(kern.usrstack) failed");
+ return NGX_ERROR;
+ }
+
+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);
+ if (zone == MAP_FAILED) {
+ ngx_log_error(NGX_LOG_ALERT, log, errno,
+ "mmap(%d, PROT_NONE, MAP_ANON) failed", 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;
+ }
+ }
+
+ 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 * sizeof(ngx_tid_t), log), NGX_ERROR);
+
+ tids[0] = ngx_getpid();
+ last_thread = 1;
+
+ return NGX_OK;
+}
+
+
+ngx_tid_t ngx_thread_self()
+{
+ return tids[ngx_gettid()];
+}
+
+
+static inline int ngx_gettid()
+{
+ char *sp;
+
+ __asm__ ("mov %%esp, %0" : "=q" (sp));
+
+ return (sp > stacks_end) ? 0: ((sp - stacks_start) / stack_size + 1);
+}