Mercurial > hg > nginx
comparison src/os/unix/ngx_freebsd_rfork_thread.c @ 267:83205e0b5522
nginx-0.0.2-2004-02-24-20:31:46 import
author | Igor Sysoev <igor@sysoev.ru> |
---|---|
date | Tue, 24 Feb 2004 17:31:46 +0000 |
parents | 5238e93961a1 |
children | 7bb9562216ce |
comparison
equal
deleted
inserted
replaced
266:5238e93961a1 | 267:83205e0b5522 |
---|---|
13 * the waiting threads. | 13 * the waiting threads. |
14 * | 14 * |
15 * The condition variable implementation uses the SysV semaphore set of two | 15 * The condition variable implementation uses the SysV semaphore set of two |
16 * semaphores. The first is used by the CV mutex, and the second is used | 16 * semaphores. The first is used by the CV mutex, and the second is used |
17 * by CV itself. | 17 * by CV itself. |
18 * | |
19 * This threads implementation currently works on i486 and amd64 | |
20 * platforms only. | |
18 */ | 21 */ |
19 | |
20 | |
21 extern int __isthreaded; | |
22 | 22 |
23 | 23 |
24 static inline int ngx_gettid(); | 24 static inline int ngx_gettid(); |
25 | 25 |
26 | 26 |
34 static ngx_uint_t nthreads; | 34 static ngx_uint_t nthreads; |
35 static ngx_uint_t max_threads; | 35 static ngx_uint_t max_threads; |
36 static ngx_tid_t *tids; /* the threads tids array */ | 36 static ngx_tid_t *tids; /* the threads tids array */ |
37 | 37 |
38 | 38 |
39 /* the thread-safe errno */ | 39 /* the thread-safe libc errno */ |
40 | 40 |
41 static int errno0; /* the main thread's errno */ | 41 static int errno0; /* the main thread's errno */ |
42 static int *errnos; /* the threads errno's array */ | 42 static int *errnos; /* the threads errno's array */ |
43 | 43 |
44 int *__error() | 44 int *__error() |
46 int tid; | 46 int tid; |
47 | 47 |
48 tid = ngx_gettid(); | 48 tid = ngx_gettid(); |
49 | 49 |
50 return tid ? &errnos[tid - 1] : &errno0; | 50 return tid ? &errnos[tid - 1] : &errno0; |
51 } | |
52 | |
53 | |
54 /* | |
55 * __isthreaded enables spinlock() in some libc functions, i.e. in malloc() | |
56 * and some other places. Nevertheless we protect our malloc()/free() calls | |
57 * by own mutex that is more efficient than the spinlock. | |
58 * | |
59 * We define own _spinlock() because a weak referenced _spinlock() stub in | |
60 * src/lib/libc/gen/_spinlock_stub.c does nothing. | |
61 */ | |
62 | |
63 extern int __isthreaded; | |
64 | |
65 void _spinlock(ngx_atomic_t *lock) | |
66 { | |
67 ngx_int_t tries; | |
68 | |
69 tries = 0; | |
70 for ( ;; ) { | |
71 | |
72 if (*lock) { | |
73 if (ngx_freebsd_hw_ncpu > 1 && tries++ < 1000) { | |
74 continue; | |
75 } | |
76 | |
77 sched_yield(); | |
78 tries = 0; | |
79 | |
80 } else { | |
81 if (ngx_atomic_cmp_set(lock, 0, 1)) { | |
82 return; | |
83 } | |
84 } | |
85 } | |
51 } | 86 } |
52 | 87 |
53 | 88 |
54 int ngx_create_thread(ngx_tid_t *tid, int (*func)(void *arg), void *arg, | 89 int ngx_create_thread(ngx_tid_t *tid, int (*func)(void *arg), void *arg, |
55 ngx_log_t *log) | 90 ngx_log_t *log) |
68 stack = mmap(last_stack, usable_stack_size, PROT_READ|PROT_WRITE, | 103 stack = mmap(last_stack, usable_stack_size, PROT_READ|PROT_WRITE, |
69 MAP_STACK, -1, 0); | 104 MAP_STACK, -1, 0); |
70 | 105 |
71 if (stack == MAP_FAILED) { | 106 if (stack == MAP_FAILED) { |
72 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, | 107 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, |
73 "mmap(%08X:%d, MAP_STACK) thread stack failed", | 108 "mmap(" PTR_FMT ":" SIZE_T_FMT |
109 ", MAP_STACK) thread stack failed", | |
74 last_stack, usable_stack_size); | 110 last_stack, usable_stack_size); |
75 return NGX_ERROR; | 111 return NGX_ERROR; |
76 } | 112 } |
77 | 113 |
78 if (stack != last_stack) { | 114 if (stack != last_stack) { |
80 } | 116 } |
81 | 117 |
82 stack_top = stack + usable_stack_size; | 118 stack_top = stack + usable_stack_size; |
83 | 119 |
84 ngx_log_debug2(NGX_LOG_DEBUG_CORE, log, 0, | 120 ngx_log_debug2(NGX_LOG_DEBUG_CORE, log, 0, |
85 "thread stack: %08X-%08X", stack, stack_top); | 121 "thread stack: " PTR_FMT "-" PTR_FMT, stack, stack_top); |
86 | 122 |
87 #if 1 | 123 #if 1 |
88 id = rfork_thread(RFPROC|RFTHREAD|RFMEM, stack_top, func, arg); | 124 id = rfork_thread(RFPROC|RFTHREAD|RFMEM, stack_top, func, arg); |
89 #elif 1 | 125 #elif 1 |
90 id = rfork_thread(RFPROC|RFMEM, stack_top, func, arg); | 126 id = rfork_thread(RFPROC|RFMEM, stack_top, func, arg); |
111 } | 147 } |
112 | 148 |
113 | 149 |
114 ngx_int_t ngx_init_threads(int n, size_t size, ngx_log_t *log) | 150 ngx_int_t ngx_init_threads(int n, size_t size, ngx_log_t *log) |
115 { | 151 { |
116 int len; | 152 size_t len; |
117 char *red_zone, *zone; | 153 char *red_zone, *zone; |
118 | 154 |
119 max_threads = n; | 155 max_threads = n; |
120 | 156 |
121 len = 4; | 157 len = sizeof(usrstack); |
122 if (sysctlbyname("kern.usrstack", &usrstack, &len, NULL, 0) == -1) { | 158 if (sysctlbyname("kern.usrstack", &usrstack, &len, NULL, 0) == -1) { |
123 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, | 159 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, |
124 "sysctlbyname(kern.usrstack) failed"); | 160 "sysctlbyname(kern.usrstack) failed"); |
125 return NGX_ERROR; | 161 return NGX_ERROR; |
126 } | 162 } |
127 | 163 |
128 /* the main thread stack red zone */ | 164 /* the main thread stack red zone */ |
129 red_zone = usrstack - (size + rz_size); | 165 red_zone = usrstack - (size + rz_size); |
130 | 166 |
131 ngx_log_debug2(NGX_LOG_DEBUG_CORE, log, 0, | 167 ngx_log_debug2(NGX_LOG_DEBUG_CORE, log, 0, |
132 "usrstack: %08X, red zone: %08X", usrstack, red_zone); | 168 "usrstack: " PTR_FMT " red zone: " PTR_FMT, |
169 usrstack, red_zone); | |
133 | 170 |
134 zone = mmap(red_zone, rz_size, PROT_NONE, MAP_ANON, -1, 0); | 171 zone = mmap(red_zone, rz_size, PROT_NONE, MAP_ANON, -1, 0); |
135 if (zone == MAP_FAILED) { | 172 if (zone == MAP_FAILED) { |
136 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, | 173 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, |
137 "mmap(%08X:%d, PROT_NONE, MAP_ANON) red zone failed", | 174 "mmap(" PTR_FMT ":" SIZE_T_FMT |
175 ", PROT_NONE, MAP_ANON) red zone failed", | |
138 red_zone, rz_size); | 176 red_zone, rz_size); |
139 return NGX_ERROR; | 177 return NGX_ERROR; |
140 } | 178 } |
141 | 179 |
142 if (zone != red_zone) { | 180 if (zone != red_zone) { |
175 | 213 |
176 if (stack_size == 0) { | 214 if (stack_size == 0) { |
177 return 0; | 215 return 0; |
178 } | 216 } |
179 | 217 |
180 __asm__ ("mov %%esp, %0" : "=q" (sp)); | 218 #if ( __i386__ ) |
219 | |
220 __asm__ volatile ("mov %%esp, %0" : "=q" (sp)); | |
221 | |
222 #elif ( __amd64__ ) | |
223 | |
224 __asm__ volatile ("mov %%rsp, %0" : "=q" (sp)); | |
225 | |
226 #endif | |
181 | 227 |
182 return (usrstack - sp) / stack_size; | 228 return (usrstack - sp) / stack_size; |
183 } | 229 } |
184 | 230 |
185 | 231 |
256 if (semctl(m->semid, 0, IPC_RMID) == -1) { | 302 if (semctl(m->semid, 0, IPC_RMID) == -1) { |
257 ngx_log_error(NGX_LOG_ALERT, m->log, ngx_errno, | 303 ngx_log_error(NGX_LOG_ALERT, m->log, ngx_errno, |
258 "semctl(IPC_RMID) failed"); | 304 "semctl(IPC_RMID) failed"); |
259 } | 305 } |
260 | 306 |
261 ngx_free(m); | 307 ngx_free((void *) m); |
262 } | 308 } |
263 | 309 |
264 | 310 |
265 ngx_int_t ngx_mutex_do_lock(ngx_mutex_t *m, ngx_int_t try) | 311 ngx_int_t ngx_mutex_do_lock(ngx_mutex_t *m, ngx_int_t try) |
266 { | 312 { |
269 struct sembuf op; | 315 struct sembuf op; |
270 | 316 |
271 #if (NGX_DEBUG) | 317 #if (NGX_DEBUG) |
272 if (try) { | 318 if (try) { |
273 ngx_log_debug2(NGX_LOG_DEBUG_CORE, m->log, 0, | 319 ngx_log_debug2(NGX_LOG_DEBUG_CORE, m->log, 0, |
274 "try lock mutex %08X lock:%X", m, m->lock); | 320 "try lock mutex " PTR_FMT " lock:%X", m, m->lock); |
275 } else { | 321 } else { |
276 ngx_log_debug2(NGX_LOG_DEBUG_CORE, m->log, 0, | 322 ngx_log_debug2(NGX_LOG_DEBUG_CORE, m->log, 0, |
277 "lock mutex %08X lock:%X", m, m->lock); | 323 "lock mutex " PTR_FMT " lock:%X", m, m->lock); |
278 } | 324 } |
279 #endif | 325 #endif |
280 | 326 |
281 old = m->lock; | 327 old = m->lock; |
282 tries = 0; | 328 tries = 0; |
303 old = m->lock; | 349 old = m->lock; |
304 continue; | 350 continue; |
305 } | 351 } |
306 | 352 |
307 ngx_log_debug2(NGX_LOG_DEBUG_CORE, m->log, 0, | 353 ngx_log_debug2(NGX_LOG_DEBUG_CORE, m->log, 0, |
308 "mutex %08X lock:%X", m, m->lock); | 354 "mutex " PTR_FMT " lock:%X", m, m->lock); |
309 | 355 |
310 /* | 356 /* |
311 * The mutex is locked so we increase a number | 357 * The mutex is locked so we increase a number |
312 * of the threads that are waiting on the mutex | 358 * of the threads that are waiting on the mutex |
313 */ | 359 */ |
314 | 360 |
315 lock = old + 1; | 361 lock = old + 1; |
316 | 362 |
317 if ((lock & ~NGX_MUTEX_LOCK_BUSY) > nthreads) { | 363 if ((lock & ~NGX_MUTEX_LOCK_BUSY) > nthreads) { |
318 ngx_log_error(NGX_LOG_ALERT, m->log, ngx_errno, | 364 ngx_log_error(NGX_LOG_ALERT, m->log, ngx_errno, |
319 "%d threads wait for mutex %0X, " | 365 "%d threads wait for mutex " PTR_FMT |
320 "while only %d threads are available", | 366 ", while only %d threads are available", |
321 lock & ~NGX_MUTEX_LOCK_BUSY, m, nthreads); | 367 lock & ~NGX_MUTEX_LOCK_BUSY, m, nthreads); |
322 return NGX_ERROR; | 368 return NGX_ERROR; |
323 } | 369 } |
324 | 370 |
325 if (ngx_atomic_cmp_set(&m->lock, old, lock)) { | 371 if (ngx_atomic_cmp_set(&m->lock, old, lock)) { |
326 | 372 |
327 ngx_log_debug2(NGX_LOG_DEBUG_CORE, m->log, 0, | 373 ngx_log_debug2(NGX_LOG_DEBUG_CORE, m->log, 0, |
328 "wait mutex %08X lock:%X", m, m->lock); | 374 "wait mutex " PTR_FMT " lock:%X", m, m->lock); |
329 | 375 |
330 /* | 376 /* |
331 * The number of the waiting threads has been increased | 377 * The number of the waiting threads has been increased |
332 * and we would wait on the SysV semaphore. | 378 * and we would wait on the SysV semaphore. |
333 * A semaphore should wake up us more efficiently than | 379 * A semaphore should wake up us more efficiently than |
339 op.sem_flg = SEM_UNDO; | 385 op.sem_flg = SEM_UNDO; |
340 | 386 |
341 if (semop(m->semid, &op, 1) == -1) { | 387 if (semop(m->semid, &op, 1) == -1) { |
342 ngx_log_error(NGX_LOG_ALERT, m->log, ngx_errno, | 388 ngx_log_error(NGX_LOG_ALERT, m->log, ngx_errno, |
343 "semop() failed while waiting " | 389 "semop() failed while waiting " |
344 "on mutex %08X", m); | 390 "on mutex " PTR_FMT, m); |
345 return NGX_ERROR; | 391 return NGX_ERROR; |
346 } | 392 } |
347 | 393 |
348 tries = 0; | 394 tries = 0; |
349 old = m->lock; | 395 old = m->lock; |
366 } | 412 } |
367 | 413 |
368 if (tries++ > 1000) { | 414 if (tries++ > 1000) { |
369 | 415 |
370 ngx_log_debug1(NGX_LOG_DEBUG_CORE, m->log, 0, | 416 ngx_log_debug1(NGX_LOG_DEBUG_CORE, m->log, 0, |
371 "mutex %08X is contested", m); | 417 "mutex " PTR_FMT " is contested", m); |
372 | 418 |
373 /* the mutex is probably contested so we are giving up now */ | 419 /* the mutex is probably contested so we are giving up now */ |
374 | 420 |
375 sched_yield(); | 421 sched_yield(); |
376 | 422 |
378 old = m->lock; | 424 old = m->lock; |
379 } | 425 } |
380 } | 426 } |
381 | 427 |
382 ngx_log_debug2(NGX_LOG_DEBUG_CORE, m->log, 0, | 428 ngx_log_debug2(NGX_LOG_DEBUG_CORE, m->log, 0, |
383 "mutex %08X is locked, lock:%X", m, m->lock); | 429 "mutex " PTR_FMT " is locked, lock:%X", m, m->lock); |
384 | 430 |
385 return NGX_OK; | 431 return NGX_OK; |
386 } | 432 } |
387 | 433 |
388 | 434 |
393 | 439 |
394 old = m->lock; | 440 old = m->lock; |
395 | 441 |
396 if (!(old & NGX_MUTEX_LOCK_BUSY)) { | 442 if (!(old & NGX_MUTEX_LOCK_BUSY)) { |
397 ngx_log_error(NGX_LOG_ALERT, m->log, ngx_errno, | 443 ngx_log_error(NGX_LOG_ALERT, m->log, ngx_errno, |
398 "tring to unlock the free mutex %0X", m); | 444 "tring to unlock the free mutex " PTR_FMT, m); |
399 return NGX_ERROR; | 445 return NGX_ERROR; |
400 } | 446 } |
401 | 447 |
402 /* free the mutex */ | 448 /* free the mutex */ |
403 | 449 |
411 old = m->lock; | 457 old = m->lock; |
412 } | 458 } |
413 | 459 |
414 if (m->semid == -1) { | 460 if (m->semid == -1) { |
415 ngx_log_debug1(NGX_LOG_DEBUG_CORE, m->log, 0, | 461 ngx_log_debug1(NGX_LOG_DEBUG_CORE, m->log, 0, |
416 "mutex %08X is unlocked", m); | 462 "mutex " PTR_FMT " is unlocked", m); |
417 | 463 |
418 return NGX_OK; | 464 return NGX_OK; |
419 } | 465 } |
420 | 466 |
421 /* check weather we need to wake up a waiting thread */ | 467 /* check weather we need to wake up a waiting thread */ |
446 op.sem_op = 1; | 492 op.sem_op = 1; |
447 op.sem_flg = SEM_UNDO; | 493 op.sem_flg = SEM_UNDO; |
448 | 494 |
449 if (semop(m->semid, &op, 1) == -1) { | 495 if (semop(m->semid, &op, 1) == -1) { |
450 ngx_log_error(NGX_LOG_ALERT, m->log, ngx_errno, | 496 ngx_log_error(NGX_LOG_ALERT, m->log, ngx_errno, |
451 "semop() failed while waking up on mutex %08X", | 497 "semop() failed while waking up on mutex " |
452 m); | 498 PTR_FMT, m); |
453 return NGX_ERROR; | 499 return NGX_ERROR; |
454 } | 500 } |
455 | 501 |
456 break; | 502 break; |
457 } | 503 } |
458 | 504 |
459 old = m->lock; | 505 old = m->lock; |
460 } | 506 } |
461 | 507 |
462 ngx_log_debug1(NGX_LOG_DEBUG_CORE, m->log, 0, | 508 ngx_log_debug1(NGX_LOG_DEBUG_CORE, m->log, 0, |
463 "mutex %08X is unlocked", m); | 509 "mutex " PTR_FMT " is unlocked", m); |
464 | 510 |
465 return NGX_OK; | 511 return NGX_OK; |
466 } | 512 } |