xref: /unit/src/nxt_fiber.c (revision 6)
10Sigor@sysoev.ru 
20Sigor@sysoev.ru /*
30Sigor@sysoev.ru  * Copyright (C) Igor Sysoev
40Sigor@sysoev.ru  * Copyright (C) NGINX, Inc.
50Sigor@sysoev.ru  */
60Sigor@sysoev.ru 
70Sigor@sysoev.ru #include <nxt_main.h>
80Sigor@sysoev.ru 
90Sigor@sysoev.ru 
101Sigor@sysoev.ru static char *nxt_fiber_create_stack(nxt_task_t *task, nxt_fiber_t *fib);
110Sigor@sysoev.ru static void nxt_fiber_switch_stack(nxt_fiber_t *fib, jmp_buf *parent);
121Sigor@sysoev.ru static void nxt_fiber_switch_handler(nxt_task_t *task, void *obj, void *data);
131Sigor@sysoev.ru static void nxt_fiber_switch(nxt_task_t *task, nxt_fiber_t *fib);
141Sigor@sysoev.ru static void nxt_fiber_timer_handler(nxt_task_t *task, void *obj, void *data);
150Sigor@sysoev.ru 
160Sigor@sysoev.ru 
170Sigor@sysoev.ru #define                                                                       \
181Sigor@sysoev.ru nxt_fiber_enqueue(thr, task, fib)                                             \
194Sigor@sysoev.ru     nxt_work_queue_add(&(thr)->engine->fast_work_queue,                       \
201Sigor@sysoev.ru                               nxt_fiber_switch_handler, task, fib, NULL)
210Sigor@sysoev.ru 
220Sigor@sysoev.ru 
230Sigor@sysoev.ru nxt_fiber_main_t *
240Sigor@sysoev.ru nxt_fiber_main_create(nxt_event_engine_t *engine)
250Sigor@sysoev.ru {
260Sigor@sysoev.ru     nxt_fiber_main_t  *fm;
270Sigor@sysoev.ru 
280Sigor@sysoev.ru     fm = nxt_zalloc(sizeof(nxt_fiber_main_t));
290Sigor@sysoev.ru     if (nxt_slow_path(fm == NULL)) {
300Sigor@sysoev.ru         return NULL;
310Sigor@sysoev.ru     }
320Sigor@sysoev.ru 
331Sigor@sysoev.ru     fm->engine = engine;
340Sigor@sysoev.ru     fm->stack_size = 512 * 1024 - nxt_pagesize;
350Sigor@sysoev.ru     fm->idle = NULL;
360Sigor@sysoev.ru 
370Sigor@sysoev.ru     return fm;
380Sigor@sysoev.ru }
390Sigor@sysoev.ru 
400Sigor@sysoev.ru 
410Sigor@sysoev.ru nxt_int_t
420Sigor@sysoev.ru nxt_fiber_create(nxt_fiber_start_t start, void *data, size_t stack)
430Sigor@sysoev.ru {
440Sigor@sysoev.ru     int                  ret;
450Sigor@sysoev.ru     jmp_buf              parent;
460Sigor@sysoev.ru     nxt_fid_t            fid;
470Sigor@sysoev.ru     nxt_fiber_t          *fib;
480Sigor@sysoev.ru     nxt_thread_t         *thr;
490Sigor@sysoev.ru     nxt_fiber_main_t     *fm;
500Sigor@sysoev.ru 
510Sigor@sysoev.ru     thr = nxt_thread();
520Sigor@sysoev.ru     fm = thr->engine->fibers;
530Sigor@sysoev.ru 
540Sigor@sysoev.ru     fid = ++fm->fid;
550Sigor@sysoev.ru 
560Sigor@sysoev.ru     if (fid == 0) {
570Sigor@sysoev.ru         fid = ++fm->fid;
580Sigor@sysoev.ru     }
590Sigor@sysoev.ru 
600Sigor@sysoev.ru     fib = fm->idle;
610Sigor@sysoev.ru 
620Sigor@sysoev.ru     if (fib != NULL) {
630Sigor@sysoev.ru         fm->idle = fib->next;
640Sigor@sysoev.ru         fib->fid = fid;
650Sigor@sysoev.ru         fib->start = start;
660Sigor@sysoev.ru         fib->data = data;
670Sigor@sysoev.ru         fib->main = fm;
680Sigor@sysoev.ru 
691Sigor@sysoev.ru         fib->task.thread = thr;
701Sigor@sysoev.ru         fib->task.log = thr->log;
711Sigor@sysoev.ru         fib->task.ident = nxt_task_next_ident();
721Sigor@sysoev.ru 
731Sigor@sysoev.ru         nxt_debug(&fib->task, "fiber create cached: %PF", fib->fid);
741Sigor@sysoev.ru 
751Sigor@sysoev.ru         nxt_fiber_enqueue(thr, &fm->engine->task, fib);
761Sigor@sysoev.ru 
770Sigor@sysoev.ru         return NXT_OK;
780Sigor@sysoev.ru     }
790Sigor@sysoev.ru 
800Sigor@sysoev.ru     nxt_log_debug(thr->log, "fiber create");
810Sigor@sysoev.ru 
820Sigor@sysoev.ru     fib = nxt_malloc(sizeof(nxt_fiber_t));
830Sigor@sysoev.ru     if (nxt_slow_path(fib == NULL)) {
840Sigor@sysoev.ru         return NXT_ERROR;
850Sigor@sysoev.ru     }
860Sigor@sysoev.ru 
870Sigor@sysoev.ru     fib->fid = fid;
880Sigor@sysoev.ru     fib->start = start;
890Sigor@sysoev.ru     fib->data = data;
900Sigor@sysoev.ru     fib->stack_size = fm->stack_size;
910Sigor@sysoev.ru     fib->main = fm;
920Sigor@sysoev.ru 
931Sigor@sysoev.ru     fib->task.thread = thr;
941Sigor@sysoev.ru     fib->task.log = thr->log;
951Sigor@sysoev.ru     fib->task.ident = nxt_task_next_ident();
961Sigor@sysoev.ru 
971Sigor@sysoev.ru     fib->stack = nxt_fiber_create_stack(&fib->task, fib);
980Sigor@sysoev.ru 
990Sigor@sysoev.ru     if (nxt_fast_path(fib->stack != NULL)) {
1000Sigor@sysoev.ru 
1010Sigor@sysoev.ru         if (_setjmp(parent) != 0) {
1020Sigor@sysoev.ru             nxt_log_debug(thr->log, "fiber create: %PF", fib->fid);
1030Sigor@sysoev.ru             return NXT_OK;
1040Sigor@sysoev.ru         }
1050Sigor@sysoev.ru 
1060Sigor@sysoev.ru         nxt_fiber_switch_stack(fib, &parent);
1070Sigor@sysoev.ru         /* It does not return if the switch was successful. */
1080Sigor@sysoev.ru     }
1090Sigor@sysoev.ru 
1100Sigor@sysoev.ru     ret = munmap(fib->stack - nxt_pagesize, fib->stack_size + nxt_pagesize);
1110Sigor@sysoev.ru 
1120Sigor@sysoev.ru     if (nxt_slow_path(ret != 0)) {
1130Sigor@sysoev.ru         nxt_log_alert(thr->log, "munmap() failed %E", nxt_errno);
1140Sigor@sysoev.ru     }
1150Sigor@sysoev.ru 
1160Sigor@sysoev.ru     nxt_free(fib);
1170Sigor@sysoev.ru 
1180Sigor@sysoev.ru     return NXT_ERROR;
1190Sigor@sysoev.ru }
1200Sigor@sysoev.ru 
1210Sigor@sysoev.ru 
1220Sigor@sysoev.ru #if (NXT_LINUX)
1230Sigor@sysoev.ru 
1240Sigor@sysoev.ru static char *
1251Sigor@sysoev.ru nxt_fiber_create_stack(nxt_task_t *task, nxt_fiber_t *fib)
1260Sigor@sysoev.ru {
1270Sigor@sysoev.ru     char    *s;
1280Sigor@sysoev.ru     size_t  size;
1290Sigor@sysoev.ru 
1300Sigor@sysoev.ru     size = fib->stack_size + nxt_pagesize;
1310Sigor@sysoev.ru 
1320Sigor@sysoev.ru     s = mmap(NULL, size, PROT_READ | PROT_WRITE,
1330Sigor@sysoev.ru              MAP_PRIVATE | MAP_ANON | MAP_GROWSDOWN, -1, 0);
1340Sigor@sysoev.ru 
1350Sigor@sysoev.ru     if (nxt_slow_path(s == MAP_FAILED)) {
1361Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "fiber stack "
1371Sigor@sysoev.ru                 "mmap(%uz, MAP_PRIVATE|MAP_ANON|MAP_GROWSDOWN) failed %E",
1381Sigor@sysoev.ru                 size, nxt_errno);
1391Sigor@sysoev.ru 
1400Sigor@sysoev.ru         return NULL;
1410Sigor@sysoev.ru     }
1420Sigor@sysoev.ru 
1430Sigor@sysoev.ru     if (nxt_slow_path(mprotect(s, nxt_pagesize, PROT_NONE) != 0)) {
1441Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT,
1451Sigor@sysoev.ru                 "fiber stack mprotect(%uz, PROT_NONE) failed %E",
1461Sigor@sysoev.ru                 size, nxt_errno);
1471Sigor@sysoev.ru 
1480Sigor@sysoev.ru         return NULL;
1490Sigor@sysoev.ru     }
1500Sigor@sysoev.ru 
1510Sigor@sysoev.ru     s += nxt_pagesize;
1520Sigor@sysoev.ru 
1531Sigor@sysoev.ru     nxt_debug(task, "fiber stack mmap: %p", s);
1540Sigor@sysoev.ru 
1550Sigor@sysoev.ru     return s;
1560Sigor@sysoev.ru }
1570Sigor@sysoev.ru 
1580Sigor@sysoev.ru #else /* Generic version. */
1590Sigor@sysoev.ru 
1600Sigor@sysoev.ru static char *
1611Sigor@sysoev.ru nxt_fiber_create_stack(nxt_task_t *task, nxt_fiber_t *fib)
1620Sigor@sysoev.ru {
1630Sigor@sysoev.ru     char    *s;
1640Sigor@sysoev.ru     size_t   size;
1650Sigor@sysoev.ru 
1660Sigor@sysoev.ru     size = fib->stack_size + nxt_pagesize;
1670Sigor@sysoev.ru 
1680Sigor@sysoev.ru     s = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
1690Sigor@sysoev.ru 
1700Sigor@sysoev.ru     if (nxt_slow_path(s == MAP_FAILED)) {
1711Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT,
1721Sigor@sysoev.ru                 "fiber stack mmap(%uz, MAP_PRIVATE|MAP_ANON) failed %E",
1731Sigor@sysoev.ru                 size, nxt_errno);
1741Sigor@sysoev.ru 
1750Sigor@sysoev.ru         return NULL;
1760Sigor@sysoev.ru     }
1770Sigor@sysoev.ru 
1780Sigor@sysoev.ru     if (nxt_slow_path(mprotect(s, nxt_pagesize, PROT_NONE) != 0)) {
1791Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT,
1801Sigor@sysoev.ru                "fiber stack mprotect(%uz, PROT_NONE) failed %E",
1811Sigor@sysoev.ru                size, nxt_errno);
1821Sigor@sysoev.ru 
1830Sigor@sysoev.ru         return NULL;
1840Sigor@sysoev.ru     }
1850Sigor@sysoev.ru 
1860Sigor@sysoev.ru     s += nxt_pagesize;
1870Sigor@sysoev.ru 
1881Sigor@sysoev.ru     nxt_debug(task, "fiber stack mmap: %p", s);
1890Sigor@sysoev.ru 
1900Sigor@sysoev.ru     return s;
1910Sigor@sysoev.ru }
1920Sigor@sysoev.ru 
1930Sigor@sysoev.ru #endif
1940Sigor@sysoev.ru 
1950Sigor@sysoev.ru 
1960Sigor@sysoev.ru #if (NXT_LINUX && NXT_64BIT)
1970Sigor@sysoev.ru 
1980Sigor@sysoev.ru /*
1990Sigor@sysoev.ru  * Linux 64-bit ucontext version.  64-bit glibc makecontext() passes
2000Sigor@sysoev.ru  * pointers as signed int's. The bug has been fixed in glibc 2.8.
2010Sigor@sysoev.ru  */
2020Sigor@sysoev.ru 
2030Sigor@sysoev.ru static void nxt_fiber_trampoline(uint32_t fh, uint32_t fl, uint32_t ph,
2040Sigor@sysoev.ru     uint32_t pl);
2050Sigor@sysoev.ru 
2060Sigor@sysoev.ru 
2070Sigor@sysoev.ru static void
2080Sigor@sysoev.ru nxt_fiber_switch_stack(nxt_fiber_t *fib, jmp_buf *parent)
2090Sigor@sysoev.ru {
2100Sigor@sysoev.ru     ucontext_t  uc;
2110Sigor@sysoev.ru 
2121Sigor@sysoev.ru     nxt_debug(&fib->task, "fiber switch to stack: %p", fib->stack);
2130Sigor@sysoev.ru 
2140Sigor@sysoev.ru     if (nxt_slow_path(getcontext(&uc) != 0)) {
2151Sigor@sysoev.ru         nxt_log(&fib->task, NXT_LOG_CRIT, "getcontext() failed");
2160Sigor@sysoev.ru         return;
2170Sigor@sysoev.ru     }
2180Sigor@sysoev.ru 
2190Sigor@sysoev.ru     uc.uc_link = NULL;
2200Sigor@sysoev.ru     uc.uc_stack.ss_sp = fib->stack;
2210Sigor@sysoev.ru     uc.uc_stack.ss_size = fib->stack_size;
2220Sigor@sysoev.ru 
2230Sigor@sysoev.ru     makecontext(&uc, (void (*)(void)) nxt_fiber_trampoline, 4,
2240Sigor@sysoev.ru                 (uint32_t) ((uintptr_t) fib >> 32),
2250Sigor@sysoev.ru                 (uint32_t) ((uintptr_t) fib & 0xffffffff),
2260Sigor@sysoev.ru                 (uint32_t) ((uintptr_t) parent >> 32),
2270Sigor@sysoev.ru                 (uint32_t) ((uintptr_t) parent & 0xffffffff));
2280Sigor@sysoev.ru 
2290Sigor@sysoev.ru     setcontext(&uc);
2300Sigor@sysoev.ru 
2311Sigor@sysoev.ru     nxt_log(&fib->task, NXT_LOG_CRIT, "setcontext() failed");
2320Sigor@sysoev.ru }
2330Sigor@sysoev.ru 
2340Sigor@sysoev.ru 
2350Sigor@sysoev.ru static void
2360Sigor@sysoev.ru nxt_fiber_trampoline(uint32_t fh, uint32_t fl, uint32_t ph, uint32_t pl)
2370Sigor@sysoev.ru {
2381Sigor@sysoev.ru     jmp_buf      *parent;
2391Sigor@sysoev.ru     nxt_task_t   *task;
2401Sigor@sysoev.ru     nxt_fiber_t  *fib;
2410Sigor@sysoev.ru 
2420Sigor@sysoev.ru     fib = (nxt_fiber_t *) (((uintptr_t) fh << 32) + fl);
2430Sigor@sysoev.ru     parent = (jmp_buf *) (((uintptr_t) ph << 32) + pl);
2440Sigor@sysoev.ru 
2451Sigor@sysoev.ru     task = &fib->task;
2460Sigor@sysoev.ru 
2470Sigor@sysoev.ru     if (_setjmp(fib->jmp) == 0) {
2481Sigor@sysoev.ru         nxt_debug(task, "fiber return to parent stack");
2490Sigor@sysoev.ru 
2501Sigor@sysoev.ru         nxt_fiber_enqueue(task->thread, task, fib);
2511Sigor@sysoev.ru 
2520Sigor@sysoev.ru         _longjmp(*parent, 1);
2531Sigor@sysoev.ru 
2540Sigor@sysoev.ru         nxt_unreachable();
2550Sigor@sysoev.ru     }
2560Sigor@sysoev.ru 
2571Sigor@sysoev.ru     nxt_debug(task, "fiber start");
2580Sigor@sysoev.ru 
2590Sigor@sysoev.ru     fib->start(fib->data);
2600Sigor@sysoev.ru 
2611Sigor@sysoev.ru     nxt_fiber_exit(task, &fib->main->fiber, NULL);
2621Sigor@sysoev.ru 
2630Sigor@sysoev.ru     nxt_unreachable();
2640Sigor@sysoev.ru }
2650Sigor@sysoev.ru 
2660Sigor@sysoev.ru #elif (NXT_HAVE_UCONTEXT)
2670Sigor@sysoev.ru 
2680Sigor@sysoev.ru /* Generic ucontext version. */
2690Sigor@sysoev.ru 
2700Sigor@sysoev.ru static void nxt_fiber_trampoline(nxt_fiber_t *fib, jmp_buf *parent);
2710Sigor@sysoev.ru 
2720Sigor@sysoev.ru 
2730Sigor@sysoev.ru static void
2740Sigor@sysoev.ru nxt_fiber_switch_stack(nxt_fiber_t *fib, jmp_buf *parent)
2750Sigor@sysoev.ru {
2760Sigor@sysoev.ru     ucontext_t  uc;
2770Sigor@sysoev.ru 
2781Sigor@sysoev.ru     nxt_debug(&fib->task, "fiber switch to stack: %p", fib->stack);
2790Sigor@sysoev.ru 
2800Sigor@sysoev.ru     if (nxt_slow_path(getcontext(&uc) != 0)) {
2811Sigor@sysoev.ru         nxt_log(&fib->task, NXT_LOG_CRIT, "getcontext() failed");
2820Sigor@sysoev.ru         return;
2830Sigor@sysoev.ru     }
2840Sigor@sysoev.ru 
2850Sigor@sysoev.ru     uc.uc_link = NULL;
2860Sigor@sysoev.ru     uc.uc_stack.ss_sp = fib->stack;
2870Sigor@sysoev.ru     uc.uc_stack.ss_size = fib->stack_size;
2880Sigor@sysoev.ru 
2890Sigor@sysoev.ru     makecontext(&uc, (void (*)(void)) nxt_fiber_trampoline, 2, fib, parent);
2900Sigor@sysoev.ru 
2910Sigor@sysoev.ru     setcontext(&uc);
2920Sigor@sysoev.ru 
2930Sigor@sysoev.ru #if !(NXT_SOLARIS)
2940Sigor@sysoev.ru     /* Solaris declares setcontext() as __NORETURN. */
2950Sigor@sysoev.ru 
2961Sigor@sysoev.ru     nxt_log(&fib->task, NXT_LOG_CRIT, "setcontext() failed");
2970Sigor@sysoev.ru #endif
2980Sigor@sysoev.ru }
2990Sigor@sysoev.ru 
3000Sigor@sysoev.ru 
3010Sigor@sysoev.ru static void
3020Sigor@sysoev.ru nxt_fiber_trampoline(nxt_fiber_t *fib, jmp_buf *parent)
3030Sigor@sysoev.ru {
3041Sigor@sysoev.ru     nxt_task_t  *task;
3050Sigor@sysoev.ru 
3061Sigor@sysoev.ru     task = &fib->task;
3070Sigor@sysoev.ru 
3080Sigor@sysoev.ru     if (_setjmp(fib->jmp) == 0) {
3091Sigor@sysoev.ru         nxt_debug(task, "fiber return to parent stack");
3100Sigor@sysoev.ru 
3111Sigor@sysoev.ru         nxt_fiber_enqueue(task->thread, task, fib);
3121Sigor@sysoev.ru 
3130Sigor@sysoev.ru         _longjmp(*parent, 1);
3141Sigor@sysoev.ru 
3150Sigor@sysoev.ru         nxt_unreachable();
3160Sigor@sysoev.ru     }
3170Sigor@sysoev.ru 
3181Sigor@sysoev.ru     nxt_debug(task, "fiber start");
3190Sigor@sysoev.ru 
3200Sigor@sysoev.ru     fib->start(fib->data);
3210Sigor@sysoev.ru 
3221Sigor@sysoev.ru     nxt_fiber_exit(task, &fib->main->fiber, NULL);
3231Sigor@sysoev.ru 
3240Sigor@sysoev.ru     nxt_unreachable();
3250Sigor@sysoev.ru }
3260Sigor@sysoev.ru 
3270Sigor@sysoev.ru #else
3280Sigor@sysoev.ru 
3290Sigor@sysoev.ru #error No ucontext(3) interface.
3300Sigor@sysoev.ru 
3310Sigor@sysoev.ru #endif
3320Sigor@sysoev.ru 
3330Sigor@sysoev.ru 
3340Sigor@sysoev.ru static void
3351Sigor@sysoev.ru nxt_fiber_switch_handler(nxt_task_t *task, void *obj, void *data)
3360Sigor@sysoev.ru {
3370Sigor@sysoev.ru     nxt_fiber_t  *fib;
3380Sigor@sysoev.ru 
3390Sigor@sysoev.ru     fib = obj;
3400Sigor@sysoev.ru 
3411Sigor@sysoev.ru     nxt_fiber_switch(task, fib);
3420Sigor@sysoev.ru     nxt_unreachable();
3430Sigor@sysoev.ru }
3440Sigor@sysoev.ru 
3450Sigor@sysoev.ru 
3460Sigor@sysoev.ru static void
3471Sigor@sysoev.ru nxt_fiber_switch(nxt_task_t *task, nxt_fiber_t *fib)
3480Sigor@sysoev.ru {
3491Sigor@sysoev.ru     nxt_debug(task, "fiber switch: %PF", fib->fid);
3500Sigor@sysoev.ru 
3511Sigor@sysoev.ru     task->thread->fiber = fib;
3521Sigor@sysoev.ru 
3530Sigor@sysoev.ru     _longjmp(fib->jmp, 1);
3541Sigor@sysoev.ru 
3550Sigor@sysoev.ru     nxt_unreachable();
3560Sigor@sysoev.ru }
3570Sigor@sysoev.ru 
3580Sigor@sysoev.ru 
3590Sigor@sysoev.ru nxt_fiber_t *
3600Sigor@sysoev.ru nxt_fiber_self(nxt_thread_t *thr)
3610Sigor@sysoev.ru {
3620Sigor@sysoev.ru     return (nxt_fast_path(thr != NULL)) ? thr->fiber : NULL;
3630Sigor@sysoev.ru }
3640Sigor@sysoev.ru 
3650Sigor@sysoev.ru 
3660Sigor@sysoev.ru void
3671Sigor@sysoev.ru nxt_fiber_yield(nxt_task_t *task)
3680Sigor@sysoev.ru {
3691Sigor@sysoev.ru     nxt_fiber_t  *fib;
3700Sigor@sysoev.ru 
3711Sigor@sysoev.ru     fib = task->thread->fiber;
3720Sigor@sysoev.ru 
3730Sigor@sysoev.ru     if (_setjmp(fib->jmp) == 0) {
3740Sigor@sysoev.ru 
3751Sigor@sysoev.ru         nxt_debug(task, "fiber yield");
3760Sigor@sysoev.ru 
3771Sigor@sysoev.ru         nxt_fiber_enqueue(task->thread, &fib->main->engine->task, fib);
3781Sigor@sysoev.ru 
3791Sigor@sysoev.ru         nxt_fiber_switch(task, &fib->main->fiber);
3801Sigor@sysoev.ru 
3810Sigor@sysoev.ru         nxt_unreachable();
3820Sigor@sysoev.ru     }
3830Sigor@sysoev.ru 
3841Sigor@sysoev.ru     nxt_debug(task, "fiber yield return");
3850Sigor@sysoev.ru }
3860Sigor@sysoev.ru 
3870Sigor@sysoev.ru 
3880Sigor@sysoev.ru void
3891Sigor@sysoev.ru nxt_fiber_sleep(nxt_task_t *task, nxt_msec_t timeout)
3900Sigor@sysoev.ru {
3911Sigor@sysoev.ru     nxt_fiber_t  *fib;
3920Sigor@sysoev.ru 
3931Sigor@sysoev.ru     fib = task->thread->fiber;
3940Sigor@sysoev.ru 
3954Sigor@sysoev.ru     fib->timer.work_queue = &task->thread->engine->fast_work_queue;
3960Sigor@sysoev.ru     fib->timer.handler = nxt_fiber_timer_handler;
3970Sigor@sysoev.ru     fib->timer.log = &nxt_main_log;
3980Sigor@sysoev.ru 
3991Sigor@sysoev.ru     task = &fib->task;
4001Sigor@sysoev.ru 
401*6Sigor@sysoev.ru     nxt_timer_add(task->thread->engine, &fib->timer, timeout);
4020Sigor@sysoev.ru 
4030Sigor@sysoev.ru     if (_setjmp(fib->jmp) == 0) {
4040Sigor@sysoev.ru 
4051Sigor@sysoev.ru         nxt_debug(task, "fiber sleep: %T", timeout);
4060Sigor@sysoev.ru 
4071Sigor@sysoev.ru         nxt_fiber_switch(task, &fib->main->fiber);
4081Sigor@sysoev.ru 
4090Sigor@sysoev.ru         nxt_unreachable();
4100Sigor@sysoev.ru     }
4110Sigor@sysoev.ru 
4121Sigor@sysoev.ru     nxt_debug(task, "fiber sleep return");
4130Sigor@sysoev.ru }
4140Sigor@sysoev.ru 
4150Sigor@sysoev.ru 
4160Sigor@sysoev.ru static void
4171Sigor@sysoev.ru nxt_fiber_timer_handler(nxt_task_t *task, void *obj, void *data)
4180Sigor@sysoev.ru {
419*6Sigor@sysoev.ru     nxt_fiber_t  *fib;
420*6Sigor@sysoev.ru     nxt_timer_t  *ev;
4210Sigor@sysoev.ru 
4220Sigor@sysoev.ru     ev = obj;
4230Sigor@sysoev.ru 
4241Sigor@sysoev.ru     nxt_debug(task, "fiber timer handler");
4250Sigor@sysoev.ru 
426*6Sigor@sysoev.ru     fib = nxt_timer_data(ev, nxt_fiber_t, timer);
4270Sigor@sysoev.ru 
4281Sigor@sysoev.ru     nxt_fiber_switch(task, fib);
4291Sigor@sysoev.ru 
4300Sigor@sysoev.ru     nxt_unreachable();
4310Sigor@sysoev.ru }
4320Sigor@sysoev.ru 
4330Sigor@sysoev.ru 
4340Sigor@sysoev.ru void
4351Sigor@sysoev.ru nxt_fiber_wait(nxt_task_t *task)
4360Sigor@sysoev.ru {
4371Sigor@sysoev.ru     nxt_fiber_t  *fib;
4380Sigor@sysoev.ru 
4391Sigor@sysoev.ru     fib = task->thread->fiber;
4400Sigor@sysoev.ru 
4410Sigor@sysoev.ru     if (_setjmp(fib->jmp) == 0) {
4421Sigor@sysoev.ru         nxt_debug(task, "fiber wait");
4430Sigor@sysoev.ru 
4441Sigor@sysoev.ru         nxt_fiber_switch(task, &fib->main->fiber);
4451Sigor@sysoev.ru 
4460Sigor@sysoev.ru         nxt_unreachable();
4470Sigor@sysoev.ru     }
4480Sigor@sysoev.ru 
4491Sigor@sysoev.ru     nxt_debug(task, "fiber wait return");
4500Sigor@sysoev.ru }
4510Sigor@sysoev.ru 
4520Sigor@sysoev.ru 
4530Sigor@sysoev.ru void
4541Sigor@sysoev.ru nxt_fiber_exit(nxt_task_t *task, nxt_fiber_t *next, void *data)
4550Sigor@sysoev.ru {
4561Sigor@sysoev.ru     nxt_fiber_t  *fib;
4570Sigor@sysoev.ru 
4581Sigor@sysoev.ru     fib = task->thread->fiber;
4590Sigor@sysoev.ru 
4601Sigor@sysoev.ru     nxt_debug(task, "fiber exit");
4610Sigor@sysoev.ru 
4620Sigor@sysoev.ru     /* TODO: limit idle fibers. */
4630Sigor@sysoev.ru     fib->next = fib->main->idle;
4640Sigor@sysoev.ru     fib->main->idle = fib;
4650Sigor@sysoev.ru 
4661Sigor@sysoev.ru     nxt_fiber_switch(task, next);
4671Sigor@sysoev.ru 
4680Sigor@sysoev.ru     nxt_unreachable();
4690Sigor@sysoev.ru }
470