10Sigor@sysoev.ru 20Sigor@sysoev.ru /* 30Sigor@sysoev.ru * Copyright (C) Igor Sysoev 40Sigor@sysoev.ru * Copyright (C) NGINX, Inc. 50Sigor@sysoev.ru */ 60Sigor@sysoev.ru 70Sigor@sysoev.ru #include <nxt_main.h> 80Sigor@sysoev.ru 90Sigor@sysoev.ru 100Sigor@sysoev.ru static void *nxt_thread_trampoline(void *data); 110Sigor@sysoev.ru static void nxt_thread_time_cleanup(void *data); 120Sigor@sysoev.ru 130Sigor@sysoev.ru 140Sigor@sysoev.ru #if (NXT_HAVE_PTHREAD_SPECIFIC_DATA) 150Sigor@sysoev.ru 160Sigor@sysoev.ru static void nxt_thread_key_dtor(void *data); 170Sigor@sysoev.ru 180Sigor@sysoev.ru 190Sigor@sysoev.ru void 200Sigor@sysoev.ru nxt_thread_init_data(nxt_thread_specific_data_t tsd) 210Sigor@sysoev.ru { 220Sigor@sysoev.ru void *p; 230Sigor@sysoev.ru nxt_err_t err; 240Sigor@sysoev.ru pthread_key_t key; 250Sigor@sysoev.ru 260Sigor@sysoev.ru while ((nxt_atomic_int_t) tsd->key < 0) { 270Sigor@sysoev.ru /* 280Sigor@sysoev.ru * Atomic allocation of a key number. 290Sigor@sysoev.ru * -1 means an uninitialized key, 300Sigor@sysoev.ru * -2 is the initializing lock to assure the single value for the key. 310Sigor@sysoev.ru */ 320Sigor@sysoev.ru if (nxt_atomic_cmp_set(&tsd->key, -1, -2)) { 330Sigor@sysoev.ru 340Sigor@sysoev.ru err = pthread_key_create(&key, nxt_thread_key_dtor); 350Sigor@sysoev.ru if (err != 0) { 360Sigor@sysoev.ru nxt_main_log_emerg("pthread_key_create() failed %E", err); 370Sigor@sysoev.ru goto fail; 380Sigor@sysoev.ru } 390Sigor@sysoev.ru 400Sigor@sysoev.ru tsd->key = (nxt_atomic_t) key; 410Sigor@sysoev.ru 420Sigor@sysoev.ru nxt_main_log_debug("pthread_key_create(): %A", tsd->key); 430Sigor@sysoev.ru } 440Sigor@sysoev.ru } 450Sigor@sysoev.ru 460Sigor@sysoev.ru if (pthread_getspecific((pthread_key_t) tsd->key) != NULL) { 470Sigor@sysoev.ru return; 480Sigor@sysoev.ru } 490Sigor@sysoev.ru 500Sigor@sysoev.ru p = nxt_zalloc(tsd->size); 510Sigor@sysoev.ru if (p == NULL) { 520Sigor@sysoev.ru goto fail; 530Sigor@sysoev.ru } 540Sigor@sysoev.ru 550Sigor@sysoev.ru err = pthread_setspecific((pthread_key_t) tsd->key, p); 560Sigor@sysoev.ru if (err == 0) { 570Sigor@sysoev.ru return; 580Sigor@sysoev.ru } 590Sigor@sysoev.ru 600Sigor@sysoev.ru nxt_main_log_alert("pthread_setspecific(%A) failed %E", tsd->key, err); 610Sigor@sysoev.ru 620Sigor@sysoev.ru fail: 630Sigor@sysoev.ru 640Sigor@sysoev.ru pthread_exit(NULL); 650Sigor@sysoev.ru nxt_unreachable(); 660Sigor@sysoev.ru } 670Sigor@sysoev.ru 680Sigor@sysoev.ru 690Sigor@sysoev.ru static void 700Sigor@sysoev.ru nxt_thread_key_dtor(void *data) 710Sigor@sysoev.ru { 720Sigor@sysoev.ru nxt_main_log_debug("pthread key dtor: %p", data); 730Sigor@sysoev.ru 740Sigor@sysoev.ru nxt_free(data); 750Sigor@sysoev.ru } 760Sigor@sysoev.ru 770Sigor@sysoev.ru #endif 780Sigor@sysoev.ru 790Sigor@sysoev.ru 800Sigor@sysoev.ru nxt_int_t 810Sigor@sysoev.ru nxt_thread_create(nxt_thread_handle_t *handle, nxt_thread_link_t *link) 820Sigor@sysoev.ru { 830Sigor@sysoev.ru nxt_err_t err; 840Sigor@sysoev.ru 850Sigor@sysoev.ru err = pthread_create(handle, NULL, nxt_thread_trampoline, link); 860Sigor@sysoev.ru 870Sigor@sysoev.ru if (nxt_fast_path(err == 0)) { 880Sigor@sysoev.ru nxt_thread_log_debug("pthread_create(): %PH", *handle); 890Sigor@sysoev.ru 900Sigor@sysoev.ru return NXT_OK; 910Sigor@sysoev.ru } 920Sigor@sysoev.ru 930Sigor@sysoev.ru nxt_thread_log_alert("pthread_create() failed %E", err); 940Sigor@sysoev.ru 950Sigor@sysoev.ru nxt_free(link); 960Sigor@sysoev.ru 970Sigor@sysoev.ru return NXT_ERROR; 980Sigor@sysoev.ru } 990Sigor@sysoev.ru 1000Sigor@sysoev.ru 1010Sigor@sysoev.ru static void * 1020Sigor@sysoev.ru nxt_thread_trampoline(void *data) 1030Sigor@sysoev.ru { 1040Sigor@sysoev.ru nxt_thread_t *thr; 1050Sigor@sysoev.ru nxt_thread_link_t *link; 1060Sigor@sysoev.ru nxt_thread_start_t start; 1070Sigor@sysoev.ru 1080Sigor@sysoev.ru link = data; 1090Sigor@sysoev.ru 1100Sigor@sysoev.ru thr = nxt_thread_init(); 1110Sigor@sysoev.ru 1120Sigor@sysoev.ru nxt_log_debug(thr->log, "thread trampoline: %PH", thr->handle); 1130Sigor@sysoev.ru 1140Sigor@sysoev.ru pthread_cleanup_push(nxt_thread_time_cleanup, thr); 1150Sigor@sysoev.ru 1160Sigor@sysoev.ru start = link->start; 11753Sigor@sysoev.ru data = link->work.data; 1180Sigor@sysoev.ru 11953Sigor@sysoev.ru if (link->work.handler != NULL) { 1200Sigor@sysoev.ru thr->link = link; 1210Sigor@sysoev.ru 1220Sigor@sysoev.ru } else { 1230Sigor@sysoev.ru nxt_free(link); 1240Sigor@sysoev.ru } 1250Sigor@sysoev.ru 1260Sigor@sysoev.ru start(data); 1270Sigor@sysoev.ru 1280Sigor@sysoev.ru /* 1290Sigor@sysoev.ru * nxt_thread_time_cleanup() should be called only if a thread 1300Sigor@sysoev.ru * would be canceled, so ignore it here because nxt_thread_exit() 1310Sigor@sysoev.ru * calls nxt_thread_time_free() as well. 1320Sigor@sysoev.ru */ 1330Sigor@sysoev.ru pthread_cleanup_pop(0); 1340Sigor@sysoev.ru 1350Sigor@sysoev.ru nxt_thread_exit(thr); 1360Sigor@sysoev.ru nxt_unreachable(); 1370Sigor@sysoev.ru return NULL; 1380Sigor@sysoev.ru } 1390Sigor@sysoev.ru 1400Sigor@sysoev.ru 1410Sigor@sysoev.ru nxt_thread_t * 1420Sigor@sysoev.ru nxt_thread_init(void) 1430Sigor@sysoev.ru { 1440Sigor@sysoev.ru nxt_thread_t *thr; 1450Sigor@sysoev.ru 1460Sigor@sysoev.ru nxt_thread_init_data(nxt_thread_context); 1470Sigor@sysoev.ru 1480Sigor@sysoev.ru thr = nxt_thread(); 1490Sigor@sysoev.ru 1500Sigor@sysoev.ru if (thr->log == NULL) { 1510Sigor@sysoev.ru thr->log = &nxt_main_log; 1520Sigor@sysoev.ru thr->handle = nxt_thread_handle(); 1530Sigor@sysoev.ru 1540Sigor@sysoev.ru /* 1550Sigor@sysoev.ru * Threads are never preempted by asynchronous signals, since 1560Sigor@sysoev.ru * the signals are processed synchronously by dedicated thread. 1570Sigor@sysoev.ru */ 1580Sigor@sysoev.ru thr->time.signal = -1; 1590Sigor@sysoev.ru 1600Sigor@sysoev.ru nxt_thread_time_update(thr); 1610Sigor@sysoev.ru } 1620Sigor@sysoev.ru 163*138Sigor@sysoev.ru nxt_random_init(&thr->random); 164*138Sigor@sysoev.ru 1650Sigor@sysoev.ru return thr; 1660Sigor@sysoev.ru } 1670Sigor@sysoev.ru 1680Sigor@sysoev.ru 1690Sigor@sysoev.ru static void 1700Sigor@sysoev.ru nxt_thread_time_cleanup(void *data) 1710Sigor@sysoev.ru { 1720Sigor@sysoev.ru nxt_thread_t *thr; 1730Sigor@sysoev.ru 1740Sigor@sysoev.ru thr = data; 1750Sigor@sysoev.ru 1760Sigor@sysoev.ru nxt_log_debug(thr->log, "thread time cleanup"); 1770Sigor@sysoev.ru 1780Sigor@sysoev.ru nxt_thread_time_free(thr); 1790Sigor@sysoev.ru } 1800Sigor@sysoev.ru 1810Sigor@sysoev.ru 1820Sigor@sysoev.ru void 1830Sigor@sysoev.ru nxt_thread_exit(nxt_thread_t *thr) 1840Sigor@sysoev.ru { 18553Sigor@sysoev.ru nxt_thread_link_t *link; 18653Sigor@sysoev.ru nxt_event_engine_t *engine; 1874Sigor@sysoev.ru 1880Sigor@sysoev.ru nxt_log_debug(thr->log, "thread exit"); 1890Sigor@sysoev.ru 1904Sigor@sysoev.ru link = thr->link; 1914Sigor@sysoev.ru thr->link = NULL; 1920Sigor@sysoev.ru 1934Sigor@sysoev.ru if (link != NULL) { 1944Sigor@sysoev.ru /* 19553Sigor@sysoev.ru * link->work.handler is already set to an exit handler, 19653Sigor@sysoev.ru * and link->work.task is already set to the correct engine->task. 1974Sigor@sysoev.ru * The link should be freed by the exit handler. 1984Sigor@sysoev.ru */ 1998Sigor@sysoev.ru link->work.obj = (void *) (uintptr_t) thr->handle; 20053Sigor@sysoev.ru engine = nxt_container_of(link->work.task, nxt_event_engine_t, task); 2014Sigor@sysoev.ru 20253Sigor@sysoev.ru nxt_event_engine_post(engine, &link->work); 2030Sigor@sysoev.ru } 2040Sigor@sysoev.ru 2050Sigor@sysoev.ru nxt_thread_time_free(thr); 2060Sigor@sysoev.ru 2070Sigor@sysoev.ru pthread_exit(NULL); 2080Sigor@sysoev.ru nxt_unreachable(); 2090Sigor@sysoev.ru } 2100Sigor@sysoev.ru 2110Sigor@sysoev.ru 2120Sigor@sysoev.ru void 2130Sigor@sysoev.ru nxt_thread_cancel(nxt_thread_handle_t handle) 2140Sigor@sysoev.ru { 2150Sigor@sysoev.ru nxt_err_t err; 2160Sigor@sysoev.ru 2170Sigor@sysoev.ru nxt_thread_log_debug("thread cancel: %PH", handle); 2180Sigor@sysoev.ru 2190Sigor@sysoev.ru err = pthread_cancel(handle); 2200Sigor@sysoev.ru 2210Sigor@sysoev.ru if (err != 0) { 2220Sigor@sysoev.ru nxt_main_log_alert("pthread_cancel(%PH) failed %E", handle, err); 2230Sigor@sysoev.ru } 2240Sigor@sysoev.ru } 2250Sigor@sysoev.ru 2260Sigor@sysoev.ru 2270Sigor@sysoev.ru void 2280Sigor@sysoev.ru nxt_thread_wait(nxt_thread_handle_t handle) 2290Sigor@sysoev.ru { 2300Sigor@sysoev.ru nxt_err_t err; 2310Sigor@sysoev.ru 2320Sigor@sysoev.ru nxt_thread_log_debug("thread wait: %PH", handle); 2330Sigor@sysoev.ru 2340Sigor@sysoev.ru err = pthread_join(handle, NULL); 2350Sigor@sysoev.ru 2360Sigor@sysoev.ru if (err != 0) { 2370Sigor@sysoev.ru nxt_main_log_alert("pthread_join(%PH) failed %E", handle, err); 2380Sigor@sysoev.ru } 2390Sigor@sysoev.ru } 240