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);