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 #ifndef _NXT_UNIX_THREAD_H_INCLUDED_ 8*0Sigor@sysoev.ru #define _NXT_UNIX_THREAD_H_INCLUDED_ 9*0Sigor@sysoev.ru 10*0Sigor@sysoev.ru 11*0Sigor@sysoev.ru #if (NXT_THREADS) 12*0Sigor@sysoev.ru 13*0Sigor@sysoev.ru /* 14*0Sigor@sysoev.ru * Thread Specific Data 15*0Sigor@sysoev.ru * 16*0Sigor@sysoev.ru * The interface unifies two TSD implementations: the __thread storage 17*0Sigor@sysoev.ru * class and pthread specific data. It works also in non-threaded mode. 18*0Sigor@sysoev.ru * The interface is optimized for the __thread storage class and non-threaded 19*0Sigor@sysoev.ru * mode, since the __thread storage is faster and is supported in modern 20*0Sigor@sysoev.ru * versions of Linux, FreeBSD, Solaris, and MacOSX. Pthread specific data 21*0Sigor@sysoev.ru * is considered as a fallback option. 22*0Sigor@sysoev.ru * 23*0Sigor@sysoev.ru * The underlining interfaces are different: pthread data must be allocated 24*0Sigor@sysoev.ru * by hand and may be accessed only by using pointers whereas __thread data 25*0Sigor@sysoev.ru * allocation is transparent and it is accessed directly. 26*0Sigor@sysoev.ru * 27*0Sigor@sysoev.ru * pthread_getspecific() is usually faster than pthread_setspecific() 28*0Sigor@sysoev.ru * (much faster on MacOSX), so there is no nxt_thread_set_data() interface 29*0Sigor@sysoev.ru * for this reason. It is better to store frequently alterable thread 30*0Sigor@sysoev.ru * log pointer in nxt_thread_t, but not in a dedicated key. 31*0Sigor@sysoev.ru */ 32*0Sigor@sysoev.ru 33*0Sigor@sysoev.ru #if (NXT_HAVE_THREAD_STORAGE_CLASS) 34*0Sigor@sysoev.ru 35*0Sigor@sysoev.ru #define \ 36*0Sigor@sysoev.ru nxt_thread_extern_data(type, tsd) \ 37*0Sigor@sysoev.ru NXT_EXPORT extern __thread type tsd 38*0Sigor@sysoev.ru 39*0Sigor@sysoev.ru #define \ 40*0Sigor@sysoev.ru nxt_thread_declare_data(type, tsd) \ 41*0Sigor@sysoev.ru __thread type tsd 42*0Sigor@sysoev.ru 43*0Sigor@sysoev.ru #define \ 44*0Sigor@sysoev.ru nxt_thread_init_data(tsd) 45*0Sigor@sysoev.ru 46*0Sigor@sysoev.ru #define \ 47*0Sigor@sysoev.ru nxt_thread_get_data(tsd) \ 48*0Sigor@sysoev.ru &tsd 49*0Sigor@sysoev.ru 50*0Sigor@sysoev.ru 51*0Sigor@sysoev.ru #else /* NXT_HAVE_PTHREAD_SPECIFIC_DATA */ 52*0Sigor@sysoev.ru 53*0Sigor@sysoev.ru /* 54*0Sigor@sysoev.ru * nxt_thread_get_data() is used as 55*0Sigor@sysoev.ru * p = nxt_thread_get_data(tsd), 56*0Sigor@sysoev.ru * but the tsd address is actually required. This could be resolved by macro 57*0Sigor@sysoev.ru * #define nxt_thread_get_data(tsd) nxt_thread_get_data_addr(&tsd) 58*0Sigor@sysoev.ru * or by definition nxt_thread_specific_data_t as an array. 59*0Sigor@sysoev.ru * 60*0Sigor@sysoev.ru * On Linux and Solaris pthread_key_t is unsigned integer. 61*0Sigor@sysoev.ru * On FreeBSD, NetBSD, OpenBSD, and HP-UX pthread_key_t is integer. 62*0Sigor@sysoev.ru * On MacOSX and AIX pthread_key_t is unsigned long integer. 63*0Sigor@sysoev.ru * On Cygwin pthread_key_t is pointer to void. 64*0Sigor@sysoev.ru */ 65*0Sigor@sysoev.ru 66*0Sigor@sysoev.ru typedef struct { 67*0Sigor@sysoev.ru nxt_atomic_t key; 68*0Sigor@sysoev.ru size_t size; 69*0Sigor@sysoev.ru } nxt_thread_specific_data_t[1]; 70*0Sigor@sysoev.ru 71*0Sigor@sysoev.ru 72*0Sigor@sysoev.ru #define \ 73*0Sigor@sysoev.ru nxt_thread_extern_data(type, tsd) \ 74*0Sigor@sysoev.ru NXT_EXPORT extern nxt_thread_specific_data_t tsd 75*0Sigor@sysoev.ru 76*0Sigor@sysoev.ru #define \ 77*0Sigor@sysoev.ru nxt_thread_declare_data(type, tsd) \ 78*0Sigor@sysoev.ru nxt_thread_specific_data_t tsd = { { (nxt_atomic_int_t) -1, sizeof(type) } } 79*0Sigor@sysoev.ru 80*0Sigor@sysoev.ru NXT_EXPORT void nxt_thread_init_data(nxt_thread_specific_data_t tsd); 81*0Sigor@sysoev.ru 82*0Sigor@sysoev.ru #define \ 83*0Sigor@sysoev.ru nxt_thread_get_data(tsd) \ 84*0Sigor@sysoev.ru pthread_getspecific((pthread_key_t) tsd->key) 85*0Sigor@sysoev.ru 86*0Sigor@sysoev.ru #endif 87*0Sigor@sysoev.ru 88*0Sigor@sysoev.ru 89*0Sigor@sysoev.ru typedef void (*nxt_thread_start_t)(void *data); 90*0Sigor@sysoev.ru 91*0Sigor@sysoev.ru typedef struct { 92*0Sigor@sysoev.ru nxt_thread_start_t start; 93*0Sigor@sysoev.ru void *data; 94*0Sigor@sysoev.ru nxt_event_engine_t *engine; 95*0Sigor@sysoev.ru nxt_work_handler_t exit; 96*0Sigor@sysoev.ru } nxt_thread_link_t; 97*0Sigor@sysoev.ru 98*0Sigor@sysoev.ru 99*0Sigor@sysoev.ru NXT_EXPORT nxt_int_t nxt_thread_create(nxt_thread_handle_t *handle, 100*0Sigor@sysoev.ru nxt_thread_link_t *link); 101*0Sigor@sysoev.ru NXT_EXPORT nxt_thread_t *nxt_thread_init(void); 102*0Sigor@sysoev.ru NXT_EXPORT void nxt_thread_exit(nxt_thread_t *thr); 103*0Sigor@sysoev.ru NXT_EXPORT void nxt_thread_cancel(nxt_thread_handle_t handle); 104*0Sigor@sysoev.ru NXT_EXPORT void nxt_thread_wait(nxt_thread_handle_t handle); 105*0Sigor@sysoev.ru 106*0Sigor@sysoev.ru 107*0Sigor@sysoev.ru #define \ 108*0Sigor@sysoev.ru nxt_thread_handle() \ 109*0Sigor@sysoev.ru pthread_self() 110*0Sigor@sysoev.ru 111*0Sigor@sysoev.ru 112*0Sigor@sysoev.ru typedef pthread_mutex_t nxt_thread_mutex_t; 113*0Sigor@sysoev.ru 114*0Sigor@sysoev.ru NXT_EXPORT nxt_int_t nxt_thread_mutex_create(nxt_thread_mutex_t *mtx); 115*0Sigor@sysoev.ru NXT_EXPORT void nxt_thread_mutex_destroy(nxt_thread_mutex_t *mtx); 116*0Sigor@sysoev.ru NXT_EXPORT nxt_int_t nxt_thread_mutex_lock(nxt_thread_mutex_t *mtx); 117*0Sigor@sysoev.ru NXT_EXPORT nxt_bool_t nxt_thread_mutex_trylock(nxt_thread_mutex_t *mtx); 118*0Sigor@sysoev.ru NXT_EXPORT nxt_int_t nxt_thread_mutex_unlock(nxt_thread_mutex_t *mtx); 119*0Sigor@sysoev.ru 120*0Sigor@sysoev.ru 121*0Sigor@sysoev.ru typedef pthread_cond_t nxt_thread_cond_t; 122*0Sigor@sysoev.ru 123*0Sigor@sysoev.ru NXT_EXPORT nxt_int_t nxt_thread_cond_create(nxt_thread_cond_t *cond); 124*0Sigor@sysoev.ru NXT_EXPORT void nxt_thread_cond_destroy(nxt_thread_cond_t *cond); 125*0Sigor@sysoev.ru NXT_EXPORT nxt_int_t nxt_thread_cond_signal(nxt_thread_cond_t *cond); 126*0Sigor@sysoev.ru NXT_EXPORT nxt_err_t nxt_thread_cond_wait(nxt_thread_cond_t *cond, 127*0Sigor@sysoev.ru nxt_thread_mutex_t *mtx, nxt_nsec_t timeout); 128*0Sigor@sysoev.ru 129*0Sigor@sysoev.ru 130*0Sigor@sysoev.ru #else /* !(NXT_THREADS) */ 131*0Sigor@sysoev.ru 132*0Sigor@sysoev.ru #define \ 133*0Sigor@sysoev.ru nxt_thread_extern_data(type, tsd) \ 134*0Sigor@sysoev.ru NXT_EXPORT extern type tsd 135*0Sigor@sysoev.ru 136*0Sigor@sysoev.ru #define \ 137*0Sigor@sysoev.ru nxt_thread_declare_data(type, tsd) \ 138*0Sigor@sysoev.ru type tsd 139*0Sigor@sysoev.ru 140*0Sigor@sysoev.ru #define \ 141*0Sigor@sysoev.ru nxt_thread_init_data(tsd) 142*0Sigor@sysoev.ru 143*0Sigor@sysoev.ru #define \ 144*0Sigor@sysoev.ru nxt_thread_get_data(tsd) \ 145*0Sigor@sysoev.ru &tsd 146*0Sigor@sysoev.ru 147*0Sigor@sysoev.ru #endif /* NXT_THREADS */ 148*0Sigor@sysoev.ru 149*0Sigor@sysoev.ru 150*0Sigor@sysoev.ru #if (NXT_HAVE_PTHREAD_YIELD) 151*0Sigor@sysoev.ru #define \ 152*0Sigor@sysoev.ru nxt_thread_yield() \ 153*0Sigor@sysoev.ru pthread_yield() 154*0Sigor@sysoev.ru 155*0Sigor@sysoev.ru #elif (NXT_HAVE_PTHREAD_YIELD_NP) 156*0Sigor@sysoev.ru #define \ 157*0Sigor@sysoev.ru nxt_thread_yield() \ 158*0Sigor@sysoev.ru pthread_yield_np() 159*0Sigor@sysoev.ru 160*0Sigor@sysoev.ru #else 161*0Sigor@sysoev.ru #define \ 162*0Sigor@sysoev.ru nxt_thread_yield() \ 163*0Sigor@sysoev.ru nxt_sched_yield() 164*0Sigor@sysoev.ru 165*0Sigor@sysoev.ru #endif 166*0Sigor@sysoev.ru 167*0Sigor@sysoev.ru 168*0Sigor@sysoev.ru struct nxt_thread_s { 169*0Sigor@sysoev.ru nxt_log_t *log; 170*0Sigor@sysoev.ru nxt_log_t main_log; 171*0Sigor@sysoev.ru 172*0Sigor@sysoev.ru nxt_tid_t tid; 173*0Sigor@sysoev.ru nxt_thread_handle_t handle; 174*0Sigor@sysoev.ru #if (NXT_THREADS) 175*0Sigor@sysoev.ru nxt_thread_link_t *link; 176*0Sigor@sysoev.ru nxt_thread_pool_t *thread_pool; 177*0Sigor@sysoev.ru #endif 178*0Sigor@sysoev.ru 179*0Sigor@sysoev.ru nxt_thread_time_t time; 180*0Sigor@sysoev.ru 181*0Sigor@sysoev.ru nxt_event_engine_t *engine; 182*0Sigor@sysoev.ru nxt_thread_work_queue_t work_queue; 183*0Sigor@sysoev.ru 184*0Sigor@sysoev.ru /* 185*0Sigor@sysoev.ru * Although pointer to a current fiber should be a property of 186*0Sigor@sysoev.ru * engine->fibers, its placement here eliminates 2 memory accesses. 187*0Sigor@sysoev.ru */ 188*0Sigor@sysoev.ru nxt_fiber_t *fiber; 189*0Sigor@sysoev.ru }; 190*0Sigor@sysoev.ru 191*0Sigor@sysoev.ru 192*0Sigor@sysoev.ru #endif /* _NXT_UNIX_THREAD_H_INCLUDED_ */ 193