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 * kqueue() has been introduced in FreeBSD 4.1 and then was ported 1212Sigor@sysoev.ru * to OpenBSD 2.9, MacOSX 10.3 (Panther), and NetBSD 2.0. 1312Sigor@sysoev.ru * DragonFlyBSD inherited it with FreeBSD 4 code base. 1412Sigor@sysoev.ru * 1512Sigor@sysoev.ru * NOTE_REVOKE has been introduced in FreeBSD 4.3 and then was ported 1612Sigor@sysoev.ru * to OpenBSD 2.9, MacOSX 10.3 (Panther), and NetBSD 2.0. 1712Sigor@sysoev.ru * DragonFlyBSD inherited it with FreeBSD 4 code base. 1812Sigor@sysoev.ru * 1912Sigor@sysoev.ru * EVFILT_TIMER has been introduced in FreeBSD 4.4-STABLE and then was 2012Sigor@sysoev.ru * ported to NetBSD 2.0, MacOSX 10.4 (Tiger), and OpenBSD 4.2. 2112Sigor@sysoev.ru * DragonFlyBSD inherited it with FreeBSD 4 code base. 2212Sigor@sysoev.ru * 2312Sigor@sysoev.ru * EVFILT_USER and EV_DISPATCH have been introduced in MacOSX 10.6 (Snow 2412Sigor@sysoev.ru * Leopard) as part of the Grand Central Dispatch framework 2512Sigor@sysoev.ru * and then were ported to FreeBSD 8.0-STABLE as part of the 2612Sigor@sysoev.ru * libdispatch support. 2712Sigor@sysoev.ru */ 2812Sigor@sysoev.ru 2912Sigor@sysoev.ru 3012Sigor@sysoev.ru /* 3112Sigor@sysoev.ru * EV_DISPATCH is better because it just disables an event on delivery 3212Sigor@sysoev.ru * whilst EV_ONESHOT deletes the event. This eliminates in-kernel memory 3312Sigor@sysoev.ru * deallocation and probable subsequent allocation with a lock acquiring. 3412Sigor@sysoev.ru */ 3512Sigor@sysoev.ru #ifdef EV_DISPATCH 3612Sigor@sysoev.ru #define NXT_KEVENT_ONESHOT EV_DISPATCH 3712Sigor@sysoev.ru #else 3812Sigor@sysoev.ru #define NXT_KEVENT_ONESHOT EV_ONESHOT 3912Sigor@sysoev.ru #endif 4012Sigor@sysoev.ru 4112Sigor@sysoev.ru 4212Sigor@sysoev.ru #if (NXT_NETBSD) 4312Sigor@sysoev.ru /* NetBSD defines the kevent.udata field as intptr_t. */ 4412Sigor@sysoev.ru 4512Sigor@sysoev.ru #define nxt_kevent_set_udata(udata) (intptr_t) (udata) 4612Sigor@sysoev.ru #define nxt_kevent_get_udata(udata) (void *) (udata) 4712Sigor@sysoev.ru 4812Sigor@sysoev.ru #else 4912Sigor@sysoev.ru #define nxt_kevent_set_udata(udata) (void *) (udata) 5012Sigor@sysoev.ru #define nxt_kevent_get_udata(udata) (udata) 5112Sigor@sysoev.ru #endif 5212Sigor@sysoev.ru 5312Sigor@sysoev.ru 5412Sigor@sysoev.ru static nxt_int_t nxt_kqueue_create(nxt_event_engine_t *engine, 5512Sigor@sysoev.ru nxt_uint_t mchanges, nxt_uint_t mevents); 5612Sigor@sysoev.ru static void nxt_kqueue_free(nxt_event_engine_t *engine); 5712Sigor@sysoev.ru static void nxt_kqueue_enable(nxt_event_engine_t *engine, nxt_fd_event_t *ev); 5812Sigor@sysoev.ru static void nxt_kqueue_disable(nxt_event_engine_t *engine, nxt_fd_event_t *ev); 5912Sigor@sysoev.ru static void nxt_kqueue_delete(nxt_event_engine_t *engine, nxt_fd_event_t *ev); 6012Sigor@sysoev.ru static nxt_bool_t nxt_kqueue_close(nxt_event_engine_t *engine, 6112Sigor@sysoev.ru nxt_fd_event_t *ev); 6212Sigor@sysoev.ru static void nxt_kqueue_enable_read(nxt_event_engine_t *engine, 6312Sigor@sysoev.ru nxt_fd_event_t *ev); 6412Sigor@sysoev.ru static void nxt_kqueue_enable_write(nxt_event_engine_t *engine, 6512Sigor@sysoev.ru nxt_fd_event_t *ev); 6612Sigor@sysoev.ru static void nxt_kqueue_disable_read(nxt_event_engine_t *engine, 6712Sigor@sysoev.ru nxt_fd_event_t *ev); 6812Sigor@sysoev.ru static void nxt_kqueue_disable_write(nxt_event_engine_t *engine, 6912Sigor@sysoev.ru nxt_fd_event_t *ev); 7012Sigor@sysoev.ru static void nxt_kqueue_block_read(nxt_event_engine_t *engine, 7112Sigor@sysoev.ru nxt_fd_event_t *ev); 7212Sigor@sysoev.ru static void nxt_kqueue_block_write(nxt_event_engine_t *engine, 7312Sigor@sysoev.ru nxt_fd_event_t *ev); 7412Sigor@sysoev.ru static void nxt_kqueue_oneshot_read(nxt_event_engine_t *engine, 7512Sigor@sysoev.ru nxt_fd_event_t *ev); 7612Sigor@sysoev.ru static void nxt_kqueue_oneshot_write(nxt_event_engine_t *engine, 7712Sigor@sysoev.ru nxt_fd_event_t *ev); 7812Sigor@sysoev.ru static void nxt_kqueue_enable_accept(nxt_event_engine_t *engine, 7912Sigor@sysoev.ru nxt_fd_event_t *ev); 8012Sigor@sysoev.ru static void nxt_kqueue_enable_file(nxt_event_engine_t *engine, 8162Sigor@sysoev.ru nxt_file_event_t *ev); 8212Sigor@sysoev.ru static void nxt_kqueue_close_file(nxt_event_engine_t *engine, 8362Sigor@sysoev.ru nxt_file_event_t *ev); 8412Sigor@sysoev.ru static void nxt_kqueue_fd_set(nxt_event_engine_t *engine, nxt_fd_event_t *ev, 8512Sigor@sysoev.ru nxt_int_t filter, nxt_uint_t flags); 8612Sigor@sysoev.ru static struct kevent *nxt_kqueue_get_kevent(nxt_event_engine_t *engine); 8712Sigor@sysoev.ru static void nxt_kqueue_error(nxt_event_engine_t *engine); 8812Sigor@sysoev.ru static void nxt_kqueue_fd_error_handler(nxt_task_t *task, void *obj, 8912Sigor@sysoev.ru void *data); 9012Sigor@sysoev.ru static void nxt_kqueue_file_error_handler(nxt_task_t *task, void *obj, 9112Sigor@sysoev.ru void *data); 9212Sigor@sysoev.ru static nxt_int_t nxt_kqueue_add_signal(nxt_event_engine_t *engine, 9312Sigor@sysoev.ru const nxt_sig_event_t *sigev); 9412Sigor@sysoev.ru #if (NXT_HAVE_EVFILT_USER) 9512Sigor@sysoev.ru static nxt_int_t nxt_kqueue_enable_post(nxt_event_engine_t *engine, 9612Sigor@sysoev.ru nxt_work_handler_t handler); 9712Sigor@sysoev.ru static void nxt_kqueue_signal(nxt_event_engine_t *engine, nxt_uint_t signo); 9812Sigor@sysoev.ru #endif 9912Sigor@sysoev.ru static void nxt_kqueue_poll(nxt_event_engine_t *engine, nxt_msec_t timeout); 10012Sigor@sysoev.ru 10162Sigor@sysoev.ru static void nxt_kqueue_conn_io_connect(nxt_task_t *task, void *obj, 10212Sigor@sysoev.ru void *data); 10362Sigor@sysoev.ru static void nxt_kqueue_conn_connected(nxt_task_t *task, void *obj, 10412Sigor@sysoev.ru void *data); 10512Sigor@sysoev.ru static void nxt_kqueue_listen_handler(nxt_task_t *task, void *obj, void *data); 10662Sigor@sysoev.ru static void nxt_kqueue_conn_io_accept(nxt_task_t *task, void *obj, 10712Sigor@sysoev.ru void *data); 10862Sigor@sysoev.ru static void nxt_kqueue_conn_io_read(nxt_task_t *task, void *obj, 10912Sigor@sysoev.ru void *data); 11062Sigor@sysoev.ru static ssize_t nxt_kqueue_conn_io_recvbuf(nxt_conn_t *c, nxt_buf_t *b); 11112Sigor@sysoev.ru 11212Sigor@sysoev.ru 11362Sigor@sysoev.ru static nxt_conn_io_t nxt_kqueue_conn_io = { 114771Sigor@sysoev.ru .connect = nxt_kqueue_conn_io_connect, 115771Sigor@sysoev.ru .accept = nxt_kqueue_conn_io_accept, 11612Sigor@sysoev.ru 117771Sigor@sysoev.ru .read = nxt_kqueue_conn_io_read, 118771Sigor@sysoev.ru .recvbuf = nxt_kqueue_conn_io_recvbuf, 119771Sigor@sysoev.ru .recv = nxt_conn_io_recv, 12012Sigor@sysoev.ru 121771Sigor@sysoev.ru .write = nxt_conn_io_write, 122771Sigor@sysoev.ru .sendbuf = nxt_conn_io_sendbuf, 12312Sigor@sysoev.ru 12412Sigor@sysoev.ru #if (NXT_HAVE_FREEBSD_SENDFILE) 125771Sigor@sysoev.ru .old_sendbuf = nxt_freebsd_event_conn_io_sendfile, 12612Sigor@sysoev.ru #elif (NXT_HAVE_MACOSX_SENDFILE) 127771Sigor@sysoev.ru .old_sendbuf = nxt_macosx_event_conn_io_sendfile, 12812Sigor@sysoev.ru #else 129771Sigor@sysoev.ru .old_sendbuf = nxt_event_conn_io_sendbuf, 13012Sigor@sysoev.ru #endif 13112Sigor@sysoev.ru 132771Sigor@sysoev.ru .writev = nxt_event_conn_io_writev, 133771Sigor@sysoev.ru .send = nxt_event_conn_io_send, 13412Sigor@sysoev.ru }; 13512Sigor@sysoev.ru 13612Sigor@sysoev.ru 13712Sigor@sysoev.ru const nxt_event_interface_t nxt_kqueue_engine = { 13812Sigor@sysoev.ru "kqueue", 13912Sigor@sysoev.ru nxt_kqueue_create, 14012Sigor@sysoev.ru nxt_kqueue_free, 14112Sigor@sysoev.ru nxt_kqueue_enable, 14212Sigor@sysoev.ru nxt_kqueue_disable, 14312Sigor@sysoev.ru nxt_kqueue_delete, 14412Sigor@sysoev.ru nxt_kqueue_close, 14512Sigor@sysoev.ru nxt_kqueue_enable_read, 14612Sigor@sysoev.ru nxt_kqueue_enable_write, 14712Sigor@sysoev.ru nxt_kqueue_disable_read, 14812Sigor@sysoev.ru nxt_kqueue_disable_write, 14912Sigor@sysoev.ru nxt_kqueue_block_read, 15012Sigor@sysoev.ru nxt_kqueue_block_write, 15112Sigor@sysoev.ru nxt_kqueue_oneshot_read, 15212Sigor@sysoev.ru nxt_kqueue_oneshot_write, 15312Sigor@sysoev.ru nxt_kqueue_enable_accept, 15412Sigor@sysoev.ru nxt_kqueue_enable_file, 15512Sigor@sysoev.ru nxt_kqueue_close_file, 15612Sigor@sysoev.ru #if (NXT_HAVE_EVFILT_USER) 15712Sigor@sysoev.ru nxt_kqueue_enable_post, 15812Sigor@sysoev.ru nxt_kqueue_signal, 15912Sigor@sysoev.ru #else 16012Sigor@sysoev.ru NULL, 16112Sigor@sysoev.ru NULL, 16212Sigor@sysoev.ru #endif 16312Sigor@sysoev.ru nxt_kqueue_poll, 16412Sigor@sysoev.ru 16562Sigor@sysoev.ru &nxt_kqueue_conn_io, 16612Sigor@sysoev.ru 16712Sigor@sysoev.ru NXT_FILE_EVENTS, 16812Sigor@sysoev.ru NXT_SIGNAL_EVENTS, 16912Sigor@sysoev.ru }; 17012Sigor@sysoev.ru 17112Sigor@sysoev.ru 17212Sigor@sysoev.ru static nxt_int_t 17312Sigor@sysoev.ru nxt_kqueue_create(nxt_event_engine_t *engine, nxt_uint_t mchanges, 17412Sigor@sysoev.ru nxt_uint_t mevents) 17512Sigor@sysoev.ru { 17612Sigor@sysoev.ru const nxt_sig_event_t *sigev; 17712Sigor@sysoev.ru 17812Sigor@sysoev.ru engine->u.kqueue.fd = -1; 17912Sigor@sysoev.ru engine->u.kqueue.mchanges = mchanges; 18012Sigor@sysoev.ru engine->u.kqueue.mevents = mevents; 18112Sigor@sysoev.ru engine->u.kqueue.pid = nxt_pid; 18212Sigor@sysoev.ru 18312Sigor@sysoev.ru engine->u.kqueue.changes = nxt_malloc(sizeof(struct kevent) * mchanges); 18412Sigor@sysoev.ru if (engine->u.kqueue.changes == NULL) { 18512Sigor@sysoev.ru goto fail; 18612Sigor@sysoev.ru } 18712Sigor@sysoev.ru 18812Sigor@sysoev.ru engine->u.kqueue.events = nxt_malloc(sizeof(struct kevent) * mevents); 18912Sigor@sysoev.ru if (engine->u.kqueue.events == NULL) { 19012Sigor@sysoev.ru goto fail; 19112Sigor@sysoev.ru } 19212Sigor@sysoev.ru 19312Sigor@sysoev.ru engine->u.kqueue.fd = kqueue(); 19412Sigor@sysoev.ru if (engine->u.kqueue.fd == -1) { 195564Svbart@nginx.com nxt_alert(&engine->task, "kqueue() failed %E", nxt_errno); 19612Sigor@sysoev.ru goto fail; 19712Sigor@sysoev.ru } 19812Sigor@sysoev.ru 19912Sigor@sysoev.ru nxt_debug(&engine->task, "kqueue(): %d", engine->u.kqueue.fd); 20012Sigor@sysoev.ru 20112Sigor@sysoev.ru if (engine->signals != NULL) { 20212Sigor@sysoev.ru for (sigev = engine->signals->sigev; sigev->signo != 0; sigev++) { 20312Sigor@sysoev.ru if (nxt_kqueue_add_signal(engine, sigev) != NXT_OK) { 20412Sigor@sysoev.ru goto fail; 20512Sigor@sysoev.ru } 20612Sigor@sysoev.ru } 20712Sigor@sysoev.ru } 20812Sigor@sysoev.ru 20912Sigor@sysoev.ru return NXT_OK; 21012Sigor@sysoev.ru 21112Sigor@sysoev.ru fail: 21212Sigor@sysoev.ru 21312Sigor@sysoev.ru nxt_kqueue_free(engine); 21412Sigor@sysoev.ru 21512Sigor@sysoev.ru return NXT_ERROR; 21612Sigor@sysoev.ru } 21712Sigor@sysoev.ru 21812Sigor@sysoev.ru 21912Sigor@sysoev.ru static void 22012Sigor@sysoev.ru nxt_kqueue_free(nxt_event_engine_t *engine) 22112Sigor@sysoev.ru { 22212Sigor@sysoev.ru nxt_fd_t fd; 22312Sigor@sysoev.ru 22412Sigor@sysoev.ru fd = engine->u.kqueue.fd; 22512Sigor@sysoev.ru 22612Sigor@sysoev.ru nxt_debug(&engine->task, "kqueue %d free", fd); 22712Sigor@sysoev.ru 22812Sigor@sysoev.ru if (fd != -1 && engine->u.kqueue.pid == nxt_pid) { 22912Sigor@sysoev.ru /* kqueue is not inherited by fork() */ 23012Sigor@sysoev.ru 23112Sigor@sysoev.ru if (close(fd) != 0) { 232564Svbart@nginx.com nxt_alert(&engine->task, "kqueue close(%d) failed %E", 233564Svbart@nginx.com fd, nxt_errno); 23412Sigor@sysoev.ru } 23512Sigor@sysoev.ru } 23612Sigor@sysoev.ru 23712Sigor@sysoev.ru nxt_free(engine->u.kqueue.events); 23812Sigor@sysoev.ru nxt_free(engine->u.kqueue.changes); 23912Sigor@sysoev.ru 24012Sigor@sysoev.ru nxt_memzero(&engine->u.kqueue, sizeof(nxt_kqueue_engine_t)); 24112Sigor@sysoev.ru } 24212Sigor@sysoev.ru 24312Sigor@sysoev.ru 24412Sigor@sysoev.ru static void 24512Sigor@sysoev.ru nxt_kqueue_enable(nxt_event_engine_t *engine, nxt_fd_event_t *ev) 24612Sigor@sysoev.ru { 24712Sigor@sysoev.ru nxt_kqueue_enable_read(engine, ev); 24812Sigor@sysoev.ru nxt_kqueue_enable_write(engine, ev); 24912Sigor@sysoev.ru } 25012Sigor@sysoev.ru 25112Sigor@sysoev.ru 25212Sigor@sysoev.ru /* 25312Sigor@sysoev.ru * EV_DISABLE is better because it eliminates in-kernel memory 25412Sigor@sysoev.ru * deallocation and probable subsequent allocation with a lock acquiring. 25512Sigor@sysoev.ru */ 25612Sigor@sysoev.ru 25712Sigor@sysoev.ru static void 25812Sigor@sysoev.ru nxt_kqueue_disable(nxt_event_engine_t *engine, nxt_fd_event_t *ev) 25912Sigor@sysoev.ru { 26012Sigor@sysoev.ru if (ev->read != NXT_EVENT_INACTIVE) { 26112Sigor@sysoev.ru ev->read = NXT_EVENT_INACTIVE; 26212Sigor@sysoev.ru nxt_kqueue_fd_set(engine, ev, EVFILT_READ, EV_DISABLE); 26312Sigor@sysoev.ru } 26412Sigor@sysoev.ru 26512Sigor@sysoev.ru if (ev->write != NXT_EVENT_INACTIVE) { 26612Sigor@sysoev.ru ev->write = NXT_EVENT_INACTIVE; 26712Sigor@sysoev.ru nxt_kqueue_fd_set(engine, ev, EVFILT_WRITE, EV_DISABLE); 26812Sigor@sysoev.ru } 26912Sigor@sysoev.ru } 27012Sigor@sysoev.ru 27112Sigor@sysoev.ru 27212Sigor@sysoev.ru static void 27312Sigor@sysoev.ru nxt_kqueue_delete(nxt_event_engine_t *engine, nxt_fd_event_t *ev) 27412Sigor@sysoev.ru { 27512Sigor@sysoev.ru if (ev->read != NXT_EVENT_INACTIVE) { 27612Sigor@sysoev.ru ev->read = NXT_EVENT_INACTIVE; 27712Sigor@sysoev.ru nxt_kqueue_fd_set(engine, ev, EVFILT_READ, EV_DELETE); 27812Sigor@sysoev.ru } 27912Sigor@sysoev.ru 28012Sigor@sysoev.ru if (ev->write != NXT_EVENT_INACTIVE) { 28112Sigor@sysoev.ru ev->write = NXT_EVENT_INACTIVE; 28212Sigor@sysoev.ru nxt_kqueue_fd_set(engine, ev, EVFILT_WRITE, EV_DELETE); 28312Sigor@sysoev.ru } 28412Sigor@sysoev.ru } 28512Sigor@sysoev.ru 28612Sigor@sysoev.ru 28712Sigor@sysoev.ru /* 28812Sigor@sysoev.ru * kqueue(2): 28912Sigor@sysoev.ru * 29012Sigor@sysoev.ru * Calling close() on a file descriptor will remove any kevents that 29112Sigor@sysoev.ru * reference the descriptor. 29212Sigor@sysoev.ru * 29355Sigor@sysoev.ru * So nxt_kqueue_close() returns true only if there are pending events. 29412Sigor@sysoev.ru */ 29512Sigor@sysoev.ru 29612Sigor@sysoev.ru static nxt_bool_t 29712Sigor@sysoev.ru nxt_kqueue_close(nxt_event_engine_t *engine, nxt_fd_event_t *ev) 29812Sigor@sysoev.ru { 29955Sigor@sysoev.ru struct kevent *kev, *end; 30055Sigor@sysoev.ru 30112Sigor@sysoev.ru ev->read = NXT_EVENT_INACTIVE; 30212Sigor@sysoev.ru ev->write = NXT_EVENT_INACTIVE; 30312Sigor@sysoev.ru 30455Sigor@sysoev.ru end = &engine->u.kqueue.changes[engine->u.kqueue.nchanges]; 30555Sigor@sysoev.ru 30655Sigor@sysoev.ru for (kev = engine->u.kqueue.changes; kev < end; kev++) { 30755Sigor@sysoev.ru if (kev->ident == (uintptr_t) ev->fd) { 30855Sigor@sysoev.ru return 1; 30955Sigor@sysoev.ru } 31055Sigor@sysoev.ru } 31155Sigor@sysoev.ru 31255Sigor@sysoev.ru return 0; 31312Sigor@sysoev.ru } 31412Sigor@sysoev.ru 31512Sigor@sysoev.ru 31612Sigor@sysoev.ru /* 31712Sigor@sysoev.ru * The kqueue event engine uses only three states: inactive, blocked, and 31812Sigor@sysoev.ru * active. An active oneshot event is marked as it is in the default 31912Sigor@sysoev.ru * state. The event will be converted eventually to the default EV_CLEAR 32012Sigor@sysoev.ru * mode after it will become inactive after delivery. 32112Sigor@sysoev.ru */ 32212Sigor@sysoev.ru 32312Sigor@sysoev.ru static void 32412Sigor@sysoev.ru nxt_kqueue_enable_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) 32512Sigor@sysoev.ru { 32612Sigor@sysoev.ru if (ev->read == NXT_EVENT_INACTIVE) { 32712Sigor@sysoev.ru nxt_kqueue_fd_set(engine, ev, EVFILT_READ, 32812Sigor@sysoev.ru EV_ADD | EV_ENABLE | EV_CLEAR); 32912Sigor@sysoev.ru } 33012Sigor@sysoev.ru 33112Sigor@sysoev.ru ev->read = NXT_EVENT_ACTIVE; 33212Sigor@sysoev.ru } 33312Sigor@sysoev.ru 33412Sigor@sysoev.ru 33512Sigor@sysoev.ru static void 33612Sigor@sysoev.ru nxt_kqueue_enable_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) 33712Sigor@sysoev.ru { 33812Sigor@sysoev.ru if (ev->write == NXT_EVENT_INACTIVE) { 33912Sigor@sysoev.ru nxt_kqueue_fd_set(engine, ev, EVFILT_WRITE, 34012Sigor@sysoev.ru EV_ADD | EV_ENABLE | EV_CLEAR); 34112Sigor@sysoev.ru } 34212Sigor@sysoev.ru 34312Sigor@sysoev.ru ev->write = NXT_EVENT_ACTIVE; 34412Sigor@sysoev.ru } 34512Sigor@sysoev.ru 34612Sigor@sysoev.ru 34712Sigor@sysoev.ru static void 34812Sigor@sysoev.ru nxt_kqueue_disable_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) 34912Sigor@sysoev.ru { 35012Sigor@sysoev.ru ev->read = NXT_EVENT_INACTIVE; 35112Sigor@sysoev.ru 35212Sigor@sysoev.ru nxt_kqueue_fd_set(engine, ev, EVFILT_READ, EV_DISABLE); 35312Sigor@sysoev.ru } 35412Sigor@sysoev.ru 35512Sigor@sysoev.ru 35612Sigor@sysoev.ru static void 35712Sigor@sysoev.ru nxt_kqueue_disable_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) 35812Sigor@sysoev.ru { 35912Sigor@sysoev.ru ev->write = NXT_EVENT_INACTIVE; 36012Sigor@sysoev.ru 36112Sigor@sysoev.ru nxt_kqueue_fd_set(engine, ev, EVFILT_WRITE, EV_DISABLE); 36212Sigor@sysoev.ru } 36312Sigor@sysoev.ru 36412Sigor@sysoev.ru 36512Sigor@sysoev.ru static void 36612Sigor@sysoev.ru nxt_kqueue_block_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) 36712Sigor@sysoev.ru { 36812Sigor@sysoev.ru if (ev->read != NXT_EVENT_INACTIVE) { 36912Sigor@sysoev.ru ev->read = NXT_EVENT_BLOCKED; 37012Sigor@sysoev.ru } 37112Sigor@sysoev.ru } 37212Sigor@sysoev.ru 37312Sigor@sysoev.ru 37412Sigor@sysoev.ru static void 37512Sigor@sysoev.ru nxt_kqueue_block_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) 37612Sigor@sysoev.ru { 37712Sigor@sysoev.ru if (ev->write != NXT_EVENT_INACTIVE) { 37812Sigor@sysoev.ru ev->write = NXT_EVENT_BLOCKED; 37912Sigor@sysoev.ru } 38012Sigor@sysoev.ru } 38112Sigor@sysoev.ru 38212Sigor@sysoev.ru 38312Sigor@sysoev.ru static void 38412Sigor@sysoev.ru nxt_kqueue_oneshot_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) 38512Sigor@sysoev.ru { 38612Sigor@sysoev.ru ev->write = NXT_EVENT_ACTIVE; 38712Sigor@sysoev.ru 38812Sigor@sysoev.ru nxt_kqueue_fd_set(engine, ev, EVFILT_WRITE, 38912Sigor@sysoev.ru EV_ADD | EV_ENABLE | NXT_KEVENT_ONESHOT); 39012Sigor@sysoev.ru } 39112Sigor@sysoev.ru 39212Sigor@sysoev.ru 39312Sigor@sysoev.ru static void 39412Sigor@sysoev.ru nxt_kqueue_oneshot_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) 39512Sigor@sysoev.ru { 39612Sigor@sysoev.ru ev->write = NXT_EVENT_ACTIVE; 39712Sigor@sysoev.ru 39812Sigor@sysoev.ru nxt_kqueue_fd_set(engine, ev, EVFILT_WRITE, 39912Sigor@sysoev.ru EV_ADD | EV_ENABLE | NXT_KEVENT_ONESHOT); 40012Sigor@sysoev.ru } 40112Sigor@sysoev.ru 40212Sigor@sysoev.ru 40312Sigor@sysoev.ru static void 40412Sigor@sysoev.ru nxt_kqueue_enable_accept(nxt_event_engine_t *engine, nxt_fd_event_t *ev) 40512Sigor@sysoev.ru { 40612Sigor@sysoev.ru ev->read = NXT_EVENT_ACTIVE; 40712Sigor@sysoev.ru ev->read_handler = nxt_kqueue_listen_handler; 40812Sigor@sysoev.ru 40912Sigor@sysoev.ru nxt_kqueue_fd_set(engine, ev, EVFILT_READ, EV_ADD | EV_ENABLE); 41012Sigor@sysoev.ru } 41112Sigor@sysoev.ru 41212Sigor@sysoev.ru 41312Sigor@sysoev.ru static void 41462Sigor@sysoev.ru nxt_kqueue_enable_file(nxt_event_engine_t *engine, nxt_file_event_t *ev) 41512Sigor@sysoev.ru { 41612Sigor@sysoev.ru struct kevent *kev; 41712Sigor@sysoev.ru 41812Sigor@sysoev.ru const nxt_int_t flags = EV_ADD | EV_ENABLE | EV_ONESHOT; 41912Sigor@sysoev.ru const nxt_uint_t fflags = NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND 42012Sigor@sysoev.ru | NOTE_ATTRIB | NOTE_RENAME | NOTE_REVOKE; 42112Sigor@sysoev.ru 42212Sigor@sysoev.ru nxt_debug(&engine->task, "kevent(%d) set: id:%d ft:%i fl:%04Xd, ff:%04XuD", 42312Sigor@sysoev.ru engine->u.kqueue.fd, ev->file->fd, EVFILT_VNODE, flags, fflags); 42412Sigor@sysoev.ru 42512Sigor@sysoev.ru kev = nxt_kqueue_get_kevent(engine); 42612Sigor@sysoev.ru 42712Sigor@sysoev.ru kev->ident = ev->file->fd; 42812Sigor@sysoev.ru kev->filter = EVFILT_VNODE; 42912Sigor@sysoev.ru kev->flags = flags; 43012Sigor@sysoev.ru kev->fflags = fflags; 43112Sigor@sysoev.ru kev->data = 0; 43212Sigor@sysoev.ru kev->udata = nxt_kevent_set_udata(ev); 43312Sigor@sysoev.ru } 43412Sigor@sysoev.ru 43512Sigor@sysoev.ru 43612Sigor@sysoev.ru static void 43762Sigor@sysoev.ru nxt_kqueue_close_file(nxt_event_engine_t *engine, nxt_file_event_t *ev) 43812Sigor@sysoev.ru { 43912Sigor@sysoev.ru /* TODO: pending event. */ 44012Sigor@sysoev.ru } 44112Sigor@sysoev.ru 44212Sigor@sysoev.ru 44312Sigor@sysoev.ru static void 44412Sigor@sysoev.ru nxt_kqueue_fd_set(nxt_event_engine_t *engine, nxt_fd_event_t *ev, 44512Sigor@sysoev.ru nxt_int_t filter, nxt_uint_t flags) 44612Sigor@sysoev.ru { 44712Sigor@sysoev.ru struct kevent *kev; 44812Sigor@sysoev.ru 44912Sigor@sysoev.ru nxt_debug(ev->task, "kevent(%d) set event: id:%d ft:%i fl:%04Xui", 45012Sigor@sysoev.ru engine->u.kqueue.fd, ev->fd, filter, flags); 45112Sigor@sysoev.ru 45212Sigor@sysoev.ru kev = nxt_kqueue_get_kevent(engine); 45312Sigor@sysoev.ru 45412Sigor@sysoev.ru kev->ident = ev->fd; 45512Sigor@sysoev.ru kev->filter = filter; 45612Sigor@sysoev.ru kev->flags = flags; 45712Sigor@sysoev.ru kev->fflags = 0; 45812Sigor@sysoev.ru kev->data = 0; 45912Sigor@sysoev.ru kev->udata = nxt_kevent_set_udata(ev); 46012Sigor@sysoev.ru } 46112Sigor@sysoev.ru 46212Sigor@sysoev.ru 46312Sigor@sysoev.ru static struct kevent * 46412Sigor@sysoev.ru nxt_kqueue_get_kevent(nxt_event_engine_t *engine) 46512Sigor@sysoev.ru { 46612Sigor@sysoev.ru int ret, nchanges; 46712Sigor@sysoev.ru 46812Sigor@sysoev.ru nchanges = engine->u.kqueue.nchanges; 46912Sigor@sysoev.ru 47012Sigor@sysoev.ru if (nxt_slow_path(nchanges >= engine->u.kqueue.mchanges)) { 47112Sigor@sysoev.ru 47212Sigor@sysoev.ru nxt_debug(&engine->task, "kevent(%d) changes:%d", 47312Sigor@sysoev.ru engine->u.kqueue.fd, nchanges); 47412Sigor@sysoev.ru 47512Sigor@sysoev.ru ret = kevent(engine->u.kqueue.fd, engine->u.kqueue.changes, nchanges, 47612Sigor@sysoev.ru NULL, 0, NULL); 47712Sigor@sysoev.ru 47812Sigor@sysoev.ru if (nxt_slow_path(ret != 0)) { 479564Svbart@nginx.com nxt_alert(&engine->task, "kevent(%d) failed %E", 480564Svbart@nginx.com engine->u.kqueue.fd, nxt_errno); 48112Sigor@sysoev.ru 48212Sigor@sysoev.ru nxt_kqueue_error(engine); 48312Sigor@sysoev.ru } 48412Sigor@sysoev.ru 48512Sigor@sysoev.ru engine->u.kqueue.nchanges = 0; 48612Sigor@sysoev.ru } 48712Sigor@sysoev.ru 48812Sigor@sysoev.ru return &engine->u.kqueue.changes[engine->u.kqueue.nchanges++]; 48912Sigor@sysoev.ru } 49012Sigor@sysoev.ru 49112Sigor@sysoev.ru 49212Sigor@sysoev.ru static void 49312Sigor@sysoev.ru nxt_kqueue_error(nxt_event_engine_t *engine) 49412Sigor@sysoev.ru { 49512Sigor@sysoev.ru struct kevent *kev, *end; 49612Sigor@sysoev.ru nxt_fd_event_t *ev; 49762Sigor@sysoev.ru nxt_file_event_t *fev; 49812Sigor@sysoev.ru nxt_work_queue_t *wq; 49912Sigor@sysoev.ru 50012Sigor@sysoev.ru wq = &engine->fast_work_queue; 50112Sigor@sysoev.ru end = &engine->u.kqueue.changes[engine->u.kqueue.nchanges]; 50212Sigor@sysoev.ru 50312Sigor@sysoev.ru for (kev = engine->u.kqueue.changes; kev < end; kev++) { 50412Sigor@sysoev.ru 50512Sigor@sysoev.ru switch (kev->filter) { 50612Sigor@sysoev.ru 50712Sigor@sysoev.ru case EVFILT_READ: 50812Sigor@sysoev.ru case EVFILT_WRITE: 50912Sigor@sysoev.ru ev = nxt_kevent_get_udata(kev->udata); 51012Sigor@sysoev.ru nxt_work_queue_add(wq, nxt_kqueue_fd_error_handler, 51112Sigor@sysoev.ru ev->task, ev, ev->data); 51212Sigor@sysoev.ru break; 51312Sigor@sysoev.ru 51412Sigor@sysoev.ru case EVFILT_VNODE: 51512Sigor@sysoev.ru fev = nxt_kevent_get_udata(kev->udata); 51612Sigor@sysoev.ru nxt_work_queue_add(wq, nxt_kqueue_file_error_handler, 51712Sigor@sysoev.ru fev->task, fev, fev->data); 51812Sigor@sysoev.ru break; 51912Sigor@sysoev.ru } 52012Sigor@sysoev.ru } 52112Sigor@sysoev.ru } 52212Sigor@sysoev.ru 52312Sigor@sysoev.ru 52412Sigor@sysoev.ru static void 52512Sigor@sysoev.ru nxt_kqueue_fd_error_handler(nxt_task_t *task, void *obj, void *data) 52612Sigor@sysoev.ru { 52712Sigor@sysoev.ru nxt_fd_event_t *ev; 52812Sigor@sysoev.ru 52912Sigor@sysoev.ru ev = obj; 53012Sigor@sysoev.ru 53153Sigor@sysoev.ru nxt_debug(task, "kqueue fd error handler fd:%d", ev->fd); 53253Sigor@sysoev.ru 53312Sigor@sysoev.ru if (ev->kq_eof && ev->kq_errno != 0) { 53412Sigor@sysoev.ru ev->error = ev->kq_errno; 53513Sigor@sysoev.ru nxt_log(task, nxt_socket_error_level(ev->kq_errno), 53612Sigor@sysoev.ru "kevent() reported error on descriptor %d %E", 53712Sigor@sysoev.ru ev->fd, ev->kq_errno); 53812Sigor@sysoev.ru } 53912Sigor@sysoev.ru 54012Sigor@sysoev.ru ev->read = NXT_EVENT_INACTIVE; 54112Sigor@sysoev.ru ev->write = NXT_EVENT_INACTIVE; 54212Sigor@sysoev.ru ev->error = ev->kq_errno; 54312Sigor@sysoev.ru 54412Sigor@sysoev.ru ev->error_handler(task, ev, data); 54512Sigor@sysoev.ru } 54612Sigor@sysoev.ru 54712Sigor@sysoev.ru 54812Sigor@sysoev.ru static void 54912Sigor@sysoev.ru nxt_kqueue_file_error_handler(nxt_task_t *task, void *obj, void *data) 55012Sigor@sysoev.ru { 55162Sigor@sysoev.ru nxt_file_event_t *ev; 55212Sigor@sysoev.ru 55312Sigor@sysoev.ru ev = obj; 55412Sigor@sysoev.ru 55553Sigor@sysoev.ru nxt_debug(task, "kqueue file error handler fd:%d", ev->file->fd); 55653Sigor@sysoev.ru 55712Sigor@sysoev.ru ev->handler(task, ev, data); 55812Sigor@sysoev.ru } 55912Sigor@sysoev.ru 56012Sigor@sysoev.ru 56112Sigor@sysoev.ru static nxt_int_t 56212Sigor@sysoev.ru nxt_kqueue_add_signal(nxt_event_engine_t *engine, const nxt_sig_event_t *sigev) 56312Sigor@sysoev.ru { 56412Sigor@sysoev.ru int signo; 56512Sigor@sysoev.ru struct kevent kev; 56612Sigor@sysoev.ru struct sigaction sa; 56712Sigor@sysoev.ru 56812Sigor@sysoev.ru signo = sigev->signo; 56912Sigor@sysoev.ru 57012Sigor@sysoev.ru nxt_memzero(&sa, sizeof(struct sigaction)); 57112Sigor@sysoev.ru sigemptyset(&sa.sa_mask); 57212Sigor@sysoev.ru 57312Sigor@sysoev.ru /* 57412Sigor@sysoev.ru * SIGCHLD must not be set to SIG_IGN, since kqueue cannot catch 57512Sigor@sysoev.ru * this signal. It should be set to SIG_DFL instead. And although 57612Sigor@sysoev.ru * SIGCHLD default action is also ignoring, nevertheless SIG_DFL 57712Sigor@sysoev.ru * allows kqueue to catch the signal. 57812Sigor@sysoev.ru */ 57912Sigor@sysoev.ru sa.sa_handler = (signo == SIGCHLD) ? SIG_DFL : SIG_IGN; 58012Sigor@sysoev.ru 58112Sigor@sysoev.ru if (sigaction(signo, &sa, NULL) != 0) { 582564Svbart@nginx.com nxt_alert(&engine->task, "sigaction(%d) failed %E", signo, nxt_errno); 58312Sigor@sysoev.ru 58412Sigor@sysoev.ru return NXT_ERROR; 58512Sigor@sysoev.ru } 58612Sigor@sysoev.ru 58712Sigor@sysoev.ru nxt_debug(&engine->task, "kevent(%d) signo:%d (%s)", 58812Sigor@sysoev.ru engine->u.kqueue.fd, signo, sigev->name); 58912Sigor@sysoev.ru 59012Sigor@sysoev.ru kev.ident = signo; 59112Sigor@sysoev.ru kev.filter = EVFILT_SIGNAL; 59212Sigor@sysoev.ru kev.flags = EV_ADD; 59312Sigor@sysoev.ru kev.fflags = 0; 59412Sigor@sysoev.ru kev.data = 0; 59512Sigor@sysoev.ru kev.udata = nxt_kevent_set_udata(sigev); 59612Sigor@sysoev.ru 59712Sigor@sysoev.ru if (kevent(engine->u.kqueue.fd, &kev, 1, NULL, 0, NULL) == 0) { 59812Sigor@sysoev.ru return NXT_OK; 59912Sigor@sysoev.ru } 60012Sigor@sysoev.ru 601564Svbart@nginx.com nxt_alert(&engine->task, "kevent(%d) failed %E", kqueue, nxt_errno); 60212Sigor@sysoev.ru 60312Sigor@sysoev.ru return NXT_ERROR; 60412Sigor@sysoev.ru } 60512Sigor@sysoev.ru 60612Sigor@sysoev.ru 60712Sigor@sysoev.ru #if (NXT_HAVE_EVFILT_USER) 60812Sigor@sysoev.ru 60912Sigor@sysoev.ru static nxt_int_t 61012Sigor@sysoev.ru nxt_kqueue_enable_post(nxt_event_engine_t *engine, nxt_work_handler_t handler) 61112Sigor@sysoev.ru { 61212Sigor@sysoev.ru struct kevent kev; 61312Sigor@sysoev.ru 61412Sigor@sysoev.ru /* EVFILT_USER must be added to a kqueue before it can be triggered. */ 61512Sigor@sysoev.ru 61612Sigor@sysoev.ru kev.ident = 0; 61712Sigor@sysoev.ru kev.filter = EVFILT_USER; 61812Sigor@sysoev.ru kev.flags = EV_ADD | EV_CLEAR; 61912Sigor@sysoev.ru kev.fflags = 0; 62012Sigor@sysoev.ru kev.data = 0; 62112Sigor@sysoev.ru kev.udata = NULL; 62212Sigor@sysoev.ru 62312Sigor@sysoev.ru engine->u.kqueue.post_handler = handler; 62412Sigor@sysoev.ru 62512Sigor@sysoev.ru if (kevent(engine->u.kqueue.fd, &kev, 1, NULL, 0, NULL) == 0) { 62612Sigor@sysoev.ru return NXT_OK; 62712Sigor@sysoev.ru } 62812Sigor@sysoev.ru 629564Svbart@nginx.com nxt_alert(&engine->task, "kevent(%d) failed %E", 630564Svbart@nginx.com engine->u.kqueue.fd, nxt_errno); 63112Sigor@sysoev.ru 63212Sigor@sysoev.ru return NXT_ERROR; 63312Sigor@sysoev.ru } 63412Sigor@sysoev.ru 63512Sigor@sysoev.ru 63612Sigor@sysoev.ru static void 63712Sigor@sysoev.ru nxt_kqueue_signal(nxt_event_engine_t *engine, nxt_uint_t signo) 63812Sigor@sysoev.ru { 63912Sigor@sysoev.ru struct kevent kev; 64012Sigor@sysoev.ru 64112Sigor@sysoev.ru /* 64212Sigor@sysoev.ru * kqueue has a builtin signal processing support, so the function 64312Sigor@sysoev.ru * is used only to post events and the signo argument is ignored. 64412Sigor@sysoev.ru */ 64512Sigor@sysoev.ru 64612Sigor@sysoev.ru kev.ident = 0; 64712Sigor@sysoev.ru kev.filter = EVFILT_USER; 64812Sigor@sysoev.ru kev.flags = 0; 64912Sigor@sysoev.ru kev.fflags = NOTE_TRIGGER; 65012Sigor@sysoev.ru kev.data = 0; 65112Sigor@sysoev.ru kev.udata = NULL; 65212Sigor@sysoev.ru 65312Sigor@sysoev.ru if (kevent(engine->u.kqueue.fd, &kev, 1, NULL, 0, NULL) != 0) { 654564Svbart@nginx.com nxt_alert(&engine->task, "kevent(%d) failed %E", 655564Svbart@nginx.com engine->u.kqueue.fd, nxt_errno); 65612Sigor@sysoev.ru } 65712Sigor@sysoev.ru } 65812Sigor@sysoev.ru 65912Sigor@sysoev.ru #endif 66012Sigor@sysoev.ru 66112Sigor@sysoev.ru 66212Sigor@sysoev.ru static void 66312Sigor@sysoev.ru nxt_kqueue_poll(nxt_event_engine_t *engine, nxt_msec_t timeout) 66412Sigor@sysoev.ru { 66512Sigor@sysoev.ru int nevents; 66612Sigor@sysoev.ru void *obj, *data; 66712Sigor@sysoev.ru nxt_int_t i; 66812Sigor@sysoev.ru nxt_err_t err; 66912Sigor@sysoev.ru nxt_uint_t level; 67012Sigor@sysoev.ru nxt_bool_t error, eof; 67112Sigor@sysoev.ru nxt_task_t *task; 67212Sigor@sysoev.ru struct kevent *kev; 67312Sigor@sysoev.ru nxt_fd_event_t *ev; 67412Sigor@sysoev.ru nxt_sig_event_t *sigev; 67512Sigor@sysoev.ru struct timespec ts, *tp; 67662Sigor@sysoev.ru nxt_file_event_t *fev; 67712Sigor@sysoev.ru nxt_work_queue_t *wq; 67812Sigor@sysoev.ru nxt_work_handler_t handler; 67912Sigor@sysoev.ru 68012Sigor@sysoev.ru if (timeout == NXT_INFINITE_MSEC) { 68112Sigor@sysoev.ru tp = NULL; 68212Sigor@sysoev.ru 68312Sigor@sysoev.ru } else { 68412Sigor@sysoev.ru ts.tv_sec = timeout / 1000; 68512Sigor@sysoev.ru ts.tv_nsec = (timeout % 1000) * 1000000; 68612Sigor@sysoev.ru tp = &ts; 68712Sigor@sysoev.ru } 68812Sigor@sysoev.ru 68912Sigor@sysoev.ru nxt_debug(&engine->task, "kevent(%d) changes:%d timeout:%M", 69012Sigor@sysoev.ru engine->u.kqueue.fd, engine->u.kqueue.nchanges, timeout); 69112Sigor@sysoev.ru 69212Sigor@sysoev.ru nevents = kevent(engine->u.kqueue.fd, 69312Sigor@sysoev.ru engine->u.kqueue.changes, engine->u.kqueue.nchanges, 69412Sigor@sysoev.ru engine->u.kqueue.events, engine->u.kqueue.mevents, tp); 69512Sigor@sysoev.ru 69612Sigor@sysoev.ru err = (nevents == -1) ? nxt_errno : 0; 69712Sigor@sysoev.ru 69812Sigor@sysoev.ru nxt_thread_time_update(engine->task.thread); 69912Sigor@sysoev.ru 70012Sigor@sysoev.ru nxt_debug(&engine->task, "kevent(%d): %d", engine->u.kqueue.fd, nevents); 70112Sigor@sysoev.ru 70212Sigor@sysoev.ru if (nevents == -1) { 703564Svbart@nginx.com level = (err == NXT_EINTR) ? NXT_LOG_INFO : NXT_LOG_ALERT; 70412Sigor@sysoev.ru 70512Sigor@sysoev.ru nxt_log(&engine->task, level, "kevent(%d) failed %E", 70612Sigor@sysoev.ru engine->u.kqueue.fd, err); 70712Sigor@sysoev.ru 70812Sigor@sysoev.ru nxt_kqueue_error(engine); 70912Sigor@sysoev.ru return; 71012Sigor@sysoev.ru } 71112Sigor@sysoev.ru 71212Sigor@sysoev.ru engine->u.kqueue.nchanges = 0; 71312Sigor@sysoev.ru 71412Sigor@sysoev.ru for (i = 0; i < nevents; i++) { 71512Sigor@sysoev.ru 71612Sigor@sysoev.ru kev = &engine->u.kqueue.events[i]; 71712Sigor@sysoev.ru 71812Sigor@sysoev.ru nxt_debug(&engine->task, 71912Sigor@sysoev.ru (kev->ident > 0x8000000 && kev->ident != (uintptr_t) -1) ? 72012Sigor@sysoev.ru "kevent: id:%p ft:%d fl:%04Xd ff:%d d:%d ud:%p": 72112Sigor@sysoev.ru "kevent: id:%d ft:%d fl:%04Xd ff:%d d:%d ud:%p", 72212Sigor@sysoev.ru kev->ident, kev->filter, kev->flags, kev->fflags, 72312Sigor@sysoev.ru kev->data, kev->udata); 72412Sigor@sysoev.ru 72512Sigor@sysoev.ru error = (kev->flags & EV_ERROR); 72612Sigor@sysoev.ru 72712Sigor@sysoev.ru if (nxt_slow_path(error)) { 728564Svbart@nginx.com nxt_alert(&engine->task, 729564Svbart@nginx.com "kevent(%d) error %E on ident:%d filter:%d", 730564Svbart@nginx.com engine->u.kqueue.fd, kev->data, kev->ident, kev->filter); 73112Sigor@sysoev.ru } 73212Sigor@sysoev.ru 73312Sigor@sysoev.ru task = &engine->task; 73412Sigor@sysoev.ru wq = &engine->fast_work_queue; 73512Sigor@sysoev.ru handler = nxt_kqueue_fd_error_handler; 73612Sigor@sysoev.ru obj = nxt_kevent_get_udata(kev->udata); 73712Sigor@sysoev.ru 73812Sigor@sysoev.ru switch (kev->filter) { 73912Sigor@sysoev.ru 74012Sigor@sysoev.ru case EVFILT_READ: 74112Sigor@sysoev.ru ev = obj; 74212Sigor@sysoev.ru ev->read_ready = 1; 74312Sigor@sysoev.ru ev->kq_available = (int32_t) kev->data; 74412Sigor@sysoev.ru err = kev->fflags; 74512Sigor@sysoev.ru eof = (kev->flags & EV_EOF) != 0; 74612Sigor@sysoev.ru ev->kq_errno = err; 74712Sigor@sysoev.ru ev->kq_eof = eof; 74812Sigor@sysoev.ru 74920Sigor@sysoev.ru if (ev->read <= NXT_EVENT_BLOCKED) { 75012Sigor@sysoev.ru nxt_debug(ev->task, "blocked read event fd:%d", ev->fd); 75112Sigor@sysoev.ru continue; 75212Sigor@sysoev.ru } 75312Sigor@sysoev.ru 75412Sigor@sysoev.ru if ((kev->flags & NXT_KEVENT_ONESHOT) != 0) { 75512Sigor@sysoev.ru ev->read = NXT_EVENT_INACTIVE; 75612Sigor@sysoev.ru } 75712Sigor@sysoev.ru 75812Sigor@sysoev.ru if (nxt_slow_path(ev->kq_available == 0 && eof && err != 0)) { 75912Sigor@sysoev.ru error = 1; 76012Sigor@sysoev.ru } 76112Sigor@sysoev.ru 76212Sigor@sysoev.ru if (nxt_fast_path(!error)) { 76312Sigor@sysoev.ru handler = ev->read_handler; 76412Sigor@sysoev.ru wq = ev->read_work_queue; 76512Sigor@sysoev.ru } 76612Sigor@sysoev.ru 76712Sigor@sysoev.ru task = ev->task; 76812Sigor@sysoev.ru data = ev->data; 76912Sigor@sysoev.ru 77012Sigor@sysoev.ru break; 77112Sigor@sysoev.ru 77212Sigor@sysoev.ru case EVFILT_WRITE: 77312Sigor@sysoev.ru ev = obj; 77412Sigor@sysoev.ru ev->write_ready = 1; 77512Sigor@sysoev.ru err = kev->fflags; 77612Sigor@sysoev.ru eof = (kev->flags & EV_EOF) != 0; 77712Sigor@sysoev.ru ev->kq_errno = err; 77812Sigor@sysoev.ru ev->kq_eof = eof; 77912Sigor@sysoev.ru 78020Sigor@sysoev.ru if (ev->write <= NXT_EVENT_BLOCKED) { 78112Sigor@sysoev.ru nxt_debug(ev->task, "blocked write event fd:%d", ev->fd); 78212Sigor@sysoev.ru continue; 78312Sigor@sysoev.ru } 78412Sigor@sysoev.ru 78512Sigor@sysoev.ru if ((kev->flags & NXT_KEVENT_ONESHOT) != 0) { 78612Sigor@sysoev.ru ev->write = NXT_EVENT_INACTIVE; 78712Sigor@sysoev.ru } 78812Sigor@sysoev.ru 78912Sigor@sysoev.ru if (nxt_slow_path(eof && err != 0)) { 79012Sigor@sysoev.ru error = 1; 79112Sigor@sysoev.ru } 79212Sigor@sysoev.ru 79312Sigor@sysoev.ru if (nxt_fast_path(!error)) { 79412Sigor@sysoev.ru handler = ev->write_handler; 79512Sigor@sysoev.ru wq = ev->write_work_queue; 79612Sigor@sysoev.ru } 79712Sigor@sysoev.ru 79812Sigor@sysoev.ru task = ev->task; 79912Sigor@sysoev.ru data = ev->data; 80012Sigor@sysoev.ru 80112Sigor@sysoev.ru break; 80212Sigor@sysoev.ru 80312Sigor@sysoev.ru case EVFILT_VNODE: 80412Sigor@sysoev.ru fev = obj; 80512Sigor@sysoev.ru handler = fev->handler; 80612Sigor@sysoev.ru task = fev->task; 80712Sigor@sysoev.ru data = fev->data; 80812Sigor@sysoev.ru break; 80912Sigor@sysoev.ru 81012Sigor@sysoev.ru case EVFILT_SIGNAL: 81112Sigor@sysoev.ru sigev = obj; 81212Sigor@sysoev.ru obj = (void *) kev->ident; 81312Sigor@sysoev.ru handler = sigev->handler; 81412Sigor@sysoev.ru data = (void *) sigev->name; 81512Sigor@sysoev.ru break; 81612Sigor@sysoev.ru 81712Sigor@sysoev.ru #if (NXT_HAVE_EVFILT_USER) 81812Sigor@sysoev.ru 81912Sigor@sysoev.ru case EVFILT_USER: 82012Sigor@sysoev.ru handler = engine->u.kqueue.post_handler; 82112Sigor@sysoev.ru data = NULL; 82212Sigor@sysoev.ru break; 82312Sigor@sysoev.ru 82412Sigor@sysoev.ru #endif 82512Sigor@sysoev.ru 82612Sigor@sysoev.ru default: 82712Sigor@sysoev.ru 82812Sigor@sysoev.ru #if (NXT_DEBUG) 829564Svbart@nginx.com nxt_alert(&engine->task, 830564Svbart@nginx.com "unexpected kevent(%d) filter %d on ident %d", 831564Svbart@nginx.com engine->u.kqueue.fd, kev->filter, kev->ident); 83212Sigor@sysoev.ru #endif 83312Sigor@sysoev.ru 83412Sigor@sysoev.ru continue; 83512Sigor@sysoev.ru } 83612Sigor@sysoev.ru 83712Sigor@sysoev.ru nxt_work_queue_add(wq, handler, task, obj, data); 83812Sigor@sysoev.ru } 83912Sigor@sysoev.ru } 84012Sigor@sysoev.ru 84112Sigor@sysoev.ru 84212Sigor@sysoev.ru /* 84312Sigor@sysoev.ru * nxt_kqueue_event_conn_io_connect() eliminates the 84412Sigor@sysoev.ru * getsockopt() syscall to test pending connect() error. 84512Sigor@sysoev.ru */ 84612Sigor@sysoev.ru 84712Sigor@sysoev.ru static void 84862Sigor@sysoev.ru nxt_kqueue_conn_io_connect(nxt_task_t *task, void *obj, void *data) 84912Sigor@sysoev.ru { 85062Sigor@sysoev.ru nxt_conn_t *c; 85112Sigor@sysoev.ru nxt_event_engine_t *engine; 85212Sigor@sysoev.ru nxt_work_handler_t handler; 85312Sigor@sysoev.ru const nxt_event_conn_state_t *state; 85412Sigor@sysoev.ru 85512Sigor@sysoev.ru c = obj; 85612Sigor@sysoev.ru 85712Sigor@sysoev.ru state = c->write_state; 85812Sigor@sysoev.ru 859*1008Szelenkov@nginx.com switch (nxt_socket_connect(task, c->socket.fd, c->remote)) { 86012Sigor@sysoev.ru 86112Sigor@sysoev.ru case NXT_OK: 86212Sigor@sysoev.ru c->socket.write_ready = 1; 86312Sigor@sysoev.ru handler = state->ready_handler; 86412Sigor@sysoev.ru break; 86512Sigor@sysoev.ru 86612Sigor@sysoev.ru case NXT_AGAIN: 86762Sigor@sysoev.ru c->socket.write_handler = nxt_kqueue_conn_connected; 86862Sigor@sysoev.ru c->socket.error_handler = nxt_conn_connect_error; 86912Sigor@sysoev.ru 87012Sigor@sysoev.ru engine = task->thread->engine; 87162Sigor@sysoev.ru nxt_conn_timer(engine, c, state, &c->write_timer); 87212Sigor@sysoev.ru 87312Sigor@sysoev.ru nxt_kqueue_enable_write(engine, &c->socket); 87412Sigor@sysoev.ru return; 87512Sigor@sysoev.ru 87612Sigor@sysoev.ru case NXT_DECLINED: 87712Sigor@sysoev.ru handler = state->close_handler; 87812Sigor@sysoev.ru break; 87912Sigor@sysoev.ru 88012Sigor@sysoev.ru default: /* NXT_ERROR */ 88112Sigor@sysoev.ru handler = state->error_handler; 88212Sigor@sysoev.ru break; 88312Sigor@sysoev.ru } 88412Sigor@sysoev.ru 88513Sigor@sysoev.ru nxt_work_queue_add(c->write_work_queue, handler, task, c, data); 88612Sigor@sysoev.ru } 88712Sigor@sysoev.ru 88812Sigor@sysoev.ru 88912Sigor@sysoev.ru static void 89062Sigor@sysoev.ru nxt_kqueue_conn_connected(nxt_task_t *task, void *obj, void *data) 89112Sigor@sysoev.ru { 89262Sigor@sysoev.ru nxt_conn_t *c; 89312Sigor@sysoev.ru 89412Sigor@sysoev.ru c = obj; 89512Sigor@sysoev.ru 89662Sigor@sysoev.ru nxt_debug(task, "kqueue conn connected fd:%d", c->socket.fd); 89712Sigor@sysoev.ru 89812Sigor@sysoev.ru c->socket.write = NXT_EVENT_BLOCKED; 89912Sigor@sysoev.ru 90056Sigor@sysoev.ru if (c->write_state->timer_autoreset) { 90112Sigor@sysoev.ru nxt_timer_disable(task->thread->engine, &c->write_timer); 90212Sigor@sysoev.ru } 90312Sigor@sysoev.ru 90412Sigor@sysoev.ru nxt_work_queue_add(c->write_work_queue, c->write_state->ready_handler, 90512Sigor@sysoev.ru task, c, data); 90612Sigor@sysoev.ru } 90712Sigor@sysoev.ru 90812Sigor@sysoev.ru 90912Sigor@sysoev.ru static void 91012Sigor@sysoev.ru nxt_kqueue_listen_handler(nxt_task_t *task, void *obj, void *data) 91112Sigor@sysoev.ru { 91262Sigor@sysoev.ru nxt_listen_event_t *lev; 91312Sigor@sysoev.ru 91462Sigor@sysoev.ru lev = obj; 91512Sigor@sysoev.ru 91612Sigor@sysoev.ru nxt_debug(task, "kevent fd:%d avail:%D", 91762Sigor@sysoev.ru lev->socket.fd, lev->socket.kq_available); 91812Sigor@sysoev.ru 91962Sigor@sysoev.ru lev->ready = nxt_min(lev->batch, (uint32_t) lev->socket.kq_available); 92012Sigor@sysoev.ru 92162Sigor@sysoev.ru nxt_kqueue_conn_io_accept(task, lev, data); 92212Sigor@sysoev.ru } 92312Sigor@sysoev.ru 92412Sigor@sysoev.ru 92512Sigor@sysoev.ru static void 92662Sigor@sysoev.ru nxt_kqueue_conn_io_accept(nxt_task_t *task, void *obj, void *data) 92712Sigor@sysoev.ru { 928312Sigor@sysoev.ru socklen_t socklen; 92962Sigor@sysoev.ru nxt_conn_t *c; 93062Sigor@sysoev.ru nxt_socket_t s; 93162Sigor@sysoev.ru struct sockaddr *sa; 93262Sigor@sysoev.ru nxt_listen_event_t *lev; 93312Sigor@sysoev.ru 93462Sigor@sysoev.ru lev = obj; 93562Sigor@sysoev.ru c = lev->next; 93612Sigor@sysoev.ru 93762Sigor@sysoev.ru lev->ready--; 93862Sigor@sysoev.ru lev->socket.read_ready = (lev->ready != 0); 93912Sigor@sysoev.ru 94062Sigor@sysoev.ru lev->socket.kq_available--; 94162Sigor@sysoev.ru lev->socket.read_ready = (lev->socket.kq_available != 0); 94212Sigor@sysoev.ru 943312Sigor@sysoev.ru sa = &c->remote->u.sockaddr; 944312Sigor@sysoev.ru socklen = c->remote->socklen; 945312Sigor@sysoev.ru /* 946312Sigor@sysoev.ru * The returned socklen is ignored here, 947312Sigor@sysoev.ru * see comment in nxt_conn_io_accept(). 948312Sigor@sysoev.ru */ 949312Sigor@sysoev.ru s = accept(lev->socket.fd, sa, &socklen); 95012Sigor@sysoev.ru 95112Sigor@sysoev.ru if (s != -1) { 95212Sigor@sysoev.ru c->socket.fd = s; 95312Sigor@sysoev.ru 95462Sigor@sysoev.ru nxt_debug(task, "accept(%d): %d", lev->socket.fd, s); 95512Sigor@sysoev.ru 95662Sigor@sysoev.ru nxt_conn_accept(task, lev, c); 95712Sigor@sysoev.ru return; 95812Sigor@sysoev.ru } 95912Sigor@sysoev.ru 96062Sigor@sysoev.ru nxt_conn_accept_error(task, lev, "accept", nxt_errno); 96112Sigor@sysoev.ru } 96212Sigor@sysoev.ru 96312Sigor@sysoev.ru 96412Sigor@sysoev.ru /* 96562Sigor@sysoev.ru * nxt_kqueue_conn_io_read() is just a wrapper to eliminate the 96612Sigor@sysoev.ru * readv() or recv() syscall if a remote side just closed connection. 96712Sigor@sysoev.ru */ 96812Sigor@sysoev.ru 96912Sigor@sysoev.ru static void 97062Sigor@sysoev.ru nxt_kqueue_conn_io_read(nxt_task_t *task, void *obj, void *data) 97112Sigor@sysoev.ru { 97262Sigor@sysoev.ru nxt_conn_t *c; 97312Sigor@sysoev.ru 97412Sigor@sysoev.ru c = obj; 97512Sigor@sysoev.ru 97662Sigor@sysoev.ru nxt_debug(task, "kqueue conn read fd:%d", c->socket.fd); 97712Sigor@sysoev.ru 97812Sigor@sysoev.ru if (c->socket.kq_available == 0 && c->socket.kq_eof) { 97912Sigor@sysoev.ru nxt_debug(task, "kevent fd:%d eof", c->socket.fd); 98012Sigor@sysoev.ru 98112Sigor@sysoev.ru c->socket.closed = 1; 98212Sigor@sysoev.ru nxt_work_queue_add(c->read_work_queue, c->read_state->close_handler, 98312Sigor@sysoev.ru task, c, data); 98412Sigor@sysoev.ru return; 98512Sigor@sysoev.ru } 98612Sigor@sysoev.ru 98762Sigor@sysoev.ru nxt_conn_io_read(task, c, data); 98812Sigor@sysoev.ru } 98912Sigor@sysoev.ru 99012Sigor@sysoev.ru 99112Sigor@sysoev.ru /* 99262Sigor@sysoev.ru * nxt_kqueue_conn_io_recvbuf() is just wrapper around standard 99362Sigor@sysoev.ru * nxt_conn_io_recvbuf() to eliminate the readv() or recv() syscalls 99412Sigor@sysoev.ru * if there is no pending data or a remote side closed connection. 99512Sigor@sysoev.ru */ 99612Sigor@sysoev.ru 99712Sigor@sysoev.ru static ssize_t 99862Sigor@sysoev.ru nxt_kqueue_conn_io_recvbuf(nxt_conn_t *c, nxt_buf_t *b) 99912Sigor@sysoev.ru { 100012Sigor@sysoev.ru ssize_t n; 100112Sigor@sysoev.ru 100212Sigor@sysoev.ru if (c->socket.kq_available == 0 && c->socket.kq_eof) { 100312Sigor@sysoev.ru c->socket.closed = 1; 100412Sigor@sysoev.ru return 0; 100512Sigor@sysoev.ru } 100612Sigor@sysoev.ru 100762Sigor@sysoev.ru n = nxt_conn_io_recvbuf(c, b); 100812Sigor@sysoev.ru 100912Sigor@sysoev.ru if (n > 0) { 101012Sigor@sysoev.ru c->socket.kq_available -= n; 101112Sigor@sysoev.ru 101212Sigor@sysoev.ru if (c->socket.kq_available < 0) { 101312Sigor@sysoev.ru c->socket.kq_available = 0; 101412Sigor@sysoev.ru } 101512Sigor@sysoev.ru 101612Sigor@sysoev.ru nxt_debug(c->socket.task, "kevent fd:%d avail:%D eof:%d", 101712Sigor@sysoev.ru c->socket.fd, c->socket.kq_available, c->socket.kq_eof); 101812Sigor@sysoev.ru 101912Sigor@sysoev.ru c->socket.read_ready = (c->socket.kq_available != 0 102012Sigor@sysoev.ru || c->socket.kq_eof); 102112Sigor@sysoev.ru } 102212Sigor@sysoev.ru 102312Sigor@sysoev.ru return n; 102412Sigor@sysoev.ru } 1025