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