#include #include extern int __isthreaded; typedef int ngx_tid_t; static inline int ngx_gettid(); 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 errno0; /* the main thread's errno */ static int *errnos; int *__error() { 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, ngx_log_t *log) { int id, err; char *stack, *stack_top; if (threads >= nthreads) { ngx_log_error(NGX_LOG_CRIT, log, 0, "no more than %d threads can be created", nthreads); 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, "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) { ngx_log_error(NGX_LOG_ALERT, log, err, "rfork() failed"); } else { *tid = id; threads = (usrstack - stack_top) / stack_size; tids[threads] = id; /* allow the spinlock in libc malloc() */ __isthreaded = 1; } return err; } int ngx_init_thread_env(int n, size_t size, ngx_log_t *log) { int len; char *rz, *zone; nthreads = n; 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); /* red zone */ 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(%08X:%d, PROT_NONE, MAP_ANON) red zone failed", rz, red_zone); return NGX_ERROR; } if (zone != rz) { 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 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; } return tids[tid]; } static inline int ngx_gettid() { char *sp; if (stack_size == 0) { return 0; } __asm__ ("mov %%esp, %0" : "=q" (sp)); return (usrstack - sp) / stack_size; }