xref: /unit/src/nxt_fiber.c (revision 2084:7d479274f334)
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 
17*2084Salx.manpages@gmail.com #define nxt_fiber_enqueue(thr, task, fib)                                     \
184Sigor@sysoev.ru     nxt_work_queue_add(&(thr)->engine->fast_work_queue,                       \
191Sigor@sysoev.ru                               nxt_fiber_switch_handler, task, fib, NULL)
200Sigor@sysoev.ru 
210Sigor@sysoev.ru 
220Sigor@sysoev.ru nxt_fiber_main_t *
nxt_fiber_main_create(nxt_event_engine_t * engine)230Sigor@sysoev.ru nxt_fiber_main_create(nxt_event_engine_t *engine)
240Sigor@sysoev.ru {
250Sigor@sysoev.ru     nxt_fiber_main_t  *fm;
260Sigor@sysoev.ru 
270Sigor@sysoev.ru     fm = nxt_zalloc(sizeof(nxt_fiber_main_t));
280Sigor@sysoev.ru     if (nxt_slow_path(fm == NULL)) {
290Sigor@sysoev.ru         return NULL;
300Sigor@sysoev.ru     }
310Sigor@sysoev.ru 
321Sigor@sysoev.ru     fm->engine = engine;
330Sigor@sysoev.ru     fm->stack_size = 512 * 1024 - nxt_pagesize;
340Sigor@sysoev.ru     fm->idle = NULL;
350Sigor@sysoev.ru 
360Sigor@sysoev.ru     return fm;
370Sigor@sysoev.ru }
380Sigor@sysoev.ru 
390Sigor@sysoev.ru 
400Sigor@sysoev.ru nxt_int_t
nxt_fiber_create(nxt_fiber_start_t start,void * data,size_t stack)410Sigor@sysoev.ru nxt_fiber_create(nxt_fiber_start_t start, void *data, size_t stack)
420Sigor@sysoev.ru {
430Sigor@sysoev.ru     int                  ret;
440Sigor@sysoev.ru     jmp_buf              parent;
450Sigor@sysoev.ru     nxt_fid_t            fid;
460Sigor@sysoev.ru     nxt_fiber_t          *fib;
470Sigor@sysoev.ru     nxt_thread_t         *thr;
480Sigor@sysoev.ru     nxt_fiber_main_t     *fm;
490Sigor@sysoev.ru 
500Sigor@sysoev.ru     thr = nxt_thread();
510Sigor@sysoev.ru     fm = thr->engine->fibers;
520Sigor@sysoev.ru 
530Sigor@sysoev.ru     fid = ++fm->fid;
540Sigor@sysoev.ru 
550Sigor@sysoev.ru     if (fid == 0) {
560Sigor@sysoev.ru         fid = ++fm->fid;
570Sigor@sysoev.ru     }
580Sigor@sysoev.ru 
590Sigor@sysoev.ru     fib = fm->idle;
600Sigor@sysoev.ru 
610Sigor@sysoev.ru     if (fib != NULL) {
620Sigor@sysoev.ru         fm->idle = fib->next;
630Sigor@sysoev.ru         fib->fid = fid;
640Sigor@sysoev.ru         fib->start = start;
650Sigor@sysoev.ru         fib->data = data;
660Sigor@sysoev.ru         fib->main = fm;
670Sigor@sysoev.ru 
681Sigor@sysoev.ru         fib->task.thread = thr;
691Sigor@sysoev.ru         fib->task.log = thr->log;
701Sigor@sysoev.ru         fib->task.ident = nxt_task_next_ident();
711Sigor@sysoev.ru 
721Sigor@sysoev.ru         nxt_debug(&fib->task, "fiber create cached: %PF", fib->fid);
731Sigor@sysoev.ru 
741Sigor@sysoev.ru         nxt_fiber_enqueue(thr, &fm->engine->task, fib);
751Sigor@sysoev.ru 
760Sigor@sysoev.ru         return NXT_OK;
770Sigor@sysoev.ru     }
780Sigor@sysoev.ru 
790Sigor@sysoev.ru     nxt_log_debug(thr->log, "fiber create");
800Sigor@sysoev.ru 
810Sigor@sysoev.ru     fib = nxt_malloc(sizeof(nxt_fiber_t));
820Sigor@sysoev.ru     if (nxt_slow_path(fib == NULL)) {
830Sigor@sysoev.ru         return NXT_ERROR;
840Sigor@sysoev.ru     }
850Sigor@sysoev.ru 
860Sigor@sysoev.ru     fib->fid = fid;
870Sigor@sysoev.ru     fib->start = start;
880Sigor@sysoev.ru     fib->data = data;
890Sigor@sysoev.ru     fib->stack_size = fm->stack_size;
900Sigor@sysoev.ru     fib->main = fm;
910Sigor@sysoev.ru 
921Sigor@sysoev.ru     fib->task.thread = thr;
931Sigor@sysoev.ru     fib->task.log = thr->log;
941Sigor@sysoev.ru     fib->task.ident = nxt_task_next_ident();
951Sigor@sysoev.ru 
961Sigor@sysoev.ru     fib->stack = nxt_fiber_create_stack(&fib->task, fib);
970Sigor@sysoev.ru 
980Sigor@sysoev.ru     if (nxt_fast_path(fib->stack != NULL)) {
990Sigor@sysoev.ru 
1000Sigor@sysoev.ru         if (_setjmp(parent) != 0) {
1010Sigor@sysoev.ru             nxt_log_debug(thr->log, "fiber create: %PF", fib->fid);
1020Sigor@sysoev.ru             return NXT_OK;
1030Sigor@sysoev.ru         }
1040Sigor@sysoev.ru 
1050Sigor@sysoev.ru         nxt_fiber_switch_stack(fib, &parent);
1060Sigor@sysoev.ru         /* It does not return if the switch was successful. */
1070Sigor@sysoev.ru     }
1080Sigor@sysoev.ru 
1090Sigor@sysoev.ru     ret = munmap(fib->stack - nxt_pagesize, fib->stack_size + nxt_pagesize);
1100Sigor@sysoev.ru 
1110Sigor@sysoev.ru     if (nxt_slow_path(ret != 0)) {
1120Sigor@sysoev.ru         nxt_log_alert(thr->log, "munmap() failed %E", nxt_errno);
1130Sigor@sysoev.ru     }
1140Sigor@sysoev.ru 
1150Sigor@sysoev.ru     nxt_free(fib);
1160Sigor@sysoev.ru 
1170Sigor@sysoev.ru     return NXT_ERROR;
1180Sigor@sysoev.ru }
1190Sigor@sysoev.ru 
1200Sigor@sysoev.ru 
1210Sigor@sysoev.ru #if (NXT_LINUX)
1220Sigor@sysoev.ru 
1230Sigor@sysoev.ru static char *
nxt_fiber_create_stack(nxt_task_t * task,nxt_fiber_t * fib)1241Sigor@sysoev.ru nxt_fiber_create_stack(nxt_task_t *task, nxt_fiber_t *fib)
1250Sigor@sysoev.ru {
1260Sigor@sysoev.ru     char    *s;
1270Sigor@sysoev.ru     size_t  size;
1280Sigor@sysoev.ru 
1290Sigor@sysoev.ru     size = fib->stack_size + nxt_pagesize;
1300Sigor@sysoev.ru 
1310Sigor@sysoev.ru     s = mmap(NULL, size, PROT_READ | PROT_WRITE,
1320Sigor@sysoev.ru              MAP_PRIVATE | MAP_ANON | MAP_GROWSDOWN, -1, 0);
1330Sigor@sysoev.ru 
1340Sigor@sysoev.ru     if (nxt_slow_path(s == MAP_FAILED)) {
135564Svbart@nginx.com         nxt_alert(task, "fiber stack "
136564Svbart@nginx.com                   "mmap(%uz, MAP_PRIVATE|MAP_ANON|MAP_GROWSDOWN) failed %E",
137564Svbart@nginx.com                   size, nxt_errno);
1381Sigor@sysoev.ru 
1390Sigor@sysoev.ru         return NULL;
1400Sigor@sysoev.ru     }
1410Sigor@sysoev.ru 
1420Sigor@sysoev.ru     if (nxt_slow_path(mprotect(s, nxt_pagesize, PROT_NONE) != 0)) {
143564Svbart@nginx.com         nxt_alert(task, "fiber stack mprotect(%uz, PROT_NONE) failed %E",
144564Svbart@nginx.com                   size, nxt_errno);
1451Sigor@sysoev.ru 
1460Sigor@sysoev.ru         return NULL;
1470Sigor@sysoev.ru     }
1480Sigor@sysoev.ru 
1490Sigor@sysoev.ru     s += nxt_pagesize;
1500Sigor@sysoev.ru 
1511Sigor@sysoev.ru     nxt_debug(task, "fiber stack mmap: %p", s);
1520Sigor@sysoev.ru 
1530Sigor@sysoev.ru     return s;
1540Sigor@sysoev.ru }
1550Sigor@sysoev.ru 
1560Sigor@sysoev.ru #else /* Generic version. */
1570Sigor@sysoev.ru 
1580Sigor@sysoev.ru static char *
nxt_fiber_create_stack(nxt_task_t * task,nxt_fiber_t * fib)1591Sigor@sysoev.ru nxt_fiber_create_stack(nxt_task_t *task, nxt_fiber_t *fib)
1600Sigor@sysoev.ru {
1610Sigor@sysoev.ru     char    *s;
1620Sigor@sysoev.ru     size_t   size;
1630Sigor@sysoev.ru 
1640Sigor@sysoev.ru     size = fib->stack_size + nxt_pagesize;
1650Sigor@sysoev.ru 
1660Sigor@sysoev.ru     s = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
1670Sigor@sysoev.ru 
1680Sigor@sysoev.ru     if (nxt_slow_path(s == MAP_FAILED)) {
169564Svbart@nginx.com         nxt_alert(task, "fiber stack mmap(%uz, MAP_PRIVATE|MAP_ANON) failed %E",
170564Svbart@nginx.com                   size, nxt_errno);
1711Sigor@sysoev.ru 
1720Sigor@sysoev.ru         return NULL;
1730Sigor@sysoev.ru     }
1740Sigor@sysoev.ru 
1750Sigor@sysoev.ru     if (nxt_slow_path(mprotect(s, nxt_pagesize, PROT_NONE) != 0)) {
176564Svbart@nginx.com         nxt_alert(task, "fiber stack mprotect(%uz, PROT_NONE) failed %E",
177564Svbart@nginx.com                   size, nxt_errno);
1781Sigor@sysoev.ru 
1790Sigor@sysoev.ru         return NULL;
1800Sigor@sysoev.ru     }
1810Sigor@sysoev.ru 
1820Sigor@sysoev.ru     s += nxt_pagesize;
1830Sigor@sysoev.ru 
1841Sigor@sysoev.ru     nxt_debug(task, "fiber stack mmap: %p", s);
1850Sigor@sysoev.ru 
1860Sigor@sysoev.ru     return s;
1870Sigor@sysoev.ru }
1880Sigor@sysoev.ru 
1890Sigor@sysoev.ru #endif
1900Sigor@sysoev.ru 
1910Sigor@sysoev.ru 
1920Sigor@sysoev.ru #if (NXT_LINUX && NXT_64BIT)
1930Sigor@sysoev.ru 
1940Sigor@sysoev.ru /*
1950Sigor@sysoev.ru  * Linux 64-bit ucontext version.  64-bit glibc makecontext() passes
1960Sigor@sysoev.ru  * pointers as signed int's. The bug has been fixed in glibc 2.8.
1970Sigor@sysoev.ru  */
1980Sigor@sysoev.ru 
1990Sigor@sysoev.ru static void nxt_fiber_trampoline(uint32_t fh, uint32_t fl, uint32_t ph,
2000Sigor@sysoev.ru     uint32_t pl);
2010Sigor@sysoev.ru 
2020Sigor@sysoev.ru 
2030Sigor@sysoev.ru static void
nxt_fiber_switch_stack(nxt_fiber_t * fib,jmp_buf * parent)2040Sigor@sysoev.ru nxt_fiber_switch_stack(nxt_fiber_t *fib, jmp_buf *parent)
2050Sigor@sysoev.ru {
2060Sigor@sysoev.ru     ucontext_t  uc;
2070Sigor@sysoev.ru 
2081Sigor@sysoev.ru     nxt_debug(&fib->task, "fiber switch to stack: %p", fib->stack);
2090Sigor@sysoev.ru 
2100Sigor@sysoev.ru     if (nxt_slow_path(getcontext(&uc) != 0)) {
211564Svbart@nginx.com         nxt_alert(&fib->task, "getcontext() failed");
2120Sigor@sysoev.ru         return;
2130Sigor@sysoev.ru     }
2140Sigor@sysoev.ru 
2150Sigor@sysoev.ru     uc.uc_link = NULL;
2160Sigor@sysoev.ru     uc.uc_stack.ss_sp = fib->stack;
2170Sigor@sysoev.ru     uc.uc_stack.ss_size = fib->stack_size;
2180Sigor@sysoev.ru 
2190Sigor@sysoev.ru     makecontext(&uc, (void (*)(void)) nxt_fiber_trampoline, 4,
2200Sigor@sysoev.ru                 (uint32_t) ((uintptr_t) fib >> 32),
221611Svbart@nginx.com                 (uint32_t) ((uintptr_t) fib & 0xFFFFFFFF),
2220Sigor@sysoev.ru                 (uint32_t) ((uintptr_t) parent >> 32),
223611Svbart@nginx.com                 (uint32_t) ((uintptr_t) parent & 0xFFFFFFFF));
2240Sigor@sysoev.ru 
2250Sigor@sysoev.ru     setcontext(&uc);
2260Sigor@sysoev.ru 
227564Svbart@nginx.com     nxt_alert(&fib->task, "setcontext() failed");
2280Sigor@sysoev.ru }
2290Sigor@sysoev.ru 
2300Sigor@sysoev.ru 
2310Sigor@sysoev.ru static void
nxt_fiber_trampoline(uint32_t fh,uint32_t fl,uint32_t ph,uint32_t pl)2320Sigor@sysoev.ru nxt_fiber_trampoline(uint32_t fh, uint32_t fl, uint32_t ph, uint32_t pl)
2330Sigor@sysoev.ru {
2341Sigor@sysoev.ru     jmp_buf      *parent;
2351Sigor@sysoev.ru     nxt_task_t   *task;
2361Sigor@sysoev.ru     nxt_fiber_t  *fib;
2370Sigor@sysoev.ru 
2380Sigor@sysoev.ru     fib = (nxt_fiber_t *) (((uintptr_t) fh << 32) + fl);
2390Sigor@sysoev.ru     parent = (jmp_buf *) (((uintptr_t) ph << 32) + pl);
2400Sigor@sysoev.ru 
2411Sigor@sysoev.ru     task = &fib->task;
2420Sigor@sysoev.ru 
2430Sigor@sysoev.ru     if (_setjmp(fib->jmp) == 0) {
2441Sigor@sysoev.ru         nxt_debug(task, "fiber return to parent stack");
2450Sigor@sysoev.ru 
2461Sigor@sysoev.ru         nxt_fiber_enqueue(task->thread, task, fib);
2471Sigor@sysoev.ru 
2480Sigor@sysoev.ru         _longjmp(*parent, 1);
2491Sigor@sysoev.ru 
2500Sigor@sysoev.ru         nxt_unreachable();
2510Sigor@sysoev.ru     }
2520Sigor@sysoev.ru 
2531Sigor@sysoev.ru     nxt_debug(task, "fiber start");
2540Sigor@sysoev.ru 
2550Sigor@sysoev.ru     fib->start(fib->data);
2560Sigor@sysoev.ru 
2571Sigor@sysoev.ru     nxt_fiber_exit(task, &fib->main->fiber, NULL);
2581Sigor@sysoev.ru 
2590Sigor@sysoev.ru     nxt_unreachable();
2600Sigor@sysoev.ru }
2610Sigor@sysoev.ru 
2620Sigor@sysoev.ru #elif (NXT_HAVE_UCONTEXT)
2630Sigor@sysoev.ru 
2640Sigor@sysoev.ru /* Generic ucontext version. */
2650Sigor@sysoev.ru 
2660Sigor@sysoev.ru static void nxt_fiber_trampoline(nxt_fiber_t *fib, jmp_buf *parent);
2670Sigor@sysoev.ru 
2680Sigor@sysoev.ru 
2690Sigor@sysoev.ru static void
nxt_fiber_switch_stack(nxt_fiber_t * fib,jmp_buf * parent)2700Sigor@sysoev.ru nxt_fiber_switch_stack(nxt_fiber_t *fib, jmp_buf *parent)
2710Sigor@sysoev.ru {
2720Sigor@sysoev.ru     ucontext_t  uc;
2730Sigor@sysoev.ru 
2741Sigor@sysoev.ru     nxt_debug(&fib->task, "fiber switch to stack: %p", fib->stack);
2750Sigor@sysoev.ru 
2760Sigor@sysoev.ru     if (nxt_slow_path(getcontext(&uc) != 0)) {
277564Svbart@nginx.com         nxt_alert(&fib->task, "getcontext() failed");
2780Sigor@sysoev.ru         return;
2790Sigor@sysoev.ru     }
2800Sigor@sysoev.ru 
2810Sigor@sysoev.ru     uc.uc_link = NULL;
2820Sigor@sysoev.ru     uc.uc_stack.ss_sp = fib->stack;
2830Sigor@sysoev.ru     uc.uc_stack.ss_size = fib->stack_size;
2840Sigor@sysoev.ru 
2850Sigor@sysoev.ru     makecontext(&uc, (void (*)(void)) nxt_fiber_trampoline, 2, fib, parent);
2860Sigor@sysoev.ru 
2870Sigor@sysoev.ru     setcontext(&uc);
2880Sigor@sysoev.ru 
2890Sigor@sysoev.ru #if !(NXT_SOLARIS)
2900Sigor@sysoev.ru     /* Solaris declares setcontext() as __NORETURN. */
2910Sigor@sysoev.ru 
292564Svbart@nginx.com     nxt_alert(&fib->task, "setcontext() failed");
2930Sigor@sysoev.ru #endif
2940Sigor@sysoev.ru }
2950Sigor@sysoev.ru 
2960Sigor@sysoev.ru 
2970Sigor@sysoev.ru static void
nxt_fiber_trampoline(nxt_fiber_t * fib,jmp_buf * parent)2980Sigor@sysoev.ru nxt_fiber_trampoline(nxt_fiber_t *fib, jmp_buf *parent)
2990Sigor@sysoev.ru {
3001Sigor@sysoev.ru     nxt_task_t  *task;
3010Sigor@sysoev.ru 
3021Sigor@sysoev.ru     task = &fib->task;
3030Sigor@sysoev.ru 
3040Sigor@sysoev.ru     if (_setjmp(fib->jmp) == 0) {
3051Sigor@sysoev.ru         nxt_debug(task, "fiber return to parent stack");
3060Sigor@sysoev.ru 
3071Sigor@sysoev.ru         nxt_fiber_enqueue(task->thread, task, fib);
3081Sigor@sysoev.ru 
3090Sigor@sysoev.ru         _longjmp(*parent, 1);
3101Sigor@sysoev.ru 
3110Sigor@sysoev.ru         nxt_unreachable();
3120Sigor@sysoev.ru     }
3130Sigor@sysoev.ru 
3141Sigor@sysoev.ru     nxt_debug(task, "fiber start");
3150Sigor@sysoev.ru 
3160Sigor@sysoev.ru     fib->start(fib->data);
3170Sigor@sysoev.ru 
3181Sigor@sysoev.ru     nxt_fiber_exit(task, &fib->main->fiber, NULL);
3191Sigor@sysoev.ru 
3200Sigor@sysoev.ru     nxt_unreachable();
3210Sigor@sysoev.ru }
3220Sigor@sysoev.ru 
3230Sigor@sysoev.ru #else
3240Sigor@sysoev.ru 
3250Sigor@sysoev.ru #error No ucontext(3) interface.
3260Sigor@sysoev.ru 
3270Sigor@sysoev.ru #endif
3280Sigor@sysoev.ru 
3290Sigor@sysoev.ru 
3300Sigor@sysoev.ru static void
nxt_fiber_switch_handler(nxt_task_t * task,void * obj,void * data)3311Sigor@sysoev.ru nxt_fiber_switch_handler(nxt_task_t *task, void *obj, void *data)
3320Sigor@sysoev.ru {
3330Sigor@sysoev.ru     nxt_fiber_t  *fib;
3340Sigor@sysoev.ru 
3350Sigor@sysoev.ru     fib = obj;
3360Sigor@sysoev.ru 
3371Sigor@sysoev.ru     nxt_fiber_switch(task, fib);
3380Sigor@sysoev.ru     nxt_unreachable();
3390Sigor@sysoev.ru }
3400Sigor@sysoev.ru 
3410Sigor@sysoev.ru 
3420Sigor@sysoev.ru static void
nxt_fiber_switch(nxt_task_t * task,nxt_fiber_t * fib)3431Sigor@sysoev.ru nxt_fiber_switch(nxt_task_t *task, nxt_fiber_t *fib)
3440Sigor@sysoev.ru {
3451Sigor@sysoev.ru     nxt_debug(task, "fiber switch: %PF", fib->fid);
3460Sigor@sysoev.ru 
3471Sigor@sysoev.ru     task->thread->fiber = fib;
3481Sigor@sysoev.ru 
3490Sigor@sysoev.ru     _longjmp(fib->jmp, 1);
3501Sigor@sysoev.ru 
3510Sigor@sysoev.ru     nxt_unreachable();
3520Sigor@sysoev.ru }
3530Sigor@sysoev.ru 
3540Sigor@sysoev.ru 
3550Sigor@sysoev.ru nxt_fiber_t *
nxt_fiber_self(nxt_thread_t * thr)3560Sigor@sysoev.ru nxt_fiber_self(nxt_thread_t *thr)
3570Sigor@sysoev.ru {
3580Sigor@sysoev.ru     return (nxt_fast_path(thr != NULL)) ? thr->fiber : NULL;
3590Sigor@sysoev.ru }
3600Sigor@sysoev.ru 
3610Sigor@sysoev.ru 
3620Sigor@sysoev.ru void
nxt_fiber_yield(nxt_task_t * task)3631Sigor@sysoev.ru nxt_fiber_yield(nxt_task_t *task)
3640Sigor@sysoev.ru {
3651Sigor@sysoev.ru     nxt_fiber_t  *fib;
3660Sigor@sysoev.ru 
3671Sigor@sysoev.ru     fib = task->thread->fiber;
3680Sigor@sysoev.ru 
3690Sigor@sysoev.ru     if (_setjmp(fib->jmp) == 0) {
3700Sigor@sysoev.ru 
3711Sigor@sysoev.ru         nxt_debug(task, "fiber yield");
3720Sigor@sysoev.ru 
3731Sigor@sysoev.ru         nxt_fiber_enqueue(task->thread, &fib->main->engine->task, fib);
3741Sigor@sysoev.ru 
3751Sigor@sysoev.ru         nxt_fiber_switch(task, &fib->main->fiber);
3761Sigor@sysoev.ru 
3770Sigor@sysoev.ru         nxt_unreachable();
3780Sigor@sysoev.ru     }
3790Sigor@sysoev.ru 
3801Sigor@sysoev.ru     nxt_debug(task, "fiber yield return");
3810Sigor@sysoev.ru }
3820Sigor@sysoev.ru 
3830Sigor@sysoev.ru 
3840Sigor@sysoev.ru void
nxt_fiber_sleep(nxt_task_t * task,nxt_msec_t timeout)3851Sigor@sysoev.ru nxt_fiber_sleep(nxt_task_t *task, nxt_msec_t timeout)
3860Sigor@sysoev.ru {
3871Sigor@sysoev.ru     nxt_fiber_t  *fib;
3880Sigor@sysoev.ru 
3891Sigor@sysoev.ru     fib = task->thread->fiber;
3900Sigor@sysoev.ru 
3914Sigor@sysoev.ru     fib->timer.work_queue = &task->thread->engine->fast_work_queue;
3920Sigor@sysoev.ru     fib->timer.handler = nxt_fiber_timer_handler;
3930Sigor@sysoev.ru     fib->timer.log = &nxt_main_log;
3940Sigor@sysoev.ru 
3951Sigor@sysoev.ru     task = &fib->task;
3961Sigor@sysoev.ru 
3976Sigor@sysoev.ru     nxt_timer_add(task->thread->engine, &fib->timer, timeout);
3980Sigor@sysoev.ru 
3990Sigor@sysoev.ru     if (_setjmp(fib->jmp) == 0) {
4000Sigor@sysoev.ru 
4011Sigor@sysoev.ru         nxt_debug(task, "fiber sleep: %T", timeout);
4020Sigor@sysoev.ru 
4031Sigor@sysoev.ru         nxt_fiber_switch(task, &fib->main->fiber);
4041Sigor@sysoev.ru 
4050Sigor@sysoev.ru         nxt_unreachable();
4060Sigor@sysoev.ru     }
4070Sigor@sysoev.ru 
4081Sigor@sysoev.ru     nxt_debug(task, "fiber sleep return");
4090Sigor@sysoev.ru }
4100Sigor@sysoev.ru 
4110Sigor@sysoev.ru 
4120Sigor@sysoev.ru static void
nxt_fiber_timer_handler(nxt_task_t * task,void * obj,void * data)4131Sigor@sysoev.ru nxt_fiber_timer_handler(nxt_task_t *task, void *obj, void *data)
4140Sigor@sysoev.ru {
4156Sigor@sysoev.ru     nxt_fiber_t  *fib;
4166Sigor@sysoev.ru     nxt_timer_t  *ev;
4170Sigor@sysoev.ru 
4180Sigor@sysoev.ru     ev = obj;
4190Sigor@sysoev.ru 
4201Sigor@sysoev.ru     nxt_debug(task, "fiber timer handler");
4210Sigor@sysoev.ru 
4226Sigor@sysoev.ru     fib = nxt_timer_data(ev, nxt_fiber_t, timer);
4230Sigor@sysoev.ru 
4241Sigor@sysoev.ru     nxt_fiber_switch(task, fib);
4251Sigor@sysoev.ru 
4260Sigor@sysoev.ru     nxt_unreachable();
4270Sigor@sysoev.ru }
4280Sigor@sysoev.ru 
4290Sigor@sysoev.ru 
4300Sigor@sysoev.ru void
nxt_fiber_wait(nxt_task_t * task)4311Sigor@sysoev.ru nxt_fiber_wait(nxt_task_t *task)
4320Sigor@sysoev.ru {
4331Sigor@sysoev.ru     nxt_fiber_t  *fib;
4340Sigor@sysoev.ru 
4351Sigor@sysoev.ru     fib = task->thread->fiber;
4360Sigor@sysoev.ru 
4370Sigor@sysoev.ru     if (_setjmp(fib->jmp) == 0) {
4381Sigor@sysoev.ru         nxt_debug(task, "fiber wait");
4390Sigor@sysoev.ru 
4401Sigor@sysoev.ru         nxt_fiber_switch(task, &fib->main->fiber);
4411Sigor@sysoev.ru 
4420Sigor@sysoev.ru         nxt_unreachable();
4430Sigor@sysoev.ru     }
4440Sigor@sysoev.ru 
4451Sigor@sysoev.ru     nxt_debug(task, "fiber wait return");
4460Sigor@sysoev.ru }
4470Sigor@sysoev.ru 
4480Sigor@sysoev.ru 
4490Sigor@sysoev.ru void
nxt_fiber_exit(nxt_task_t * task,nxt_fiber_t * next,void * data)4501Sigor@sysoev.ru nxt_fiber_exit(nxt_task_t *task, nxt_fiber_t *next, void *data)
4510Sigor@sysoev.ru {
4521Sigor@sysoev.ru     nxt_fiber_t  *fib;
4530Sigor@sysoev.ru 
4541Sigor@sysoev.ru     fib = task->thread->fiber;
4550Sigor@sysoev.ru 
4561Sigor@sysoev.ru     nxt_debug(task, "fiber exit");
4570Sigor@sysoev.ru 
4580Sigor@sysoev.ru     /* TODO: limit idle fibers. */
4590Sigor@sysoev.ru     fib->next = fib->main->idle;
4600Sigor@sysoev.ru     fib->main->idle = fib;
4610Sigor@sysoev.ru 
4621Sigor@sysoev.ru     nxt_fiber_switch(task, next);
4631Sigor@sysoev.ru 
4640Sigor@sysoev.ru     nxt_unreachable();
4650Sigor@sysoev.ru }
466