Mercurial > hg > nginx-vendor-current
comparison src/os/unix/ngx_freebsd_rfork_thread.c @ 0:f0b350454894 NGINX_0_1_0
nginx 0.1.0
*) The first public version.
author | Igor Sysoev <http://sysoev.ru> |
---|---|
date | Mon, 04 Oct 2004 00:00:00 +0400 |
parents | |
children | 46833bd150cb |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:f0b350454894 |
---|---|
1 | |
2 /* | |
3 * Copyright (C) Igor Sysoev | |
4 */ | |
5 | |
6 | |
7 #include <ngx_config.h> | |
8 #include <ngx_core.h> | |
9 | |
10 /* | |
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 | |
13 * below the main stack. Thus the current thread id is determinated via | |
14 * the stack pointer value. | |
15 * | |
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 and to wake up | |
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 | |
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. | |
23 * | |
24 * The condition variable implementation uses signal #64. The signal handler | |
25 * is SIG_IGN so the kill() is a cheap syscall. The thread waits a signal | |
26 * in kevent(). The use of the EVFILT_SIGNAL is safe since FreeBSD 4.7. | |
27 * | |
28 * This threads implementation currently works on i386 (486+) and amd64 | |
29 * platforms only. | |
30 */ | |
31 | |
32 | |
33 char *ngx_freebsd_kern_usrstack; | |
34 size_t ngx_thread_stack_size; | |
35 | |
36 | |
37 static size_t rz_size; | |
38 static size_t usable_stack_size; | |
39 static char *last_stack; | |
40 | |
41 static ngx_uint_t nthreads; | |
42 static ngx_uint_t max_threads; | |
43 | |
44 static ngx_uint_t nkeys; | |
45 static ngx_tid_t *tids; /* the threads tids array */ | |
46 void **ngx_tls; /* the threads tls's array */ | |
47 | |
48 /* the thread-safe libc errno */ | |
49 | |
50 static int errno0; /* the main thread's errno */ | |
51 static int *errnos; /* the threads errno's array */ | |
52 | |
53 int *__error() | |
54 { | |
55 int tid; | |
56 | |
57 tid = ngx_gettid(); | |
58 | |
59 return tid ? &errnos[tid - 1] : &errno0; | |
60 } | |
61 | |
62 | |
63 /* | |
64 * __isthreaded enables the spinlocks in some libc functions, i.e. in malloc() | |
65 * and some other places. Nevertheless we protect our malloc()/free() calls | |
66 * by own mutex that is more efficient than the spinlock. | |
67 * | |
68 * _spinlock() is a weak referenced stub in src/lib/libc/gen/_spinlock_stub.c | |
69 * that does nothing. | |
70 */ | |
71 | |
72 extern int __isthreaded; | |
73 | |
74 void _spinlock(ngx_atomic_t *lock) | |
75 { | |
76 ngx_int_t tries; | |
77 | |
78 tries = 0; | |
79 | |
80 for ( ;; ) { | |
81 | |
82 if (*lock) { | |
83 if (ngx_ncpu > 1 && tries++ < 1000) { | |
84 continue; | |
85 } | |
86 | |
87 sched_yield(); | |
88 tries = 0; | |
89 | |
90 } else { | |
91 if (ngx_atomic_cmp_set(lock, 0, 1)) { | |
92 return; | |
93 } | |
94 } | |
95 } | |
96 } | |
97 | |
98 | |
99 /* | |
100 * Before FreeBSD 5.1 _spinunlock() is a simple #define in | |
101 * src/lib/libc/include/spinlock.h that zeroes lock. | |
102 * | |
103 * Since FreeBSD 5.1 _spinunlock() is a weak referenced stub in | |
104 * src/lib/libc/gen/_spinlock_stub.c that does nothing. | |
105 */ | |
106 | |
107 #ifndef _spinunlock | |
108 | |
109 void _spinunlock(ngx_atomic_t *lock) | |
110 { | |
111 *lock = 0; | |
112 } | |
113 | |
114 #endif | |
115 | |
116 | |
117 int ngx_create_thread(ngx_tid_t *tid, void* (*func)(void *arg), void *arg, | |
118 ngx_log_t *log) | |
119 { | |
120 int id, err; | |
121 char *stack, *stack_top; | |
122 | |
123 if (nthreads >= max_threads) { | |
124 ngx_log_error(NGX_LOG_CRIT, log, 0, | |
125 "no more than %d threads can be created", max_threads); | |
126 return NGX_ERROR; | |
127 } | |
128 | |
129 last_stack -= ngx_thread_stack_size; | |
130 | |
131 stack = mmap(last_stack, usable_stack_size, PROT_READ|PROT_WRITE, | |
132 MAP_STACK, -1, 0); | |
133 | |
134 if (stack == MAP_FAILED) { | |
135 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, | |
136 "mmap(" PTR_FMT ":" SIZE_T_FMT | |
137 ", MAP_STACK) thread stack failed", | |
138 last_stack, usable_stack_size); | |
139 return NGX_ERROR; | |
140 } | |
141 | |
142 if (stack != last_stack) { | |
143 ngx_log_error(NGX_LOG_ALERT, log, 0, "stack address was changed"); | |
144 } | |
145 | |
146 stack_top = stack + usable_stack_size; | |
147 | |
148 ngx_log_debug2(NGX_LOG_DEBUG_CORE, log, 0, | |
149 "thread stack: " PTR_FMT "-" PTR_FMT, stack, stack_top); | |
150 | |
151 ngx_set_errno(0); | |
152 | |
153 id = rfork_thread(RFPROC|RFTHREAD|RFMEM, stack_top, | |
154 (ngx_rfork_thread_func_pt) func, arg); | |
155 | |
156 err = ngx_errno; | |
157 | |
158 if (id == -1) { | |
159 ngx_log_error(NGX_LOG_ALERT, log, err, "rfork() failed"); | |
160 | |
161 } else { | |
162 *tid = id; | |
163 nthreads = (ngx_freebsd_kern_usrstack - stack_top) | |
164 / ngx_thread_stack_size; | |
165 tids[nthreads] = id; | |
166 | |
167 ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0, "rfork()ed thread: %d", id); | |
168 } | |
169 | |
170 return err; | |
171 } | |
172 | |
173 | |
174 ngx_int_t ngx_init_threads(int n, size_t size, ngx_cycle_t *cycle) | |
175 { | |
176 char *red_zone, *zone; | |
177 size_t len; | |
178 ngx_int_t i; | |
179 struct sigaction sa; | |
180 | |
181 max_threads = n + 1; | |
182 | |
183 for (i = 0; i < n; i++) { | |
184 ngx_memzero(&sa, sizeof(struct sigaction)); | |
185 sa.sa_handler = SIG_IGN; | |
186 sigemptyset(&sa.sa_mask); | |
187 if (sigaction(NGX_CV_SIGNAL, &sa, NULL) == -1) { | |
188 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, | |
189 "sigaction(%d, SIG_IGN) failed", NGX_CV_SIGNAL); | |
190 return NGX_ERROR; | |
191 } | |
192 } | |
193 | |
194 len = sizeof(ngx_freebsd_kern_usrstack); | |
195 if (sysctlbyname("kern.usrstack", &ngx_freebsd_kern_usrstack, &len, | |
196 NULL, 0) == -1) | |
197 { | |
198 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, | |
199 "sysctlbyname(kern.usrstack) failed"); | |
200 return NGX_ERROR; | |
201 } | |
202 | |
203 /* the main thread stack red zone */ | |
204 rz_size = ngx_pagesize; | |
205 red_zone = ngx_freebsd_kern_usrstack - (size + rz_size); | |
206 | |
207 ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0, | |
208 "usrstack: " PTR_FMT " red zone: " PTR_FMT, | |
209 ngx_freebsd_kern_usrstack, red_zone); | |
210 | |
211 zone = mmap(red_zone, rz_size, PROT_NONE, MAP_ANON, -1, 0); | |
212 if (zone == MAP_FAILED) { | |
213 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, | |
214 "mmap(" PTR_FMT ":" SIZE_T_FMT | |
215 ", PROT_NONE, MAP_ANON) red zone failed", | |
216 red_zone, rz_size); | |
217 return NGX_ERROR; | |
218 } | |
219 | |
220 if (zone != red_zone) { | |
221 ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, | |
222 "red zone address was changed"); | |
223 } | |
224 | |
225 /* create the threads errno's array */ | |
226 | |
227 if (!(errnos = ngx_calloc(n * sizeof(int), cycle->log))) { | |
228 return NGX_ERROR; | |
229 } | |
230 | |
231 /* create the threads tids array */ | |
232 | |
233 if (!(tids = ngx_calloc((n + 1) * sizeof(ngx_tid_t), cycle->log))) { | |
234 return NGX_ERROR; | |
235 } | |
236 | |
237 tids[0] = ngx_pid; | |
238 | |
239 /* create the threads tls's array */ | |
240 | |
241 ngx_tls = ngx_calloc(NGX_THREAD_KEYS_MAX * (n + 1) * sizeof(void *), | |
242 cycle->log); | |
243 if (ngx_tls == NULL) { | |
244 return NGX_ERROR; | |
245 } | |
246 | |
247 nthreads = 1; | |
248 | |
249 last_stack = zone + rz_size; | |
250 usable_stack_size = size; | |
251 ngx_thread_stack_size = size + rz_size; | |
252 | |
253 /* allow the spinlock in libc malloc() */ | |
254 __isthreaded = 1; | |
255 | |
256 ngx_threaded = 1; | |
257 | |
258 return NGX_OK; | |
259 } | |
260 | |
261 | |
262 ngx_tid_t ngx_thread_self() | |
263 { | |
264 int tid; | |
265 ngx_tid_t pid; | |
266 | |
267 tid = ngx_gettid(); | |
268 | |
269 if (tids == NULL) { | |
270 return ngx_pid; | |
271 } | |
272 | |
273 return tids[tid]; | |
274 } | |
275 | |
276 | |
277 ngx_int_t ngx_thread_key_create(ngx_tls_key_t *key) | |
278 { | |
279 if (nkeys >= NGX_THREAD_KEYS_MAX) { | |
280 return NGX_ENOMEM; | |
281 } | |
282 | |
283 *key = nkeys++; | |
284 | |
285 return 0; | |
286 } | |
287 | |
288 | |
289 ngx_int_t ngx_thread_set_tls(ngx_tls_key_t key, void *value) | |
290 { | |
291 if (key >= NGX_THREAD_KEYS_MAX) { | |
292 return NGX_EINVAL; | |
293 } | |
294 | |
295 ngx_tls[key * NGX_THREAD_KEYS_MAX + ngx_gettid()] = value; | |
296 return 0; | |
297 } | |
298 | |
299 | |
300 ngx_mutex_t *ngx_mutex_init(ngx_log_t *log, uint flags) | |
301 { | |
302 ngx_mutex_t *m; | |
303 union semun op; | |
304 | |
305 if (!(m = ngx_alloc(sizeof(ngx_mutex_t), log))) { | |
306 return NULL; | |
307 } | |
308 | |
309 m->lock = 0; | |
310 m->log = log; | |
311 | |
312 if (flags & NGX_MUTEX_LIGHT) { | |
313 m->semid = -1; | |
314 return m; | |
315 } | |
316 | |
317 m->semid = semget(IPC_PRIVATE, 1, SEM_R|SEM_A); | |
318 if (m->semid == -1) { | |
319 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, "semget() failed"); | |
320 return NULL; | |
321 } | |
322 | |
323 op.val = 0; | |
324 | |
325 if (semctl(m->semid, 0, SETVAL, op) == -1) { | |
326 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, "semctl(SETVAL) failed"); | |
327 | |
328 if (semctl(m->semid, 0, IPC_RMID) == -1) { | |
329 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, | |
330 "semctl(IPC_RMID) failed"); | |
331 } | |
332 | |
333 return NULL; | |
334 } | |
335 | |
336 return m; | |
337 } | |
338 | |
339 | |
340 void ngx_mutex_destroy(ngx_mutex_t *m) | |
341 { | |
342 if (semctl(m->semid, 0, IPC_RMID) == -1) { | |
343 ngx_log_error(NGX_LOG_ALERT, m->log, ngx_errno, | |
344 "semctl(IPC_RMID) failed"); | |
345 } | |
346 | |
347 ngx_free((void *) m); | |
348 } | |
349 | |
350 | |
351 ngx_int_t ngx_mutex_dolock(ngx_mutex_t *m, ngx_int_t try) | |
352 { | |
353 uint32_t lock, new, old; | |
354 ngx_uint_t tries; | |
355 struct sembuf op; | |
356 | |
357 if (!ngx_threaded) { | |
358 return NGX_OK; | |
359 } | |
360 | |
361 #if (NGX_DEBUG) | |
362 if (try) { | |
363 ngx_log_debug2(NGX_LOG_DEBUG_MUTEX, m->log, 0, | |
364 "try lock mutex " PTR_FMT " lock:%X", m, m->lock); | |
365 } else { | |
366 ngx_log_debug2(NGX_LOG_DEBUG_MUTEX, m->log, 0, | |
367 "lock mutex " PTR_FMT " lock:%X", m, m->lock); | |
368 } | |
369 #endif | |
370 | |
371 old = m->lock; | |
372 tries = 0; | |
373 | |
374 for ( ;; ) { | |
375 if (old & NGX_MUTEX_LOCK_BUSY) { | |
376 | |
377 if (try) { | |
378 return NGX_AGAIN; | |
379 } | |
380 | |
381 if (ngx_freebsd_hw_ncpu > 1 && tries++ < 1000) { | |
382 | |
383 /* the spinlock is used only on the SMP system */ | |
384 | |
385 old = m->lock; | |
386 continue; | |
387 } | |
388 | |
389 if (m->semid == -1) { | |
390 sched_yield(); | |
391 | |
392 tries = 0; | |
393 old = m->lock; | |
394 continue; | |
395 } | |
396 | |
397 ngx_log_debug2(NGX_LOG_DEBUG_MUTEX, m->log, 0, | |
398 "mutex " PTR_FMT " lock:%X", m, m->lock); | |
399 | |
400 /* | |
401 * The mutex is locked so we increase a number | |
402 * of the threads that are waiting on the mutex | |
403 */ | |
404 | |
405 lock = old + 1; | |
406 | |
407 if ((lock & ~NGX_MUTEX_LOCK_BUSY) > nthreads) { | |
408 ngx_log_error(NGX_LOG_ALERT, m->log, ngx_errno, | |
409 "%d threads wait for mutex " PTR_FMT | |
410 ", while only %d threads are available", | |
411 lock & ~NGX_MUTEX_LOCK_BUSY, m, nthreads); | |
412 return NGX_ERROR; | |
413 } | |
414 | |
415 if (ngx_atomic_cmp_set(&m->lock, old, lock)) { | |
416 | |
417 ngx_log_debug2(NGX_LOG_DEBUG_MUTEX, m->log, 0, | |
418 "wait mutex " PTR_FMT " lock:%X", m, m->lock); | |
419 | |
420 /* | |
421 * The number of the waiting threads has been increased | |
422 * and we would wait on the SysV semaphore. | |
423 * A semaphore should wake up us more efficiently than | |
424 * a simple sched_yield() or usleep(). | |
425 */ | |
426 | |
427 op.sem_num = 0; | |
428 op.sem_op = -1; | |
429 op.sem_flg = 0; | |
430 | |
431 if (semop(m->semid, &op, 1) == -1) { | |
432 ngx_log_error(NGX_LOG_ALERT, m->log, ngx_errno, | |
433 "semop() failed while waiting " | |
434 "on mutex " PTR_FMT, m); | |
435 return NGX_ERROR; | |
436 } | |
437 | |
438 ngx_log_debug2(NGX_LOG_DEBUG_MUTEX, m->log, 0, | |
439 "mutex waked up " PTR_FMT " lock:%X", | |
440 m, m->lock); | |
441 | |
442 tries = 0; | |
443 old = m->lock; | |
444 continue; | |
445 } | |
446 | |
447 old = m->lock; | |
448 | |
449 } else { | |
450 lock = old | NGX_MUTEX_LOCK_BUSY; | |
451 | |
452 if (ngx_atomic_cmp_set(&m->lock, old, lock)) { | |
453 | |
454 /* we locked the mutex */ | |
455 | |
456 break; | |
457 } | |
458 | |
459 old = m->lock; | |
460 } | |
461 | |
462 if (tries++ > 1000) { | |
463 | |
464 ngx_log_debug1(NGX_LOG_DEBUG_MUTEX, m->log, 0, | |
465 "mutex " PTR_FMT " is contested", m); | |
466 | |
467 /* the mutex is probably contested so we are giving up now */ | |
468 | |
469 sched_yield(); | |
470 | |
471 tries = 0; | |
472 old = m->lock; | |
473 } | |
474 } | |
475 | |
476 ngx_log_debug2(NGX_LOG_DEBUG_MUTEX, m->log, 0, | |
477 "mutex " PTR_FMT " is locked, lock:%X", m, m->lock); | |
478 | |
479 return NGX_OK; | |
480 } | |
481 | |
482 | |
483 ngx_int_t ngx_mutex_unlock(ngx_mutex_t *m) | |
484 { | |
485 uint32_t lock, new, old; | |
486 struct sembuf op; | |
487 | |
488 if (!ngx_threaded) { | |
489 return NGX_OK; | |
490 } | |
491 | |
492 old = m->lock; | |
493 | |
494 if (!(old & NGX_MUTEX_LOCK_BUSY)) { | |
495 ngx_log_error(NGX_LOG_ALERT, m->log, 0, | |
496 "trying to unlock the free mutex " PTR_FMT, m); | |
497 return NGX_ERROR; | |
498 } | |
499 | |
500 /* free the mutex */ | |
501 | |
502 #if 0 | |
503 ngx_log_debug2(NGX_LOG_DEBUG_MUTEX, m->log, 0, | |
504 "unlock mutex " PTR_FMT " lock:%X", m, old); | |
505 #endif | |
506 | |
507 for ( ;; ) { | |
508 lock = old & ~NGX_MUTEX_LOCK_BUSY; | |
509 | |
510 if (ngx_atomic_cmp_set(&m->lock, old, lock)) { | |
511 break; | |
512 } | |
513 | |
514 old = m->lock; | |
515 } | |
516 | |
517 if (m->semid == -1) { | |
518 ngx_log_debug1(NGX_LOG_DEBUG_MUTEX, m->log, 0, | |
519 "mutex " PTR_FMT " is unlocked", m); | |
520 | |
521 return NGX_OK; | |
522 } | |
523 | |
524 /* check whether we need to wake up a waiting thread */ | |
525 | |
526 old = m->lock; | |
527 | |
528 for ( ;; ) { | |
529 if (old & NGX_MUTEX_LOCK_BUSY) { | |
530 | |
531 /* the mutex is just locked by another thread */ | |
532 | |
533 break; | |
534 } | |
535 | |
536 if (old == 0) { | |
537 break; | |
538 } | |
539 | |
540 /* there are the waiting threads */ | |
541 | |
542 lock = old - 1; | |
543 | |
544 if (ngx_atomic_cmp_set(&m->lock, old, lock)) { | |
545 | |
546 /* wake up the thread that waits on semaphore */ | |
547 | |
548 ngx_log_debug1(NGX_LOG_DEBUG_MUTEX, m->log, 0, | |
549 "wake up mutex " PTR_FMT "", m); | |
550 | |
551 op.sem_num = 0; | |
552 op.sem_op = 1; | |
553 op.sem_flg = 0; | |
554 | |
555 if (semop(m->semid, &op, 1) == -1) { | |
556 ngx_log_error(NGX_LOG_ALERT, m->log, ngx_errno, | |
557 "semop() failed while waking up on mutex " | |
558 PTR_FMT, m); | |
559 return NGX_ERROR; | |
560 } | |
561 | |
562 break; | |
563 } | |
564 | |
565 old = m->lock; | |
566 } | |
567 | |
568 ngx_log_debug1(NGX_LOG_DEBUG_MUTEX, m->log, 0, | |
569 "mutex " PTR_FMT " is unlocked", m); | |
570 | |
571 return NGX_OK; | |
572 } | |
573 | |
574 | |
575 ngx_cond_t *ngx_cond_init(ngx_log_t *log) | |
576 { | |
577 ngx_cond_t *cv; | |
578 | |
579 if (!(cv = ngx_alloc(sizeof(ngx_cond_t), log))) { | |
580 return NULL; | |
581 } | |
582 | |
583 cv->signo = NGX_CV_SIGNAL; | |
584 cv->tid = 0; | |
585 cv->log = log; | |
586 cv->kq = -1; | |
587 | |
588 return cv; | |
589 } | |
590 | |
591 | |
592 void ngx_cond_destroy(ngx_cond_t *cv) | |
593 { | |
594 if (close(cv->kq) == -1) { | |
595 ngx_log_error(NGX_LOG_ALERT, cv->log, ngx_errno, | |
596 "kqueue close() failed"); | |
597 } | |
598 | |
599 ngx_free(cv); | |
600 } | |
601 | |
602 | |
603 ngx_int_t ngx_cond_wait(ngx_cond_t *cv, ngx_mutex_t *m) | |
604 { | |
605 int n; | |
606 ngx_err_t err; | |
607 struct kevent kev; | |
608 struct timespec ts; | |
609 | |
610 if (cv->kq == -1) { | |
611 | |
612 /* | |
613 * We have to add the EVFILT_SIGNAL filter in the rfork()ed thread. | |
614 * Otherwise the thread would not get a signal event. | |
615 * | |
616 * However, we have not to open the kqueue in the thread, | |
617 * it is simply handy do it together. | |
618 */ | |
619 | |
620 cv->kq = kqueue(); | |
621 if (cv->kq == -1) { | |
622 ngx_log_error(NGX_LOG_ALERT, cv->log, ngx_errno, "kqueue() failed"); | |
623 return NGX_ERROR; | |
624 } | |
625 | |
626 ngx_log_debug2(NGX_LOG_DEBUG_CORE, cv->log, 0, | |
627 "cv kq:%d signo:%d", cv->kq, cv->signo); | |
628 | |
629 kev.ident = cv->signo; | |
630 kev.filter = EVFILT_SIGNAL; | |
631 kev.flags = EV_ADD; | |
632 kev.fflags = 0; | |
633 kev.data = 0; | |
634 kev.udata = NULL; | |
635 | |
636 ts.tv_sec = 0; | |
637 ts.tv_nsec = 0; | |
638 | |
639 if (kevent(cv->kq, &kev, 1, NULL, 0, &ts) == -1) { | |
640 ngx_log_error(NGX_LOG_ALERT, cv->log, ngx_errno, "kevent() failed"); | |
641 return NGX_ERROR; | |
642 } | |
643 } | |
644 | |
645 if (ngx_mutex_unlock(m) == NGX_ERROR) { | |
646 return NGX_ERROR; | |
647 } | |
648 | |
649 ngx_log_debug3(NGX_LOG_DEBUG_CORE, cv->log, 0, | |
650 "cv " PTR_FMT " wait, kq:%d, signo:%d", | |
651 cv, cv->kq, cv->signo); | |
652 | |
653 for ( ;; ) { | |
654 n = kevent(cv->kq, NULL, 0, &kev, 1, NULL); | |
655 | |
656 ngx_log_debug2(NGX_LOG_DEBUG_CORE, cv->log, 0, | |
657 "cv " PTR_FMT " kevent: %d", cv, n); | |
658 | |
659 if (n == -1) { | |
660 err = ngx_errno; | |
661 ngx_log_error((err == NGX_EINTR) ? NGX_LOG_INFO : NGX_LOG_ALERT, | |
662 cv->log, ngx_errno, | |
663 "kevent() failed while waiting condition variable " | |
664 PTR_FMT, cv); | |
665 | |
666 if (err == NGX_EINTR) { | |
667 break; | |
668 } | |
669 | |
670 return NGX_ERROR; | |
671 } | |
672 | |
673 if (n == 0) { | |
674 ngx_log_error(NGX_LOG_ALERT, cv->log, 0, | |
675 "kevent() returned no events " | |
676 "while waiting condition variable " PTR_FMT, | |
677 cv); | |
678 continue; | |
679 } | |
680 | |
681 if (kev.filter != EVFILT_SIGNAL) { | |
682 ngx_log_error(NGX_LOG_ALERT, cv->log, 0, | |
683 "kevent() returned unexpected events: %d " | |
684 "while waiting condition variable " PTR_FMT, | |
685 kev.filter, cv); | |
686 continue; | |
687 } | |
688 | |
689 if (kev.ident != (uintptr_t) cv->signo) { | |
690 ngx_log_error(NGX_LOG_ALERT, cv->log, 0, | |
691 "kevent() returned unexpected signal: %d ", | |
692 "while waiting condition variable " PTR_FMT, | |
693 kev.ident, cv); | |
694 continue; | |
695 } | |
696 | |
697 break; | |
698 } | |
699 | |
700 ngx_log_debug1(NGX_LOG_DEBUG_CORE, cv->log, 0, | |
701 "cv " PTR_FMT " is waked up", cv); | |
702 | |
703 if (ngx_mutex_lock(m) == NGX_ERROR) { | |
704 return NGX_ERROR; | |
705 } | |
706 | |
707 return NGX_OK; | |
708 } | |
709 | |
710 | |
711 ngx_int_t ngx_cond_signal(ngx_cond_t *cv) | |
712 { | |
713 ngx_err_t err; | |
714 | |
715 ngx_log_debug3(NGX_LOG_DEBUG_CORE, cv->log, 0, | |
716 "cv " PTR_FMT " to signal " PID_T_FMT " %d", | |
717 cv, cv->tid, cv->signo); | |
718 | |
719 if (kill(cv->tid, cv->signo) == -1) { | |
720 | |
721 err = ngx_errno; | |
722 | |
723 ngx_log_error(NGX_LOG_ALERT, cv->log, err, | |
724 "kill() failed while signaling condition variable " | |
725 PTR_FMT, cv); | |
726 | |
727 if (err == NGX_ESRCH) { | |
728 cv->tid = -1; | |
729 } | |
730 | |
731 return NGX_ERROR; | |
732 } | |
733 | |
734 ngx_log_debug1(NGX_LOG_DEBUG_CORE, cv->log, 0, | |
735 "cv " PTR_FMT " is signaled", cv); | |
736 | |
737 return NGX_OK; | |
738 } |