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 }