xref: /unit/src/nxt_fiber.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 char *nxt_fiber_create_stack(nxt_fiber_t *fib);
11*0Sigor@sysoev.ru static void nxt_fiber_switch_stack(nxt_fiber_t *fib, jmp_buf *parent);
12*0Sigor@sysoev.ru static void nxt_fiber_switch_handler(nxt_thread_t *thr, void *obj,
13*0Sigor@sysoev.ru     void *data);
14*0Sigor@sysoev.ru static void nxt_fiber_switch(nxt_thread_t *thr, nxt_fiber_t *fib);
15*0Sigor@sysoev.ru static void nxt_fiber_timer_handler(nxt_thread_t *thr, void *obj,
16*0Sigor@sysoev.ru     void *data);
17*0Sigor@sysoev.ru 
18*0Sigor@sysoev.ru 
19*0Sigor@sysoev.ru #define                                                                       \
20*0Sigor@sysoev.ru nxt_fiber_enqueue(thr, fib)                                                   \
21*0Sigor@sysoev.ru     nxt_thread_work_queue_add(thr, &(thr)->work_queue.main,                   \
22*0Sigor@sysoev.ru                               nxt_fiber_switch_handler, fib, NULL, thr->log)
23*0Sigor@sysoev.ru 
24*0Sigor@sysoev.ru 
25*0Sigor@sysoev.ru nxt_fiber_main_t *
26*0Sigor@sysoev.ru nxt_fiber_main_create(nxt_event_engine_t *engine)
27*0Sigor@sysoev.ru {
28*0Sigor@sysoev.ru     nxt_fiber_main_t  *fm;
29*0Sigor@sysoev.ru 
30*0Sigor@sysoev.ru     fm = nxt_zalloc(sizeof(nxt_fiber_main_t));
31*0Sigor@sysoev.ru     if (nxt_slow_path(fm == NULL)) {
32*0Sigor@sysoev.ru         return NULL;
33*0Sigor@sysoev.ru     }
34*0Sigor@sysoev.ru 
35*0Sigor@sysoev.ru     fm->stack_size = 512 * 1024 - nxt_pagesize;
36*0Sigor@sysoev.ru     fm->idle = NULL;
37*0Sigor@sysoev.ru 
38*0Sigor@sysoev.ru     return fm;
39*0Sigor@sysoev.ru }
40*0Sigor@sysoev.ru 
41*0Sigor@sysoev.ru 
42*0Sigor@sysoev.ru nxt_int_t
43*0Sigor@sysoev.ru nxt_fiber_create(nxt_fiber_start_t start, void *data, size_t stack)
44*0Sigor@sysoev.ru {
45*0Sigor@sysoev.ru     int                  ret;
46*0Sigor@sysoev.ru     jmp_buf              parent;
47*0Sigor@sysoev.ru     nxt_fid_t            fid;
48*0Sigor@sysoev.ru     nxt_fiber_t          *fib;
49*0Sigor@sysoev.ru     nxt_thread_t         *thr;
50*0Sigor@sysoev.ru     nxt_fiber_main_t     *fm;
51*0Sigor@sysoev.ru 
52*0Sigor@sysoev.ru     thr = nxt_thread();
53*0Sigor@sysoev.ru     fm = thr->engine->fibers;
54*0Sigor@sysoev.ru 
55*0Sigor@sysoev.ru     fid = ++fm->fid;
56*0Sigor@sysoev.ru 
57*0Sigor@sysoev.ru     if (fid == 0) {
58*0Sigor@sysoev.ru         fid = ++fm->fid;
59*0Sigor@sysoev.ru     }
60*0Sigor@sysoev.ru 
61*0Sigor@sysoev.ru     fib = fm->idle;
62*0Sigor@sysoev.ru 
63*0Sigor@sysoev.ru     if (fib != NULL) {
64*0Sigor@sysoev.ru         fm->idle = fib->next;
65*0Sigor@sysoev.ru         fib->fid = fid;
66*0Sigor@sysoev.ru         fib->start = start;
67*0Sigor@sysoev.ru         fib->data = data;
68*0Sigor@sysoev.ru         fib->main = fm;
69*0Sigor@sysoev.ru 
70*0Sigor@sysoev.ru         nxt_log_debug(thr->log, "fiber create cached: %PF", fib->fid);
71*0Sigor@sysoev.ru         nxt_fiber_enqueue(thr, fib);
72*0Sigor@sysoev.ru         return NXT_OK;
73*0Sigor@sysoev.ru     }
74*0Sigor@sysoev.ru 
75*0Sigor@sysoev.ru     nxt_log_debug(thr->log, "fiber create");
76*0Sigor@sysoev.ru 
77*0Sigor@sysoev.ru     fib = nxt_malloc(sizeof(nxt_fiber_t));
78*0Sigor@sysoev.ru     if (nxt_slow_path(fib == NULL)) {
79*0Sigor@sysoev.ru         return NXT_ERROR;
80*0Sigor@sysoev.ru     }
81*0Sigor@sysoev.ru 
82*0Sigor@sysoev.ru     fib->fid = fid;
83*0Sigor@sysoev.ru     fib->start = start;
84*0Sigor@sysoev.ru     fib->data = data;
85*0Sigor@sysoev.ru     fib->stack_size = fm->stack_size;
86*0Sigor@sysoev.ru     fib->main = fm;
87*0Sigor@sysoev.ru 
88*0Sigor@sysoev.ru     fib->stack = nxt_fiber_create_stack(fib);
89*0Sigor@sysoev.ru 
90*0Sigor@sysoev.ru     if (nxt_fast_path(fib->stack != NULL)) {
91*0Sigor@sysoev.ru 
92*0Sigor@sysoev.ru         if (_setjmp(parent) != 0) {
93*0Sigor@sysoev.ru             nxt_log_debug(thr->log, "fiber create: %PF", fib->fid);
94*0Sigor@sysoev.ru             return NXT_OK;
95*0Sigor@sysoev.ru         }
96*0Sigor@sysoev.ru 
97*0Sigor@sysoev.ru         nxt_fiber_switch_stack(fib, &parent);
98*0Sigor@sysoev.ru         /* It does not return if the switch was successful. */
99*0Sigor@sysoev.ru     }
100*0Sigor@sysoev.ru 
101*0Sigor@sysoev.ru     ret = munmap(fib->stack - nxt_pagesize, fib->stack_size + nxt_pagesize);
102*0Sigor@sysoev.ru 
103*0Sigor@sysoev.ru     if (nxt_slow_path(ret != 0)) {
104*0Sigor@sysoev.ru         nxt_log_alert(thr->log, "munmap() failed %E", nxt_errno);
105*0Sigor@sysoev.ru     }
106*0Sigor@sysoev.ru 
107*0Sigor@sysoev.ru     nxt_free(fib);
108*0Sigor@sysoev.ru 
109*0Sigor@sysoev.ru     return NXT_ERROR;
110*0Sigor@sysoev.ru }
111*0Sigor@sysoev.ru 
112*0Sigor@sysoev.ru 
113*0Sigor@sysoev.ru #if (NXT_LINUX)
114*0Sigor@sysoev.ru 
115*0Sigor@sysoev.ru static char *
116*0Sigor@sysoev.ru nxt_fiber_create_stack(nxt_fiber_t *fib)
117*0Sigor@sysoev.ru {
118*0Sigor@sysoev.ru     char    *s;
119*0Sigor@sysoev.ru     size_t  size;
120*0Sigor@sysoev.ru 
121*0Sigor@sysoev.ru     size = fib->stack_size + nxt_pagesize;
122*0Sigor@sysoev.ru 
123*0Sigor@sysoev.ru     s = mmap(NULL, size, PROT_READ | PROT_WRITE,
124*0Sigor@sysoev.ru              MAP_PRIVATE | MAP_ANON | MAP_GROWSDOWN, -1, 0);
125*0Sigor@sysoev.ru 
126*0Sigor@sysoev.ru     if (nxt_slow_path(s == MAP_FAILED)) {
127*0Sigor@sysoev.ru         nxt_thread_log_alert("fiber stack "
128*0Sigor@sysoev.ru                    "mmap(%uz, MAP_PRIVATE|MAP_ANON|MAP_GROWSDOWN) failed %E",
129*0Sigor@sysoev.ru                    size, nxt_errno);
130*0Sigor@sysoev.ru         return NULL;
131*0Sigor@sysoev.ru     }
132*0Sigor@sysoev.ru 
133*0Sigor@sysoev.ru     if (nxt_slow_path(mprotect(s, nxt_pagesize, PROT_NONE) != 0)) {
134*0Sigor@sysoev.ru         nxt_thread_log_alert("fiber stack mprotect(%uz, PROT_NONE) failed %E",
135*0Sigor@sysoev.ru                              size, nxt_errno);
136*0Sigor@sysoev.ru         return NULL;
137*0Sigor@sysoev.ru     }
138*0Sigor@sysoev.ru 
139*0Sigor@sysoev.ru     s += nxt_pagesize;
140*0Sigor@sysoev.ru 
141*0Sigor@sysoev.ru     nxt_thread_log_debug("fiber stack mmap: %p", s);
142*0Sigor@sysoev.ru 
143*0Sigor@sysoev.ru     return s;
144*0Sigor@sysoev.ru }
145*0Sigor@sysoev.ru 
146*0Sigor@sysoev.ru #else /* Generic version. */
147*0Sigor@sysoev.ru 
148*0Sigor@sysoev.ru static char *
149*0Sigor@sysoev.ru nxt_fiber_create_stack(nxt_fiber_t *fib)
150*0Sigor@sysoev.ru {
151*0Sigor@sysoev.ru     char    *s;
152*0Sigor@sysoev.ru     size_t   size;
153*0Sigor@sysoev.ru 
154*0Sigor@sysoev.ru     size = fib->stack_size + nxt_pagesize;
155*0Sigor@sysoev.ru 
156*0Sigor@sysoev.ru     s = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
157*0Sigor@sysoev.ru 
158*0Sigor@sysoev.ru     if (nxt_slow_path(s == MAP_FAILED)) {
159*0Sigor@sysoev.ru         nxt_thread_log_alert("fiber stack "
160*0Sigor@sysoev.ru                              "mmap(%uz, MAP_PRIVATE|MAP_ANON) failed %E",
161*0Sigor@sysoev.ru                              size, nxt_errno);
162*0Sigor@sysoev.ru         return NULL;
163*0Sigor@sysoev.ru     }
164*0Sigor@sysoev.ru 
165*0Sigor@sysoev.ru     if (nxt_slow_path(mprotect(s, nxt_pagesize, PROT_NONE) != 0)) {
166*0Sigor@sysoev.ru         nxt_thread_log_alert("fiber stack mprotect(%uz, PROT_NONE) failed %E",
167*0Sigor@sysoev.ru                               size, nxt_errno);
168*0Sigor@sysoev.ru         return NULL;
169*0Sigor@sysoev.ru     }
170*0Sigor@sysoev.ru 
171*0Sigor@sysoev.ru     s += nxt_pagesize;
172*0Sigor@sysoev.ru 
173*0Sigor@sysoev.ru     nxt_thread_log_debug("fiber stack mmap: %p", s);
174*0Sigor@sysoev.ru 
175*0Sigor@sysoev.ru     return s;
176*0Sigor@sysoev.ru }
177*0Sigor@sysoev.ru 
178*0Sigor@sysoev.ru #endif
179*0Sigor@sysoev.ru 
180*0Sigor@sysoev.ru 
181*0Sigor@sysoev.ru #if (NXT_LINUX && NXT_64BIT)
182*0Sigor@sysoev.ru 
183*0Sigor@sysoev.ru /*
184*0Sigor@sysoev.ru  * Linux 64-bit ucontext version.  64-bit glibc makecontext() passes
185*0Sigor@sysoev.ru  * pointers as signed int's. The bug has been fixed in glibc 2.8.
186*0Sigor@sysoev.ru  */
187*0Sigor@sysoev.ru 
188*0Sigor@sysoev.ru static void nxt_fiber_trampoline(uint32_t fh, uint32_t fl, uint32_t ph,
189*0Sigor@sysoev.ru     uint32_t pl);
190*0Sigor@sysoev.ru 
191*0Sigor@sysoev.ru 
192*0Sigor@sysoev.ru static void
193*0Sigor@sysoev.ru nxt_fiber_switch_stack(nxt_fiber_t *fib, jmp_buf *parent)
194*0Sigor@sysoev.ru {
195*0Sigor@sysoev.ru     ucontext_t  uc;
196*0Sigor@sysoev.ru 
197*0Sigor@sysoev.ru     nxt_thread_log_debug("fiber switch to stack: %p", fib->stack);
198*0Sigor@sysoev.ru 
199*0Sigor@sysoev.ru     if (nxt_slow_path(getcontext(&uc) != 0)) {
200*0Sigor@sysoev.ru         nxt_thread_log_alert("getcontext() failed");
201*0Sigor@sysoev.ru         return;
202*0Sigor@sysoev.ru     }
203*0Sigor@sysoev.ru 
204*0Sigor@sysoev.ru     uc.uc_link = NULL;
205*0Sigor@sysoev.ru     uc.uc_stack.ss_sp = fib->stack;
206*0Sigor@sysoev.ru     uc.uc_stack.ss_size = fib->stack_size;
207*0Sigor@sysoev.ru 
208*0Sigor@sysoev.ru     makecontext(&uc, (void (*)(void)) nxt_fiber_trampoline, 4,
209*0Sigor@sysoev.ru                 (uint32_t) ((uintptr_t) fib >> 32),
210*0Sigor@sysoev.ru                 (uint32_t) ((uintptr_t) fib & 0xffffffff),
211*0Sigor@sysoev.ru                 (uint32_t) ((uintptr_t) parent >> 32),
212*0Sigor@sysoev.ru                 (uint32_t) ((uintptr_t) parent & 0xffffffff));
213*0Sigor@sysoev.ru 
214*0Sigor@sysoev.ru     setcontext(&uc);
215*0Sigor@sysoev.ru 
216*0Sigor@sysoev.ru     nxt_thread_log_alert("setcontext() failed");
217*0Sigor@sysoev.ru }
218*0Sigor@sysoev.ru 
219*0Sigor@sysoev.ru 
220*0Sigor@sysoev.ru static void
221*0Sigor@sysoev.ru nxt_fiber_trampoline(uint32_t fh, uint32_t fl, uint32_t ph, uint32_t pl)
222*0Sigor@sysoev.ru {
223*0Sigor@sysoev.ru     jmp_buf       *parent;
224*0Sigor@sysoev.ru     nxt_fiber_t   *fib;
225*0Sigor@sysoev.ru     nxt_thread_t  *thr;
226*0Sigor@sysoev.ru 
227*0Sigor@sysoev.ru     fib = (nxt_fiber_t *) (((uintptr_t) fh << 32) + fl);
228*0Sigor@sysoev.ru     parent = (jmp_buf *) (((uintptr_t) ph << 32) + pl);
229*0Sigor@sysoev.ru 
230*0Sigor@sysoev.ru     thr = nxt_thread();
231*0Sigor@sysoev.ru 
232*0Sigor@sysoev.ru     if (_setjmp(fib->jmp) == 0) {
233*0Sigor@sysoev.ru         nxt_log_debug(thr->log, "fiber return to parent stack");
234*0Sigor@sysoev.ru 
235*0Sigor@sysoev.ru         nxt_fiber_enqueue(thr, fib);
236*0Sigor@sysoev.ru         _longjmp(*parent, 1);
237*0Sigor@sysoev.ru         nxt_unreachable();
238*0Sigor@sysoev.ru     }
239*0Sigor@sysoev.ru 
240*0Sigor@sysoev.ru     nxt_log_debug(thr->log, "fiber start");
241*0Sigor@sysoev.ru 
242*0Sigor@sysoev.ru     fib->start(fib->data);
243*0Sigor@sysoev.ru 
244*0Sigor@sysoev.ru     nxt_fiber_exit(&fib->main->fiber, NULL);
245*0Sigor@sysoev.ru     nxt_unreachable();
246*0Sigor@sysoev.ru }
247*0Sigor@sysoev.ru 
248*0Sigor@sysoev.ru #elif (NXT_HAVE_UCONTEXT)
249*0Sigor@sysoev.ru 
250*0Sigor@sysoev.ru /* Generic ucontext version. */
251*0Sigor@sysoev.ru 
252*0Sigor@sysoev.ru static void nxt_fiber_trampoline(nxt_fiber_t *fib, jmp_buf *parent);
253*0Sigor@sysoev.ru 
254*0Sigor@sysoev.ru 
255*0Sigor@sysoev.ru static void
256*0Sigor@sysoev.ru nxt_fiber_switch_stack(nxt_fiber_t *fib, jmp_buf *parent)
257*0Sigor@sysoev.ru {
258*0Sigor@sysoev.ru     ucontext_t  uc;
259*0Sigor@sysoev.ru 
260*0Sigor@sysoev.ru     nxt_thread_log_debug("fiber switch to stack: %p", fib->stack);
261*0Sigor@sysoev.ru 
262*0Sigor@sysoev.ru     if (nxt_slow_path(getcontext(&uc) != 0)) {
263*0Sigor@sysoev.ru         nxt_thread_log_alert("getcontext() failed");
264*0Sigor@sysoev.ru         return;
265*0Sigor@sysoev.ru     }
266*0Sigor@sysoev.ru 
267*0Sigor@sysoev.ru     uc.uc_link = NULL;
268*0Sigor@sysoev.ru     uc.uc_stack.ss_sp = fib->stack;
269*0Sigor@sysoev.ru     uc.uc_stack.ss_size = fib->stack_size;
270*0Sigor@sysoev.ru 
271*0Sigor@sysoev.ru     makecontext(&uc, (void (*)(void)) nxt_fiber_trampoline, 2, fib, parent);
272*0Sigor@sysoev.ru 
273*0Sigor@sysoev.ru     setcontext(&uc);
274*0Sigor@sysoev.ru 
275*0Sigor@sysoev.ru #if !(NXT_SOLARIS)
276*0Sigor@sysoev.ru     /* Solaris declares setcontext() as __NORETURN. */
277*0Sigor@sysoev.ru 
278*0Sigor@sysoev.ru     nxt_thread_log_alert("setcontext() failed");
279*0Sigor@sysoev.ru #endif
280*0Sigor@sysoev.ru }
281*0Sigor@sysoev.ru 
282*0Sigor@sysoev.ru 
283*0Sigor@sysoev.ru static void
284*0Sigor@sysoev.ru nxt_fiber_trampoline(nxt_fiber_t *fib, jmp_buf *parent)
285*0Sigor@sysoev.ru {
286*0Sigor@sysoev.ru     nxt_thread_t  *thr;
287*0Sigor@sysoev.ru 
288*0Sigor@sysoev.ru     thr = nxt_thread();
289*0Sigor@sysoev.ru 
290*0Sigor@sysoev.ru     if (_setjmp(fib->jmp) == 0) {
291*0Sigor@sysoev.ru         nxt_log_debug(thr->log, "fiber return to parent stack");
292*0Sigor@sysoev.ru 
293*0Sigor@sysoev.ru         nxt_fiber_enqueue(thr, fib);
294*0Sigor@sysoev.ru         _longjmp(*parent, 1);
295*0Sigor@sysoev.ru         nxt_unreachable();
296*0Sigor@sysoev.ru     }
297*0Sigor@sysoev.ru 
298*0Sigor@sysoev.ru     nxt_log_debug(thr->log, "fiber start");
299*0Sigor@sysoev.ru 
300*0Sigor@sysoev.ru     fib->start(fib->data);
301*0Sigor@sysoev.ru 
302*0Sigor@sysoev.ru     nxt_fiber_exit(&fib->main->fiber, NULL);
303*0Sigor@sysoev.ru     nxt_unreachable();
304*0Sigor@sysoev.ru }
305*0Sigor@sysoev.ru 
306*0Sigor@sysoev.ru #else
307*0Sigor@sysoev.ru 
308*0Sigor@sysoev.ru #error No ucontext(3) interface.
309*0Sigor@sysoev.ru 
310*0Sigor@sysoev.ru #endif
311*0Sigor@sysoev.ru 
312*0Sigor@sysoev.ru 
313*0Sigor@sysoev.ru static void
314*0Sigor@sysoev.ru nxt_fiber_switch_handler(nxt_thread_t *thr, void *obj, void *data)
315*0Sigor@sysoev.ru {
316*0Sigor@sysoev.ru     nxt_fiber_t  *fib;
317*0Sigor@sysoev.ru 
318*0Sigor@sysoev.ru     fib = obj;
319*0Sigor@sysoev.ru 
320*0Sigor@sysoev.ru     nxt_fiber_switch(thr, fib);
321*0Sigor@sysoev.ru     nxt_unreachable();
322*0Sigor@sysoev.ru }
323*0Sigor@sysoev.ru 
324*0Sigor@sysoev.ru 
325*0Sigor@sysoev.ru static void
326*0Sigor@sysoev.ru nxt_fiber_switch(nxt_thread_t *thr, nxt_fiber_t *fib)
327*0Sigor@sysoev.ru {
328*0Sigor@sysoev.ru     nxt_log_debug(thr->log, "fiber switch: %PF", fib->fid);
329*0Sigor@sysoev.ru 
330*0Sigor@sysoev.ru     thr->fiber = fib;
331*0Sigor@sysoev.ru     _longjmp(fib->jmp, 1);
332*0Sigor@sysoev.ru     nxt_unreachable();
333*0Sigor@sysoev.ru }
334*0Sigor@sysoev.ru 
335*0Sigor@sysoev.ru 
336*0Sigor@sysoev.ru nxt_fiber_t *
337*0Sigor@sysoev.ru nxt_fiber_self(nxt_thread_t *thr)
338*0Sigor@sysoev.ru {
339*0Sigor@sysoev.ru     return (nxt_fast_path(thr != NULL)) ? thr->fiber : NULL;
340*0Sigor@sysoev.ru }
341*0Sigor@sysoev.ru 
342*0Sigor@sysoev.ru 
343*0Sigor@sysoev.ru void
344*0Sigor@sysoev.ru nxt_fiber_yield(void)
345*0Sigor@sysoev.ru {
346*0Sigor@sysoev.ru     nxt_fiber_t   *fib;
347*0Sigor@sysoev.ru     nxt_thread_t  *thr;
348*0Sigor@sysoev.ru 
349*0Sigor@sysoev.ru     thr = nxt_thread();
350*0Sigor@sysoev.ru     fib = thr->fiber;
351*0Sigor@sysoev.ru 
352*0Sigor@sysoev.ru     if (_setjmp(fib->jmp) == 0) {
353*0Sigor@sysoev.ru 
354*0Sigor@sysoev.ru         nxt_log_debug(thr->log, "fiber yield");
355*0Sigor@sysoev.ru 
356*0Sigor@sysoev.ru         nxt_fiber_enqueue(thr, fib);
357*0Sigor@sysoev.ru         nxt_fiber_switch(thr, &fib->main->fiber);
358*0Sigor@sysoev.ru         nxt_unreachable();
359*0Sigor@sysoev.ru     }
360*0Sigor@sysoev.ru 
361*0Sigor@sysoev.ru     nxt_log_debug(thr->log, "fiber yield return");
362*0Sigor@sysoev.ru }
363*0Sigor@sysoev.ru 
364*0Sigor@sysoev.ru 
365*0Sigor@sysoev.ru void
366*0Sigor@sysoev.ru nxt_fiber_sleep(nxt_msec_t timeout)
367*0Sigor@sysoev.ru {
368*0Sigor@sysoev.ru     nxt_fiber_t   *fib;
369*0Sigor@sysoev.ru     nxt_thread_t  *thr;
370*0Sigor@sysoev.ru 
371*0Sigor@sysoev.ru     thr = nxt_thread();
372*0Sigor@sysoev.ru     fib = thr->fiber;
373*0Sigor@sysoev.ru 
374*0Sigor@sysoev.ru     fib->timer.work_queue = &thr->work_queue.main;
375*0Sigor@sysoev.ru     fib->timer.handler = nxt_fiber_timer_handler;
376*0Sigor@sysoev.ru     fib->timer.log = &nxt_main_log;
377*0Sigor@sysoev.ru 
378*0Sigor@sysoev.ru     nxt_event_timer_add(thr->engine, &fib->timer, timeout);
379*0Sigor@sysoev.ru 
380*0Sigor@sysoev.ru     if (_setjmp(fib->jmp) == 0) {
381*0Sigor@sysoev.ru 
382*0Sigor@sysoev.ru         nxt_log_debug(thr->log, "fiber sleep: %T", timeout);
383*0Sigor@sysoev.ru 
384*0Sigor@sysoev.ru         nxt_fiber_switch(thr, &fib->main->fiber);
385*0Sigor@sysoev.ru         nxt_unreachable();
386*0Sigor@sysoev.ru     }
387*0Sigor@sysoev.ru 
388*0Sigor@sysoev.ru     nxt_log_debug(thr->log, "fiber sleep return");
389*0Sigor@sysoev.ru }
390*0Sigor@sysoev.ru 
391*0Sigor@sysoev.ru 
392*0Sigor@sysoev.ru static void
393*0Sigor@sysoev.ru nxt_fiber_timer_handler(nxt_thread_t *thr, void *obj, void *data)
394*0Sigor@sysoev.ru {
395*0Sigor@sysoev.ru     nxt_fiber_t        *fib;
396*0Sigor@sysoev.ru     nxt_event_timer_t  *ev;
397*0Sigor@sysoev.ru 
398*0Sigor@sysoev.ru     ev = obj;
399*0Sigor@sysoev.ru 
400*0Sigor@sysoev.ru     nxt_log_debug(thr->log, "fiber timer handler");
401*0Sigor@sysoev.ru 
402*0Sigor@sysoev.ru     fib = nxt_event_timer_data(ev, nxt_fiber_t, timer);
403*0Sigor@sysoev.ru 
404*0Sigor@sysoev.ru     nxt_fiber_switch(thr, fib);
405*0Sigor@sysoev.ru     nxt_unreachable();
406*0Sigor@sysoev.ru }
407*0Sigor@sysoev.ru 
408*0Sigor@sysoev.ru 
409*0Sigor@sysoev.ru void
410*0Sigor@sysoev.ru nxt_fiber_wait(void)
411*0Sigor@sysoev.ru {
412*0Sigor@sysoev.ru     nxt_fiber_t   *fib;
413*0Sigor@sysoev.ru     nxt_thread_t  *thr;
414*0Sigor@sysoev.ru 
415*0Sigor@sysoev.ru     thr = nxt_thread();
416*0Sigor@sysoev.ru     fib = thr->fiber;
417*0Sigor@sysoev.ru 
418*0Sigor@sysoev.ru     if (_setjmp(fib->jmp) == 0) {
419*0Sigor@sysoev.ru         nxt_log_debug(thr->log, "fiber wait");
420*0Sigor@sysoev.ru 
421*0Sigor@sysoev.ru         nxt_fiber_switch(thr, &fib->main->fiber);
422*0Sigor@sysoev.ru         nxt_unreachable();
423*0Sigor@sysoev.ru     }
424*0Sigor@sysoev.ru 
425*0Sigor@sysoev.ru     nxt_log_debug(thr->log, "fiber wait return");
426*0Sigor@sysoev.ru }
427*0Sigor@sysoev.ru 
428*0Sigor@sysoev.ru 
429*0Sigor@sysoev.ru void
430*0Sigor@sysoev.ru nxt_fiber_exit(nxt_fiber_t *next, void *data)
431*0Sigor@sysoev.ru {
432*0Sigor@sysoev.ru     nxt_fiber_t   *fib;
433*0Sigor@sysoev.ru     nxt_thread_t  *thr;
434*0Sigor@sysoev.ru 
435*0Sigor@sysoev.ru     thr = nxt_thread();
436*0Sigor@sysoev.ru     fib = thr->fiber;
437*0Sigor@sysoev.ru 
438*0Sigor@sysoev.ru     nxt_log_debug(thr->log, "fiber exit");
439*0Sigor@sysoev.ru 
440*0Sigor@sysoev.ru     /* TODO: limit idle fibers. */
441*0Sigor@sysoev.ru     fib->next = fib->main->idle;
442*0Sigor@sysoev.ru     fib->main->idle = fib;
443*0Sigor@sysoev.ru 
444*0Sigor@sysoev.ru     nxt_fiber_switch(thr, next);
445*0Sigor@sysoev.ru     nxt_unreachable();
446*0Sigor@sysoev.ru }
447