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