#include #include #include #include #include extern int __isthreaded; 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 int red_zone = 4096; /* the thread-safe errno */ static int errnos[NGX_MAX_THREADS]; int *__error() { return &errnos[ngx_gettid()]; } 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(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 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; 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); }