1*0Sigor@sysoev.ru 2*0Sigor@sysoev.ru /* 3*0Sigor@sysoev.ru * Copyright (C) Igor Sysoev 4*0Sigor@sysoev.ru * Copyright (C) NGINX, Inc. 5*0Sigor@sysoev.ru */ 6*0Sigor@sysoev.ru 7*0Sigor@sysoev.ru #include <nxt_main.h> 8*0Sigor@sysoev.ru 9*0Sigor@sysoev.ru 10*0Sigor@sysoev.ru static void *nxt_thread_trampoline(void *data); 11*0Sigor@sysoev.ru static void nxt_thread_time_cleanup(void *data); 12*0Sigor@sysoev.ru 13*0Sigor@sysoev.ru 14*0Sigor@sysoev.ru #if (NXT_HAVE_PTHREAD_SPECIFIC_DATA) 15*0Sigor@sysoev.ru 16*0Sigor@sysoev.ru static void nxt_thread_key_dtor(void *data); 17*0Sigor@sysoev.ru 18*0Sigor@sysoev.ru 19*0Sigor@sysoev.ru void 20*0Sigor@sysoev.ru nxt_thread_init_data(nxt_thread_specific_data_t tsd) 21*0Sigor@sysoev.ru { 22*0Sigor@sysoev.ru void *p; 23*0Sigor@sysoev.ru nxt_err_t err; 24*0Sigor@sysoev.ru pthread_key_t key; 25*0Sigor@sysoev.ru 26*0Sigor@sysoev.ru while ((nxt_atomic_int_t) tsd->key < 0) { 27*0Sigor@sysoev.ru /* 28*0Sigor@sysoev.ru * Atomic allocation of a key number. 29*0Sigor@sysoev.ru * -1 means an uninitialized key, 30*0Sigor@sysoev.ru * -2 is the initializing lock to assure the single value for the key. 31*0Sigor@sysoev.ru */ 32*0Sigor@sysoev.ru if (nxt_atomic_cmp_set(&tsd->key, -1, -2)) { 33*0Sigor@sysoev.ru 34*0Sigor@sysoev.ru err = pthread_key_create(&key, nxt_thread_key_dtor); 35*0Sigor@sysoev.ru if (err != 0) { 36*0Sigor@sysoev.ru nxt_main_log_emerg("pthread_key_create() failed %E", err); 37*0Sigor@sysoev.ru goto fail; 38*0Sigor@sysoev.ru } 39*0Sigor@sysoev.ru 40*0Sigor@sysoev.ru tsd->key = (nxt_atomic_t) key; 41*0Sigor@sysoev.ru 42*0Sigor@sysoev.ru nxt_main_log_debug("pthread_key_create(): %A", tsd->key); 43*0Sigor@sysoev.ru } 44*0Sigor@sysoev.ru } 45*0Sigor@sysoev.ru 46*0Sigor@sysoev.ru if (pthread_getspecific((pthread_key_t) tsd->key) != NULL) { 47*0Sigor@sysoev.ru return; 48*0Sigor@sysoev.ru } 49*0Sigor@sysoev.ru 50*0Sigor@sysoev.ru p = nxt_zalloc(tsd->size); 51*0Sigor@sysoev.ru if (p == NULL) { 52*0Sigor@sysoev.ru goto fail; 53*0Sigor@sysoev.ru } 54*0Sigor@sysoev.ru 55*0Sigor@sysoev.ru err = pthread_setspecific((pthread_key_t) tsd->key, p); 56*0Sigor@sysoev.ru if (err == 0) { 57*0Sigor@sysoev.ru return; 58*0Sigor@sysoev.ru } 59*0Sigor@sysoev.ru 60*0Sigor@sysoev.ru nxt_main_log_alert("pthread_setspecific(%A) failed %E", tsd->key, err); 61*0Sigor@sysoev.ru 62*0Sigor@sysoev.ru fail: 63*0Sigor@sysoev.ru 64*0Sigor@sysoev.ru pthread_exit(NULL); 65*0Sigor@sysoev.ru nxt_unreachable(); 66*0Sigor@sysoev.ru } 67*0Sigor@sysoev.ru 68*0Sigor@sysoev.ru 69*0Sigor@sysoev.ru static void 70*0Sigor@sysoev.ru nxt_thread_key_dtor(void *data) 71*0Sigor@sysoev.ru { 72*0Sigor@sysoev.ru nxt_main_log_debug("pthread key dtor: %p", data); 73*0Sigor@sysoev.ru 74*0Sigor@sysoev.ru nxt_free(data); 75*0Sigor@sysoev.ru } 76*0Sigor@sysoev.ru 77*0Sigor@sysoev.ru #endif 78*0Sigor@sysoev.ru 79*0Sigor@sysoev.ru 80*0Sigor@sysoev.ru nxt_int_t 81*0Sigor@sysoev.ru nxt_thread_create(nxt_thread_handle_t *handle, nxt_thread_link_t *link) 82*0Sigor@sysoev.ru { 83*0Sigor@sysoev.ru nxt_err_t err; 84*0Sigor@sysoev.ru 85*0Sigor@sysoev.ru err = pthread_create(handle, NULL, nxt_thread_trampoline, link); 86*0Sigor@sysoev.ru 87*0Sigor@sysoev.ru if (nxt_fast_path(err == 0)) { 88*0Sigor@sysoev.ru nxt_thread_log_debug("pthread_create(): %PH", *handle); 89*0Sigor@sysoev.ru 90*0Sigor@sysoev.ru return NXT_OK; 91*0Sigor@sysoev.ru } 92*0Sigor@sysoev.ru 93*0Sigor@sysoev.ru nxt_thread_log_alert("pthread_create() failed %E", err); 94*0Sigor@sysoev.ru 95*0Sigor@sysoev.ru nxt_free(link); 96*0Sigor@sysoev.ru 97*0Sigor@sysoev.ru return NXT_ERROR; 98*0Sigor@sysoev.ru } 99*0Sigor@sysoev.ru 100*0Sigor@sysoev.ru 101*0Sigor@sysoev.ru static void * 102*0Sigor@sysoev.ru nxt_thread_trampoline(void *data) 103*0Sigor@sysoev.ru { 104*0Sigor@sysoev.ru nxt_thread_t *thr; 105*0Sigor@sysoev.ru nxt_thread_link_t *link; 106*0Sigor@sysoev.ru nxt_thread_start_t start; 107*0Sigor@sysoev.ru 108*0Sigor@sysoev.ru link = data; 109*0Sigor@sysoev.ru 110*0Sigor@sysoev.ru thr = nxt_thread_init(); 111*0Sigor@sysoev.ru 112*0Sigor@sysoev.ru nxt_log_debug(thr->log, "thread trampoline: %PH", thr->handle); 113*0Sigor@sysoev.ru 114*0Sigor@sysoev.ru pthread_cleanup_push(nxt_thread_time_cleanup, thr); 115*0Sigor@sysoev.ru 116*0Sigor@sysoev.ru start = link->start; 117*0Sigor@sysoev.ru data = link->data; 118*0Sigor@sysoev.ru 119*0Sigor@sysoev.ru if (link->engine != NULL) { 120*0Sigor@sysoev.ru thr->link = link; 121*0Sigor@sysoev.ru 122*0Sigor@sysoev.ru } else { 123*0Sigor@sysoev.ru nxt_free(link); 124*0Sigor@sysoev.ru } 125*0Sigor@sysoev.ru 126*0Sigor@sysoev.ru start(data); 127*0Sigor@sysoev.ru 128*0Sigor@sysoev.ru /* 129*0Sigor@sysoev.ru * nxt_thread_time_cleanup() should be called only if a thread 130*0Sigor@sysoev.ru * would be canceled, so ignore it here because nxt_thread_exit() 131*0Sigor@sysoev.ru * calls nxt_thread_time_free() as well. 132*0Sigor@sysoev.ru */ 133*0Sigor@sysoev.ru pthread_cleanup_pop(0); 134*0Sigor@sysoev.ru 135*0Sigor@sysoev.ru nxt_thread_exit(thr); 136*0Sigor@sysoev.ru nxt_unreachable(); 137*0Sigor@sysoev.ru return NULL; 138*0Sigor@sysoev.ru } 139*0Sigor@sysoev.ru 140*0Sigor@sysoev.ru 141*0Sigor@sysoev.ru nxt_thread_t * 142*0Sigor@sysoev.ru nxt_thread_init(void) 143*0Sigor@sysoev.ru { 144*0Sigor@sysoev.ru nxt_thread_t *thr; 145*0Sigor@sysoev.ru 146*0Sigor@sysoev.ru nxt_thread_init_data(nxt_thread_context); 147*0Sigor@sysoev.ru 148*0Sigor@sysoev.ru thr = nxt_thread(); 149*0Sigor@sysoev.ru 150*0Sigor@sysoev.ru if (thr->log == NULL) { 151*0Sigor@sysoev.ru thr->log = &nxt_main_log; 152*0Sigor@sysoev.ru thr->handle = nxt_thread_handle(); 153*0Sigor@sysoev.ru 154*0Sigor@sysoev.ru /* 155*0Sigor@sysoev.ru * Threads are never preempted by asynchronous signals, since 156*0Sigor@sysoev.ru * the signals are processed synchronously by dedicated thread. 157*0Sigor@sysoev.ru */ 158*0Sigor@sysoev.ru thr->time.signal = -1; 159*0Sigor@sysoev.ru 160*0Sigor@sysoev.ru nxt_thread_time_update(thr); 161*0Sigor@sysoev.ru } 162*0Sigor@sysoev.ru 163*0Sigor@sysoev.ru return thr; 164*0Sigor@sysoev.ru } 165*0Sigor@sysoev.ru 166*0Sigor@sysoev.ru 167*0Sigor@sysoev.ru static void 168*0Sigor@sysoev.ru nxt_thread_time_cleanup(void *data) 169*0Sigor@sysoev.ru { 170*0Sigor@sysoev.ru nxt_thread_t *thr; 171*0Sigor@sysoev.ru 172*0Sigor@sysoev.ru thr = data; 173*0Sigor@sysoev.ru 174*0Sigor@sysoev.ru nxt_log_debug(thr->log, "thread time cleanup"); 175*0Sigor@sysoev.ru 176*0Sigor@sysoev.ru nxt_thread_time_free(thr); 177*0Sigor@sysoev.ru } 178*0Sigor@sysoev.ru 179*0Sigor@sysoev.ru 180*0Sigor@sysoev.ru void 181*0Sigor@sysoev.ru nxt_thread_exit(nxt_thread_t *thr) 182*0Sigor@sysoev.ru { 183*0Sigor@sysoev.ru nxt_log_debug(thr->log, "thread exit"); 184*0Sigor@sysoev.ru 185*0Sigor@sysoev.ru if (thr->link != NULL) { 186*0Sigor@sysoev.ru nxt_event_engine_post(thr->link->engine, thr->link->exit, 187*0Sigor@sysoev.ru (void *) (uintptr_t) thr->handle, NULL, 188*0Sigor@sysoev.ru &nxt_main_log); 189*0Sigor@sysoev.ru 190*0Sigor@sysoev.ru nxt_free(thr->link); 191*0Sigor@sysoev.ru thr->link = NULL; 192*0Sigor@sysoev.ru } 193*0Sigor@sysoev.ru 194*0Sigor@sysoev.ru nxt_thread_time_free(thr); 195*0Sigor@sysoev.ru 196*0Sigor@sysoev.ru pthread_exit(NULL); 197*0Sigor@sysoev.ru nxt_unreachable(); 198*0Sigor@sysoev.ru } 199*0Sigor@sysoev.ru 200*0Sigor@sysoev.ru 201*0Sigor@sysoev.ru void 202*0Sigor@sysoev.ru nxt_thread_cancel(nxt_thread_handle_t handle) 203*0Sigor@sysoev.ru { 204*0Sigor@sysoev.ru nxt_err_t err; 205*0Sigor@sysoev.ru 206*0Sigor@sysoev.ru nxt_thread_log_debug("thread cancel: %PH", handle); 207*0Sigor@sysoev.ru 208*0Sigor@sysoev.ru err = pthread_cancel(handle); 209*0Sigor@sysoev.ru 210*0Sigor@sysoev.ru if (err != 0) { 211*0Sigor@sysoev.ru nxt_main_log_alert("pthread_cancel(%PH) failed %E", handle, err); 212*0Sigor@sysoev.ru } 213*0Sigor@sysoev.ru } 214*0Sigor@sysoev.ru 215*0Sigor@sysoev.ru 216*0Sigor@sysoev.ru void 217*0Sigor@sysoev.ru nxt_thread_wait(nxt_thread_handle_t handle) 218*0Sigor@sysoev.ru { 219*0Sigor@sysoev.ru nxt_err_t err; 220*0Sigor@sysoev.ru 221*0Sigor@sysoev.ru nxt_thread_log_debug("thread wait: %PH", handle); 222*0Sigor@sysoev.ru 223*0Sigor@sysoev.ru err = pthread_join(handle, NULL); 224*0Sigor@sysoev.ru 225*0Sigor@sysoev.ru if (err != 0) { 226*0Sigor@sysoev.ru nxt_main_log_alert("pthread_join(%PH) failed %E", handle, err); 227*0Sigor@sysoev.ru } 228*0Sigor@sysoev.ru } 229