xref: /unit/src/nxt_event_engine.c (revision 1927:ac8d11e34427)
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 
10337Sigor@sysoev.ru typedef struct nxt_mem_cache_block_s  nxt_mem_cache_block_t;
11337Sigor@sysoev.ru 
12337Sigor@sysoev.ru struct nxt_mem_cache_block_s {
13337Sigor@sysoev.ru     nxt_mem_cache_block_t  *next;
14337Sigor@sysoev.ru };
15337Sigor@sysoev.ru 
16337Sigor@sysoev.ru 
17337Sigor@sysoev.ru typedef struct {
18337Sigor@sysoev.ru     nxt_mem_cache_block_t  *free;
19337Sigor@sysoev.ru     uint32_t               size;
20337Sigor@sysoev.ru     uint32_t               count;
21337Sigor@sysoev.ru } nxt_mem_cache_t;
22337Sigor@sysoev.ru 
23337Sigor@sysoev.ru 
241Sigor@sysoev.ru static nxt_int_t nxt_event_engine_post_init(nxt_event_engine_t *engine);
251Sigor@sysoev.ru static nxt_int_t nxt_event_engine_signal_pipe_create(
260Sigor@sysoev.ru     nxt_event_engine_t *engine);
271Sigor@sysoev.ru static void nxt_event_engine_signal_pipe_close(nxt_task_t *task, void *obj,
280Sigor@sysoev.ru     void *data);
291Sigor@sysoev.ru static void nxt_event_engine_signal_pipe(nxt_task_t *task, void *obj,
300Sigor@sysoev.ru     void *data);
311Sigor@sysoev.ru static void nxt_event_engine_post_handler(nxt_task_t *task, void *obj,
320Sigor@sysoev.ru     void *data);
331Sigor@sysoev.ru static void nxt_event_engine_signal_pipe_error(nxt_task_t *task, void *obj,
340Sigor@sysoev.ru     void *data);
351Sigor@sysoev.ru static void nxt_event_engine_signal_handler(nxt_task_t *task, void *obj,
360Sigor@sysoev.ru     void *data);
374Sigor@sysoev.ru static nxt_work_handler_t nxt_event_engine_queue_pop(nxt_event_engine_t *engine,
384Sigor@sysoev.ru     nxt_task_t **task, void **obj, void **data);
390Sigor@sysoev.ru 
400Sigor@sysoev.ru 
410Sigor@sysoev.ru nxt_event_engine_t *
nxt_event_engine_create(nxt_task_t * task,const nxt_event_interface_t * interface,const nxt_sig_event_t * signals,nxt_uint_t flags,nxt_uint_t batch)4220Sigor@sysoev.ru nxt_event_engine_create(nxt_task_t *task,
4312Sigor@sysoev.ru     const nxt_event_interface_t *interface, const nxt_sig_event_t *signals,
4412Sigor@sysoev.ru     nxt_uint_t flags, nxt_uint_t batch)
450Sigor@sysoev.ru {
460Sigor@sysoev.ru     nxt_uint_t          events;
4720Sigor@sysoev.ru     nxt_thread_t        *thread;
480Sigor@sysoev.ru     nxt_event_engine_t  *engine;
490Sigor@sysoev.ru 
500Sigor@sysoev.ru     engine = nxt_zalloc(sizeof(nxt_event_engine_t));
510Sigor@sysoev.ru     if (engine == NULL) {
520Sigor@sysoev.ru         return NULL;
530Sigor@sysoev.ru     }
540Sigor@sysoev.ru 
55163Smax.romanov@nginx.com     nxt_debug(task, "create engine %p", engine);
56163Smax.romanov@nginx.com 
5720Sigor@sysoev.ru     thread = task->thread;
5820Sigor@sysoev.ru 
5920Sigor@sysoev.ru     engine->task.thread = thread;
6020Sigor@sysoev.ru     engine->task.log = thread->log;
611Sigor@sysoev.ru     engine->task.ident = nxt_task_next_ident();
621Sigor@sysoev.ru 
6320Sigor@sysoev.ru     engine->batch = batch;
640Sigor@sysoev.ru 
65326Svbart@nginx.com #if 0
660Sigor@sysoev.ru     if (flags & NXT_ENGINE_FIBERS) {
670Sigor@sysoev.ru         engine->fibers = nxt_fiber_main_create(engine);
680Sigor@sysoev.ru         if (engine->fibers == NULL) {
690Sigor@sysoev.ru             goto fibers_fail;
700Sigor@sysoev.ru         }
710Sigor@sysoev.ru     }
72326Svbart@nginx.com #endif
730Sigor@sysoev.ru 
744Sigor@sysoev.ru     engine->current_work_queue = &engine->fast_work_queue;
754Sigor@sysoev.ru 
764Sigor@sysoev.ru     nxt_work_queue_cache_create(&engine->work_queue_cache, 0);
770Sigor@sysoev.ru 
784Sigor@sysoev.ru     engine->fast_work_queue.cache = &engine->work_queue_cache;
794Sigor@sysoev.ru     engine->accept_work_queue.cache = &engine->work_queue_cache;
804Sigor@sysoev.ru     engine->read_work_queue.cache = &engine->work_queue_cache;
814Sigor@sysoev.ru     engine->socket_work_queue.cache = &engine->work_queue_cache;
824Sigor@sysoev.ru     engine->connect_work_queue.cache = &engine->work_queue_cache;
834Sigor@sysoev.ru     engine->write_work_queue.cache = &engine->work_queue_cache;
844Sigor@sysoev.ru     engine->shutdown_work_queue.cache = &engine->work_queue_cache;
854Sigor@sysoev.ru     engine->close_work_queue.cache = &engine->work_queue_cache;
864Sigor@sysoev.ru 
874Sigor@sysoev.ru     nxt_work_queue_name(&engine->fast_work_queue, "fast");
880Sigor@sysoev.ru     nxt_work_queue_name(&engine->accept_work_queue, "accept");
890Sigor@sysoev.ru     nxt_work_queue_name(&engine->read_work_queue, "read");
900Sigor@sysoev.ru     nxt_work_queue_name(&engine->socket_work_queue, "socket");
910Sigor@sysoev.ru     nxt_work_queue_name(&engine->connect_work_queue, "connect");
920Sigor@sysoev.ru     nxt_work_queue_name(&engine->write_work_queue, "write");
930Sigor@sysoev.ru     nxt_work_queue_name(&engine->shutdown_work_queue, "shutdown");
940Sigor@sysoev.ru     nxt_work_queue_name(&engine->close_work_queue, "close");
950Sigor@sysoev.ru 
960Sigor@sysoev.ru     if (signals != NULL) {
970Sigor@sysoev.ru         engine->signals = nxt_event_engine_signals(signals);
980Sigor@sysoev.ru         if (engine->signals == NULL) {
990Sigor@sysoev.ru             goto signals_fail;
1000Sigor@sysoev.ru         }
1010Sigor@sysoev.ru 
1020Sigor@sysoev.ru         engine->signals->handler = nxt_event_engine_signal_handler;
1030Sigor@sysoev.ru 
10412Sigor@sysoev.ru         if (!interface->signal_support) {
1050Sigor@sysoev.ru             if (nxt_event_engine_signals_start(engine) != NXT_OK) {
1060Sigor@sysoev.ru                 goto signals_fail;
1070Sigor@sysoev.ru             }
1080Sigor@sysoev.ru         }
1090Sigor@sysoev.ru     }
1100Sigor@sysoev.ru 
1110Sigor@sysoev.ru     /*
1120Sigor@sysoev.ru      * Number of event set and timers changes should be at least twice
1130Sigor@sysoev.ru      * more than number of events to avoid premature flushes of the changes.
1140Sigor@sysoev.ru      * Fourfold is for sure.
1150Sigor@sysoev.ru      */
1160Sigor@sysoev.ru     events = (batch != 0) ? batch : 32;
1170Sigor@sysoev.ru 
11812Sigor@sysoev.ru     if (interface->create(engine, 4 * events, events) != NXT_OK) {
1190Sigor@sysoev.ru         goto event_set_fail;
1200Sigor@sysoev.ru     }
1210Sigor@sysoev.ru 
12212Sigor@sysoev.ru     engine->event = *interface;
1230Sigor@sysoev.ru 
1241Sigor@sysoev.ru     if (nxt_event_engine_post_init(engine) != NXT_OK) {
1250Sigor@sysoev.ru         goto post_fail;
1260Sigor@sysoev.ru     }
1270Sigor@sysoev.ru 
1286Sigor@sysoev.ru     if (nxt_timers_init(&engine->timers, 4 * events) != NXT_OK) {
1290Sigor@sysoev.ru         goto timers_fail;
1300Sigor@sysoev.ru     }
1310Sigor@sysoev.ru 
13220Sigor@sysoev.ru     thread = task->thread;
13320Sigor@sysoev.ru 
13420Sigor@sysoev.ru     nxt_thread_time_update(thread);
13520Sigor@sysoev.ru     engine->timers.now = nxt_thread_monotonic_time(thread) / 1000000;
1360Sigor@sysoev.ru 
137611Svbart@nginx.com     engine->max_connections = 0xFFFFFFFF;
1380Sigor@sysoev.ru 
13953Sigor@sysoev.ru     nxt_queue_init(&engine->joints);
1400Sigor@sysoev.ru     nxt_queue_init(&engine->listen_connections);
1410Sigor@sysoev.ru     nxt_queue_init(&engine->idle_connections);
1420Sigor@sysoev.ru 
1430Sigor@sysoev.ru     return engine;
1440Sigor@sysoev.ru 
1450Sigor@sysoev.ru timers_fail:
1460Sigor@sysoev.ru post_fail:
1470Sigor@sysoev.ru 
14812Sigor@sysoev.ru     interface->free(engine);
1490Sigor@sysoev.ru 
1500Sigor@sysoev.ru event_set_fail:
1510Sigor@sysoev.ru signals_fail:
1520Sigor@sysoev.ru 
1530Sigor@sysoev.ru     nxt_free(engine->signals);
1544Sigor@sysoev.ru     nxt_work_queue_cache_destroy(&engine->work_queue_cache);
1550Sigor@sysoev.ru     nxt_free(engine->fibers);
1560Sigor@sysoev.ru 
157326Svbart@nginx.com #if 0
1580Sigor@sysoev.ru fibers_fail:
1591347Smax.romanov@nginx.com #endif
1600Sigor@sysoev.ru 
1610Sigor@sysoev.ru     nxt_free(engine);
162326Svbart@nginx.com 
1630Sigor@sysoev.ru     return NULL;
1640Sigor@sysoev.ru }
1650Sigor@sysoev.ru 
1660Sigor@sysoev.ru 
1670Sigor@sysoev.ru static nxt_int_t
nxt_event_engine_post_init(nxt_event_engine_t * engine)1681Sigor@sysoev.ru nxt_event_engine_post_init(nxt_event_engine_t *engine)
1690Sigor@sysoev.ru {
17012Sigor@sysoev.ru     if (engine->event.enable_post != NULL) {
17112Sigor@sysoev.ru         return engine->event.enable_post(engine, nxt_event_engine_post_handler);
1720Sigor@sysoev.ru     }
1730Sigor@sysoev.ru 
1741Sigor@sysoev.ru     if (nxt_event_engine_signal_pipe_create(engine) != NXT_OK) {
1750Sigor@sysoev.ru         return NXT_ERROR;
1760Sigor@sysoev.ru     }
1770Sigor@sysoev.ru 
1780Sigor@sysoev.ru     return NXT_OK;
1790Sigor@sysoev.ru }
1800Sigor@sysoev.ru 
1810Sigor@sysoev.ru 
1820Sigor@sysoev.ru static nxt_int_t
nxt_event_engine_signal_pipe_create(nxt_event_engine_t * engine)1831Sigor@sysoev.ru nxt_event_engine_signal_pipe_create(nxt_event_engine_t *engine)
1840Sigor@sysoev.ru {
1850Sigor@sysoev.ru     nxt_event_engine_pipe_t  *pipe;
1860Sigor@sysoev.ru 
1870Sigor@sysoev.ru     pipe = nxt_zalloc(sizeof(nxt_event_engine_pipe_t));
1880Sigor@sysoev.ru     if (pipe == NULL) {
1890Sigor@sysoev.ru         return NXT_ERROR;
1900Sigor@sysoev.ru     }
1910Sigor@sysoev.ru 
1920Sigor@sysoev.ru     engine->pipe = pipe;
1930Sigor@sysoev.ru 
1940Sigor@sysoev.ru     /*
1950Sigor@sysoev.ru      * An event engine pipe is in blocking mode for writer
1960Sigor@sysoev.ru      * and in non-blocking node for reader.
1970Sigor@sysoev.ru      */
1980Sigor@sysoev.ru 
19913Sigor@sysoev.ru     if (nxt_pipe_create(&engine->task, pipe->fds, 1, 0) != NXT_OK) {
2000Sigor@sysoev.ru         nxt_free(pipe);
2010Sigor@sysoev.ru         return NXT_ERROR;
2020Sigor@sysoev.ru     }
2030Sigor@sysoev.ru 
2040Sigor@sysoev.ru     pipe->event.fd = pipe->fds[0];
20512Sigor@sysoev.ru     pipe->event.task = &engine->task;
2064Sigor@sysoev.ru     pipe->event.read_work_queue = &engine->fast_work_queue;
2070Sigor@sysoev.ru     pipe->event.read_handler = nxt_event_engine_signal_pipe;
2084Sigor@sysoev.ru     pipe->event.write_work_queue = &engine->fast_work_queue;
2090Sigor@sysoev.ru     pipe->event.error_handler = nxt_event_engine_signal_pipe_error;
21012Sigor@sysoev.ru     pipe->event.log = engine->task.log;
2110Sigor@sysoev.ru 
21212Sigor@sysoev.ru     nxt_fd_event_enable_read(engine, &pipe->event);
2130Sigor@sysoev.ru 
2140Sigor@sysoev.ru     return NXT_OK;
2150Sigor@sysoev.ru }
2160Sigor@sysoev.ru 
2170Sigor@sysoev.ru 
2180Sigor@sysoev.ru static void
nxt_event_engine_signal_pipe_free(nxt_event_engine_t * engine)2190Sigor@sysoev.ru nxt_event_engine_signal_pipe_free(nxt_event_engine_t *engine)
2200Sigor@sysoev.ru {
2210Sigor@sysoev.ru     nxt_event_engine_pipe_t  *pipe;
2220Sigor@sysoev.ru 
2230Sigor@sysoev.ru     pipe = engine->pipe;
2240Sigor@sysoev.ru 
2250Sigor@sysoev.ru     if (pipe != NULL) {
2260Sigor@sysoev.ru 
2270Sigor@sysoev.ru         if (pipe->event.read_work_queue != NULL) {
22812Sigor@sysoev.ru             nxt_fd_event_close(engine, &pipe->event);
22913Sigor@sysoev.ru             nxt_pipe_close(pipe->event.task, pipe->fds);
2300Sigor@sysoev.ru         }
2310Sigor@sysoev.ru 
2320Sigor@sysoev.ru         nxt_free(pipe);
2330Sigor@sysoev.ru     }
2340Sigor@sysoev.ru }
2350Sigor@sysoev.ru 
2360Sigor@sysoev.ru 
2370Sigor@sysoev.ru static void
nxt_event_engine_signal_pipe_close(nxt_task_t * task,void * obj,void * data)2381Sigor@sysoev.ru nxt_event_engine_signal_pipe_close(nxt_task_t *task, void *obj, void *data)
2390Sigor@sysoev.ru {
2400Sigor@sysoev.ru     nxt_event_engine_pipe_t  *pipe;
2410Sigor@sysoev.ru 
2420Sigor@sysoev.ru     pipe = obj;
2430Sigor@sysoev.ru 
24413Sigor@sysoev.ru     nxt_pipe_close(pipe->event.task, pipe->fds);
2450Sigor@sysoev.ru     nxt_free(pipe);
2460Sigor@sysoev.ru }
2470Sigor@sysoev.ru 
2480Sigor@sysoev.ru 
2490Sigor@sysoev.ru void
nxt_event_engine_post(nxt_event_engine_t * engine,nxt_work_t * work)2504Sigor@sysoev.ru nxt_event_engine_post(nxt_event_engine_t *engine, nxt_work_t *work)
2510Sigor@sysoev.ru {
25212Sigor@sysoev.ru     nxt_debug(&engine->task, "event engine post");
2530Sigor@sysoev.ru 
254318Smax.romanov@nginx.com #if (NXT_DEBUG)
255318Smax.romanov@nginx.com     if (nxt_slow_path(work->next != NULL)) {
256318Smax.romanov@nginx.com         nxt_debug(&engine->task, "event engine post multiple works");
257318Smax.romanov@nginx.com     }
258318Smax.romanov@nginx.com #endif
259318Smax.romanov@nginx.com 
2604Sigor@sysoev.ru     nxt_locked_work_queue_add(&engine->locked_work_queue, work);
2610Sigor@sysoev.ru 
2620Sigor@sysoev.ru     nxt_event_engine_signal(engine, 0);
2630Sigor@sysoev.ru }
2640Sigor@sysoev.ru 
2650Sigor@sysoev.ru 
2660Sigor@sysoev.ru void
nxt_event_engine_signal(nxt_event_engine_t * engine,nxt_uint_t signo)2670Sigor@sysoev.ru nxt_event_engine_signal(nxt_event_engine_t *engine, nxt_uint_t signo)
2680Sigor@sysoev.ru {
2690Sigor@sysoev.ru     u_char  buf;
2700Sigor@sysoev.ru 
27112Sigor@sysoev.ru     nxt_debug(&engine->task, "event engine signal:%ui", signo);
2720Sigor@sysoev.ru 
2730Sigor@sysoev.ru     /*
2740Sigor@sysoev.ru      * A signal number may be sent in a signal context, so the signal
2750Sigor@sysoev.ru      * information cannot be passed via a locked work queue.
2760Sigor@sysoev.ru      */
2770Sigor@sysoev.ru 
27812Sigor@sysoev.ru     if (engine->event.signal != NULL) {
27912Sigor@sysoev.ru         engine->event.signal(engine, signo);
2800Sigor@sysoev.ru         return;
2810Sigor@sysoev.ru     }
2820Sigor@sysoev.ru 
2830Sigor@sysoev.ru     buf = (u_char) signo;
2840Sigor@sysoev.ru     (void) nxt_fd_write(engine->pipe->fds[1], &buf, 1);
2850Sigor@sysoev.ru }
2860Sigor@sysoev.ru 
2870Sigor@sysoev.ru 
2880Sigor@sysoev.ru static void
nxt_event_engine_signal_pipe(nxt_task_t * task,void * obj,void * data)2891Sigor@sysoev.ru nxt_event_engine_signal_pipe(nxt_task_t *task, void *obj, void *data)
2900Sigor@sysoev.ru {
2914Sigor@sysoev.ru     int             i, n;
2924Sigor@sysoev.ru     u_char          signo;
2934Sigor@sysoev.ru     nxt_bool_t      post;
29412Sigor@sysoev.ru     nxt_fd_event_t  *ev;
2954Sigor@sysoev.ru     u_char          buf[128];
2960Sigor@sysoev.ru 
2970Sigor@sysoev.ru     ev = obj;
2980Sigor@sysoev.ru 
2991Sigor@sysoev.ru     nxt_debug(task, "engine signal pipe");
3000Sigor@sysoev.ru 
3010Sigor@sysoev.ru     post = 0;
3020Sigor@sysoev.ru 
3030Sigor@sysoev.ru     do {
3040Sigor@sysoev.ru         n = nxt_fd_read(ev->fd, buf, sizeof(buf));
3050Sigor@sysoev.ru 
3060Sigor@sysoev.ru         for (i = 0; i < n; i++) {
3070Sigor@sysoev.ru             signo = buf[i];
3080Sigor@sysoev.ru 
3091Sigor@sysoev.ru             nxt_debug(task, "engine pipe signo:%d", signo);
3100Sigor@sysoev.ru 
3110Sigor@sysoev.ru             if (signo == 0) {
3120Sigor@sysoev.ru                 /* A post should be processed only once. */
3130Sigor@sysoev.ru                 post = 1;
3140Sigor@sysoev.ru 
3150Sigor@sysoev.ru             } else {
3164Sigor@sysoev.ru                 nxt_event_engine_signal_handler(task,
3174Sigor@sysoev.ru                                              (void *) (uintptr_t) signo, NULL);
3180Sigor@sysoev.ru             }
3190Sigor@sysoev.ru         }
3200Sigor@sysoev.ru 
3210Sigor@sysoev.ru     } while (n == sizeof(buf));
3220Sigor@sysoev.ru 
3230Sigor@sysoev.ru     if (post) {
3241Sigor@sysoev.ru         nxt_event_engine_post_handler(task, NULL, NULL);
3250Sigor@sysoev.ru     }
3260Sigor@sysoev.ru }
3270Sigor@sysoev.ru 
3280Sigor@sysoev.ru 
3290Sigor@sysoev.ru static void
nxt_event_engine_post_handler(nxt_task_t * task,void * obj,void * data)3301Sigor@sysoev.ru nxt_event_engine_post_handler(nxt_task_t *task, void *obj, void *data)
3310Sigor@sysoev.ru {
3324Sigor@sysoev.ru     nxt_thread_t        *thread;
3334Sigor@sysoev.ru     nxt_event_engine_t  *engine;
3341Sigor@sysoev.ru 
3351Sigor@sysoev.ru     thread = task->thread;
3364Sigor@sysoev.ru     engine = thread->engine;
3371Sigor@sysoev.ru 
3384Sigor@sysoev.ru     nxt_locked_work_queue_move(thread, &engine->locked_work_queue,
3394Sigor@sysoev.ru                                &engine->fast_work_queue);
3400Sigor@sysoev.ru }
3410Sigor@sysoev.ru 
3420Sigor@sysoev.ru 
3430Sigor@sysoev.ru static void
nxt_event_engine_signal_pipe_error(nxt_task_t * task,void * obj,void * data)3441Sigor@sysoev.ru nxt_event_engine_signal_pipe_error(nxt_task_t *task, void *obj, void *data)
3450Sigor@sysoev.ru {
34613Sigor@sysoev.ru     nxt_event_engine_t       *engine;
34713Sigor@sysoev.ru     nxt_event_engine_pipe_t  *pipe;
3480Sigor@sysoev.ru 
3491Sigor@sysoev.ru     engine = task->thread->engine;
35013Sigor@sysoev.ru     pipe = engine->pipe;
3510Sigor@sysoev.ru 
352564Svbart@nginx.com     nxt_alert(task, "engine pipe(%FD:%FD) event error",
353564Svbart@nginx.com               pipe->fds[0], pipe->fds[1]);
3540Sigor@sysoev.ru 
35513Sigor@sysoev.ru     nxt_fd_event_close(engine, &pipe->event);
35613Sigor@sysoev.ru     nxt_pipe_close(pipe->event.task, pipe->fds);
3570Sigor@sysoev.ru }
3580Sigor@sysoev.ru 
3590Sigor@sysoev.ru 
3600Sigor@sysoev.ru static void
nxt_event_engine_signal_handler(nxt_task_t * task,void * obj,void * data)3611Sigor@sysoev.ru nxt_event_engine_signal_handler(nxt_task_t *task, void *obj, void *data)
3620Sigor@sysoev.ru {
3630Sigor@sysoev.ru     uintptr_t              signo;
36412Sigor@sysoev.ru     const nxt_sig_event_t  *sigev;
3650Sigor@sysoev.ru 
3660Sigor@sysoev.ru     signo = (uintptr_t) obj;
3670Sigor@sysoev.ru 
3681Sigor@sysoev.ru     for (sigev = task->thread->engine->signals->sigev;
3691Sigor@sysoev.ru          sigev->signo != 0;
3701Sigor@sysoev.ru          sigev++)
3711Sigor@sysoev.ru     {
3720Sigor@sysoev.ru         if (signo == (nxt_uint_t) sigev->signo) {
3734Sigor@sysoev.ru             sigev->handler(task, (void *) signo, (void *) sigev->name);
3744Sigor@sysoev.ru             return;
3750Sigor@sysoev.ru         }
3760Sigor@sysoev.ru     }
3770Sigor@sysoev.ru 
378564Svbart@nginx.com     nxt_alert(task, "signal %ui handler not found", (nxt_uint_t) signo);
3790Sigor@sysoev.ru }
3800Sigor@sysoev.ru 
3810Sigor@sysoev.ru 
3820Sigor@sysoev.ru nxt_int_t
nxt_event_engine_change(nxt_event_engine_t * engine,const nxt_event_interface_t * interface,nxt_uint_t batch)38320Sigor@sysoev.ru nxt_event_engine_change(nxt_event_engine_t *engine,
38412Sigor@sysoev.ru     const nxt_event_interface_t *interface, nxt_uint_t batch)
3850Sigor@sysoev.ru {
38620Sigor@sysoev.ru     nxt_uint_t  events;
3870Sigor@sysoev.ru 
38820Sigor@sysoev.ru     engine->batch = batch;
3890Sigor@sysoev.ru 
39012Sigor@sysoev.ru     if (!engine->event.signal_support && interface->signal_support) {
3910Sigor@sysoev.ru         /*
3920Sigor@sysoev.ru          * Block signal processing if the current event
3930Sigor@sysoev.ru          * facility does not support signal processing.
3940Sigor@sysoev.ru          */
3950Sigor@sysoev.ru         nxt_event_engine_signals_stop(engine);
3960Sigor@sysoev.ru 
3970Sigor@sysoev.ru         /*
3984Sigor@sysoev.ru          * Add to engine fast work queue the signal events possibly
3990Sigor@sysoev.ru          * received before the blocking signal processing.
4000Sigor@sysoev.ru          */
40120Sigor@sysoev.ru         nxt_event_engine_signal_pipe(&engine->task, &engine->pipe->event, NULL);
4020Sigor@sysoev.ru     }
4030Sigor@sysoev.ru 
40412Sigor@sysoev.ru     if (engine->pipe != NULL && interface->enable_post != NULL) {
4050Sigor@sysoev.ru         /*
4060Sigor@sysoev.ru          * An engine pipe must be closed after all signal events
4074Sigor@sysoev.ru          * added above to engine fast work queue will be processed.
4080Sigor@sysoev.ru          */
40912Sigor@sysoev.ru         nxt_work_queue_add(&engine->fast_work_queue,
4104Sigor@sysoev.ru                            nxt_event_engine_signal_pipe_close,
4114Sigor@sysoev.ru                            &engine->task, engine->pipe, NULL);
4120Sigor@sysoev.ru 
4130Sigor@sysoev.ru         engine->pipe = NULL;
4140Sigor@sysoev.ru     }
4150Sigor@sysoev.ru 
41612Sigor@sysoev.ru     engine->event.free(engine);
4170Sigor@sysoev.ru 
4180Sigor@sysoev.ru     events = (batch != 0) ? batch : 32;
4190Sigor@sysoev.ru 
42012Sigor@sysoev.ru     if (interface->create(engine, 4 * events, events) != NXT_OK) {
4210Sigor@sysoev.ru         return NXT_ERROR;
4220Sigor@sysoev.ru     }
4230Sigor@sysoev.ru 
42412Sigor@sysoev.ru     engine->event = *interface;
4250Sigor@sysoev.ru 
4261Sigor@sysoev.ru     if (nxt_event_engine_post_init(engine) != NXT_OK) {
4270Sigor@sysoev.ru         return NXT_ERROR;
4280Sigor@sysoev.ru     }
4290Sigor@sysoev.ru 
4300Sigor@sysoev.ru     if (engine->signals != NULL) {
4310Sigor@sysoev.ru 
43212Sigor@sysoev.ru         if (!engine->event.signal_support) {
4330Sigor@sysoev.ru             return nxt_event_engine_signals_start(engine);
4340Sigor@sysoev.ru         }
4350Sigor@sysoev.ru 
4360Sigor@sysoev.ru         /*
4370Sigor@sysoev.ru          * Reset the PID flag to start the signal thread if
4380Sigor@sysoev.ru          * some future event facility will not support signals.
4390Sigor@sysoev.ru          */
4400Sigor@sysoev.ru         engine->signals->process = 0;
4410Sigor@sysoev.ru     }
4420Sigor@sysoev.ru 
4430Sigor@sysoev.ru     return NXT_OK;
4440Sigor@sysoev.ru }
4450Sigor@sysoev.ru 
4460Sigor@sysoev.ru 
4470Sigor@sysoev.ru void
nxt_event_engine_free(nxt_event_engine_t * engine)4480Sigor@sysoev.ru nxt_event_engine_free(nxt_event_engine_t *engine)
4490Sigor@sysoev.ru {
450163Smax.romanov@nginx.com     nxt_thread_log_debug("free engine %p", engine);
451163Smax.romanov@nginx.com 
4520Sigor@sysoev.ru     nxt_event_engine_signal_pipe_free(engine);
4530Sigor@sysoev.ru     nxt_free(engine->signals);
4540Sigor@sysoev.ru 
4554Sigor@sysoev.ru     nxt_work_queue_cache_destroy(&engine->work_queue_cache);
4560Sigor@sysoev.ru 
45712Sigor@sysoev.ru     engine->event.free(engine);
4580Sigor@sysoev.ru 
4590Sigor@sysoev.ru     /* TODO: free timers */
4600Sigor@sysoev.ru 
4610Sigor@sysoev.ru     nxt_free(engine);
4620Sigor@sysoev.ru }
4630Sigor@sysoev.ru 
4640Sigor@sysoev.ru 
4654Sigor@sysoev.ru static nxt_work_handler_t
nxt_event_engine_queue_pop(nxt_event_engine_t * engine,nxt_task_t ** task,void ** obj,void ** data)4664Sigor@sysoev.ru nxt_event_engine_queue_pop(nxt_event_engine_t *engine, nxt_task_t **task,
4674Sigor@sysoev.ru     void **obj, void **data)
4684Sigor@sysoev.ru {
4698Sigor@sysoev.ru     nxt_work_queue_t  *wq, *last;
4704Sigor@sysoev.ru 
4714Sigor@sysoev.ru     wq = engine->current_work_queue;
4728Sigor@sysoev.ru     last = wq;
4734Sigor@sysoev.ru 
4744Sigor@sysoev.ru     if (wq->head == NULL) {
4754Sigor@sysoev.ru         wq = &engine->fast_work_queue;
4764Sigor@sysoev.ru 
4778Sigor@sysoev.ru         if (wq->head == NULL) {
4788Sigor@sysoev.ru 
4798Sigor@sysoev.ru             do {
4808Sigor@sysoev.ru                 engine->current_work_queue++;
4818Sigor@sysoev.ru                 wq = engine->current_work_queue;
4824Sigor@sysoev.ru 
48312Sigor@sysoev.ru                 if (wq > &engine->close_work_queue) {
4848Sigor@sysoev.ru                     wq = &engine->fast_work_queue;
4858Sigor@sysoev.ru                     engine->current_work_queue = wq;
4868Sigor@sysoev.ru                 }
4874Sigor@sysoev.ru 
4888Sigor@sysoev.ru                 if (wq->head != NULL) {
4898Sigor@sysoev.ru                     goto found;
4908Sigor@sysoev.ru                 }
4918Sigor@sysoev.ru 
4928Sigor@sysoev.ru             } while (wq != last);
4938Sigor@sysoev.ru 
4948Sigor@sysoev.ru             engine->current_work_queue = &engine->fast_work_queue;
4958Sigor@sysoev.ru 
4968Sigor@sysoev.ru             return NULL;
4974Sigor@sysoev.ru         }
4984Sigor@sysoev.ru     }
4994Sigor@sysoev.ru 
5008Sigor@sysoev.ru found:
5018Sigor@sysoev.ru 
5024Sigor@sysoev.ru     nxt_debug(&engine->task, "work queue: %s", wq->name);
5034Sigor@sysoev.ru 
5044Sigor@sysoev.ru     return nxt_work_queue_pop(wq, task, obj, data);
5054Sigor@sysoev.ru }
5064Sigor@sysoev.ru 
5074Sigor@sysoev.ru 
5080Sigor@sysoev.ru void
nxt_event_engine_start(nxt_event_engine_t * engine)5090Sigor@sysoev.ru nxt_event_engine_start(nxt_event_engine_t *engine)
5100Sigor@sysoev.ru {
5110Sigor@sysoev.ru     void                *obj, *data;
5121Sigor@sysoev.ru     nxt_task_t          *task;
5130Sigor@sysoev.ru     nxt_msec_t          timeout, now;
5140Sigor@sysoev.ru     nxt_thread_t        *thr;
5150Sigor@sysoev.ru     nxt_work_handler_t  handler;
5160Sigor@sysoev.ru 
5170Sigor@sysoev.ru     thr = nxt_thread();
5180Sigor@sysoev.ru 
5190Sigor@sysoev.ru     if (engine->fibers) {
5200Sigor@sysoev.ru         /*
5210Sigor@sysoev.ru          * _setjmp() cannot be wrapped in a function since return from
5220Sigor@sysoev.ru          * the function clobbers stack used by future _setjmp() returns.
5230Sigor@sysoev.ru          */
5240Sigor@sysoev.ru         _setjmp(engine->fibers->fiber.jmp);
5250Sigor@sysoev.ru 
5260Sigor@sysoev.ru         /* A return point from fibers. */
5270Sigor@sysoev.ru     }
5280Sigor@sysoev.ru 
52912Sigor@sysoev.ru     thr->log = engine->task.log;
5304Sigor@sysoev.ru 
5310Sigor@sysoev.ru     for ( ;; ) {
5320Sigor@sysoev.ru 
5330Sigor@sysoev.ru         for ( ;; ) {
5344Sigor@sysoev.ru             handler = nxt_event_engine_queue_pop(engine, &task, &obj, &data);
5350Sigor@sysoev.ru 
5360Sigor@sysoev.ru             if (handler == NULL) {
5370Sigor@sysoev.ru                 break;
5380Sigor@sysoev.ru             }
5390Sigor@sysoev.ru 
54063Sigor@sysoev.ru             thr->task = task;
54163Sigor@sysoev.ru 
5421Sigor@sysoev.ru             handler(task, obj, data);
5430Sigor@sysoev.ru         }
5440Sigor@sysoev.ru 
5450Sigor@sysoev.ru         /* Attach some event engine work queues in preferred order. */
5460Sigor@sysoev.ru 
5476Sigor@sysoev.ru         timeout = nxt_timer_find(engine);
5480Sigor@sysoev.ru 
54912Sigor@sysoev.ru         engine->event.poll(engine, timeout);
5500Sigor@sysoev.ru 
5510Sigor@sysoev.ru         now = nxt_thread_monotonic_time(thr) / 1000000;
5520Sigor@sysoev.ru 
5537Sigor@sysoev.ru         nxt_timer_expire(engine, now);
5540Sigor@sysoev.ru     }
5550Sigor@sysoev.ru }
55688Smax.romanov@nginx.com 
55788Smax.romanov@nginx.com 
558337Sigor@sysoev.ru void *
nxt_event_engine_mem_alloc(nxt_event_engine_t * engine,uint8_t * hint,size_t size)5591266Sigor@sysoev.ru nxt_event_engine_mem_alloc(nxt_event_engine_t *engine, uint8_t *hint,
560337Sigor@sysoev.ru     size_t size)
561337Sigor@sysoev.ru {
5621266Sigor@sysoev.ru     uint32_t               n;
563337Sigor@sysoev.ru     nxt_uint_t             items;
564337Sigor@sysoev.ru     nxt_array_t            *mem_cache;
565337Sigor@sysoev.ru     nxt_mem_cache_t        *cache;
566337Sigor@sysoev.ru     nxt_mem_cache_block_t  *block;
567337Sigor@sysoev.ru 
568337Sigor@sysoev.ru     mem_cache = engine->mem_cache;
5691266Sigor@sysoev.ru     n = *hint;
570337Sigor@sysoev.ru 
5711266Sigor@sysoev.ru     if (n == NXT_EVENT_ENGINE_NO_MEM_HINT) {
572337Sigor@sysoev.ru 
573337Sigor@sysoev.ru         if (mem_cache == NULL) {
574337Sigor@sysoev.ru             /* IPv4 nxt_sockaddr_t and HTTP/1 and HTTP/2 buffers. */
575337Sigor@sysoev.ru             items = 3;
576337Sigor@sysoev.ru #if (NXT_INET6)
577337Sigor@sysoev.ru             items++;
578337Sigor@sysoev.ru #endif
579337Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN)
580337Sigor@sysoev.ru             items++;
581337Sigor@sysoev.ru #endif
582337Sigor@sysoev.ru 
583337Sigor@sysoev.ru             mem_cache = nxt_array_create(engine->mem_pool, items,
584337Sigor@sysoev.ru                                          sizeof(nxt_mem_cache_t));
585337Sigor@sysoev.ru             if (nxt_slow_path(mem_cache == NULL)) {
586337Sigor@sysoev.ru                 return mem_cache;
587337Sigor@sysoev.ru             }
588337Sigor@sysoev.ru 
589337Sigor@sysoev.ru             engine->mem_cache = mem_cache;
590337Sigor@sysoev.ru         }
591337Sigor@sysoev.ru 
592337Sigor@sysoev.ru         cache = mem_cache->elts;
593337Sigor@sysoev.ru         for (n = 0; n < mem_cache->nelts; n++) {
594337Sigor@sysoev.ru             if (cache[n].size == size) {
595337Sigor@sysoev.ru                 goto found;
596337Sigor@sysoev.ru             }
597337Sigor@sysoev.ru         }
598337Sigor@sysoev.ru 
599337Sigor@sysoev.ru         cache = nxt_array_add(mem_cache);
600337Sigor@sysoev.ru         if (nxt_slow_path(cache == NULL)) {
601337Sigor@sysoev.ru             return cache;
602337Sigor@sysoev.ru         }
603337Sigor@sysoev.ru 
604337Sigor@sysoev.ru         cache->free = NULL;
605337Sigor@sysoev.ru         cache->size = size;
606337Sigor@sysoev.ru         cache->count = 0;
607337Sigor@sysoev.ru 
608337Sigor@sysoev.ru     found:
609337Sigor@sysoev.ru 
6101266Sigor@sysoev.ru         if (n < NXT_EVENT_ENGINE_NO_MEM_HINT) {
6111266Sigor@sysoev.ru             *hint = (uint8_t) n;
6121266Sigor@sysoev.ru         }
613337Sigor@sysoev.ru     }
614337Sigor@sysoev.ru 
615337Sigor@sysoev.ru     cache = mem_cache->elts;
616337Sigor@sysoev.ru     cache = cache + n;
617337Sigor@sysoev.ru 
618337Sigor@sysoev.ru     block = cache->free;
619337Sigor@sysoev.ru 
620337Sigor@sysoev.ru     if (block != NULL) {
621337Sigor@sysoev.ru         cache->free = block->next;
622337Sigor@sysoev.ru         cache->count--;
623337Sigor@sysoev.ru         return block;
624337Sigor@sysoev.ru     }
625337Sigor@sysoev.ru 
626337Sigor@sysoev.ru     return nxt_mp_alloc(engine->mem_pool, size);
627337Sigor@sysoev.ru }
628337Sigor@sysoev.ru 
629337Sigor@sysoev.ru 
630337Sigor@sysoev.ru void
nxt_event_engine_mem_free(nxt_event_engine_t * engine,uint8_t hint,void * p,size_t size)6311266Sigor@sysoev.ru nxt_event_engine_mem_free(nxt_event_engine_t *engine, uint8_t hint, void *p,
6321266Sigor@sysoev.ru     size_t size)
633337Sigor@sysoev.ru {
6341266Sigor@sysoev.ru     uint32_t               n;
6351266Sigor@sysoev.ru     nxt_array_t            *mem_cache;
636337Sigor@sysoev.ru     nxt_mem_cache_t        *cache;
637337Sigor@sysoev.ru     nxt_mem_cache_block_t  *block;
638337Sigor@sysoev.ru 
639337Sigor@sysoev.ru     block = p;
6401266Sigor@sysoev.ru     mem_cache = engine->mem_cache;
6411266Sigor@sysoev.ru     cache = mem_cache->elts;
642337Sigor@sysoev.ru 
6431266Sigor@sysoev.ru     n = hint;
6441266Sigor@sysoev.ru 
6451266Sigor@sysoev.ru     if (nxt_slow_path(n == NXT_EVENT_ENGINE_NO_MEM_HINT)) {
6461266Sigor@sysoev.ru 
6471266Sigor@sysoev.ru         if (size != 0) {
6481266Sigor@sysoev.ru             for (n = 0; n < mem_cache->nelts; n++) {
6491266Sigor@sysoev.ru                 if (cache[n].size == size) {
6501266Sigor@sysoev.ru                     goto found;
6511266Sigor@sysoev.ru                 }
6521266Sigor@sysoev.ru             }
6531266Sigor@sysoev.ru 
6541266Sigor@sysoev.ru             nxt_alert(&engine->task,
6551266Sigor@sysoev.ru                       "event engine mem free(%p, %z) not found", p, size);
6561266Sigor@sysoev.ru         }
6571266Sigor@sysoev.ru 
6581266Sigor@sysoev.ru         goto done;
6591266Sigor@sysoev.ru     }
6601266Sigor@sysoev.ru 
6611266Sigor@sysoev.ru found:
6621266Sigor@sysoev.ru 
6631266Sigor@sysoev.ru     cache = cache + n;
664337Sigor@sysoev.ru 
665337Sigor@sysoev.ru     if (cache->count < 16) {
666337Sigor@sysoev.ru         cache->count++;
667337Sigor@sysoev.ru         block->next = cache->free;
668337Sigor@sysoev.ru         cache->free = block;
669337Sigor@sysoev.ru 
670337Sigor@sysoev.ru         return;
671337Sigor@sysoev.ru     }
672337Sigor@sysoev.ru 
6731266Sigor@sysoev.ru done:
6741266Sigor@sysoev.ru 
675337Sigor@sysoev.ru     nxt_mp_free(engine->mem_pool, p);
676337Sigor@sysoev.ru }
677337Sigor@sysoev.ru 
678337Sigor@sysoev.ru 
6791267Sigor@sysoev.ru void *
nxt_event_engine_buf_mem_alloc(nxt_event_engine_t * engine,size_t size)6801267Sigor@sysoev.ru nxt_event_engine_buf_mem_alloc(nxt_event_engine_t *engine, size_t size)
6811267Sigor@sysoev.ru {
6821267Sigor@sysoev.ru     nxt_buf_t  *b;
6831267Sigor@sysoev.ru     uint8_t    hint;
6841267Sigor@sysoev.ru 
6851267Sigor@sysoev.ru     hint = NXT_EVENT_ENGINE_NO_MEM_HINT;
6861267Sigor@sysoev.ru 
6871267Sigor@sysoev.ru     b = nxt_event_engine_mem_alloc(engine, &hint, NXT_BUF_MEM_SIZE + size);
6881267Sigor@sysoev.ru     if (nxt_slow_path(b == NULL)) {
6891267Sigor@sysoev.ru         return NULL;
6901267Sigor@sysoev.ru     }
6911267Sigor@sysoev.ru 
6921267Sigor@sysoev.ru     nxt_memzero(b, NXT_BUF_MEM_SIZE);
6931267Sigor@sysoev.ru 
6941267Sigor@sysoev.ru     b->cache_hint = hint;
6951267Sigor@sysoev.ru     b->data = engine;
6961267Sigor@sysoev.ru     b->completion_handler = nxt_event_engine_buf_mem_completion;
6971267Sigor@sysoev.ru 
6981267Sigor@sysoev.ru     if (size != 0) {
6991267Sigor@sysoev.ru         b->mem.start = nxt_pointer_to(b, NXT_BUF_MEM_SIZE);
7001267Sigor@sysoev.ru         b->mem.pos = b->mem.start;
7011267Sigor@sysoev.ru         b->mem.free = b->mem.start;
7021267Sigor@sysoev.ru         b->mem.end = b->mem.start + size;
7031267Sigor@sysoev.ru     }
7041267Sigor@sysoev.ru 
7051267Sigor@sysoev.ru     return b;
7061267Sigor@sysoev.ru }
7071267Sigor@sysoev.ru 
7081267Sigor@sysoev.ru 
7091267Sigor@sysoev.ru void
nxt_event_engine_buf_mem_free(nxt_event_engine_t * engine,nxt_buf_t * b)7101267Sigor@sysoev.ru nxt_event_engine_buf_mem_free(nxt_event_engine_t *engine, nxt_buf_t *b)
7111267Sigor@sysoev.ru {
7121267Sigor@sysoev.ru     size_t  size;
7131267Sigor@sysoev.ru 
7141267Sigor@sysoev.ru     size = NXT_BUF_MEM_SIZE + nxt_buf_mem_size(&b->mem);
7151267Sigor@sysoev.ru 
7161267Sigor@sysoev.ru     nxt_event_engine_mem_free(engine, b->cache_hint, b, size);
7171267Sigor@sysoev.ru }
7181267Sigor@sysoev.ru 
7191267Sigor@sysoev.ru 
7201267Sigor@sysoev.ru void
nxt_event_engine_buf_mem_completion(nxt_task_t * task,void * obj,void * data)7211267Sigor@sysoev.ru nxt_event_engine_buf_mem_completion(nxt_task_t *task, void *obj, void *data)
7221267Sigor@sysoev.ru {
723*1927Smax.romanov@nginx.com     nxt_buf_t           *b, *next, *parent;
7241267Sigor@sysoev.ru     nxt_event_engine_t  *engine;
7251267Sigor@sysoev.ru 
7261267Sigor@sysoev.ru     b = obj;
7271267Sigor@sysoev.ru 
7281267Sigor@sysoev.ru     nxt_debug(task, "buf completion: %p %p", b, b->mem.start);
7291267Sigor@sysoev.ru 
7301267Sigor@sysoev.ru     engine = b->data;
7311269Sigor@sysoev.ru 
7321269Sigor@sysoev.ru     do {
7331269Sigor@sysoev.ru         next = b->next;
7341269Sigor@sysoev.ru         parent = b->parent;
7351267Sigor@sysoev.ru 
7361269Sigor@sysoev.ru         nxt_event_engine_buf_mem_free(engine, b);
7371269Sigor@sysoev.ru 
7381269Sigor@sysoev.ru         nxt_buf_parent_completion(task, parent);
7391269Sigor@sysoev.ru 
7401269Sigor@sysoev.ru         b = next;
7411269Sigor@sysoev.ru     } while (b != NULL);
7421267Sigor@sysoev.ru }
7431267Sigor@sysoev.ru 
7441267Sigor@sysoev.ru 
745165Smax.romanov@nginx.com #if (NXT_DEBUG)
746165Smax.romanov@nginx.com 
nxt_event_engine_thread_adopt(nxt_event_engine_t * engine)747165Smax.romanov@nginx.com void nxt_event_engine_thread_adopt(nxt_event_engine_t *engine)
748165Smax.romanov@nginx.com {
749165Smax.romanov@nginx.com     nxt_work_queue_thread_adopt(&engine->fast_work_queue);
750165Smax.romanov@nginx.com     nxt_work_queue_thread_adopt(&engine->accept_work_queue);
751165Smax.romanov@nginx.com     nxt_work_queue_thread_adopt(&engine->read_work_queue);
752165Smax.romanov@nginx.com     nxt_work_queue_thread_adopt(&engine->socket_work_queue);
753165Smax.romanov@nginx.com     nxt_work_queue_thread_adopt(&engine->connect_work_queue);
754165Smax.romanov@nginx.com     nxt_work_queue_thread_adopt(&engine->write_work_queue);
755165Smax.romanov@nginx.com     nxt_work_queue_thread_adopt(&engine->shutdown_work_queue);
756165Smax.romanov@nginx.com     nxt_work_queue_thread_adopt(&engine->close_work_queue);
757165Smax.romanov@nginx.com }
758165Smax.romanov@nginx.com 
759165Smax.romanov@nginx.com #endif
760