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