112Sigor@sysoev.ru
212Sigor@sysoev.ru /*
312Sigor@sysoev.ru * Copyright (C) Igor Sysoev
412Sigor@sysoev.ru * Copyright (C) NGINX, Inc.
512Sigor@sysoev.ru */
612Sigor@sysoev.ru
712Sigor@sysoev.ru #include <nxt_main.h>
812Sigor@sysoev.ru
912Sigor@sysoev.ru
1012Sigor@sysoev.ru /*
1112Sigor@sysoev.ru * The first epoll version has been introduced in Linux 2.5.44. The
1212Sigor@sysoev.ru * interface was changed several times since then and the final version
1312Sigor@sysoev.ru * of epoll_create(), epoll_ctl(), epoll_wait(), and EPOLLET mode has
1412Sigor@sysoev.ru * been introduced in Linux 2.6.0 and is supported since glibc 2.3.2.
1512Sigor@sysoev.ru *
1612Sigor@sysoev.ru * EPOLLET mode did not work reliable in early implementaions and in
1712Sigor@sysoev.ru * Linux 2.4 backport.
1812Sigor@sysoev.ru *
1912Sigor@sysoev.ru * EPOLLONESHOT Linux 2.6.2, glibc 2.3.
2012Sigor@sysoev.ru * EPOLLRDHUP Linux 2.6.17, glibc 2.8.
2112Sigor@sysoev.ru * epoll_pwait() Linux 2.6.19, glibc 2.6.
2212Sigor@sysoev.ru * signalfd() Linux 2.6.22, glibc 2.7.
2312Sigor@sysoev.ru * eventfd() Linux 2.6.22, glibc 2.7.
2412Sigor@sysoev.ru * timerfd_create() Linux 2.6.25, glibc 2.8.
2512Sigor@sysoev.ru * epoll_create1() Linux 2.6.27, glibc 2.9.
2612Sigor@sysoev.ru * signalfd4() Linux 2.6.27, glibc 2.9.
2712Sigor@sysoev.ru * eventfd2() Linux 2.6.27, glibc 2.9.
2812Sigor@sysoev.ru * accept4() Linux 2.6.28, glibc 2.10.
2912Sigor@sysoev.ru * eventfd2(EFD_SEMAPHORE) Linux 2.6.30, glibc 2.10.
30353Sigor@sysoev.ru * EPOLLEXCLUSIVE Linux 4.5, glibc 2.24.
3112Sigor@sysoev.ru */
3212Sigor@sysoev.ru
3312Sigor@sysoev.ru
3412Sigor@sysoev.ru #if (NXT_HAVE_EPOLL_EDGE)
3512Sigor@sysoev.ru static nxt_int_t nxt_epoll_edge_create(nxt_event_engine_t *engine,
3612Sigor@sysoev.ru nxt_uint_t mchanges, nxt_uint_t mevents);
3712Sigor@sysoev.ru #endif
3812Sigor@sysoev.ru static nxt_int_t nxt_epoll_level_create(nxt_event_engine_t *engine,
3912Sigor@sysoev.ru nxt_uint_t mchanges, nxt_uint_t mevents);
4012Sigor@sysoev.ru static nxt_int_t nxt_epoll_create(nxt_event_engine_t *engine,
4162Sigor@sysoev.ru nxt_uint_t mchanges, nxt_uint_t mevents, nxt_conn_io_t *io, uint32_t mode);
4212Sigor@sysoev.ru static void nxt_epoll_test_accept4(nxt_event_engine_t *engine,
4362Sigor@sysoev.ru nxt_conn_io_t *io);
4412Sigor@sysoev.ru static void nxt_epoll_free(nxt_event_engine_t *engine);
4512Sigor@sysoev.ru static void nxt_epoll_enable(nxt_event_engine_t *engine, nxt_fd_event_t *ev);
4612Sigor@sysoev.ru static void nxt_epoll_disable(nxt_event_engine_t *engine, nxt_fd_event_t *ev);
4712Sigor@sysoev.ru static void nxt_epoll_delete(nxt_event_engine_t *engine, nxt_fd_event_t *ev);
4812Sigor@sysoev.ru static nxt_bool_t nxt_epoll_close(nxt_event_engine_t *engine,
4912Sigor@sysoev.ru nxt_fd_event_t *ev);
5012Sigor@sysoev.ru static void nxt_epoll_enable_read(nxt_event_engine_t *engine,
5112Sigor@sysoev.ru nxt_fd_event_t *ev);
5212Sigor@sysoev.ru static void nxt_epoll_enable_write(nxt_event_engine_t *engine,
5312Sigor@sysoev.ru nxt_fd_event_t *ev);
5412Sigor@sysoev.ru static void nxt_epoll_disable_read(nxt_event_engine_t *engine,
5512Sigor@sysoev.ru nxt_fd_event_t *ev);
5612Sigor@sysoev.ru static void nxt_epoll_disable_write(nxt_event_engine_t *engine,
5712Sigor@sysoev.ru nxt_fd_event_t *ev);
5812Sigor@sysoev.ru static void nxt_epoll_block_read(nxt_event_engine_t *engine,
5912Sigor@sysoev.ru nxt_fd_event_t *ev);
6012Sigor@sysoev.ru static void nxt_epoll_block_write(nxt_event_engine_t *engine,
6112Sigor@sysoev.ru nxt_fd_event_t *ev);
6212Sigor@sysoev.ru static void nxt_epoll_oneshot_read(nxt_event_engine_t *engine,
6312Sigor@sysoev.ru nxt_fd_event_t *ev);
6412Sigor@sysoev.ru static void nxt_epoll_oneshot_write(nxt_event_engine_t *engine,
6512Sigor@sysoev.ru nxt_fd_event_t *ev);
6612Sigor@sysoev.ru static void nxt_epoll_enable_accept(nxt_event_engine_t *engine,
6712Sigor@sysoev.ru nxt_fd_event_t *ev);
6812Sigor@sysoev.ru static void nxt_epoll_change(nxt_event_engine_t *engine, nxt_fd_event_t *ev,
6912Sigor@sysoev.ru int op, uint32_t events);
70813Sigor@sysoev.ru static void nxt_epoll_commit_changes(nxt_event_engine_t *engine);
7112Sigor@sysoev.ru static void nxt_epoll_error_handler(nxt_task_t *task, void *obj, void *data);
7212Sigor@sysoev.ru #if (NXT_HAVE_SIGNALFD)
7312Sigor@sysoev.ru static nxt_int_t nxt_epoll_add_signal(nxt_event_engine_t *engine);
7412Sigor@sysoev.ru static void nxt_epoll_signalfd_handler(nxt_task_t *task, void *obj, void *data);
7512Sigor@sysoev.ru #endif
7612Sigor@sysoev.ru #if (NXT_HAVE_EVENTFD)
7712Sigor@sysoev.ru static nxt_int_t nxt_epoll_enable_post(nxt_event_engine_t *engine,
7812Sigor@sysoev.ru nxt_work_handler_t handler);
7912Sigor@sysoev.ru static void nxt_epoll_eventfd_handler(nxt_task_t *task, void *obj, void *data);
8012Sigor@sysoev.ru static void nxt_epoll_signal(nxt_event_engine_t *engine, nxt_uint_t signo);
8112Sigor@sysoev.ru #endif
8212Sigor@sysoev.ru static void nxt_epoll_poll(nxt_event_engine_t *engine, nxt_msec_t timeout);
8312Sigor@sysoev.ru
8412Sigor@sysoev.ru #if (NXT_HAVE_ACCEPT4)
8562Sigor@sysoev.ru static void nxt_epoll_conn_io_accept4(nxt_task_t *task, void *obj,
8612Sigor@sysoev.ru void *data);
8712Sigor@sysoev.ru #endif
8812Sigor@sysoev.ru
8912Sigor@sysoev.ru
9012Sigor@sysoev.ru #if (NXT_HAVE_EPOLL_EDGE)
9112Sigor@sysoev.ru
9262Sigor@sysoev.ru static void nxt_epoll_edge_conn_io_connect(nxt_task_t *task, void *obj,
9312Sigor@sysoev.ru void *data);
9462Sigor@sysoev.ru static void nxt_epoll_edge_conn_connected(nxt_task_t *task, void *obj,
9512Sigor@sysoev.ru void *data);
9662Sigor@sysoev.ru static ssize_t nxt_epoll_edge_conn_io_recvbuf(nxt_conn_t *c, nxt_buf_t *b);
9712Sigor@sysoev.ru
9812Sigor@sysoev.ru
9962Sigor@sysoev.ru static nxt_conn_io_t nxt_epoll_edge_conn_io = {
100771Sigor@sysoev.ru .connect = nxt_epoll_edge_conn_io_connect,
101771Sigor@sysoev.ru .accept = nxt_conn_io_accept,
10212Sigor@sysoev.ru
103771Sigor@sysoev.ru .read = nxt_conn_io_read,
104771Sigor@sysoev.ru .recvbuf = nxt_epoll_edge_conn_io_recvbuf,
105771Sigor@sysoev.ru .recv = nxt_conn_io_recv,
10612Sigor@sysoev.ru
107771Sigor@sysoev.ru .write = nxt_conn_io_write,
108771Sigor@sysoev.ru .sendbuf = nxt_conn_io_sendbuf,
10912Sigor@sysoev.ru
11012Sigor@sysoev.ru #if (NXT_HAVE_LINUX_SENDFILE)
111771Sigor@sysoev.ru .old_sendbuf = nxt_linux_event_conn_io_sendfile,
11212Sigor@sysoev.ru #else
113771Sigor@sysoev.ru .old_sendbuf = nxt_event_conn_io_sendbuf,
11412Sigor@sysoev.ru #endif
11512Sigor@sysoev.ru
116771Sigor@sysoev.ru .writev = nxt_event_conn_io_writev,
117771Sigor@sysoev.ru .send = nxt_event_conn_io_send,
11812Sigor@sysoev.ru };
11912Sigor@sysoev.ru
12012Sigor@sysoev.ru
12112Sigor@sysoev.ru const nxt_event_interface_t nxt_epoll_edge_engine = {
12212Sigor@sysoev.ru "epoll_edge",
12312Sigor@sysoev.ru nxt_epoll_edge_create,
12412Sigor@sysoev.ru nxt_epoll_free,
12512Sigor@sysoev.ru nxt_epoll_enable,
12612Sigor@sysoev.ru nxt_epoll_disable,
12712Sigor@sysoev.ru nxt_epoll_delete,
12812Sigor@sysoev.ru nxt_epoll_close,
12912Sigor@sysoev.ru nxt_epoll_enable_read,
13012Sigor@sysoev.ru nxt_epoll_enable_write,
13112Sigor@sysoev.ru nxt_epoll_disable_read,
13212Sigor@sysoev.ru nxt_epoll_disable_write,
13312Sigor@sysoev.ru nxt_epoll_block_read,
13412Sigor@sysoev.ru nxt_epoll_block_write,
13512Sigor@sysoev.ru nxt_epoll_oneshot_read,
13612Sigor@sysoev.ru nxt_epoll_oneshot_write,
13712Sigor@sysoev.ru nxt_epoll_enable_accept,
13812Sigor@sysoev.ru NULL,
13912Sigor@sysoev.ru NULL,
14012Sigor@sysoev.ru #if (NXT_HAVE_EVENTFD)
14112Sigor@sysoev.ru nxt_epoll_enable_post,
14212Sigor@sysoev.ru nxt_epoll_signal,
14312Sigor@sysoev.ru #else
14412Sigor@sysoev.ru NULL,
14512Sigor@sysoev.ru NULL,
14612Sigor@sysoev.ru #endif
14712Sigor@sysoev.ru nxt_epoll_poll,
14812Sigor@sysoev.ru
14962Sigor@sysoev.ru &nxt_epoll_edge_conn_io,
15012Sigor@sysoev.ru
15112Sigor@sysoev.ru #if (NXT_HAVE_INOTIFY)
15212Sigor@sysoev.ru NXT_FILE_EVENTS,
15312Sigor@sysoev.ru #else
15412Sigor@sysoev.ru NXT_NO_FILE_EVENTS,
15512Sigor@sysoev.ru #endif
15612Sigor@sysoev.ru
15712Sigor@sysoev.ru #if (NXT_HAVE_SIGNALFD)
15812Sigor@sysoev.ru NXT_SIGNAL_EVENTS,
15912Sigor@sysoev.ru #else
16012Sigor@sysoev.ru NXT_NO_SIGNAL_EVENTS,
16112Sigor@sysoev.ru #endif
16212Sigor@sysoev.ru };
16312Sigor@sysoev.ru
16412Sigor@sysoev.ru #endif
16512Sigor@sysoev.ru
16612Sigor@sysoev.ru
16712Sigor@sysoev.ru const nxt_event_interface_t nxt_epoll_level_engine = {
16812Sigor@sysoev.ru "epoll_level",
16912Sigor@sysoev.ru nxt_epoll_level_create,
17012Sigor@sysoev.ru nxt_epoll_free,
17112Sigor@sysoev.ru nxt_epoll_enable,
17212Sigor@sysoev.ru nxt_epoll_disable,
17312Sigor@sysoev.ru nxt_epoll_delete,
17412Sigor@sysoev.ru nxt_epoll_close,
17512Sigor@sysoev.ru nxt_epoll_enable_read,
17612Sigor@sysoev.ru nxt_epoll_enable_write,
17712Sigor@sysoev.ru nxt_epoll_disable_read,
17812Sigor@sysoev.ru nxt_epoll_disable_write,
17912Sigor@sysoev.ru nxt_epoll_block_read,
18012Sigor@sysoev.ru nxt_epoll_block_write,
18112Sigor@sysoev.ru nxt_epoll_oneshot_read,
18212Sigor@sysoev.ru nxt_epoll_oneshot_write,
18312Sigor@sysoev.ru nxt_epoll_enable_accept,
18412Sigor@sysoev.ru NULL,
18512Sigor@sysoev.ru NULL,
18612Sigor@sysoev.ru #if (NXT_HAVE_EVENTFD)
18712Sigor@sysoev.ru nxt_epoll_enable_post,
18812Sigor@sysoev.ru nxt_epoll_signal,
18912Sigor@sysoev.ru #else
19012Sigor@sysoev.ru NULL,
19112Sigor@sysoev.ru NULL,
19212Sigor@sysoev.ru #endif
19312Sigor@sysoev.ru nxt_epoll_poll,
19412Sigor@sysoev.ru
19562Sigor@sysoev.ru &nxt_unix_conn_io,
19612Sigor@sysoev.ru
19712Sigor@sysoev.ru #if (NXT_HAVE_INOTIFY)
19812Sigor@sysoev.ru NXT_FILE_EVENTS,
19912Sigor@sysoev.ru #else
20012Sigor@sysoev.ru NXT_NO_FILE_EVENTS,
20112Sigor@sysoev.ru #endif
20212Sigor@sysoev.ru
20312Sigor@sysoev.ru #if (NXT_HAVE_SIGNALFD)
20412Sigor@sysoev.ru NXT_SIGNAL_EVENTS,
20512Sigor@sysoev.ru #else
20612Sigor@sysoev.ru NXT_NO_SIGNAL_EVENTS,
20712Sigor@sysoev.ru #endif
20812Sigor@sysoev.ru };
20912Sigor@sysoev.ru
21012Sigor@sysoev.ru
21112Sigor@sysoev.ru #if (NXT_HAVE_EPOLL_EDGE)
21212Sigor@sysoev.ru
21312Sigor@sysoev.ru static nxt_int_t
nxt_epoll_edge_create(nxt_event_engine_t * engine,nxt_uint_t mchanges,nxt_uint_t mevents)21412Sigor@sysoev.ru nxt_epoll_edge_create(nxt_event_engine_t *engine, nxt_uint_t mchanges,
21512Sigor@sysoev.ru nxt_uint_t mevents)
21612Sigor@sysoev.ru {
21762Sigor@sysoev.ru return nxt_epoll_create(engine, mchanges, mevents, &nxt_epoll_edge_conn_io,
21812Sigor@sysoev.ru EPOLLET | EPOLLRDHUP);
21912Sigor@sysoev.ru }
22012Sigor@sysoev.ru
22112Sigor@sysoev.ru #endif
22212Sigor@sysoev.ru
22312Sigor@sysoev.ru
22412Sigor@sysoev.ru static nxt_int_t
nxt_epoll_level_create(nxt_event_engine_t * engine,nxt_uint_t mchanges,nxt_uint_t mevents)22512Sigor@sysoev.ru nxt_epoll_level_create(nxt_event_engine_t *engine, nxt_uint_t mchanges,
22612Sigor@sysoev.ru nxt_uint_t mevents)
22712Sigor@sysoev.ru {
22812Sigor@sysoev.ru return nxt_epoll_create(engine, mchanges, mevents,
22962Sigor@sysoev.ru &nxt_unix_conn_io, 0);
23012Sigor@sysoev.ru }
23112Sigor@sysoev.ru
23212Sigor@sysoev.ru
23312Sigor@sysoev.ru static nxt_int_t
nxt_epoll_create(nxt_event_engine_t * engine,nxt_uint_t mchanges,nxt_uint_t mevents,nxt_conn_io_t * io,uint32_t mode)23412Sigor@sysoev.ru nxt_epoll_create(nxt_event_engine_t *engine, nxt_uint_t mchanges,
23562Sigor@sysoev.ru nxt_uint_t mevents, nxt_conn_io_t *io, uint32_t mode)
23612Sigor@sysoev.ru {
23712Sigor@sysoev.ru engine->u.epoll.fd = -1;
23812Sigor@sysoev.ru engine->u.epoll.mode = mode;
23912Sigor@sysoev.ru engine->u.epoll.mchanges = mchanges;
24012Sigor@sysoev.ru engine->u.epoll.mevents = mevents;
24112Sigor@sysoev.ru #if (NXT_HAVE_SIGNALFD)
24212Sigor@sysoev.ru engine->u.epoll.signalfd.fd = -1;
24312Sigor@sysoev.ru #endif
24412Sigor@sysoev.ru
24512Sigor@sysoev.ru engine->u.epoll.changes = nxt_malloc(sizeof(nxt_epoll_change_t) * mchanges);
24612Sigor@sysoev.ru if (engine->u.epoll.changes == NULL) {
24712Sigor@sysoev.ru goto fail;
24812Sigor@sysoev.ru }
24912Sigor@sysoev.ru
25012Sigor@sysoev.ru engine->u.epoll.events = nxt_malloc(sizeof(struct epoll_event) * mevents);
25112Sigor@sysoev.ru if (engine->u.epoll.events == NULL) {
25212Sigor@sysoev.ru goto fail;
25312Sigor@sysoev.ru }
25412Sigor@sysoev.ru
25512Sigor@sysoev.ru engine->u.epoll.fd = epoll_create(1);
25612Sigor@sysoev.ru if (engine->u.epoll.fd == -1) {
257564Svbart@nginx.com nxt_alert(&engine->task, "epoll_create() failed %E", nxt_errno);
25812Sigor@sysoev.ru goto fail;
25912Sigor@sysoev.ru }
26012Sigor@sysoev.ru
26112Sigor@sysoev.ru nxt_debug(&engine->task, "epoll_create(): %d", engine->u.epoll.fd);
26212Sigor@sysoev.ru
26312Sigor@sysoev.ru if (engine->signals != NULL) {
26412Sigor@sysoev.ru
26512Sigor@sysoev.ru #if (NXT_HAVE_SIGNALFD)
26612Sigor@sysoev.ru
26712Sigor@sysoev.ru if (nxt_epoll_add_signal(engine) != NXT_OK) {
26812Sigor@sysoev.ru goto fail;
26912Sigor@sysoev.ru }
27012Sigor@sysoev.ru
27112Sigor@sysoev.ru #endif
27212Sigor@sysoev.ru
27312Sigor@sysoev.ru nxt_epoll_test_accept4(engine, io);
27412Sigor@sysoev.ru }
27512Sigor@sysoev.ru
27612Sigor@sysoev.ru return NXT_OK;
27712Sigor@sysoev.ru
27812Sigor@sysoev.ru fail:
27912Sigor@sysoev.ru
28012Sigor@sysoev.ru nxt_epoll_free(engine);
28112Sigor@sysoev.ru
28212Sigor@sysoev.ru return NXT_ERROR;
28312Sigor@sysoev.ru }
28412Sigor@sysoev.ru
28512Sigor@sysoev.ru
28612Sigor@sysoev.ru static void
nxt_epoll_test_accept4(nxt_event_engine_t * engine,nxt_conn_io_t * io)28762Sigor@sysoev.ru nxt_epoll_test_accept4(nxt_event_engine_t *engine, nxt_conn_io_t *io)
28812Sigor@sysoev.ru {
28912Sigor@sysoev.ru static nxt_work_handler_t handler;
29012Sigor@sysoev.ru
29112Sigor@sysoev.ru if (handler == NULL) {
29212Sigor@sysoev.ru
29312Sigor@sysoev.ru handler = io->accept;
29412Sigor@sysoev.ru
29512Sigor@sysoev.ru #if (NXT_HAVE_ACCEPT4)
29612Sigor@sysoev.ru
29712Sigor@sysoev.ru (void) accept4(-1, NULL, NULL, SOCK_NONBLOCK);
29812Sigor@sysoev.ru
29912Sigor@sysoev.ru if (nxt_errno != NXT_ENOSYS) {
30062Sigor@sysoev.ru handler = nxt_epoll_conn_io_accept4;
30112Sigor@sysoev.ru
30212Sigor@sysoev.ru } else {
30312Sigor@sysoev.ru nxt_log(&engine->task, NXT_LOG_INFO, "accept4() failed %E",
30412Sigor@sysoev.ru NXT_ENOSYS);
30512Sigor@sysoev.ru }
30612Sigor@sysoev.ru
30712Sigor@sysoev.ru #endif
30812Sigor@sysoev.ru }
30912Sigor@sysoev.ru
31012Sigor@sysoev.ru io->accept = handler;
31112Sigor@sysoev.ru }
31212Sigor@sysoev.ru
31312Sigor@sysoev.ru
31412Sigor@sysoev.ru static void
nxt_epoll_free(nxt_event_engine_t * engine)31512Sigor@sysoev.ru nxt_epoll_free(nxt_event_engine_t *engine)
31612Sigor@sysoev.ru {
31712Sigor@sysoev.ru int fd;
31812Sigor@sysoev.ru
31912Sigor@sysoev.ru nxt_debug(&engine->task, "epoll %d free", engine->u.epoll.fd);
32012Sigor@sysoev.ru
32112Sigor@sysoev.ru #if (NXT_HAVE_SIGNALFD)
32212Sigor@sysoev.ru
32312Sigor@sysoev.ru fd = engine->u.epoll.signalfd.fd;
32412Sigor@sysoev.ru
32512Sigor@sysoev.ru if (fd != -1 && close(fd) != 0) {
326564Svbart@nginx.com nxt_alert(&engine->task, "signalfd close(%d) failed %E", fd, nxt_errno);
32712Sigor@sysoev.ru }
32812Sigor@sysoev.ru
32912Sigor@sysoev.ru #endif
33012Sigor@sysoev.ru
33112Sigor@sysoev.ru #if (NXT_HAVE_EVENTFD)
33212Sigor@sysoev.ru
33312Sigor@sysoev.ru fd = engine->u.epoll.eventfd.fd;
33412Sigor@sysoev.ru
33512Sigor@sysoev.ru if (fd != -1 && close(fd) != 0) {
336564Svbart@nginx.com nxt_alert(&engine->task, "eventfd close(%d) failed %E", fd, nxt_errno);
33712Sigor@sysoev.ru }
33812Sigor@sysoev.ru
33912Sigor@sysoev.ru #endif
34012Sigor@sysoev.ru
34112Sigor@sysoev.ru fd = engine->u.epoll.fd;
34212Sigor@sysoev.ru
34312Sigor@sysoev.ru if (fd != -1 && close(fd) != 0) {
344564Svbart@nginx.com nxt_alert(&engine->task, "epoll close(%d) failed %E", fd, nxt_errno);
34512Sigor@sysoev.ru }
34612Sigor@sysoev.ru
34712Sigor@sysoev.ru nxt_free(engine->u.epoll.events);
348309Savagin@virtuozzo.com nxt_free(engine->u.epoll.changes);
34912Sigor@sysoev.ru
35012Sigor@sysoev.ru nxt_memzero(&engine->u.epoll, sizeof(nxt_epoll_engine_t));
35112Sigor@sysoev.ru }
35212Sigor@sysoev.ru
35312Sigor@sysoev.ru
35412Sigor@sysoev.ru static void
nxt_epoll_enable(nxt_event_engine_t * engine,nxt_fd_event_t * ev)35512Sigor@sysoev.ru nxt_epoll_enable(nxt_event_engine_t *engine, nxt_fd_event_t *ev)
35612Sigor@sysoev.ru {
35712Sigor@sysoev.ru ev->read = NXT_EVENT_ACTIVE;
35812Sigor@sysoev.ru ev->write = NXT_EVENT_ACTIVE;
35912Sigor@sysoev.ru
36012Sigor@sysoev.ru nxt_epoll_change(engine, ev, EPOLL_CTL_ADD,
36112Sigor@sysoev.ru EPOLLIN | EPOLLOUT | engine->u.epoll.mode);
36212Sigor@sysoev.ru }
36312Sigor@sysoev.ru
36412Sigor@sysoev.ru
36512Sigor@sysoev.ru static void
nxt_epoll_disable(nxt_event_engine_t * engine,nxt_fd_event_t * ev)36612Sigor@sysoev.ru nxt_epoll_disable(nxt_event_engine_t *engine, nxt_fd_event_t *ev)
36712Sigor@sysoev.ru {
36812Sigor@sysoev.ru if (ev->read > NXT_EVENT_DISABLED || ev->write > NXT_EVENT_DISABLED) {
36912Sigor@sysoev.ru
37012Sigor@sysoev.ru ev->read = NXT_EVENT_INACTIVE;
37112Sigor@sysoev.ru ev->write = NXT_EVENT_INACTIVE;
37212Sigor@sysoev.ru
37312Sigor@sysoev.ru nxt_epoll_change(engine, ev, EPOLL_CTL_DEL, 0);
37412Sigor@sysoev.ru }
37512Sigor@sysoev.ru }
37612Sigor@sysoev.ru
37712Sigor@sysoev.ru
37812Sigor@sysoev.ru static void
nxt_epoll_delete(nxt_event_engine_t * engine,nxt_fd_event_t * ev)37912Sigor@sysoev.ru nxt_epoll_delete(nxt_event_engine_t *engine, nxt_fd_event_t *ev)
38012Sigor@sysoev.ru {
38112Sigor@sysoev.ru if (ev->read != NXT_EVENT_INACTIVE || ev->write != NXT_EVENT_INACTIVE) {
38212Sigor@sysoev.ru
38312Sigor@sysoev.ru ev->read = NXT_EVENT_INACTIVE;
38412Sigor@sysoev.ru ev->write = NXT_EVENT_INACTIVE;
38512Sigor@sysoev.ru
38612Sigor@sysoev.ru nxt_epoll_change(engine, ev, EPOLL_CTL_DEL, 0);
38712Sigor@sysoev.ru }
38812Sigor@sysoev.ru }
38912Sigor@sysoev.ru
39012Sigor@sysoev.ru
39112Sigor@sysoev.ru /*
39212Sigor@sysoev.ru * Although calling close() on a file descriptor will remove any epoll
39312Sigor@sysoev.ru * events that reference the descriptor, in this case the close() acquires
39412Sigor@sysoev.ru * the kernel global "epmutex" while epoll_ctl(EPOLL_CTL_DEL) does not
39512Sigor@sysoev.ru * acquire the "epmutex" since Linux 3.13 if the file descriptor presents
39612Sigor@sysoev.ru * only in one epoll set. Thus removing events explicitly before closing
39712Sigor@sysoev.ru * eliminates possible lock contention.
39812Sigor@sysoev.ru */
39912Sigor@sysoev.ru
40012Sigor@sysoev.ru static nxt_bool_t
nxt_epoll_close(nxt_event_engine_t * engine,nxt_fd_event_t * ev)40112Sigor@sysoev.ru nxt_epoll_close(nxt_event_engine_t *engine, nxt_fd_event_t *ev)
40212Sigor@sysoev.ru {
40312Sigor@sysoev.ru nxt_epoll_delete(engine, ev);
40412Sigor@sysoev.ru
40512Sigor@sysoev.ru return ev->changing;
40612Sigor@sysoev.ru }
40712Sigor@sysoev.ru
40812Sigor@sysoev.ru
40912Sigor@sysoev.ru static void
nxt_epoll_enable_read(nxt_event_engine_t * engine,nxt_fd_event_t * ev)41012Sigor@sysoev.ru nxt_epoll_enable_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev)
41112Sigor@sysoev.ru {
41212Sigor@sysoev.ru int op;
41312Sigor@sysoev.ru uint32_t events;
41412Sigor@sysoev.ru
41512Sigor@sysoev.ru if (ev->read != NXT_EVENT_BLOCKED) {
41612Sigor@sysoev.ru
41712Sigor@sysoev.ru op = EPOLL_CTL_MOD;
41812Sigor@sysoev.ru events = EPOLLIN | engine->u.epoll.mode;
41912Sigor@sysoev.ru
42012Sigor@sysoev.ru if (ev->read == NXT_EVENT_INACTIVE && ev->write == NXT_EVENT_INACTIVE) {
42112Sigor@sysoev.ru op = EPOLL_CTL_ADD;
42212Sigor@sysoev.ru
42312Sigor@sysoev.ru } else if (ev->write >= NXT_EVENT_BLOCKED) {
42412Sigor@sysoev.ru events |= EPOLLOUT;
42512Sigor@sysoev.ru }
42612Sigor@sysoev.ru
42712Sigor@sysoev.ru nxt_epoll_change(engine, ev, op, events);
42812Sigor@sysoev.ru }
42912Sigor@sysoev.ru
43012Sigor@sysoev.ru ev->read = NXT_EVENT_ACTIVE;
43112Sigor@sysoev.ru }
43212Sigor@sysoev.ru
43312Sigor@sysoev.ru
43412Sigor@sysoev.ru static void
nxt_epoll_enable_write(nxt_event_engine_t * engine,nxt_fd_event_t * ev)43512Sigor@sysoev.ru nxt_epoll_enable_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev)
43612Sigor@sysoev.ru {
43712Sigor@sysoev.ru int op;
43812Sigor@sysoev.ru uint32_t events;
43912Sigor@sysoev.ru
44012Sigor@sysoev.ru if (ev->write != NXT_EVENT_BLOCKED) {
44112Sigor@sysoev.ru
44212Sigor@sysoev.ru op = EPOLL_CTL_MOD;
44312Sigor@sysoev.ru events = EPOLLOUT | engine->u.epoll.mode;
44412Sigor@sysoev.ru
44512Sigor@sysoev.ru if (ev->read == NXT_EVENT_INACTIVE && ev->write == NXT_EVENT_INACTIVE) {
44612Sigor@sysoev.ru op = EPOLL_CTL_ADD;
44712Sigor@sysoev.ru
44812Sigor@sysoev.ru } else if (ev->read >= NXT_EVENT_BLOCKED) {
44912Sigor@sysoev.ru events |= EPOLLIN;
45012Sigor@sysoev.ru }
45112Sigor@sysoev.ru
45212Sigor@sysoev.ru nxt_epoll_change(engine, ev, op, events);
45312Sigor@sysoev.ru }
45412Sigor@sysoev.ru
45512Sigor@sysoev.ru ev->write = NXT_EVENT_ACTIVE;
45612Sigor@sysoev.ru }
45712Sigor@sysoev.ru
45812Sigor@sysoev.ru
45912Sigor@sysoev.ru static void
nxt_epoll_disable_read(nxt_event_engine_t * engine,nxt_fd_event_t * ev)46012Sigor@sysoev.ru nxt_epoll_disable_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev)
46112Sigor@sysoev.ru {
46212Sigor@sysoev.ru int op;
46312Sigor@sysoev.ru uint32_t events;
46412Sigor@sysoev.ru
46512Sigor@sysoev.ru ev->read = NXT_EVENT_INACTIVE;
46612Sigor@sysoev.ru
46712Sigor@sysoev.ru if (ev->write <= NXT_EVENT_DISABLED) {
46812Sigor@sysoev.ru ev->write = NXT_EVENT_INACTIVE;
46912Sigor@sysoev.ru op = EPOLL_CTL_DEL;
47012Sigor@sysoev.ru events = 0;
47112Sigor@sysoev.ru
47212Sigor@sysoev.ru } else {
47312Sigor@sysoev.ru op = EPOLL_CTL_MOD;
47412Sigor@sysoev.ru events = EPOLLOUT | engine->u.epoll.mode;
47512Sigor@sysoev.ru }
47612Sigor@sysoev.ru
47712Sigor@sysoev.ru nxt_epoll_change(engine, ev, op, events);
47812Sigor@sysoev.ru }
47912Sigor@sysoev.ru
48012Sigor@sysoev.ru
48112Sigor@sysoev.ru static void
nxt_epoll_disable_write(nxt_event_engine_t * engine,nxt_fd_event_t * ev)48212Sigor@sysoev.ru nxt_epoll_disable_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev)
48312Sigor@sysoev.ru {
48412Sigor@sysoev.ru int op;
48512Sigor@sysoev.ru uint32_t events;
48612Sigor@sysoev.ru
48712Sigor@sysoev.ru ev->write = NXT_EVENT_INACTIVE;
48812Sigor@sysoev.ru
48912Sigor@sysoev.ru if (ev->read <= NXT_EVENT_DISABLED) {
490764Sigor@sysoev.ru ev->read = NXT_EVENT_INACTIVE;
49112Sigor@sysoev.ru op = EPOLL_CTL_DEL;
49212Sigor@sysoev.ru events = 0;
49312Sigor@sysoev.ru
49412Sigor@sysoev.ru } else {
49512Sigor@sysoev.ru op = EPOLL_CTL_MOD;
49612Sigor@sysoev.ru events = EPOLLIN | engine->u.epoll.mode;
49712Sigor@sysoev.ru }
49812Sigor@sysoev.ru
49912Sigor@sysoev.ru nxt_epoll_change(engine, ev, op, events);
50012Sigor@sysoev.ru }
50112Sigor@sysoev.ru
50212Sigor@sysoev.ru
50312Sigor@sysoev.ru static void
nxt_epoll_block_read(nxt_event_engine_t * engine,nxt_fd_event_t * ev)50412Sigor@sysoev.ru nxt_epoll_block_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev)
50512Sigor@sysoev.ru {
50612Sigor@sysoev.ru if (ev->read != NXT_EVENT_INACTIVE) {
50712Sigor@sysoev.ru ev->read = NXT_EVENT_BLOCKED;
50812Sigor@sysoev.ru }
50912Sigor@sysoev.ru }
51012Sigor@sysoev.ru
51112Sigor@sysoev.ru
51212Sigor@sysoev.ru static void
nxt_epoll_block_write(nxt_event_engine_t * engine,nxt_fd_event_t * ev)51312Sigor@sysoev.ru nxt_epoll_block_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev)
51412Sigor@sysoev.ru {
51512Sigor@sysoev.ru if (ev->write != NXT_EVENT_INACTIVE) {
51612Sigor@sysoev.ru ev->write = NXT_EVENT_BLOCKED;
51712Sigor@sysoev.ru }
51812Sigor@sysoev.ru }
51912Sigor@sysoev.ru
52012Sigor@sysoev.ru
52112Sigor@sysoev.ru /*
52212Sigor@sysoev.ru * NXT_EVENT_DISABLED state is used to track whether EPOLLONESHOT
52312Sigor@sysoev.ru * event should be added or modified, epoll_ctl(2):
52412Sigor@sysoev.ru *
52512Sigor@sysoev.ru * EPOLLONESHOT (since Linux 2.6.2)
52612Sigor@sysoev.ru * Sets the one-shot behavior for the associated file descriptor.
52712Sigor@sysoev.ru * This means that after an event is pulled out with epoll_wait(2)
52812Sigor@sysoev.ru * the associated file descriptor is internally disabled and no
52912Sigor@sysoev.ru * other events will be reported by the epoll interface. The user
53012Sigor@sysoev.ru * must call epoll_ctl() with EPOLL_CTL_MOD to rearm the file
53112Sigor@sysoev.ru * descriptor with a new event mask.
53212Sigor@sysoev.ru */
53312Sigor@sysoev.ru
53412Sigor@sysoev.ru static void
nxt_epoll_oneshot_read(nxt_event_engine_t * engine,nxt_fd_event_t * ev)53512Sigor@sysoev.ru nxt_epoll_oneshot_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev)
53612Sigor@sysoev.ru {
53712Sigor@sysoev.ru int op;
53812Sigor@sysoev.ru
53912Sigor@sysoev.ru op = (ev->read == NXT_EVENT_INACTIVE && ev->write == NXT_EVENT_INACTIVE) ?
54012Sigor@sysoev.ru EPOLL_CTL_ADD : EPOLL_CTL_MOD;
54112Sigor@sysoev.ru
54212Sigor@sysoev.ru ev->read = NXT_EVENT_ONESHOT;
54312Sigor@sysoev.ru ev->write = NXT_EVENT_INACTIVE;
54412Sigor@sysoev.ru
54512Sigor@sysoev.ru nxt_epoll_change(engine, ev, op, EPOLLIN | EPOLLONESHOT);
54612Sigor@sysoev.ru }
54712Sigor@sysoev.ru
54812Sigor@sysoev.ru
54912Sigor@sysoev.ru static void
nxt_epoll_oneshot_write(nxt_event_engine_t * engine,nxt_fd_event_t * ev)55012Sigor@sysoev.ru nxt_epoll_oneshot_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev)
55112Sigor@sysoev.ru {
55212Sigor@sysoev.ru int op;
55312Sigor@sysoev.ru
55412Sigor@sysoev.ru op = (ev->read == NXT_EVENT_INACTIVE && ev->write == NXT_EVENT_INACTIVE) ?
55512Sigor@sysoev.ru EPOLL_CTL_ADD : EPOLL_CTL_MOD;
55612Sigor@sysoev.ru
55712Sigor@sysoev.ru ev->read = NXT_EVENT_INACTIVE;
55812Sigor@sysoev.ru ev->write = NXT_EVENT_ONESHOT;
55912Sigor@sysoev.ru
56012Sigor@sysoev.ru nxt_epoll_change(engine, ev, op, EPOLLOUT | EPOLLONESHOT);
56112Sigor@sysoev.ru }
56212Sigor@sysoev.ru
56312Sigor@sysoev.ru
56412Sigor@sysoev.ru static void
nxt_epoll_enable_accept(nxt_event_engine_t * engine,nxt_fd_event_t * ev)56512Sigor@sysoev.ru nxt_epoll_enable_accept(nxt_event_engine_t *engine, nxt_fd_event_t *ev)
56612Sigor@sysoev.ru {
567353Sigor@sysoev.ru uint32_t events;
568353Sigor@sysoev.ru
56912Sigor@sysoev.ru ev->read = NXT_EVENT_ACTIVE;
57012Sigor@sysoev.ru
571353Sigor@sysoev.ru events = EPOLLIN;
572353Sigor@sysoev.ru
573353Sigor@sysoev.ru #ifdef EPOLLEXCLUSIVE
574353Sigor@sysoev.ru events |= EPOLLEXCLUSIVE;
575353Sigor@sysoev.ru #endif
576353Sigor@sysoev.ru
577353Sigor@sysoev.ru nxt_epoll_change(engine, ev, EPOLL_CTL_ADD, events);
57812Sigor@sysoev.ru }
57912Sigor@sysoev.ru
58012Sigor@sysoev.ru
58112Sigor@sysoev.ru /*
58212Sigor@sysoev.ru * epoll changes are batched to improve instruction and data cache
58312Sigor@sysoev.ru * locality of several epoll_ctl() calls followed by epoll_wait() call.
58412Sigor@sysoev.ru */
58512Sigor@sysoev.ru
58612Sigor@sysoev.ru static void
nxt_epoll_change(nxt_event_engine_t * engine,nxt_fd_event_t * ev,int op,uint32_t events)58712Sigor@sysoev.ru nxt_epoll_change(nxt_event_engine_t *engine, nxt_fd_event_t *ev, int op,
58812Sigor@sysoev.ru uint32_t events)
58912Sigor@sysoev.ru {
59012Sigor@sysoev.ru nxt_epoll_change_t *change;
59112Sigor@sysoev.ru
59212Sigor@sysoev.ru nxt_debug(ev->task, "epoll %d set event: fd:%d op:%d ev:%XD",
59312Sigor@sysoev.ru engine->u.epoll.fd, ev->fd, op, events);
59412Sigor@sysoev.ru
59512Sigor@sysoev.ru if (engine->u.epoll.nchanges >= engine->u.epoll.mchanges) {
596813Sigor@sysoev.ru nxt_epoll_commit_changes(engine);
59712Sigor@sysoev.ru }
59812Sigor@sysoev.ru
59912Sigor@sysoev.ru ev->changing = 1;
60012Sigor@sysoev.ru
60112Sigor@sysoev.ru change = &engine->u.epoll.changes[engine->u.epoll.nchanges++];
60212Sigor@sysoev.ru change->op = op;
60312Sigor@sysoev.ru change->event.events = events;
60412Sigor@sysoev.ru change->event.data.ptr = ev;
60512Sigor@sysoev.ru }
60612Sigor@sysoev.ru
60712Sigor@sysoev.ru
608813Sigor@sysoev.ru static void
nxt_epoll_commit_changes(nxt_event_engine_t * engine)60912Sigor@sysoev.ru nxt_epoll_commit_changes(nxt_event_engine_t *engine)
61012Sigor@sysoev.ru {
61112Sigor@sysoev.ru int ret;
61212Sigor@sysoev.ru nxt_fd_event_t *ev;
61312Sigor@sysoev.ru nxt_epoll_change_t *change, *end;
61412Sigor@sysoev.ru
61512Sigor@sysoev.ru nxt_debug(&engine->task, "epoll %d changes:%ui",
61612Sigor@sysoev.ru engine->u.epoll.fd, engine->u.epoll.nchanges);
61712Sigor@sysoev.ru
61812Sigor@sysoev.ru change = engine->u.epoll.changes;
61912Sigor@sysoev.ru end = change + engine->u.epoll.nchanges;
62012Sigor@sysoev.ru
62112Sigor@sysoev.ru do {
62212Sigor@sysoev.ru ev = change->event.data.ptr;
62312Sigor@sysoev.ru ev->changing = 0;
62412Sigor@sysoev.ru
62512Sigor@sysoev.ru nxt_debug(ev->task, "epoll_ctl(%d): fd:%d op:%d ev:%XD",
62612Sigor@sysoev.ru engine->u.epoll.fd, ev->fd, change->op,
62712Sigor@sysoev.ru change->event.events);
62812Sigor@sysoev.ru
62912Sigor@sysoev.ru ret = epoll_ctl(engine->u.epoll.fd, change->op, ev->fd, &change->event);
63012Sigor@sysoev.ru
63112Sigor@sysoev.ru if (nxt_slow_path(ret != 0)) {
632564Svbart@nginx.com nxt_alert(ev->task, "epoll_ctl(%d, %d, %d) failed %E",
633564Svbart@nginx.com engine->u.epoll.fd, change->op, ev->fd, nxt_errno);
63412Sigor@sysoev.ru
63512Sigor@sysoev.ru nxt_work_queue_add(&engine->fast_work_queue,
63612Sigor@sysoev.ru nxt_epoll_error_handler, ev->task, ev, ev->data);
63712Sigor@sysoev.ru
638813Sigor@sysoev.ru engine->u.epoll.error = 1;
63912Sigor@sysoev.ru }
64012Sigor@sysoev.ru
64112Sigor@sysoev.ru change++;
64212Sigor@sysoev.ru
64312Sigor@sysoev.ru } while (change < end);
64412Sigor@sysoev.ru
64512Sigor@sysoev.ru engine->u.epoll.nchanges = 0;
64612Sigor@sysoev.ru }
64712Sigor@sysoev.ru
64812Sigor@sysoev.ru
64912Sigor@sysoev.ru static void
nxt_epoll_error_handler(nxt_task_t * task,void * obj,void * data)65012Sigor@sysoev.ru nxt_epoll_error_handler(nxt_task_t *task, void *obj, void *data)
65112Sigor@sysoev.ru {
65212Sigor@sysoev.ru nxt_fd_event_t *ev;
65312Sigor@sysoev.ru
65412Sigor@sysoev.ru ev = obj;
65512Sigor@sysoev.ru
65612Sigor@sysoev.ru ev->read = NXT_EVENT_INACTIVE;
65712Sigor@sysoev.ru ev->write = NXT_EVENT_INACTIVE;
65812Sigor@sysoev.ru
65912Sigor@sysoev.ru ev->error_handler(ev->task, ev, data);
66012Sigor@sysoev.ru }
66112Sigor@sysoev.ru
66212Sigor@sysoev.ru
66312Sigor@sysoev.ru #if (NXT_HAVE_SIGNALFD)
66412Sigor@sysoev.ru
66512Sigor@sysoev.ru static nxt_int_t
nxt_epoll_add_signal(nxt_event_engine_t * engine)66612Sigor@sysoev.ru nxt_epoll_add_signal(nxt_event_engine_t *engine)
66712Sigor@sysoev.ru {
66812Sigor@sysoev.ru int fd;
66912Sigor@sysoev.ru struct epoll_event ee;
67012Sigor@sysoev.ru
67112Sigor@sysoev.ru if (sigprocmask(SIG_BLOCK, &engine->signals->sigmask, NULL) != 0) {
672564Svbart@nginx.com nxt_alert(&engine->task, "sigprocmask(SIG_BLOCK) failed %E", nxt_errno);
67312Sigor@sysoev.ru return NXT_ERROR;
67412Sigor@sysoev.ru }
67512Sigor@sysoev.ru
67612Sigor@sysoev.ru /*
67712Sigor@sysoev.ru * Glibc signalfd() wrapper always has the flags argument. Glibc 2.7
67812Sigor@sysoev.ru * and 2.8 signalfd() wrappers call the original signalfd() syscall
67912Sigor@sysoev.ru * without the flags argument. Glibc 2.9+ signalfd() wrapper at first
68012Sigor@sysoev.ru * tries to call signalfd4() syscall and if it fails then calls the
68112Sigor@sysoev.ru * original signalfd() syscall. For this reason the non-blocking mode
68212Sigor@sysoev.ru * is set separately.
68312Sigor@sysoev.ru */
68412Sigor@sysoev.ru
68512Sigor@sysoev.ru fd = signalfd(-1, &engine->signals->sigmask, 0);
68612Sigor@sysoev.ru
68712Sigor@sysoev.ru if (fd == -1) {
688564Svbart@nginx.com nxt_alert(&engine->task, "signalfd(%d) failed %E",
689564Svbart@nginx.com engine->u.epoll.signalfd.fd, nxt_errno);
69012Sigor@sysoev.ru return NXT_ERROR;
69112Sigor@sysoev.ru }
69212Sigor@sysoev.ru
69312Sigor@sysoev.ru engine->u.epoll.signalfd.fd = fd;
69412Sigor@sysoev.ru
69513Sigor@sysoev.ru if (nxt_fd_nonblocking(&engine->task, fd) != NXT_OK) {
69612Sigor@sysoev.ru return NXT_ERROR;
69712Sigor@sysoev.ru }
69812Sigor@sysoev.ru
69912Sigor@sysoev.ru nxt_debug(&engine->task, "signalfd(): %d", fd);
70012Sigor@sysoev.ru
70112Sigor@sysoev.ru engine->u.epoll.signalfd.data = engine->signals->handler;
70212Sigor@sysoev.ru engine->u.epoll.signalfd.read_work_queue = &engine->fast_work_queue;
70312Sigor@sysoev.ru engine->u.epoll.signalfd.read_handler = nxt_epoll_signalfd_handler;
70412Sigor@sysoev.ru engine->u.epoll.signalfd.log = engine->task.log;
70512Sigor@sysoev.ru engine->u.epoll.signalfd.task = &engine->task;
70612Sigor@sysoev.ru
70712Sigor@sysoev.ru ee.events = EPOLLIN;
70812Sigor@sysoev.ru ee.data.ptr = &engine->u.epoll.signalfd;
70912Sigor@sysoev.ru
71012Sigor@sysoev.ru if (epoll_ctl(engine->u.epoll.fd, EPOLL_CTL_ADD, fd, &ee) != 0) {
711564Svbart@nginx.com nxt_alert(&engine->task, "epoll_ctl(%d, %d, %d) failed %E",
712564Svbart@nginx.com engine->u.epoll.fd, EPOLL_CTL_ADD, fd, nxt_errno);
71312Sigor@sysoev.ru
71412Sigor@sysoev.ru return NXT_ERROR;
71512Sigor@sysoev.ru }
71612Sigor@sysoev.ru
71712Sigor@sysoev.ru return NXT_OK;
71812Sigor@sysoev.ru }
71912Sigor@sysoev.ru
72012Sigor@sysoev.ru
72112Sigor@sysoev.ru static void
nxt_epoll_signalfd_handler(nxt_task_t * task,void * obj,void * data)72212Sigor@sysoev.ru nxt_epoll_signalfd_handler(nxt_task_t *task, void *obj, void *data)
72312Sigor@sysoev.ru {
72412Sigor@sysoev.ru int n;
72512Sigor@sysoev.ru nxt_fd_event_t *ev;
72612Sigor@sysoev.ru nxt_work_handler_t handler;
72712Sigor@sysoev.ru struct signalfd_siginfo sfd;
72812Sigor@sysoev.ru
72912Sigor@sysoev.ru ev = obj;
73012Sigor@sysoev.ru handler = data;
73112Sigor@sysoev.ru
73212Sigor@sysoev.ru nxt_debug(task, "signalfd handler");
73312Sigor@sysoev.ru
73412Sigor@sysoev.ru n = read(ev->fd, &sfd, sizeof(struct signalfd_siginfo));
73512Sigor@sysoev.ru
73612Sigor@sysoev.ru nxt_debug(task, "read signalfd(%d): %d", ev->fd, n);
73712Sigor@sysoev.ru
73812Sigor@sysoev.ru if (n != sizeof(struct signalfd_siginfo)) {
739564Svbart@nginx.com nxt_alert(task, "read signalfd(%d) failed %E", ev->fd, nxt_errno);
740545Sigor@sysoev.ru return;
74112Sigor@sysoev.ru }
74212Sigor@sysoev.ru
74312Sigor@sysoev.ru nxt_debug(task, "signalfd(%d) signo:%d", ev->fd, sfd.ssi_signo);
74412Sigor@sysoev.ru
74512Sigor@sysoev.ru handler(task, (void *) (uintptr_t) sfd.ssi_signo, NULL);
74612Sigor@sysoev.ru }
74712Sigor@sysoev.ru
74812Sigor@sysoev.ru #endif
74912Sigor@sysoev.ru
75012Sigor@sysoev.ru
75112Sigor@sysoev.ru #if (NXT_HAVE_EVENTFD)
75212Sigor@sysoev.ru
75312Sigor@sysoev.ru static nxt_int_t
nxt_epoll_enable_post(nxt_event_engine_t * engine,nxt_work_handler_t handler)75412Sigor@sysoev.ru nxt_epoll_enable_post(nxt_event_engine_t *engine, nxt_work_handler_t handler)
75512Sigor@sysoev.ru {
75612Sigor@sysoev.ru int ret;
75712Sigor@sysoev.ru struct epoll_event ee;
75812Sigor@sysoev.ru
75912Sigor@sysoev.ru engine->u.epoll.post_handler = handler;
76012Sigor@sysoev.ru
76112Sigor@sysoev.ru /*
76212Sigor@sysoev.ru * Glibc eventfd() wrapper always has the flags argument. Glibc 2.7
76312Sigor@sysoev.ru * and 2.8 eventfd() wrappers call the original eventfd() syscall
76412Sigor@sysoev.ru * without the flags argument. Glibc 2.9+ eventfd() wrapper at first
76512Sigor@sysoev.ru * tries to call eventfd2() syscall and if it fails then calls the
76612Sigor@sysoev.ru * original eventfd() syscall. For this reason the non-blocking mode
76712Sigor@sysoev.ru * is set separately.
76812Sigor@sysoev.ru */
76912Sigor@sysoev.ru
77012Sigor@sysoev.ru engine->u.epoll.eventfd.fd = eventfd(0, 0);
77112Sigor@sysoev.ru
77212Sigor@sysoev.ru if (engine->u.epoll.eventfd.fd == -1) {
773564Svbart@nginx.com nxt_alert(&engine->task, "eventfd() failed %E", nxt_errno);
77412Sigor@sysoev.ru return NXT_ERROR;
77512Sigor@sysoev.ru }
77612Sigor@sysoev.ru
77713Sigor@sysoev.ru ret = nxt_fd_nonblocking(&engine->task, engine->u.epoll.eventfd.fd);
77813Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) {
77912Sigor@sysoev.ru return NXT_ERROR;
78012Sigor@sysoev.ru }
78112Sigor@sysoev.ru
78212Sigor@sysoev.ru nxt_debug(&engine->task, "eventfd(): %d", engine->u.epoll.eventfd.fd);
78312Sigor@sysoev.ru
78412Sigor@sysoev.ru engine->u.epoll.eventfd.read_work_queue = &engine->fast_work_queue;
78512Sigor@sysoev.ru engine->u.epoll.eventfd.read_handler = nxt_epoll_eventfd_handler;
78612Sigor@sysoev.ru engine->u.epoll.eventfd.data = engine;
78712Sigor@sysoev.ru engine->u.epoll.eventfd.log = engine->task.log;
78812Sigor@sysoev.ru engine->u.epoll.eventfd.task = &engine->task;
78912Sigor@sysoev.ru
79012Sigor@sysoev.ru ee.events = EPOLLIN | EPOLLET;
79112Sigor@sysoev.ru ee.data.ptr = &engine->u.epoll.eventfd;
79212Sigor@sysoev.ru
79312Sigor@sysoev.ru ret = epoll_ctl(engine->u.epoll.fd, EPOLL_CTL_ADD,
79412Sigor@sysoev.ru engine->u.epoll.eventfd.fd, &ee);
79512Sigor@sysoev.ru
79612Sigor@sysoev.ru if (nxt_fast_path(ret == 0)) {
79712Sigor@sysoev.ru return NXT_OK;
79812Sigor@sysoev.ru }
79912Sigor@sysoev.ru
800564Svbart@nginx.com nxt_alert(&engine->task, "epoll_ctl(%d, %d, %d) failed %E",
801564Svbart@nginx.com engine->u.epoll.fd, EPOLL_CTL_ADD, engine->u.epoll.eventfd.fd,
802564Svbart@nginx.com nxt_errno);
80312Sigor@sysoev.ru
80412Sigor@sysoev.ru return NXT_ERROR;
80512Sigor@sysoev.ru }
80612Sigor@sysoev.ru
80712Sigor@sysoev.ru
80812Sigor@sysoev.ru static void
nxt_epoll_eventfd_handler(nxt_task_t * task,void * obj,void * data)80912Sigor@sysoev.ru nxt_epoll_eventfd_handler(nxt_task_t *task, void *obj, void *data)
81012Sigor@sysoev.ru {
81112Sigor@sysoev.ru int n;
81212Sigor@sysoev.ru uint64_t events;
81312Sigor@sysoev.ru nxt_event_engine_t *engine;
81412Sigor@sysoev.ru
81512Sigor@sysoev.ru engine = data;
81612Sigor@sysoev.ru
81712Sigor@sysoev.ru nxt_debug(task, "eventfd handler, times:%ui", engine->u.epoll.neventfd);
81812Sigor@sysoev.ru
81912Sigor@sysoev.ru /*
82012Sigor@sysoev.ru * The maximum value after write() to a eventfd() descriptor will
821611Svbart@nginx.com * block or return EAGAIN is 0xFFFFFFFFFFFFFFFE, so the descriptor
82212Sigor@sysoev.ru * can be read once per many notifications, for example, once per
82312Sigor@sysoev.ru * 2^32-2 noticifcations. Since the eventfd() file descriptor is
82412Sigor@sysoev.ru * always registered in EPOLLET mode, epoll returns event about
82512Sigor@sysoev.ru * only the latest write() to the descriptor.
82612Sigor@sysoev.ru */
82712Sigor@sysoev.ru
828611Svbart@nginx.com if (engine->u.epoll.neventfd++ >= 0xFFFFFFFE) {
82912Sigor@sysoev.ru engine->u.epoll.neventfd = 0;
83012Sigor@sysoev.ru
83112Sigor@sysoev.ru n = read(engine->u.epoll.eventfd.fd, &events, sizeof(uint64_t));
83212Sigor@sysoev.ru
83312Sigor@sysoev.ru nxt_debug(task, "read(%d): %d events:%uL",
83412Sigor@sysoev.ru engine->u.epoll.eventfd.fd, n, events);
83512Sigor@sysoev.ru
83612Sigor@sysoev.ru if (n != sizeof(uint64_t)) {
837564Svbart@nginx.com nxt_alert(task, "read eventfd(%d) failed %E",
838564Svbart@nginx.com engine->u.epoll.eventfd.fd, nxt_errno);
83912Sigor@sysoev.ru }
84012Sigor@sysoev.ru }
84112Sigor@sysoev.ru
84212Sigor@sysoev.ru engine->u.epoll.post_handler(task, NULL, NULL);
84312Sigor@sysoev.ru }
84412Sigor@sysoev.ru
84512Sigor@sysoev.ru
84612Sigor@sysoev.ru static void
nxt_epoll_signal(nxt_event_engine_t * engine,nxt_uint_t signo)84712Sigor@sysoev.ru nxt_epoll_signal(nxt_event_engine_t *engine, nxt_uint_t signo)
84812Sigor@sysoev.ru {
84912Sigor@sysoev.ru size_t ret;
85012Sigor@sysoev.ru uint64_t event;
85112Sigor@sysoev.ru
85212Sigor@sysoev.ru /*
85312Sigor@sysoev.ru * eventfd() presents along with signalfd(), so the function
85412Sigor@sysoev.ru * is used only to post events and the signo argument is ignored.
85512Sigor@sysoev.ru */
85612Sigor@sysoev.ru
85712Sigor@sysoev.ru event = 1;
85812Sigor@sysoev.ru
85912Sigor@sysoev.ru ret = write(engine->u.epoll.eventfd.fd, &event, sizeof(uint64_t));
86012Sigor@sysoev.ru
86112Sigor@sysoev.ru if (nxt_slow_path(ret != sizeof(uint64_t))) {
862564Svbart@nginx.com nxt_alert(&engine->task, "write(%d) to eventfd failed %E",
863564Svbart@nginx.com engine->u.epoll.eventfd.fd, nxt_errno);
86412Sigor@sysoev.ru }
86512Sigor@sysoev.ru }
86612Sigor@sysoev.ru
86712Sigor@sysoev.ru #endif
86812Sigor@sysoev.ru
86912Sigor@sysoev.ru
87012Sigor@sysoev.ru static void
nxt_epoll_poll(nxt_event_engine_t * engine,nxt_msec_t timeout)87112Sigor@sysoev.ru nxt_epoll_poll(nxt_event_engine_t *engine, nxt_msec_t timeout)
87212Sigor@sysoev.ru {
87312Sigor@sysoev.ru int nevents;
87412Sigor@sysoev.ru uint32_t events;
87512Sigor@sysoev.ru nxt_int_t i;
87612Sigor@sysoev.ru nxt_err_t err;
87712Sigor@sysoev.ru nxt_bool_t error;
87812Sigor@sysoev.ru nxt_uint_t level;
87912Sigor@sysoev.ru nxt_fd_event_t *ev;
88012Sigor@sysoev.ru struct epoll_event *event;
88112Sigor@sysoev.ru
88212Sigor@sysoev.ru if (engine->u.epoll.nchanges != 0) {
883813Sigor@sysoev.ru nxt_epoll_commit_changes(engine);
884813Sigor@sysoev.ru }
885813Sigor@sysoev.ru
886813Sigor@sysoev.ru if (engine->u.epoll.error) {
887813Sigor@sysoev.ru engine->u.epoll.error = 0;
888813Sigor@sysoev.ru /* Error handlers have been enqueued on failure. */
889813Sigor@sysoev.ru timeout = 0;
89012Sigor@sysoev.ru }
89112Sigor@sysoev.ru
89212Sigor@sysoev.ru nxt_debug(&engine->task, "epoll_wait(%d) timeout:%M",
89312Sigor@sysoev.ru engine->u.epoll.fd, timeout);
89412Sigor@sysoev.ru
89512Sigor@sysoev.ru nevents = epoll_wait(engine->u.epoll.fd, engine->u.epoll.events,
89612Sigor@sysoev.ru engine->u.epoll.mevents, timeout);
89712Sigor@sysoev.ru
89812Sigor@sysoev.ru err = (nevents == -1) ? nxt_errno : 0;
89912Sigor@sysoev.ru
90012Sigor@sysoev.ru nxt_thread_time_update(engine->task.thread);
90112Sigor@sysoev.ru
90212Sigor@sysoev.ru nxt_debug(&engine->task, "epoll_wait(%d): %d", engine->u.epoll.fd, nevents);
90312Sigor@sysoev.ru
90412Sigor@sysoev.ru if (nevents == -1) {
905564Svbart@nginx.com level = (err == NXT_EINTR) ? NXT_LOG_INFO : NXT_LOG_ALERT;
90612Sigor@sysoev.ru
90712Sigor@sysoev.ru nxt_log(&engine->task, level, "epoll_wait(%d) failed %E",
90812Sigor@sysoev.ru engine->u.epoll.fd, err);
90912Sigor@sysoev.ru
91012Sigor@sysoev.ru return;
91112Sigor@sysoev.ru }
91212Sigor@sysoev.ru
91312Sigor@sysoev.ru for (i = 0; i < nevents; i++) {
91412Sigor@sysoev.ru
91512Sigor@sysoev.ru event = &engine->u.epoll.events[i];
91612Sigor@sysoev.ru events = event->events;
91712Sigor@sysoev.ru ev = event->data.ptr;
91812Sigor@sysoev.ru
91912Sigor@sysoev.ru nxt_debug(ev->task, "epoll: fd:%d ev:%04XD d:%p rd:%d wr:%d",
92012Sigor@sysoev.ru ev->fd, events, ev, ev->read, ev->write);
92112Sigor@sysoev.ru
92212Sigor@sysoev.ru /*
923817Sigor@sysoev.ru * On error epoll may set EPOLLERR and EPOLLHUP only without EPOLLIN
924817Sigor@sysoev.ru * or EPOLLOUT, so the "error" variable enqueues only error handler.
92512Sigor@sysoev.ru */
92612Sigor@sysoev.ru error = ((events & (EPOLLERR | EPOLLHUP)) != 0);
92712Sigor@sysoev.ru ev->epoll_error = error;
92812Sigor@sysoev.ru
929*1456Sigor@sysoev.ru if (error
930*1456Sigor@sysoev.ru && ev->read <= NXT_EVENT_BLOCKED
931*1456Sigor@sysoev.ru && ev->write <= NXT_EVENT_BLOCKED)
932*1456Sigor@sysoev.ru {
933*1456Sigor@sysoev.ru error = 0;
934*1456Sigor@sysoev.ru }
935*1456Sigor@sysoev.ru
93612Sigor@sysoev.ru #if (NXT_HAVE_EPOLL_EDGE)
93712Sigor@sysoev.ru
93812Sigor@sysoev.ru ev->epoll_eof = ((events & EPOLLRDHUP) != 0);
93912Sigor@sysoev.ru
94012Sigor@sysoev.ru #endif
94112Sigor@sysoev.ru
942817Sigor@sysoev.ru if ((events & EPOLLIN) != 0) {
94312Sigor@sysoev.ru ev->read_ready = 1;
94412Sigor@sysoev.ru
94512Sigor@sysoev.ru if (ev->read != NXT_EVENT_BLOCKED) {
94612Sigor@sysoev.ru
94712Sigor@sysoev.ru if (ev->read == NXT_EVENT_ONESHOT) {
94812Sigor@sysoev.ru ev->read = NXT_EVENT_DISABLED;
94912Sigor@sysoev.ru }
95012Sigor@sysoev.ru
95112Sigor@sysoev.ru nxt_work_queue_add(ev->read_work_queue, ev->read_handler,
95212Sigor@sysoev.ru ev->task, ev, ev->data);
95312Sigor@sysoev.ru
9541263Sigor@sysoev.ru error = 0;
9551263Sigor@sysoev.ru
95612Sigor@sysoev.ru } else if (engine->u.epoll.mode == 0) {
95712Sigor@sysoev.ru /* Level-triggered mode. */
95812Sigor@sysoev.ru nxt_epoll_disable_read(engine, ev);
95912Sigor@sysoev.ru }
96012Sigor@sysoev.ru }
96112Sigor@sysoev.ru
962817Sigor@sysoev.ru if ((events & EPOLLOUT) != 0) {
96312Sigor@sysoev.ru ev->write_ready = 1;
96412Sigor@sysoev.ru
96512Sigor@sysoev.ru if (ev->write != NXT_EVENT_BLOCKED) {
96612Sigor@sysoev.ru
96712Sigor@sysoev.ru if (ev->write == NXT_EVENT_ONESHOT) {
96812Sigor@sysoev.ru ev->write = NXT_EVENT_DISABLED;
96912Sigor@sysoev.ru }
97012Sigor@sysoev.ru
97112Sigor@sysoev.ru nxt_work_queue_add(ev->write_work_queue, ev->write_handler,
97212Sigor@sysoev.ru ev->task, ev, ev->data);
97312Sigor@sysoev.ru
9741263Sigor@sysoev.ru error = 0;
9751263Sigor@sysoev.ru
97612Sigor@sysoev.ru } else if (engine->u.epoll.mode == 0) {
97712Sigor@sysoev.ru /* Level-triggered mode. */
97812Sigor@sysoev.ru nxt_epoll_disable_write(engine, ev);
97912Sigor@sysoev.ru }
98012Sigor@sysoev.ru }
981817Sigor@sysoev.ru
982817Sigor@sysoev.ru if (!error) {
983817Sigor@sysoev.ru continue;
984817Sigor@sysoev.ru }
985817Sigor@sysoev.ru
986817Sigor@sysoev.ru ev->read_ready = 1;
987817Sigor@sysoev.ru ev->write_ready = 1;
988817Sigor@sysoev.ru
989817Sigor@sysoev.ru if (ev->read == NXT_EVENT_BLOCKED && ev->write == NXT_EVENT_BLOCKED) {
990817Sigor@sysoev.ru
991817Sigor@sysoev.ru if (engine->u.epoll.mode == 0) {
992817Sigor@sysoev.ru /* Level-triggered mode. */
993817Sigor@sysoev.ru nxt_epoll_disable(engine, ev);
994817Sigor@sysoev.ru }
995817Sigor@sysoev.ru
996817Sigor@sysoev.ru continue;
997817Sigor@sysoev.ru }
998817Sigor@sysoev.ru
999817Sigor@sysoev.ru nxt_work_queue_add(&engine->fast_work_queue, nxt_epoll_error_handler,
1000817Sigor@sysoev.ru ev->task, ev, ev->data);
100112Sigor@sysoev.ru }
100212Sigor@sysoev.ru }
100312Sigor@sysoev.ru
100412Sigor@sysoev.ru
100512Sigor@sysoev.ru #if (NXT_HAVE_ACCEPT4)
100612Sigor@sysoev.ru
100712Sigor@sysoev.ru static void
nxt_epoll_conn_io_accept4(nxt_task_t * task,void * obj,void * data)100862Sigor@sysoev.ru nxt_epoll_conn_io_accept4(nxt_task_t *task, void *obj, void *data)
100912Sigor@sysoev.ru {
1010312Sigor@sysoev.ru socklen_t socklen;
101162Sigor@sysoev.ru nxt_conn_t *c;
101262Sigor@sysoev.ru nxt_socket_t s;
101362Sigor@sysoev.ru struct sockaddr *sa;
101462Sigor@sysoev.ru nxt_listen_event_t *lev;
101512Sigor@sysoev.ru
101662Sigor@sysoev.ru lev = obj;
101762Sigor@sysoev.ru c = lev->next;
101812Sigor@sysoev.ru
101962Sigor@sysoev.ru lev->ready--;
102062Sigor@sysoev.ru lev->socket.read_ready = (lev->ready != 0);
102112Sigor@sysoev.ru
1022312Sigor@sysoev.ru sa = &c->remote->u.sockaddr;
1023312Sigor@sysoev.ru socklen = c->remote->socklen;
1024312Sigor@sysoev.ru /*
1025312Sigor@sysoev.ru * The returned socklen is ignored here,
1026312Sigor@sysoev.ru * see comment in nxt_conn_io_accept().
1027312Sigor@sysoev.ru */
1028312Sigor@sysoev.ru s = accept4(lev->socket.fd, sa, &socklen, SOCK_NONBLOCK);
102912Sigor@sysoev.ru
103012Sigor@sysoev.ru if (s != -1) {
103112Sigor@sysoev.ru c->socket.fd = s;
103212Sigor@sysoev.ru
103362Sigor@sysoev.ru nxt_debug(task, "accept4(%d): %d", lev->socket.fd, s);
103412Sigor@sysoev.ru
103562Sigor@sysoev.ru nxt_conn_accept(task, lev, c);
103612Sigor@sysoev.ru return;
103712Sigor@sysoev.ru }
103812Sigor@sysoev.ru
103962Sigor@sysoev.ru nxt_conn_accept_error(task, lev, "accept4", nxt_errno);
104012Sigor@sysoev.ru }
104112Sigor@sysoev.ru
104212Sigor@sysoev.ru #endif
104312Sigor@sysoev.ru
104412Sigor@sysoev.ru
104512Sigor@sysoev.ru #if (NXT_HAVE_EPOLL_EDGE)
104612Sigor@sysoev.ru
104712Sigor@sysoev.ru /*
104812Sigor@sysoev.ru * nxt_epoll_edge_event_conn_io_connect() eliminates the getsockopt()
104912Sigor@sysoev.ru * syscall to test pending connect() error. Although this special
105012Sigor@sysoev.ru * interface can work in both edge-triggered and level-triggered
105112Sigor@sysoev.ru * modes it is enabled only for the former mode because this mode is
105212Sigor@sysoev.ru * available in all modern Linux distributions. For the latter mode
105312Sigor@sysoev.ru * it is required to create additional nxt_epoll_level_event_conn_io
105412Sigor@sysoev.ru * with single non-generic connect() interface.
105512Sigor@sysoev.ru */
105612Sigor@sysoev.ru
105712Sigor@sysoev.ru static void
nxt_epoll_edge_conn_io_connect(nxt_task_t * task,void * obj,void * data)105862Sigor@sysoev.ru nxt_epoll_edge_conn_io_connect(nxt_task_t *task, void *obj, void *data)
105912Sigor@sysoev.ru {
106062Sigor@sysoev.ru nxt_conn_t *c;
106112Sigor@sysoev.ru nxt_event_engine_t *engine;
106212Sigor@sysoev.ru nxt_work_handler_t handler;
106312Sigor@sysoev.ru const nxt_event_conn_state_t *state;
106412Sigor@sysoev.ru
106512Sigor@sysoev.ru c = obj;
106612Sigor@sysoev.ru
106712Sigor@sysoev.ru state = c->write_state;
106812Sigor@sysoev.ru
10691008Szelenkov@nginx.com switch (nxt_socket_connect(task, c->socket.fd, c->remote)) {
107012Sigor@sysoev.ru
107112Sigor@sysoev.ru case NXT_OK:
107212Sigor@sysoev.ru c->socket.write_ready = 1;
107312Sigor@sysoev.ru handler = state->ready_handler;
107412Sigor@sysoev.ru break;
107512Sigor@sysoev.ru
107612Sigor@sysoev.ru case NXT_AGAIN:
107762Sigor@sysoev.ru c->socket.write_handler = nxt_epoll_edge_conn_connected;
107862Sigor@sysoev.ru c->socket.error_handler = nxt_conn_connect_error;
107912Sigor@sysoev.ru
108012Sigor@sysoev.ru engine = task->thread->engine;
108162Sigor@sysoev.ru nxt_conn_timer(engine, c, state, &c->write_timer);
108212Sigor@sysoev.ru
108312Sigor@sysoev.ru nxt_epoll_enable(engine, &c->socket);
108412Sigor@sysoev.ru c->socket.read = NXT_EVENT_BLOCKED;
108512Sigor@sysoev.ru return;
108612Sigor@sysoev.ru
108712Sigor@sysoev.ru #if 0
108812Sigor@sysoev.ru case NXT_AGAIN:
108962Sigor@sysoev.ru nxt_conn_timer(engine, c, state, &c->write_timer);
109012Sigor@sysoev.ru
109112Sigor@sysoev.ru /* Fall through. */
109212Sigor@sysoev.ru
109312Sigor@sysoev.ru case NXT_OK:
109412Sigor@sysoev.ru /*
109512Sigor@sysoev.ru * Mark both read and write directions as ready and try to perform
109612Sigor@sysoev.ru * I/O operations before receiving readiness notifications.
109712Sigor@sysoev.ru * On unconnected socket Linux send() and recv() return EAGAIN
109812Sigor@sysoev.ru * instead of ENOTCONN.
109912Sigor@sysoev.ru */
110012Sigor@sysoev.ru c->socket.read_ready = 1;
110112Sigor@sysoev.ru c->socket.write_ready = 1;
110212Sigor@sysoev.ru /*
110312Sigor@sysoev.ru * Enabling both read and write notifications on a getting
110412Sigor@sysoev.ru * connected socket eliminates one epoll_ctl() syscall.
110512Sigor@sysoev.ru */
110612Sigor@sysoev.ru c->socket.write_handler = nxt_epoll_edge_event_conn_connected;
110712Sigor@sysoev.ru c->socket.error_handler = state->error_handler;
110812Sigor@sysoev.ru
110912Sigor@sysoev.ru nxt_epoll_enable(engine, &c->socket);
111012Sigor@sysoev.ru c->socket.read = NXT_EVENT_BLOCKED;
111112Sigor@sysoev.ru
111212Sigor@sysoev.ru handler = state->ready_handler;
111312Sigor@sysoev.ru break;
111412Sigor@sysoev.ru #endif
111512Sigor@sysoev.ru
111612Sigor@sysoev.ru case NXT_ERROR:
111712Sigor@sysoev.ru handler = state->error_handler;
111812Sigor@sysoev.ru break;
111912Sigor@sysoev.ru
112012Sigor@sysoev.ru default: /* NXT_DECLINED: connection refused. */
112112Sigor@sysoev.ru handler = state->close_handler;
112212Sigor@sysoev.ru break;
112312Sigor@sysoev.ru }
112412Sigor@sysoev.ru
112513Sigor@sysoev.ru nxt_work_queue_add(c->write_work_queue, handler, task, c, data);
112612Sigor@sysoev.ru }
112712Sigor@sysoev.ru
112812Sigor@sysoev.ru
112912Sigor@sysoev.ru static void
nxt_epoll_edge_conn_connected(nxt_task_t * task,void * obj,void * data)113062Sigor@sysoev.ru nxt_epoll_edge_conn_connected(nxt_task_t *task, void *obj, void *data)
113112Sigor@sysoev.ru {
113262Sigor@sysoev.ru nxt_conn_t *c;
113312Sigor@sysoev.ru
113412Sigor@sysoev.ru c = obj;
113512Sigor@sysoev.ru
113612Sigor@sysoev.ru nxt_debug(task, "epoll event conn connected fd:%d", c->socket.fd);
113712Sigor@sysoev.ru
113812Sigor@sysoev.ru if (!c->socket.epoll_error) {
113912Sigor@sysoev.ru c->socket.write = NXT_EVENT_BLOCKED;
114012Sigor@sysoev.ru
114157Svbart@nginx.com if (c->write_state->timer_autoreset) {
114212Sigor@sysoev.ru nxt_timer_disable(task->thread->engine, &c->write_timer);
114312Sigor@sysoev.ru }
114412Sigor@sysoev.ru
114513Sigor@sysoev.ru nxt_work_queue_add(c->write_work_queue, c->write_state->ready_handler,
114613Sigor@sysoev.ru task, c, data);
114712Sigor@sysoev.ru return;
114812Sigor@sysoev.ru }
114912Sigor@sysoev.ru
115062Sigor@sysoev.ru nxt_conn_connect_test(task, c, data);
115112Sigor@sysoev.ru }
115212Sigor@sysoev.ru
115312Sigor@sysoev.ru
115412Sigor@sysoev.ru /*
115562Sigor@sysoev.ru * nxt_epoll_edge_conn_io_recvbuf() is just wrapper around
115662Sigor@sysoev.ru * standard nxt_conn_io_recvbuf() to enforce to read a pending EOF
115712Sigor@sysoev.ru * in edge-triggered mode.
115812Sigor@sysoev.ru */
115912Sigor@sysoev.ru
116012Sigor@sysoev.ru static ssize_t
nxt_epoll_edge_conn_io_recvbuf(nxt_conn_t * c,nxt_buf_t * b)116162Sigor@sysoev.ru nxt_epoll_edge_conn_io_recvbuf(nxt_conn_t *c, nxt_buf_t *b)
116212Sigor@sysoev.ru {
116312Sigor@sysoev.ru ssize_t n;
116412Sigor@sysoev.ru
116562Sigor@sysoev.ru n = nxt_conn_io_recvbuf(c, b);
116612Sigor@sysoev.ru
116712Sigor@sysoev.ru if (n > 0 && c->socket.epoll_eof) {
116812Sigor@sysoev.ru c->socket.read_ready = 1;
116912Sigor@sysoev.ru }
117012Sigor@sysoev.ru
117112Sigor@sysoev.ru return n;
117212Sigor@sysoev.ru }
117312Sigor@sysoev.ru
117412Sigor@sysoev.ru #endif
1175