xref: /unit/src/nxt_thread.c (revision 0)
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 #include <nxt_main.h>
8*0Sigor@sysoev.ru 
9*0Sigor@sysoev.ru 
10*0Sigor@sysoev.ru static void *nxt_thread_trampoline(void *data);
11*0Sigor@sysoev.ru static void nxt_thread_time_cleanup(void *data);
12*0Sigor@sysoev.ru 
13*0Sigor@sysoev.ru 
14*0Sigor@sysoev.ru #if (NXT_HAVE_PTHREAD_SPECIFIC_DATA)
15*0Sigor@sysoev.ru 
16*0Sigor@sysoev.ru static void nxt_thread_key_dtor(void *data);
17*0Sigor@sysoev.ru 
18*0Sigor@sysoev.ru 
19*0Sigor@sysoev.ru void
20*0Sigor@sysoev.ru nxt_thread_init_data(nxt_thread_specific_data_t tsd)
21*0Sigor@sysoev.ru {
22*0Sigor@sysoev.ru     void           *p;
23*0Sigor@sysoev.ru     nxt_err_t      err;
24*0Sigor@sysoev.ru     pthread_key_t  key;
25*0Sigor@sysoev.ru 
26*0Sigor@sysoev.ru     while ((nxt_atomic_int_t) tsd->key < 0) {
27*0Sigor@sysoev.ru         /*
28*0Sigor@sysoev.ru          * Atomic allocation of a key number.
29*0Sigor@sysoev.ru          * -1 means an uninitialized key,
30*0Sigor@sysoev.ru          * -2 is the initializing lock to assure the single value for the key.
31*0Sigor@sysoev.ru          */
32*0Sigor@sysoev.ru         if (nxt_atomic_cmp_set(&tsd->key, -1, -2)) {
33*0Sigor@sysoev.ru 
34*0Sigor@sysoev.ru             err = pthread_key_create(&key, nxt_thread_key_dtor);
35*0Sigor@sysoev.ru             if (err != 0) {
36*0Sigor@sysoev.ru                 nxt_main_log_emerg("pthread_key_create() failed %E", err);
37*0Sigor@sysoev.ru                 goto fail;
38*0Sigor@sysoev.ru             }
39*0Sigor@sysoev.ru 
40*0Sigor@sysoev.ru             tsd->key = (nxt_atomic_t) key;
41*0Sigor@sysoev.ru 
42*0Sigor@sysoev.ru             nxt_main_log_debug("pthread_key_create(): %A", tsd->key);
43*0Sigor@sysoev.ru         }
44*0Sigor@sysoev.ru     }
45*0Sigor@sysoev.ru 
46*0Sigor@sysoev.ru     if (pthread_getspecific((pthread_key_t) tsd->key) != NULL) {
47*0Sigor@sysoev.ru         return;
48*0Sigor@sysoev.ru     }
49*0Sigor@sysoev.ru 
50*0Sigor@sysoev.ru     p = nxt_zalloc(tsd->size);
51*0Sigor@sysoev.ru     if (p == NULL) {
52*0Sigor@sysoev.ru         goto fail;
53*0Sigor@sysoev.ru     }
54*0Sigor@sysoev.ru 
55*0Sigor@sysoev.ru     err = pthread_setspecific((pthread_key_t) tsd->key, p);
56*0Sigor@sysoev.ru     if (err == 0) {
57*0Sigor@sysoev.ru         return;
58*0Sigor@sysoev.ru     }
59*0Sigor@sysoev.ru 
60*0Sigor@sysoev.ru     nxt_main_log_alert("pthread_setspecific(%A) failed %E", tsd->key, err);
61*0Sigor@sysoev.ru 
62*0Sigor@sysoev.ru fail:
63*0Sigor@sysoev.ru 
64*0Sigor@sysoev.ru     pthread_exit(NULL);
65*0Sigor@sysoev.ru     nxt_unreachable();
66*0Sigor@sysoev.ru }
67*0Sigor@sysoev.ru 
68*0Sigor@sysoev.ru 
69*0Sigor@sysoev.ru static void
70*0Sigor@sysoev.ru nxt_thread_key_dtor(void *data)
71*0Sigor@sysoev.ru {
72*0Sigor@sysoev.ru     nxt_main_log_debug("pthread key dtor: %p", data);
73*0Sigor@sysoev.ru 
74*0Sigor@sysoev.ru     nxt_free(data);
75*0Sigor@sysoev.ru }
76*0Sigor@sysoev.ru 
77*0Sigor@sysoev.ru #endif
78*0Sigor@sysoev.ru 
79*0Sigor@sysoev.ru 
80*0Sigor@sysoev.ru nxt_int_t
81*0Sigor@sysoev.ru nxt_thread_create(nxt_thread_handle_t *handle, nxt_thread_link_t *link)
82*0Sigor@sysoev.ru {
83*0Sigor@sysoev.ru     nxt_err_t  err;
84*0Sigor@sysoev.ru 
85*0Sigor@sysoev.ru     err = pthread_create(handle, NULL, nxt_thread_trampoline, link);
86*0Sigor@sysoev.ru 
87*0Sigor@sysoev.ru     if (nxt_fast_path(err == 0)) {
88*0Sigor@sysoev.ru         nxt_thread_log_debug("pthread_create(): %PH", *handle);
89*0Sigor@sysoev.ru 
90*0Sigor@sysoev.ru         return NXT_OK;
91*0Sigor@sysoev.ru     }
92*0Sigor@sysoev.ru 
93*0Sigor@sysoev.ru     nxt_thread_log_alert("pthread_create() failed %E", err);
94*0Sigor@sysoev.ru 
95*0Sigor@sysoev.ru     nxt_free(link);
96*0Sigor@sysoev.ru 
97*0Sigor@sysoev.ru     return NXT_ERROR;
98*0Sigor@sysoev.ru }
99*0Sigor@sysoev.ru 
100*0Sigor@sysoev.ru 
101*0Sigor@sysoev.ru static void *
102*0Sigor@sysoev.ru nxt_thread_trampoline(void *data)
103*0Sigor@sysoev.ru {
104*0Sigor@sysoev.ru     nxt_thread_t        *thr;
105*0Sigor@sysoev.ru     nxt_thread_link_t   *link;
106*0Sigor@sysoev.ru     nxt_thread_start_t  start;
107*0Sigor@sysoev.ru 
108*0Sigor@sysoev.ru     link = data;
109*0Sigor@sysoev.ru 
110*0Sigor@sysoev.ru     thr = nxt_thread_init();
111*0Sigor@sysoev.ru 
112*0Sigor@sysoev.ru     nxt_log_debug(thr->log, "thread trampoline: %PH", thr->handle);
113*0Sigor@sysoev.ru 
114*0Sigor@sysoev.ru     pthread_cleanup_push(nxt_thread_time_cleanup, thr);
115*0Sigor@sysoev.ru 
116*0Sigor@sysoev.ru     start = link->start;
117*0Sigor@sysoev.ru     data = link->data;
118*0Sigor@sysoev.ru 
119*0Sigor@sysoev.ru     if (link->engine != NULL) {
120*0Sigor@sysoev.ru         thr->link = link;
121*0Sigor@sysoev.ru 
122*0Sigor@sysoev.ru     } else {
123*0Sigor@sysoev.ru         nxt_free(link);
124*0Sigor@sysoev.ru     }
125*0Sigor@sysoev.ru 
126*0Sigor@sysoev.ru     start(data);
127*0Sigor@sysoev.ru 
128*0Sigor@sysoev.ru     /*
129*0Sigor@sysoev.ru      * nxt_thread_time_cleanup() should be called only if a thread
130*0Sigor@sysoev.ru      * would be canceled, so ignore it here because nxt_thread_exit()
131*0Sigor@sysoev.ru      * calls nxt_thread_time_free() as well.
132*0Sigor@sysoev.ru      */
133*0Sigor@sysoev.ru     pthread_cleanup_pop(0);
134*0Sigor@sysoev.ru 
135*0Sigor@sysoev.ru     nxt_thread_exit(thr);
136*0Sigor@sysoev.ru     nxt_unreachable();
137*0Sigor@sysoev.ru     return NULL;
138*0Sigor@sysoev.ru }
139*0Sigor@sysoev.ru 
140*0Sigor@sysoev.ru 
141*0Sigor@sysoev.ru nxt_thread_t *
142*0Sigor@sysoev.ru nxt_thread_init(void)
143*0Sigor@sysoev.ru {
144*0Sigor@sysoev.ru     nxt_thread_t  *thr;
145*0Sigor@sysoev.ru 
146*0Sigor@sysoev.ru     nxt_thread_init_data(nxt_thread_context);
147*0Sigor@sysoev.ru 
148*0Sigor@sysoev.ru     thr = nxt_thread();
149*0Sigor@sysoev.ru 
150*0Sigor@sysoev.ru     if (thr->log == NULL) {
151*0Sigor@sysoev.ru         thr->log = &nxt_main_log;
152*0Sigor@sysoev.ru         thr->handle = nxt_thread_handle();
153*0Sigor@sysoev.ru 
154*0Sigor@sysoev.ru         /*
155*0Sigor@sysoev.ru          * Threads are never preempted by asynchronous signals, since
156*0Sigor@sysoev.ru          * the signals are processed synchronously by dedicated thread.
157*0Sigor@sysoev.ru          */
158*0Sigor@sysoev.ru         thr->time.signal = -1;
159*0Sigor@sysoev.ru 
160*0Sigor@sysoev.ru         nxt_thread_time_update(thr);
161*0Sigor@sysoev.ru     }
162*0Sigor@sysoev.ru 
163*0Sigor@sysoev.ru     return thr;
164*0Sigor@sysoev.ru }
165*0Sigor@sysoev.ru 
166*0Sigor@sysoev.ru 
167*0Sigor@sysoev.ru static void
168*0Sigor@sysoev.ru nxt_thread_time_cleanup(void *data)
169*0Sigor@sysoev.ru {
170*0Sigor@sysoev.ru     nxt_thread_t  *thr;
171*0Sigor@sysoev.ru 
172*0Sigor@sysoev.ru     thr = data;
173*0Sigor@sysoev.ru 
174*0Sigor@sysoev.ru     nxt_log_debug(thr->log, "thread time cleanup");
175*0Sigor@sysoev.ru 
176*0Sigor@sysoev.ru     nxt_thread_time_free(thr);
177*0Sigor@sysoev.ru }
178*0Sigor@sysoev.ru 
179*0Sigor@sysoev.ru 
180*0Sigor@sysoev.ru void
181*0Sigor@sysoev.ru nxt_thread_exit(nxt_thread_t *thr)
182*0Sigor@sysoev.ru {
183*0Sigor@sysoev.ru     nxt_log_debug(thr->log, "thread exit");
184*0Sigor@sysoev.ru 
185*0Sigor@sysoev.ru     if (thr->link != NULL) {
186*0Sigor@sysoev.ru         nxt_event_engine_post(thr->link->engine, thr->link->exit,
187*0Sigor@sysoev.ru                               (void *) (uintptr_t) thr->handle, NULL,
188*0Sigor@sysoev.ru                               &nxt_main_log);
189*0Sigor@sysoev.ru 
190*0Sigor@sysoev.ru         nxt_free(thr->link);
191*0Sigor@sysoev.ru         thr->link = NULL;
192*0Sigor@sysoev.ru     }
193*0Sigor@sysoev.ru 
194*0Sigor@sysoev.ru     nxt_thread_time_free(thr);
195*0Sigor@sysoev.ru 
196*0Sigor@sysoev.ru     pthread_exit(NULL);
197*0Sigor@sysoev.ru     nxt_unreachable();
198*0Sigor@sysoev.ru }
199*0Sigor@sysoev.ru 
200*0Sigor@sysoev.ru 
201*0Sigor@sysoev.ru void
202*0Sigor@sysoev.ru nxt_thread_cancel(nxt_thread_handle_t handle)
203*0Sigor@sysoev.ru {
204*0Sigor@sysoev.ru     nxt_err_t  err;
205*0Sigor@sysoev.ru 
206*0Sigor@sysoev.ru     nxt_thread_log_debug("thread cancel: %PH", handle);
207*0Sigor@sysoev.ru 
208*0Sigor@sysoev.ru     err = pthread_cancel(handle);
209*0Sigor@sysoev.ru 
210*0Sigor@sysoev.ru     if (err != 0) {
211*0Sigor@sysoev.ru         nxt_main_log_alert("pthread_cancel(%PH) failed %E", handle, err);
212*0Sigor@sysoev.ru     }
213*0Sigor@sysoev.ru }
214*0Sigor@sysoev.ru 
215*0Sigor@sysoev.ru 
216*0Sigor@sysoev.ru void
217*0Sigor@sysoev.ru nxt_thread_wait(nxt_thread_handle_t handle)
218*0Sigor@sysoev.ru {
219*0Sigor@sysoev.ru     nxt_err_t  err;
220*0Sigor@sysoev.ru 
221*0Sigor@sysoev.ru     nxt_thread_log_debug("thread wait: %PH", handle);
222*0Sigor@sysoev.ru 
223*0Sigor@sysoev.ru     err = pthread_join(handle, NULL);
224*0Sigor@sysoev.ru 
225*0Sigor@sysoev.ru     if (err != 0) {
226*0Sigor@sysoev.ru         nxt_main_log_alert("pthread_join(%PH) failed %E", handle, err);
227*0Sigor@sysoev.ru     }
228*0Sigor@sysoev.ru }
229