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