Mercurial > hg > nginx
comparison src/os/unix/ngx_freebsd_rfork_thread.c @ 376:d0451e402e27
nginx-0.0.7-2004-07-05-10:55:54 import
author | Igor Sysoev <igor@sysoev.ru> |
---|---|
date | Mon, 05 Jul 2004 06:55:54 +0000 |
parents | 744ccb59062d |
children | 41437e4fd9b4 |
comparison
equal
deleted
inserted
replaced
375:744ccb59062d | 376:d0451e402e27 |
---|---|
8 #include <ngx_core.h> | 8 #include <ngx_core.h> |
9 | 9 |
10 /* | 10 /* |
11 * The threads implementation uses the rfork(RFPROC|RFTHREAD|RFMEM) syscall | 11 * The threads implementation uses the rfork(RFPROC|RFTHREAD|RFMEM) syscall |
12 * to create threads. All threads use the stacks of the same size mmap()ed | 12 * to create threads. All threads use the stacks of the same size mmap()ed |
13 * below the main stack. Thus the current thread id is determinated through | 13 * below the main stack. Thus the current thread id is determinated via |
14 * the stack pointer. | 14 * the stack pointer value. |
15 * | 15 * |
16 * The mutex implementation uses the ngx_atomic_cmp_set() operation | 16 * The mutex implementation uses the ngx_atomic_cmp_set() operation |
17 * to acquire a mutex and the SysV semaphore to wait on a mutex or to wake up | 17 * to acquire a mutex and the SysV semaphore to wait on a mutex and to wake up |
18 * the waiting threads. The light mutex does not use semaphore, so after | 18 * the waiting threads. The light mutex does not use semaphore, so after |
19 * spinning in the lock the thread calls sched_yield(). However the light | 19 * spinning in the lock the thread calls sched_yield(). However the light |
20 * mutecies are intended to be used with the "trylock" operation only. | 20 * mutecies are intended to be used with the "trylock" operation only. |
21 * The SysV semop() is a cheap syscall, particularly if it has little sembuf's | |
22 * and does not use SEM_UNDO. | |
21 * | 23 * |
22 * The condition variable implementation uses the SysV semaphore set of two | 24 * The condition variable implementation uses signal #64. The signal handler |
23 * semaphores. The first is used by the CV mutex, and the second is used | 25 * is SIG_IGN so the kill() is a cheap syscall. The thread waits a signal |
24 * by the CV to signal. | 26 * in kevent(). The use of the EVFILT_SIGNAL is safe since FreeBSD 4.7. |
25 * | 27 * |
26 * This threads implementation currently works on i386 (486+) and amd64 | 28 * This threads implementation currently works on i386 (486+) and amd64 |
27 * platforms only. | 29 * platforms only. |
28 */ | 30 */ |
29 | 31 |
74 tries = 0; | 76 tries = 0; |
75 | 77 |
76 for ( ;; ) { | 78 for ( ;; ) { |
77 | 79 |
78 if (*lock) { | 80 if (*lock) { |
79 if (ngx_freebsd_hw_ncpu > 1 && tries++ < 1000) { | 81 if (ngx_ncpu > 1 && tries++ < 1000) { |
80 continue; | 82 continue; |
81 } | 83 } |
82 | 84 |
83 sched_yield(); | 85 sched_yield(); |
84 tries = 0; | 86 tries = 0; |
108 } | 110 } |
109 | 111 |
110 #endif | 112 #endif |
111 | 113 |
112 | 114 |
113 int ngx_create_thread(ngx_tid_t *tid, int (*func)(void *arg), void *arg, | 115 int ngx_create_thread(ngx_tid_t *tid, void* (*func)(void *arg), void *arg, |
114 ngx_log_t *log) | 116 ngx_log_t *log) |
115 { | 117 { |
116 int id, err; | 118 int id, err; |
117 char *stack, *stack_top; | 119 char *stack, *stack_top; |
118 | 120 |
142 stack_top = stack + usable_stack_size; | 144 stack_top = stack + usable_stack_size; |
143 | 145 |
144 ngx_log_debug2(NGX_LOG_DEBUG_CORE, log, 0, | 146 ngx_log_debug2(NGX_LOG_DEBUG_CORE, log, 0, |
145 "thread stack: " PTR_FMT "-" PTR_FMT, stack, stack_top); | 147 "thread stack: " PTR_FMT "-" PTR_FMT, stack, stack_top); |
146 | 148 |
147 #if 1 | 149 ngx_set_errno(0); |
148 id = rfork_thread(RFPROC|RFTHREAD|RFMEM, stack_top, func, arg); | 150 |
149 #elif 1 | 151 id = rfork_thread(RFPROC|RFTHREAD|RFMEM, stack_top, |
150 id = rfork_thread(RFPROC|RFMEM, stack_top, func, arg); | 152 (ngx_rfork_thread_func_pt) func, arg); |
151 #elif 1 | |
152 id = rfork_thread(RFFDG|RFCFDG, stack_top, func, arg); | |
153 #else | |
154 id = rfork(RFFDG|RFCFDG); | |
155 #endif | |
156 | 153 |
157 err = ngx_errno; | 154 err = ngx_errno; |
158 | 155 |
159 if (id == -1) { | 156 if (id == -1) { |
160 ngx_log_error(NGX_LOG_ALERT, log, err, "rfork() failed"); | 157 ngx_log_error(NGX_LOG_ALERT, log, err, "rfork() failed"); |
172 } | 169 } |
173 | 170 |
174 | 171 |
175 ngx_int_t ngx_init_threads(int n, size_t size, ngx_cycle_t *cycle) | 172 ngx_int_t ngx_init_threads(int n, size_t size, ngx_cycle_t *cycle) |
176 { | 173 { |
177 size_t len; | 174 char *red_zone, *zone; |
178 char *red_zone, *zone; | 175 size_t len; |
179 | 176 ngx_int_t i; |
180 max_threads = n; | 177 struct sigaction sa; |
178 | |
179 max_threads = n + 1; | |
180 | |
181 for (i = 0; i < n; i++) { | |
182 ngx_memzero(&sa, sizeof(struct sigaction)); | |
183 sa.sa_handler = SIG_IGN; | |
184 sigemptyset(&sa.sa_mask); | |
185 if (sigaction(NGX_CV_SIGNAL, &sa, NULL) == -1) { | |
186 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, | |
187 "sigaction(%d, SIG_IGN) failed", NGX_CV_SIGNAL); | |
188 return NGX_ERROR; | |
189 } | |
190 } | |
181 | 191 |
182 len = sizeof(ngx_freebsd_kern_usrstack); | 192 len = sizeof(ngx_freebsd_kern_usrstack); |
183 if (sysctlbyname("kern.usrstack", &ngx_freebsd_kern_usrstack, &len, | 193 if (sysctlbyname("kern.usrstack", &ngx_freebsd_kern_usrstack, &len, |
184 NULL, 0) == -1) | 194 NULL, 0) == -1) |
185 { | 195 { |
247 | 257 |
248 if (tids == NULL) { | 258 if (tids == NULL) { |
249 return ngx_pid; | 259 return ngx_pid; |
250 } | 260 } |
251 | 261 |
252 #if 0 | |
253 if (tids[tid] == 0) { | |
254 pid = ngx_pid; | |
255 tids[tid] = pid; | |
256 return pid; | |
257 } | |
258 #endif | |
259 | |
260 return tids[tid]; | 262 return tids[tid]; |
261 } | 263 } |
262 | 264 |
263 | 265 |
264 ngx_mutex_t *ngx_mutex_init(ngx_log_t *log, uint flags) | 266 ngx_mutex_t *ngx_mutex_init(ngx_log_t *log, uint flags) |
299 | 301 |
300 return m; | 302 return m; |
301 } | 303 } |
302 | 304 |
303 | 305 |
304 void ngx_mutex_done(ngx_mutex_t *m) | 306 void ngx_mutex_destroy(ngx_mutex_t *m) |
305 { | 307 { |
306 if (semctl(m->semid, 0, IPC_RMID) == -1) { | 308 if (semctl(m->semid, 0, IPC_RMID) == -1) { |
307 ngx_log_error(NGX_LOG_ALERT, m->log, ngx_errno, | 309 ngx_log_error(NGX_LOG_ALERT, m->log, ngx_errno, |
308 "semctl(IPC_RMID) failed"); | 310 "semctl(IPC_RMID) failed"); |
309 } | 311 } |
536 } | 538 } |
537 | 539 |
538 | 540 |
539 ngx_cond_t *ngx_cond_init(ngx_log_t *log) | 541 ngx_cond_t *ngx_cond_init(ngx_log_t *log) |
540 { | 542 { |
541 ngx_cond_t *cv; | 543 ngx_cond_t *cv; |
542 union semun op; | |
543 | 544 |
544 if (!(cv = ngx_alloc(sizeof(ngx_cond_t), log))) { | 545 if (!(cv = ngx_alloc(sizeof(ngx_cond_t), log))) { |
545 return NULL; | 546 return NULL; |
546 } | 547 } |
547 | 548 |
549 cv->signo = NGX_CV_SIGNAL; | |
550 cv->tid = 0; | |
548 cv->log = log; | 551 cv->log = log; |
549 | 552 cv->kq = -1; |
550 cv->semid = semget(IPC_PRIVATE, 2, SEM_R|SEM_A); | |
551 if (cv->semid == -1) { | |
552 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, "semget() failed"); | |
553 return NULL; | |
554 } | |
555 | |
556 op.val = 0; | |
557 | |
558 if (semctl(cv->semid, 0, SETVAL, op) == -1) { | |
559 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, "semctl(SETVAL) failed"); | |
560 | |
561 if (semctl(cv->semid, 0, IPC_RMID) == -1) { | |
562 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, | |
563 "semctl(IPC_RMID) failed"); | |
564 } | |
565 | |
566 return NULL; | |
567 } | |
568 | 553 |
569 return cv; | 554 return cv; |
570 } | 555 } |
571 | 556 |
572 | 557 |
573 void ngx_cond_done(ngx_cond_t *cv) | 558 void ngx_cond_destroy(ngx_cond_t *cv) |
574 { | 559 { |
575 if (semctl(cv->semid, 0, IPC_RMID) == -1) { | 560 if (close(cv->kq) == -1) { |
576 ngx_log_error(NGX_LOG_ALERT, cv->log, ngx_errno, | 561 ngx_log_error(NGX_LOG_ALERT, cv->log, ngx_errno, |
577 "semctl(IPC_RMID) failed"); | 562 "kqueue close() failed"); |
578 } | 563 } |
579 | 564 |
580 ngx_free(cv); | 565 ngx_free(cv); |
581 } | 566 } |
582 | 567 |
583 | 568 |
584 ngx_int_t ngx_cond_wait(ngx_cond_t *cv, ngx_mutex_t *m) | 569 ngx_int_t ngx_cond_wait(ngx_cond_t *cv, ngx_mutex_t *m) |
585 { | 570 { |
586 struct sembuf op; | 571 int n; |
587 | 572 ngx_err_t err; |
588 ngx_log_debug1(NGX_LOG_DEBUG_CORE, cv->log, 0, | 573 struct kevent kev; |
589 "cv " PTR_FMT " wait", cv); | 574 struct timespec ts; |
590 | 575 |
591 op.sem_num = 0; | 576 if (cv->kq == -1) { |
592 op.sem_op = -1; | 577 |
593 op.sem_flg = 0; | 578 /* |
594 | 579 * We have to add the EVFILT_SIGNAL filter in the rfork()ed thread. |
595 if (semop(cv->semid, &op, 1) == -1) { | 580 * Otherwise the thread would not get a signal event. |
596 ngx_log_error(NGX_LOG_ALERT, cv->log, ngx_errno, | 581 * |
597 "semop() failed while waiting on cv " PTR_FMT, cv); | 582 * However, we have not to open the kqueue in the thread, |
598 return NGX_ERROR; | 583 * it is simply handy do it together. |
584 */ | |
585 | |
586 cv->kq = kqueue(); | |
587 if (cv->kq == -1) { | |
588 ngx_log_error(NGX_LOG_ALERT, cv->log, ngx_errno, "kqueue() failed"); | |
589 return NGX_ERROR; | |
590 } | |
591 | |
592 ngx_log_debug2(NGX_LOG_DEBUG_CORE, cv->log, 0, | |
593 "cv kq:%d signo:%d", cv->kq, cv->signo); | |
594 | |
595 kev.ident = cv->signo; | |
596 kev.filter = EVFILT_SIGNAL; | |
597 kev.flags = EV_ADD; | |
598 kev.fflags = 0; | |
599 kev.data = 0; | |
600 kev.udata = NULL; | |
601 | |
602 ts.tv_sec = 0; | |
603 ts.tv_nsec = 0; | |
604 | |
605 if (kevent(cv->kq, &kev, 1, NULL, 0, &ts) == -1) { | |
606 ngx_log_error(NGX_LOG_ALERT, cv->log, ngx_errno, "kevent() failed"); | |
607 return NGX_ERROR; | |
608 } | |
609 } | |
610 | |
611 if (ngx_mutex_unlock(m) == NGX_ERROR) { | |
612 return NGX_ERROR; | |
613 } | |
614 | |
615 ngx_log_debug3(NGX_LOG_DEBUG_CORE, cv->log, 0, | |
616 "cv " PTR_FMT " wait, kq:%d, signo:%d", | |
617 cv, cv->kq, cv->signo); | |
618 | |
619 for ( ;; ) { | |
620 n = kevent(cv->kq, NULL, 0, &kev, 1, NULL); | |
621 | |
622 ngx_log_debug2(NGX_LOG_DEBUG_CORE, cv->log, 0, | |
623 "cv " PTR_FMT " kevent: %d", cv, n); | |
624 | |
625 if (n == -1) { | |
626 err = ngx_errno; | |
627 ngx_log_error((err == NGX_EINTR) ? NGX_LOG_INFO : NGX_LOG_ALERT, | |
628 cv->log, ngx_errno, | |
629 "kevent() failed while waiting condition variable " | |
630 PTR_FMT, cv); | |
631 | |
632 if (err == NGX_EINTR) { | |
633 break; | |
634 } | |
635 | |
636 return NGX_ERROR; | |
637 } | |
638 | |
639 if (n == 0) { | |
640 ngx_log_error(NGX_LOG_ALERT, cv->log, 0, | |
641 "kevent() returned no events " | |
642 "while waiting condition variable " PTR_FMT, | |
643 cv); | |
644 continue; | |
645 } | |
646 | |
647 if (kev.filter != EVFILT_SIGNAL) { | |
648 ngx_log_error(NGX_LOG_ALERT, cv->log, 0, | |
649 "kevent() returned unexpected events: %d " | |
650 "while waiting condition variable " PTR_FMT, | |
651 kev.filter, cv); | |
652 continue; | |
653 } | |
654 | |
655 if (kev.ident != (uintptr_t) cv->signo) { | |
656 ngx_log_error(NGX_LOG_ALERT, cv->log, 0, | |
657 "kevent() returned unexpected signal: %d ", | |
658 "while waiting condition variable " PTR_FMT, | |
659 kev.ident, cv); | |
660 continue; | |
661 } | |
662 | |
663 break; | |
599 } | 664 } |
600 | 665 |
601 ngx_log_debug1(NGX_LOG_DEBUG_CORE, cv->log, 0, | 666 ngx_log_debug1(NGX_LOG_DEBUG_CORE, cv->log, 0, |
602 "cv " PTR_FMT " is waked up", cv); | 667 "cv " PTR_FMT " is waked up", cv); |
603 | 668 |
609 } | 674 } |
610 | 675 |
611 | 676 |
612 ngx_int_t ngx_cond_signal(ngx_cond_t *cv) | 677 ngx_int_t ngx_cond_signal(ngx_cond_t *cv) |
613 { | 678 { |
614 struct sembuf op; | 679 ngx_log_debug3(NGX_LOG_DEBUG_CORE, cv->log, 0, |
615 | 680 "cv " PTR_FMT " to signal " PID_T_FMT " %d", |
616 ngx_log_debug1(NGX_LOG_DEBUG_CORE, cv->log, 0, | 681 cv, cv->tid, cv->signo); |
617 "cv " PTR_FMT " to signal", cv); | 682 |
618 | 683 if (kill(cv->tid, cv->signo) == -1) { |
619 op.sem_num = 0; | |
620 op.sem_op = 1; | |
621 op.sem_flg = 0; | |
622 | |
623 if (semop(cv->semid, &op, 1) == -1) { | |
624 ngx_log_error(NGX_LOG_ALERT, cv->log, ngx_errno, | 684 ngx_log_error(NGX_LOG_ALERT, cv->log, ngx_errno, |
625 "semop() failed while signaling cv " PTR_FMT, cv); | 685 "kill() failed while signaling condition variable " |
686 PTR_FMT, cv); | |
626 return NGX_ERROR; | 687 return NGX_ERROR; |
627 } | 688 } |
628 | 689 |
629 ngx_log_debug1(NGX_LOG_DEBUG_CORE, cv->log, 0, | 690 ngx_log_debug1(NGX_LOG_DEBUG_CORE, cv->log, 0, |
630 "cv " PTR_FMT " is signaled", cv); | 691 "cv " PTR_FMT " is signaled", cv); |