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 = { 11462Sigor@sysoev.ru nxt_kqueue_conn_io_connect, 11562Sigor@sysoev.ru nxt_kqueue_conn_io_accept, 11612Sigor@sysoev.ru 11762Sigor@sysoev.ru nxt_kqueue_conn_io_read, 11862Sigor@sysoev.ru nxt_kqueue_conn_io_recvbuf, 11962Sigor@sysoev.ru nxt_conn_io_recv, 12012Sigor@sysoev.ru 12113Sigor@sysoev.ru nxt_conn_io_write, 12212Sigor@sysoev.ru nxt_event_conn_io_write_chunk, 12312Sigor@sysoev.ru 12412Sigor@sysoev.ru #if (NXT_HAVE_FREEBSD_SENDFILE) 12512Sigor@sysoev.ru nxt_freebsd_event_conn_io_sendfile, 12612Sigor@sysoev.ru #elif (NXT_HAVE_MACOSX_SENDFILE) 12712Sigor@sysoev.ru nxt_macosx_event_conn_io_sendfile, 12812Sigor@sysoev.ru #else 12912Sigor@sysoev.ru nxt_event_conn_io_sendbuf, 13012Sigor@sysoev.ru #endif 13112Sigor@sysoev.ru 13212Sigor@sysoev.ru nxt_event_conn_io_writev, 13312Sigor@sysoev.ru nxt_event_conn_io_send, 13412Sigor@sysoev.ru 13562Sigor@sysoev.ru nxt_conn_io_shutdown, 13612Sigor@sysoev.ru }; 13712Sigor@sysoev.ru 13812Sigor@sysoev.ru 13912Sigor@sysoev.ru const nxt_event_interface_t nxt_kqueue_engine = { 14012Sigor@sysoev.ru "kqueue", 14112Sigor@sysoev.ru nxt_kqueue_create, 14212Sigor@sysoev.ru nxt_kqueue_free, 14312Sigor@sysoev.ru nxt_kqueue_enable, 14412Sigor@sysoev.ru nxt_kqueue_disable, 14512Sigor@sysoev.ru nxt_kqueue_delete, 14612Sigor@sysoev.ru nxt_kqueue_close, 14712Sigor@sysoev.ru nxt_kqueue_enable_read, 14812Sigor@sysoev.ru nxt_kqueue_enable_write, 14912Sigor@sysoev.ru nxt_kqueue_disable_read, 15012Sigor@sysoev.ru nxt_kqueue_disable_write, 15112Sigor@sysoev.ru nxt_kqueue_block_read, 15212Sigor@sysoev.ru nxt_kqueue_block_write, 15312Sigor@sysoev.ru nxt_kqueue_oneshot_read, 15412Sigor@sysoev.ru nxt_kqueue_oneshot_write, 15512Sigor@sysoev.ru nxt_kqueue_enable_accept, 15612Sigor@sysoev.ru nxt_kqueue_enable_file, 15712Sigor@sysoev.ru nxt_kqueue_close_file, 15812Sigor@sysoev.ru #if (NXT_HAVE_EVFILT_USER) 15912Sigor@sysoev.ru nxt_kqueue_enable_post, 16012Sigor@sysoev.ru nxt_kqueue_signal, 16112Sigor@sysoev.ru #else 16212Sigor@sysoev.ru NULL, 16312Sigor@sysoev.ru NULL, 16412Sigor@sysoev.ru #endif 16512Sigor@sysoev.ru nxt_kqueue_poll, 16612Sigor@sysoev.ru 16762Sigor@sysoev.ru &nxt_kqueue_conn_io, 16812Sigor@sysoev.ru 16912Sigor@sysoev.ru NXT_FILE_EVENTS, 17012Sigor@sysoev.ru NXT_SIGNAL_EVENTS, 17112Sigor@sysoev.ru }; 17212Sigor@sysoev.ru 17312Sigor@sysoev.ru 17412Sigor@sysoev.ru static nxt_int_t 17512Sigor@sysoev.ru nxt_kqueue_create(nxt_event_engine_t *engine, nxt_uint_t mchanges, 17612Sigor@sysoev.ru nxt_uint_t mevents) 17712Sigor@sysoev.ru { 17812Sigor@sysoev.ru const nxt_sig_event_t *sigev; 17912Sigor@sysoev.ru 18012Sigor@sysoev.ru engine->u.kqueue.fd = -1; 18112Sigor@sysoev.ru engine->u.kqueue.mchanges = mchanges; 18212Sigor@sysoev.ru engine->u.kqueue.mevents = mevents; 18312Sigor@sysoev.ru engine->u.kqueue.pid = nxt_pid; 18412Sigor@sysoev.ru 18512Sigor@sysoev.ru engine->u.kqueue.changes = nxt_malloc(sizeof(struct kevent) * mchanges); 18612Sigor@sysoev.ru if (engine->u.kqueue.changes == NULL) { 18712Sigor@sysoev.ru goto fail; 18812Sigor@sysoev.ru } 18912Sigor@sysoev.ru 19012Sigor@sysoev.ru engine->u.kqueue.events = nxt_malloc(sizeof(struct kevent) * mevents); 19112Sigor@sysoev.ru if (engine->u.kqueue.events == NULL) { 19212Sigor@sysoev.ru goto fail; 19312Sigor@sysoev.ru } 19412Sigor@sysoev.ru 19512Sigor@sysoev.ru engine->u.kqueue.fd = kqueue(); 19612Sigor@sysoev.ru if (engine->u.kqueue.fd == -1) { 19712Sigor@sysoev.ru nxt_log(&engine->task, NXT_LOG_CRIT, "kqueue() failed %E", nxt_errno); 19812Sigor@sysoev.ru goto fail; 19912Sigor@sysoev.ru } 20012Sigor@sysoev.ru 20112Sigor@sysoev.ru nxt_debug(&engine->task, "kqueue(): %d", engine->u.kqueue.fd); 20212Sigor@sysoev.ru 20312Sigor@sysoev.ru if (engine->signals != NULL) { 20412Sigor@sysoev.ru for (sigev = engine->signals->sigev; sigev->signo != 0; sigev++) { 20512Sigor@sysoev.ru if (nxt_kqueue_add_signal(engine, sigev) != NXT_OK) { 20612Sigor@sysoev.ru goto fail; 20712Sigor@sysoev.ru } 20812Sigor@sysoev.ru } 20912Sigor@sysoev.ru } 21012Sigor@sysoev.ru 21112Sigor@sysoev.ru return NXT_OK; 21212Sigor@sysoev.ru 21312Sigor@sysoev.ru fail: 21412Sigor@sysoev.ru 21512Sigor@sysoev.ru nxt_kqueue_free(engine); 21612Sigor@sysoev.ru 21712Sigor@sysoev.ru return NXT_ERROR; 21812Sigor@sysoev.ru } 21912Sigor@sysoev.ru 22012Sigor@sysoev.ru 22112Sigor@sysoev.ru static void 22212Sigor@sysoev.ru nxt_kqueue_free(nxt_event_engine_t *engine) 22312Sigor@sysoev.ru { 22412Sigor@sysoev.ru nxt_fd_t fd; 22512Sigor@sysoev.ru 22612Sigor@sysoev.ru fd = engine->u.kqueue.fd; 22712Sigor@sysoev.ru 22812Sigor@sysoev.ru nxt_debug(&engine->task, "kqueue %d free", fd); 22912Sigor@sysoev.ru 23012Sigor@sysoev.ru if (fd != -1 && engine->u.kqueue.pid == nxt_pid) { 23112Sigor@sysoev.ru /* kqueue is not inherited by fork() */ 23212Sigor@sysoev.ru 23312Sigor@sysoev.ru if (close(fd) != 0) { 23412Sigor@sysoev.ru nxt_log(&engine->task, NXT_LOG_CRIT, "kqueue close(%d) failed %E", 23512Sigor@sysoev.ru fd, nxt_errno); 23612Sigor@sysoev.ru } 23712Sigor@sysoev.ru } 23812Sigor@sysoev.ru 23912Sigor@sysoev.ru nxt_free(engine->u.kqueue.events); 24012Sigor@sysoev.ru nxt_free(engine->u.kqueue.changes); 24112Sigor@sysoev.ru 24212Sigor@sysoev.ru nxt_memzero(&engine->u.kqueue, sizeof(nxt_kqueue_engine_t)); 24312Sigor@sysoev.ru } 24412Sigor@sysoev.ru 24512Sigor@sysoev.ru 24612Sigor@sysoev.ru static void 24712Sigor@sysoev.ru nxt_kqueue_enable(nxt_event_engine_t *engine, nxt_fd_event_t *ev) 24812Sigor@sysoev.ru { 24912Sigor@sysoev.ru nxt_kqueue_enable_read(engine, ev); 25012Sigor@sysoev.ru nxt_kqueue_enable_write(engine, ev); 25112Sigor@sysoev.ru } 25212Sigor@sysoev.ru 25312Sigor@sysoev.ru 25412Sigor@sysoev.ru /* 25512Sigor@sysoev.ru * EV_DISABLE is better because it eliminates in-kernel memory 25612Sigor@sysoev.ru * deallocation and probable subsequent allocation with a lock acquiring. 25712Sigor@sysoev.ru */ 25812Sigor@sysoev.ru 25912Sigor@sysoev.ru static void 26012Sigor@sysoev.ru nxt_kqueue_disable(nxt_event_engine_t *engine, nxt_fd_event_t *ev) 26112Sigor@sysoev.ru { 26212Sigor@sysoev.ru if (ev->read != NXT_EVENT_INACTIVE) { 26312Sigor@sysoev.ru ev->read = NXT_EVENT_INACTIVE; 26412Sigor@sysoev.ru nxt_kqueue_fd_set(engine, ev, EVFILT_READ, EV_DISABLE); 26512Sigor@sysoev.ru } 26612Sigor@sysoev.ru 26712Sigor@sysoev.ru if (ev->write != NXT_EVENT_INACTIVE) { 26812Sigor@sysoev.ru ev->write = NXT_EVENT_INACTIVE; 26912Sigor@sysoev.ru nxt_kqueue_fd_set(engine, ev, EVFILT_WRITE, EV_DISABLE); 27012Sigor@sysoev.ru } 27112Sigor@sysoev.ru } 27212Sigor@sysoev.ru 27312Sigor@sysoev.ru 27412Sigor@sysoev.ru static void 27512Sigor@sysoev.ru nxt_kqueue_delete(nxt_event_engine_t *engine, nxt_fd_event_t *ev) 27612Sigor@sysoev.ru { 27712Sigor@sysoev.ru if (ev->read != NXT_EVENT_INACTIVE) { 27812Sigor@sysoev.ru ev->read = NXT_EVENT_INACTIVE; 27912Sigor@sysoev.ru nxt_kqueue_fd_set(engine, ev, EVFILT_READ, EV_DELETE); 28012Sigor@sysoev.ru } 28112Sigor@sysoev.ru 28212Sigor@sysoev.ru if (ev->write != NXT_EVENT_INACTIVE) { 28312Sigor@sysoev.ru ev->write = NXT_EVENT_INACTIVE; 28412Sigor@sysoev.ru nxt_kqueue_fd_set(engine, ev, EVFILT_WRITE, EV_DELETE); 28512Sigor@sysoev.ru } 28612Sigor@sysoev.ru } 28712Sigor@sysoev.ru 28812Sigor@sysoev.ru 28912Sigor@sysoev.ru /* 29012Sigor@sysoev.ru * kqueue(2): 29112Sigor@sysoev.ru * 29212Sigor@sysoev.ru * Calling close() on a file descriptor will remove any kevents that 29312Sigor@sysoev.ru * reference the descriptor. 29412Sigor@sysoev.ru * 29555Sigor@sysoev.ru * So nxt_kqueue_close() returns true only if there are pending events. 29612Sigor@sysoev.ru */ 29712Sigor@sysoev.ru 29812Sigor@sysoev.ru static nxt_bool_t 29912Sigor@sysoev.ru nxt_kqueue_close(nxt_event_engine_t *engine, nxt_fd_event_t *ev) 30012Sigor@sysoev.ru { 30155Sigor@sysoev.ru struct kevent *kev, *end; 30255Sigor@sysoev.ru 30312Sigor@sysoev.ru ev->read = NXT_EVENT_INACTIVE; 30412Sigor@sysoev.ru ev->write = NXT_EVENT_INACTIVE; 30512Sigor@sysoev.ru 30655Sigor@sysoev.ru end = &engine->u.kqueue.changes[engine->u.kqueue.nchanges]; 30755Sigor@sysoev.ru 30855Sigor@sysoev.ru for (kev = engine->u.kqueue.changes; kev < end; kev++) { 30955Sigor@sysoev.ru if (kev->ident == (uintptr_t) ev->fd) { 31055Sigor@sysoev.ru return 1; 31155Sigor@sysoev.ru } 31255Sigor@sysoev.ru } 31355Sigor@sysoev.ru 31455Sigor@sysoev.ru return 0; 31512Sigor@sysoev.ru } 31612Sigor@sysoev.ru 31712Sigor@sysoev.ru 31812Sigor@sysoev.ru /* 31912Sigor@sysoev.ru * The kqueue event engine uses only three states: inactive, blocked, and 32012Sigor@sysoev.ru * active. An active oneshot event is marked as it is in the default 32112Sigor@sysoev.ru * state. The event will be converted eventually to the default EV_CLEAR 32212Sigor@sysoev.ru * mode after it will become inactive after delivery. 32312Sigor@sysoev.ru */ 32412Sigor@sysoev.ru 32512Sigor@sysoev.ru static void 32612Sigor@sysoev.ru nxt_kqueue_enable_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) 32712Sigor@sysoev.ru { 32812Sigor@sysoev.ru if (ev->read == NXT_EVENT_INACTIVE) { 32912Sigor@sysoev.ru nxt_kqueue_fd_set(engine, ev, EVFILT_READ, 33012Sigor@sysoev.ru EV_ADD | EV_ENABLE | EV_CLEAR); 33112Sigor@sysoev.ru } 33212Sigor@sysoev.ru 33312Sigor@sysoev.ru ev->read = NXT_EVENT_ACTIVE; 33412Sigor@sysoev.ru } 33512Sigor@sysoev.ru 33612Sigor@sysoev.ru 33712Sigor@sysoev.ru static void 33812Sigor@sysoev.ru nxt_kqueue_enable_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) 33912Sigor@sysoev.ru { 34012Sigor@sysoev.ru if (ev->write == NXT_EVENT_INACTIVE) { 34112Sigor@sysoev.ru nxt_kqueue_fd_set(engine, ev, EVFILT_WRITE, 34212Sigor@sysoev.ru EV_ADD | EV_ENABLE | EV_CLEAR); 34312Sigor@sysoev.ru } 34412Sigor@sysoev.ru 34512Sigor@sysoev.ru ev->write = NXT_EVENT_ACTIVE; 34612Sigor@sysoev.ru } 34712Sigor@sysoev.ru 34812Sigor@sysoev.ru 34912Sigor@sysoev.ru static void 35012Sigor@sysoev.ru nxt_kqueue_disable_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) 35112Sigor@sysoev.ru { 35212Sigor@sysoev.ru ev->read = NXT_EVENT_INACTIVE; 35312Sigor@sysoev.ru 35412Sigor@sysoev.ru nxt_kqueue_fd_set(engine, ev, EVFILT_READ, EV_DISABLE); 35512Sigor@sysoev.ru } 35612Sigor@sysoev.ru 35712Sigor@sysoev.ru 35812Sigor@sysoev.ru static void 35912Sigor@sysoev.ru nxt_kqueue_disable_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) 36012Sigor@sysoev.ru { 36112Sigor@sysoev.ru ev->write = NXT_EVENT_INACTIVE; 36212Sigor@sysoev.ru 36312Sigor@sysoev.ru nxt_kqueue_fd_set(engine, ev, EVFILT_WRITE, EV_DISABLE); 36412Sigor@sysoev.ru } 36512Sigor@sysoev.ru 36612Sigor@sysoev.ru 36712Sigor@sysoev.ru static void 36812Sigor@sysoev.ru nxt_kqueue_block_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) 36912Sigor@sysoev.ru { 37012Sigor@sysoev.ru if (ev->read != NXT_EVENT_INACTIVE) { 37112Sigor@sysoev.ru ev->read = NXT_EVENT_BLOCKED; 37212Sigor@sysoev.ru } 37312Sigor@sysoev.ru } 37412Sigor@sysoev.ru 37512Sigor@sysoev.ru 37612Sigor@sysoev.ru static void 37712Sigor@sysoev.ru nxt_kqueue_block_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) 37812Sigor@sysoev.ru { 37912Sigor@sysoev.ru if (ev->write != NXT_EVENT_INACTIVE) { 38012Sigor@sysoev.ru ev->write = NXT_EVENT_BLOCKED; 38112Sigor@sysoev.ru } 38212Sigor@sysoev.ru } 38312Sigor@sysoev.ru 38412Sigor@sysoev.ru 38512Sigor@sysoev.ru static void 38612Sigor@sysoev.ru nxt_kqueue_oneshot_read(nxt_event_engine_t *engine, nxt_fd_event_t *ev) 38712Sigor@sysoev.ru { 38812Sigor@sysoev.ru ev->write = NXT_EVENT_ACTIVE; 38912Sigor@sysoev.ru 39012Sigor@sysoev.ru nxt_kqueue_fd_set(engine, ev, EVFILT_WRITE, 39112Sigor@sysoev.ru EV_ADD | EV_ENABLE | NXT_KEVENT_ONESHOT); 39212Sigor@sysoev.ru } 39312Sigor@sysoev.ru 39412Sigor@sysoev.ru 39512Sigor@sysoev.ru static void 39612Sigor@sysoev.ru nxt_kqueue_oneshot_write(nxt_event_engine_t *engine, nxt_fd_event_t *ev) 39712Sigor@sysoev.ru { 39812Sigor@sysoev.ru ev->write = NXT_EVENT_ACTIVE; 39912Sigor@sysoev.ru 40012Sigor@sysoev.ru nxt_kqueue_fd_set(engine, ev, EVFILT_WRITE, 40112Sigor@sysoev.ru EV_ADD | EV_ENABLE | NXT_KEVENT_ONESHOT); 40212Sigor@sysoev.ru } 40312Sigor@sysoev.ru 40412Sigor@sysoev.ru 40512Sigor@sysoev.ru static void 40612Sigor@sysoev.ru nxt_kqueue_enable_accept(nxt_event_engine_t *engine, nxt_fd_event_t *ev) 40712Sigor@sysoev.ru { 40812Sigor@sysoev.ru ev->read = NXT_EVENT_ACTIVE; 40912Sigor@sysoev.ru ev->read_handler = nxt_kqueue_listen_handler; 41012Sigor@sysoev.ru 41112Sigor@sysoev.ru nxt_kqueue_fd_set(engine, ev, EVFILT_READ, EV_ADD | EV_ENABLE); 41212Sigor@sysoev.ru } 41312Sigor@sysoev.ru 41412Sigor@sysoev.ru 41512Sigor@sysoev.ru static void 41662Sigor@sysoev.ru nxt_kqueue_enable_file(nxt_event_engine_t *engine, nxt_file_event_t *ev) 41712Sigor@sysoev.ru { 41812Sigor@sysoev.ru struct kevent *kev; 41912Sigor@sysoev.ru 42012Sigor@sysoev.ru const nxt_int_t flags = EV_ADD | EV_ENABLE | EV_ONESHOT; 42112Sigor@sysoev.ru const nxt_uint_t fflags = NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND 42212Sigor@sysoev.ru | NOTE_ATTRIB | NOTE_RENAME | NOTE_REVOKE; 42312Sigor@sysoev.ru 42412Sigor@sysoev.ru nxt_debug(&engine->task, "kevent(%d) set: id:%d ft:%i fl:%04Xd, ff:%04XuD", 42512Sigor@sysoev.ru engine->u.kqueue.fd, ev->file->fd, EVFILT_VNODE, flags, fflags); 42612Sigor@sysoev.ru 42712Sigor@sysoev.ru kev = nxt_kqueue_get_kevent(engine); 42812Sigor@sysoev.ru 42912Sigor@sysoev.ru kev->ident = ev->file->fd; 43012Sigor@sysoev.ru kev->filter = EVFILT_VNODE; 43112Sigor@sysoev.ru kev->flags = flags; 43212Sigor@sysoev.ru kev->fflags = fflags; 43312Sigor@sysoev.ru kev->data = 0; 43412Sigor@sysoev.ru kev->udata = nxt_kevent_set_udata(ev); 43512Sigor@sysoev.ru } 43612Sigor@sysoev.ru 43712Sigor@sysoev.ru 43812Sigor@sysoev.ru static void 43962Sigor@sysoev.ru nxt_kqueue_close_file(nxt_event_engine_t *engine, nxt_file_event_t *ev) 44012Sigor@sysoev.ru { 44112Sigor@sysoev.ru /* TODO: pending event. */ 44212Sigor@sysoev.ru } 44312Sigor@sysoev.ru 44412Sigor@sysoev.ru 44512Sigor@sysoev.ru static void 44612Sigor@sysoev.ru nxt_kqueue_fd_set(nxt_event_engine_t *engine, nxt_fd_event_t *ev, 44712Sigor@sysoev.ru nxt_int_t filter, nxt_uint_t flags) 44812Sigor@sysoev.ru { 44912Sigor@sysoev.ru struct kevent *kev; 45012Sigor@sysoev.ru 45112Sigor@sysoev.ru nxt_debug(ev->task, "kevent(%d) set event: id:%d ft:%i fl:%04Xui", 45212Sigor@sysoev.ru engine->u.kqueue.fd, ev->fd, filter, flags); 45312Sigor@sysoev.ru 45412Sigor@sysoev.ru kev = nxt_kqueue_get_kevent(engine); 45512Sigor@sysoev.ru 45612Sigor@sysoev.ru kev->ident = ev->fd; 45712Sigor@sysoev.ru kev->filter = filter; 45812Sigor@sysoev.ru kev->flags = flags; 45912Sigor@sysoev.ru kev->fflags = 0; 46012Sigor@sysoev.ru kev->data = 0; 46112Sigor@sysoev.ru kev->udata = nxt_kevent_set_udata(ev); 46212Sigor@sysoev.ru } 46312Sigor@sysoev.ru 46412Sigor@sysoev.ru 46512Sigor@sysoev.ru static struct kevent * 46612Sigor@sysoev.ru nxt_kqueue_get_kevent(nxt_event_engine_t *engine) 46712Sigor@sysoev.ru { 46812Sigor@sysoev.ru int ret, nchanges; 46912Sigor@sysoev.ru 47012Sigor@sysoev.ru nchanges = engine->u.kqueue.nchanges; 47112Sigor@sysoev.ru 47212Sigor@sysoev.ru if (nxt_slow_path(nchanges >= engine->u.kqueue.mchanges)) { 47312Sigor@sysoev.ru 47412Sigor@sysoev.ru nxt_debug(&engine->task, "kevent(%d) changes:%d", 47512Sigor@sysoev.ru engine->u.kqueue.fd, nchanges); 47612Sigor@sysoev.ru 47712Sigor@sysoev.ru ret = kevent(engine->u.kqueue.fd, engine->u.kqueue.changes, nchanges, 47812Sigor@sysoev.ru NULL, 0, NULL); 47912Sigor@sysoev.ru 48012Sigor@sysoev.ru if (nxt_slow_path(ret != 0)) { 48112Sigor@sysoev.ru nxt_log(&engine->task, NXT_LOG_CRIT, "kevent(%d) failed %E", 48212Sigor@sysoev.ru engine->u.kqueue.fd, nxt_errno); 48312Sigor@sysoev.ru 48412Sigor@sysoev.ru nxt_kqueue_error(engine); 48512Sigor@sysoev.ru } 48612Sigor@sysoev.ru 48712Sigor@sysoev.ru engine->u.kqueue.nchanges = 0; 48812Sigor@sysoev.ru } 48912Sigor@sysoev.ru 49012Sigor@sysoev.ru return &engine->u.kqueue.changes[engine->u.kqueue.nchanges++]; 49112Sigor@sysoev.ru } 49212Sigor@sysoev.ru 49312Sigor@sysoev.ru 49412Sigor@sysoev.ru static void 49512Sigor@sysoev.ru nxt_kqueue_error(nxt_event_engine_t *engine) 49612Sigor@sysoev.ru { 49712Sigor@sysoev.ru struct kevent *kev, *end; 49812Sigor@sysoev.ru nxt_fd_event_t *ev; 49962Sigor@sysoev.ru nxt_file_event_t *fev; 50012Sigor@sysoev.ru nxt_work_queue_t *wq; 50112Sigor@sysoev.ru 50212Sigor@sysoev.ru wq = &engine->fast_work_queue; 50312Sigor@sysoev.ru end = &engine->u.kqueue.changes[engine->u.kqueue.nchanges]; 50412Sigor@sysoev.ru 50512Sigor@sysoev.ru for (kev = engine->u.kqueue.changes; kev < end; kev++) { 50612Sigor@sysoev.ru 50712Sigor@sysoev.ru switch (kev->filter) { 50812Sigor@sysoev.ru 50912Sigor@sysoev.ru case EVFILT_READ: 51012Sigor@sysoev.ru case EVFILT_WRITE: 51112Sigor@sysoev.ru ev = nxt_kevent_get_udata(kev->udata); 51212Sigor@sysoev.ru nxt_work_queue_add(wq, nxt_kqueue_fd_error_handler, 51312Sigor@sysoev.ru ev->task, ev, ev->data); 51412Sigor@sysoev.ru break; 51512Sigor@sysoev.ru 51612Sigor@sysoev.ru case EVFILT_VNODE: 51712Sigor@sysoev.ru fev = nxt_kevent_get_udata(kev->udata); 51812Sigor@sysoev.ru nxt_work_queue_add(wq, nxt_kqueue_file_error_handler, 51912Sigor@sysoev.ru fev->task, fev, fev->data); 52012Sigor@sysoev.ru break; 52112Sigor@sysoev.ru } 52212Sigor@sysoev.ru } 52312Sigor@sysoev.ru } 52412Sigor@sysoev.ru 52512Sigor@sysoev.ru 52612Sigor@sysoev.ru static void 52712Sigor@sysoev.ru nxt_kqueue_fd_error_handler(nxt_task_t *task, void *obj, void *data) 52812Sigor@sysoev.ru { 52912Sigor@sysoev.ru nxt_fd_event_t *ev; 53012Sigor@sysoev.ru 53112Sigor@sysoev.ru ev = obj; 53212Sigor@sysoev.ru 53353Sigor@sysoev.ru nxt_debug(task, "kqueue fd error handler fd:%d", ev->fd); 53453Sigor@sysoev.ru 53512Sigor@sysoev.ru if (ev->kq_eof && ev->kq_errno != 0) { 53612Sigor@sysoev.ru ev->error = ev->kq_errno; 53713Sigor@sysoev.ru nxt_log(task, nxt_socket_error_level(ev->kq_errno), 53812Sigor@sysoev.ru "kevent() reported error on descriptor %d %E", 53912Sigor@sysoev.ru ev->fd, ev->kq_errno); 54012Sigor@sysoev.ru } 54112Sigor@sysoev.ru 54212Sigor@sysoev.ru ev->read = NXT_EVENT_INACTIVE; 54312Sigor@sysoev.ru ev->write = NXT_EVENT_INACTIVE; 54412Sigor@sysoev.ru ev->error = ev->kq_errno; 54512Sigor@sysoev.ru 54612Sigor@sysoev.ru ev->error_handler(task, ev, data); 54712Sigor@sysoev.ru } 54812Sigor@sysoev.ru 54912Sigor@sysoev.ru 55012Sigor@sysoev.ru static void 55112Sigor@sysoev.ru nxt_kqueue_file_error_handler(nxt_task_t *task, void *obj, void *data) 55212Sigor@sysoev.ru { 55362Sigor@sysoev.ru nxt_file_event_t *ev; 55412Sigor@sysoev.ru 55512Sigor@sysoev.ru ev = obj; 55612Sigor@sysoev.ru 55753Sigor@sysoev.ru nxt_debug(task, "kqueue file error handler fd:%d", ev->file->fd); 55853Sigor@sysoev.ru 55912Sigor@sysoev.ru ev->handler(task, ev, data); 56012Sigor@sysoev.ru } 56112Sigor@sysoev.ru 56212Sigor@sysoev.ru 56312Sigor@sysoev.ru static nxt_int_t 56412Sigor@sysoev.ru nxt_kqueue_add_signal(nxt_event_engine_t *engine, const nxt_sig_event_t *sigev) 56512Sigor@sysoev.ru { 56612Sigor@sysoev.ru int signo; 56712Sigor@sysoev.ru struct kevent kev; 56812Sigor@sysoev.ru struct sigaction sa; 56912Sigor@sysoev.ru 57012Sigor@sysoev.ru signo = sigev->signo; 57112Sigor@sysoev.ru 57212Sigor@sysoev.ru nxt_memzero(&sa, sizeof(struct sigaction)); 57312Sigor@sysoev.ru sigemptyset(&sa.sa_mask); 57412Sigor@sysoev.ru 57512Sigor@sysoev.ru /* 57612Sigor@sysoev.ru * SIGCHLD must not be set to SIG_IGN, since kqueue cannot catch 57712Sigor@sysoev.ru * this signal. It should be set to SIG_DFL instead. And although 57812Sigor@sysoev.ru * SIGCHLD default action is also ignoring, nevertheless SIG_DFL 57912Sigor@sysoev.ru * allows kqueue to catch the signal. 58012Sigor@sysoev.ru */ 58112Sigor@sysoev.ru sa.sa_handler = (signo == SIGCHLD) ? SIG_DFL : SIG_IGN; 58212Sigor@sysoev.ru 58312Sigor@sysoev.ru if (sigaction(signo, &sa, NULL) != 0) { 58412Sigor@sysoev.ru nxt_log(&engine->task, NXT_LOG_CRIT, "sigaction(%d) failed %E", 58512Sigor@sysoev.ru signo, nxt_errno); 58612Sigor@sysoev.ru 58712Sigor@sysoev.ru return NXT_ERROR; 58812Sigor@sysoev.ru } 58912Sigor@sysoev.ru 59012Sigor@sysoev.ru nxt_debug(&engine->task, "kevent(%d) signo:%d (%s)", 59112Sigor@sysoev.ru engine->u.kqueue.fd, signo, sigev->name); 59212Sigor@sysoev.ru 59312Sigor@sysoev.ru kev.ident = signo; 59412Sigor@sysoev.ru kev.filter = EVFILT_SIGNAL; 59512Sigor@sysoev.ru kev.flags = EV_ADD; 59612Sigor@sysoev.ru kev.fflags = 0; 59712Sigor@sysoev.ru kev.data = 0; 59812Sigor@sysoev.ru kev.udata = nxt_kevent_set_udata(sigev); 59912Sigor@sysoev.ru 60012Sigor@sysoev.ru if (kevent(engine->u.kqueue.fd, &kev, 1, NULL, 0, NULL) == 0) { 60112Sigor@sysoev.ru return NXT_OK; 60212Sigor@sysoev.ru } 60312Sigor@sysoev.ru 60412Sigor@sysoev.ru nxt_log(&engine->task, NXT_LOG_CRIT, "kevent(%d) failed %E", 60512Sigor@sysoev.ru kqueue, nxt_errno); 60612Sigor@sysoev.ru 60712Sigor@sysoev.ru return NXT_ERROR; 60812Sigor@sysoev.ru } 60912Sigor@sysoev.ru 61012Sigor@sysoev.ru 61112Sigor@sysoev.ru #if (NXT_HAVE_EVFILT_USER) 61212Sigor@sysoev.ru 61312Sigor@sysoev.ru static nxt_int_t 61412Sigor@sysoev.ru nxt_kqueue_enable_post(nxt_event_engine_t *engine, nxt_work_handler_t handler) 61512Sigor@sysoev.ru { 61612Sigor@sysoev.ru struct kevent kev; 61712Sigor@sysoev.ru 61812Sigor@sysoev.ru /* EVFILT_USER must be added to a kqueue before it can be triggered. */ 61912Sigor@sysoev.ru 62012Sigor@sysoev.ru kev.ident = 0; 62112Sigor@sysoev.ru kev.filter = EVFILT_USER; 62212Sigor@sysoev.ru kev.flags = EV_ADD | EV_CLEAR; 62312Sigor@sysoev.ru kev.fflags = 0; 62412Sigor@sysoev.ru kev.data = 0; 62512Sigor@sysoev.ru kev.udata = NULL; 62612Sigor@sysoev.ru 62712Sigor@sysoev.ru engine->u.kqueue.post_handler = handler; 62812Sigor@sysoev.ru 62912Sigor@sysoev.ru if (kevent(engine->u.kqueue.fd, &kev, 1, NULL, 0, NULL) == 0) { 63012Sigor@sysoev.ru return NXT_OK; 63112Sigor@sysoev.ru } 63212Sigor@sysoev.ru 63312Sigor@sysoev.ru nxt_log(&engine->task, NXT_LOG_CRIT, "kevent(%d) failed %E", 63412Sigor@sysoev.ru engine->u.kqueue.fd, nxt_errno); 63512Sigor@sysoev.ru 63612Sigor@sysoev.ru return NXT_ERROR; 63712Sigor@sysoev.ru } 63812Sigor@sysoev.ru 63912Sigor@sysoev.ru 64012Sigor@sysoev.ru static void 64112Sigor@sysoev.ru nxt_kqueue_signal(nxt_event_engine_t *engine, nxt_uint_t signo) 64212Sigor@sysoev.ru { 64312Sigor@sysoev.ru struct kevent kev; 64412Sigor@sysoev.ru 64512Sigor@sysoev.ru /* 64612Sigor@sysoev.ru * kqueue has a builtin signal processing support, so the function 64712Sigor@sysoev.ru * is used only to post events and the signo argument is ignored. 64812Sigor@sysoev.ru */ 64912Sigor@sysoev.ru 65012Sigor@sysoev.ru kev.ident = 0; 65112Sigor@sysoev.ru kev.filter = EVFILT_USER; 65212Sigor@sysoev.ru kev.flags = 0; 65312Sigor@sysoev.ru kev.fflags = NOTE_TRIGGER; 65412Sigor@sysoev.ru kev.data = 0; 65512Sigor@sysoev.ru kev.udata = NULL; 65612Sigor@sysoev.ru 65712Sigor@sysoev.ru if (kevent(engine->u.kqueue.fd, &kev, 1, NULL, 0, NULL) != 0) { 65812Sigor@sysoev.ru nxt_log(&engine->task, NXT_LOG_CRIT, "kevent(%d) failed %E", 65912Sigor@sysoev.ru engine->u.kqueue.fd, nxt_errno); 66012Sigor@sysoev.ru } 66112Sigor@sysoev.ru } 66212Sigor@sysoev.ru 66312Sigor@sysoev.ru #endif 66412Sigor@sysoev.ru 66512Sigor@sysoev.ru 66612Sigor@sysoev.ru static void 66712Sigor@sysoev.ru nxt_kqueue_poll(nxt_event_engine_t *engine, nxt_msec_t timeout) 66812Sigor@sysoev.ru { 66912Sigor@sysoev.ru int nevents; 67012Sigor@sysoev.ru void *obj, *data; 67112Sigor@sysoev.ru nxt_int_t i; 67212Sigor@sysoev.ru nxt_err_t err; 67312Sigor@sysoev.ru nxt_uint_t level; 67412Sigor@sysoev.ru nxt_bool_t error, eof; 67512Sigor@sysoev.ru nxt_task_t *task; 67612Sigor@sysoev.ru struct kevent *kev; 67712Sigor@sysoev.ru nxt_fd_event_t *ev; 67812Sigor@sysoev.ru nxt_sig_event_t *sigev; 67912Sigor@sysoev.ru struct timespec ts, *tp; 68062Sigor@sysoev.ru nxt_file_event_t *fev; 68112Sigor@sysoev.ru nxt_work_queue_t *wq; 68212Sigor@sysoev.ru nxt_work_handler_t handler; 68312Sigor@sysoev.ru 68412Sigor@sysoev.ru if (timeout == NXT_INFINITE_MSEC) { 68512Sigor@sysoev.ru tp = NULL; 68612Sigor@sysoev.ru 68712Sigor@sysoev.ru } else { 68812Sigor@sysoev.ru ts.tv_sec = timeout / 1000; 68912Sigor@sysoev.ru ts.tv_nsec = (timeout % 1000) * 1000000; 69012Sigor@sysoev.ru tp = &ts; 69112Sigor@sysoev.ru } 69212Sigor@sysoev.ru 69312Sigor@sysoev.ru nxt_debug(&engine->task, "kevent(%d) changes:%d timeout:%M", 69412Sigor@sysoev.ru engine->u.kqueue.fd, engine->u.kqueue.nchanges, timeout); 69512Sigor@sysoev.ru 69612Sigor@sysoev.ru nevents = kevent(engine->u.kqueue.fd, 69712Sigor@sysoev.ru engine->u.kqueue.changes, engine->u.kqueue.nchanges, 69812Sigor@sysoev.ru engine->u.kqueue.events, engine->u.kqueue.mevents, tp); 69912Sigor@sysoev.ru 70012Sigor@sysoev.ru err = (nevents == -1) ? nxt_errno : 0; 70112Sigor@sysoev.ru 70212Sigor@sysoev.ru nxt_thread_time_update(engine->task.thread); 70312Sigor@sysoev.ru 70412Sigor@sysoev.ru nxt_debug(&engine->task, "kevent(%d): %d", engine->u.kqueue.fd, nevents); 70512Sigor@sysoev.ru 70612Sigor@sysoev.ru if (nevents == -1) { 70712Sigor@sysoev.ru level = (err == NXT_EINTR) ? NXT_LOG_INFO : NXT_LOG_CRIT; 70812Sigor@sysoev.ru 70912Sigor@sysoev.ru nxt_log(&engine->task, level, "kevent(%d) failed %E", 71012Sigor@sysoev.ru engine->u.kqueue.fd, err); 71112Sigor@sysoev.ru 71212Sigor@sysoev.ru nxt_kqueue_error(engine); 71312Sigor@sysoev.ru return; 71412Sigor@sysoev.ru } 71512Sigor@sysoev.ru 71612Sigor@sysoev.ru engine->u.kqueue.nchanges = 0; 71712Sigor@sysoev.ru 71812Sigor@sysoev.ru for (i = 0; i < nevents; i++) { 71912Sigor@sysoev.ru 72012Sigor@sysoev.ru kev = &engine->u.kqueue.events[i]; 72112Sigor@sysoev.ru 72212Sigor@sysoev.ru nxt_debug(&engine->task, 72312Sigor@sysoev.ru (kev->ident > 0x8000000 && kev->ident != (uintptr_t) -1) ? 72412Sigor@sysoev.ru "kevent: id:%p ft:%d fl:%04Xd ff:%d d:%d ud:%p": 72512Sigor@sysoev.ru "kevent: id:%d ft:%d fl:%04Xd ff:%d d:%d ud:%p", 72612Sigor@sysoev.ru kev->ident, kev->filter, kev->flags, kev->fflags, 72712Sigor@sysoev.ru kev->data, kev->udata); 72812Sigor@sysoev.ru 72912Sigor@sysoev.ru error = (kev->flags & EV_ERROR); 73012Sigor@sysoev.ru 73112Sigor@sysoev.ru if (nxt_slow_path(error)) { 73212Sigor@sysoev.ru nxt_log(&engine->task, NXT_LOG_CRIT, 73312Sigor@sysoev.ru "kevent(%d) error %E on ident:%d filter:%d", 73412Sigor@sysoev.ru engine->u.kqueue.fd, kev->data, kev->ident, kev->filter); 73512Sigor@sysoev.ru } 73612Sigor@sysoev.ru 73712Sigor@sysoev.ru task = &engine->task; 73812Sigor@sysoev.ru wq = &engine->fast_work_queue; 73912Sigor@sysoev.ru handler = nxt_kqueue_fd_error_handler; 74012Sigor@sysoev.ru obj = nxt_kevent_get_udata(kev->udata); 74112Sigor@sysoev.ru 74212Sigor@sysoev.ru switch (kev->filter) { 74312Sigor@sysoev.ru 74412Sigor@sysoev.ru case EVFILT_READ: 74512Sigor@sysoev.ru ev = obj; 74612Sigor@sysoev.ru ev->read_ready = 1; 74712Sigor@sysoev.ru ev->kq_available = (int32_t) kev->data; 74812Sigor@sysoev.ru err = kev->fflags; 74912Sigor@sysoev.ru eof = (kev->flags & EV_EOF) != 0; 75012Sigor@sysoev.ru ev->kq_errno = err; 75112Sigor@sysoev.ru ev->kq_eof = eof; 75212Sigor@sysoev.ru 75320Sigor@sysoev.ru if (ev->read <= NXT_EVENT_BLOCKED) { 75412Sigor@sysoev.ru nxt_debug(ev->task, "blocked read event fd:%d", ev->fd); 75512Sigor@sysoev.ru continue; 75612Sigor@sysoev.ru } 75712Sigor@sysoev.ru 75812Sigor@sysoev.ru if ((kev->flags & NXT_KEVENT_ONESHOT) != 0) { 75912Sigor@sysoev.ru ev->read = NXT_EVENT_INACTIVE; 76012Sigor@sysoev.ru } 76112Sigor@sysoev.ru 76212Sigor@sysoev.ru if (nxt_slow_path(ev->kq_available == 0 && eof && err != 0)) { 76312Sigor@sysoev.ru error = 1; 76412Sigor@sysoev.ru } 76512Sigor@sysoev.ru 76612Sigor@sysoev.ru if (nxt_fast_path(!error)) { 76712Sigor@sysoev.ru handler = ev->read_handler; 76812Sigor@sysoev.ru wq = ev->read_work_queue; 76912Sigor@sysoev.ru } 77012Sigor@sysoev.ru 77112Sigor@sysoev.ru task = ev->task; 77212Sigor@sysoev.ru data = ev->data; 77312Sigor@sysoev.ru 77412Sigor@sysoev.ru break; 77512Sigor@sysoev.ru 77612Sigor@sysoev.ru case EVFILT_WRITE: 77712Sigor@sysoev.ru ev = obj; 77812Sigor@sysoev.ru ev->write_ready = 1; 77912Sigor@sysoev.ru err = kev->fflags; 78012Sigor@sysoev.ru eof = (kev->flags & EV_EOF) != 0; 78112Sigor@sysoev.ru ev->kq_errno = err; 78212Sigor@sysoev.ru ev->kq_eof = eof; 78312Sigor@sysoev.ru 78420Sigor@sysoev.ru if (ev->write <= NXT_EVENT_BLOCKED) { 78512Sigor@sysoev.ru nxt_debug(ev->task, "blocked write event fd:%d", ev->fd); 78612Sigor@sysoev.ru continue; 78712Sigor@sysoev.ru } 78812Sigor@sysoev.ru 78912Sigor@sysoev.ru if ((kev->flags & NXT_KEVENT_ONESHOT) != 0) { 79012Sigor@sysoev.ru ev->write = NXT_EVENT_INACTIVE; 79112Sigor@sysoev.ru } 79212Sigor@sysoev.ru 79312Sigor@sysoev.ru if (nxt_slow_path(eof && err != 0)) { 79412Sigor@sysoev.ru error = 1; 79512Sigor@sysoev.ru } 79612Sigor@sysoev.ru 79712Sigor@sysoev.ru if (nxt_fast_path(!error)) { 79812Sigor@sysoev.ru handler = ev->write_handler; 79912Sigor@sysoev.ru wq = ev->write_work_queue; 80012Sigor@sysoev.ru } 80112Sigor@sysoev.ru 80212Sigor@sysoev.ru task = ev->task; 80312Sigor@sysoev.ru data = ev->data; 80412Sigor@sysoev.ru 80512Sigor@sysoev.ru break; 80612Sigor@sysoev.ru 80712Sigor@sysoev.ru case EVFILT_VNODE: 80812Sigor@sysoev.ru fev = obj; 80912Sigor@sysoev.ru handler = fev->handler; 81012Sigor@sysoev.ru task = fev->task; 81112Sigor@sysoev.ru data = fev->data; 81212Sigor@sysoev.ru break; 81312Sigor@sysoev.ru 81412Sigor@sysoev.ru case EVFILT_SIGNAL: 81512Sigor@sysoev.ru sigev = obj; 81612Sigor@sysoev.ru obj = (void *) kev->ident; 81712Sigor@sysoev.ru handler = sigev->handler; 81812Sigor@sysoev.ru data = (void *) sigev->name; 81912Sigor@sysoev.ru break; 82012Sigor@sysoev.ru 82112Sigor@sysoev.ru #if (NXT_HAVE_EVFILT_USER) 82212Sigor@sysoev.ru 82312Sigor@sysoev.ru case EVFILT_USER: 82412Sigor@sysoev.ru handler = engine->u.kqueue.post_handler; 82512Sigor@sysoev.ru data = NULL; 82612Sigor@sysoev.ru break; 82712Sigor@sysoev.ru 82812Sigor@sysoev.ru #endif 82912Sigor@sysoev.ru 83012Sigor@sysoev.ru default: 83112Sigor@sysoev.ru 83212Sigor@sysoev.ru #if (NXT_DEBUG) 83312Sigor@sysoev.ru nxt_log(&engine->task, NXT_LOG_CRIT, 83412Sigor@sysoev.ru "unexpected kevent(%d) filter %d on ident %d", 83512Sigor@sysoev.ru engine->u.kqueue.fd, kev->filter, kev->ident); 83612Sigor@sysoev.ru #endif 83712Sigor@sysoev.ru 83812Sigor@sysoev.ru continue; 83912Sigor@sysoev.ru } 84012Sigor@sysoev.ru 84112Sigor@sysoev.ru nxt_work_queue_add(wq, handler, task, obj, data); 84212Sigor@sysoev.ru } 84312Sigor@sysoev.ru } 84412Sigor@sysoev.ru 84512Sigor@sysoev.ru 84612Sigor@sysoev.ru /* 84712Sigor@sysoev.ru * nxt_kqueue_event_conn_io_connect() eliminates the 84812Sigor@sysoev.ru * getsockopt() syscall to test pending connect() error. 84912Sigor@sysoev.ru */ 85012Sigor@sysoev.ru 85112Sigor@sysoev.ru static void 85262Sigor@sysoev.ru nxt_kqueue_conn_io_connect(nxt_task_t *task, void *obj, void *data) 85312Sigor@sysoev.ru { 85462Sigor@sysoev.ru nxt_conn_t *c; 85512Sigor@sysoev.ru nxt_event_engine_t *engine; 85612Sigor@sysoev.ru nxt_work_handler_t handler; 85712Sigor@sysoev.ru const nxt_event_conn_state_t *state; 85812Sigor@sysoev.ru 85912Sigor@sysoev.ru c = obj; 86012Sigor@sysoev.ru 86112Sigor@sysoev.ru state = c->write_state; 86212Sigor@sysoev.ru 86313Sigor@sysoev.ru switch (nxt_socket_connect(task, c->socket.fd, c->remote) ){ 86412Sigor@sysoev.ru 86512Sigor@sysoev.ru case NXT_OK: 86612Sigor@sysoev.ru c->socket.write_ready = 1; 86712Sigor@sysoev.ru handler = state->ready_handler; 86812Sigor@sysoev.ru break; 86912Sigor@sysoev.ru 87012Sigor@sysoev.ru case NXT_AGAIN: 87162Sigor@sysoev.ru c->socket.write_handler = nxt_kqueue_conn_connected; 87262Sigor@sysoev.ru c->socket.error_handler = nxt_conn_connect_error; 87312Sigor@sysoev.ru 87412Sigor@sysoev.ru engine = task->thread->engine; 87562Sigor@sysoev.ru nxt_conn_timer(engine, c, state, &c->write_timer); 87612Sigor@sysoev.ru 87712Sigor@sysoev.ru nxt_kqueue_enable_write(engine, &c->socket); 87812Sigor@sysoev.ru return; 87912Sigor@sysoev.ru 88012Sigor@sysoev.ru case NXT_DECLINED: 88112Sigor@sysoev.ru handler = state->close_handler; 88212Sigor@sysoev.ru break; 88312Sigor@sysoev.ru 88412Sigor@sysoev.ru default: /* NXT_ERROR */ 88512Sigor@sysoev.ru handler = state->error_handler; 88612Sigor@sysoev.ru break; 88712Sigor@sysoev.ru } 88812Sigor@sysoev.ru 88913Sigor@sysoev.ru nxt_work_queue_add(c->write_work_queue, handler, task, c, data); 89012Sigor@sysoev.ru } 89112Sigor@sysoev.ru 89212Sigor@sysoev.ru 89312Sigor@sysoev.ru static void 89462Sigor@sysoev.ru nxt_kqueue_conn_connected(nxt_task_t *task, void *obj, void *data) 89512Sigor@sysoev.ru { 89662Sigor@sysoev.ru nxt_conn_t *c; 89712Sigor@sysoev.ru 89812Sigor@sysoev.ru c = obj; 89912Sigor@sysoev.ru 90062Sigor@sysoev.ru nxt_debug(task, "kqueue conn connected fd:%d", c->socket.fd); 90112Sigor@sysoev.ru 90212Sigor@sysoev.ru c->socket.write = NXT_EVENT_BLOCKED; 90312Sigor@sysoev.ru 90456Sigor@sysoev.ru if (c->write_state->timer_autoreset) { 90512Sigor@sysoev.ru nxt_timer_disable(task->thread->engine, &c->write_timer); 90612Sigor@sysoev.ru } 90712Sigor@sysoev.ru 90812Sigor@sysoev.ru nxt_work_queue_add(c->write_work_queue, c->write_state->ready_handler, 90912Sigor@sysoev.ru task, c, data); 91012Sigor@sysoev.ru } 91112Sigor@sysoev.ru 91212Sigor@sysoev.ru 91312Sigor@sysoev.ru static void 91412Sigor@sysoev.ru nxt_kqueue_listen_handler(nxt_task_t *task, void *obj, void *data) 91512Sigor@sysoev.ru { 91662Sigor@sysoev.ru nxt_listen_event_t *lev; 91712Sigor@sysoev.ru 91862Sigor@sysoev.ru lev = obj; 91912Sigor@sysoev.ru 92012Sigor@sysoev.ru nxt_debug(task, "kevent fd:%d avail:%D", 92162Sigor@sysoev.ru lev->socket.fd, lev->socket.kq_available); 92212Sigor@sysoev.ru 92362Sigor@sysoev.ru lev->ready = nxt_min(lev->batch, (uint32_t) lev->socket.kq_available); 92412Sigor@sysoev.ru 92562Sigor@sysoev.ru nxt_kqueue_conn_io_accept(task, lev, data); 92612Sigor@sysoev.ru } 92712Sigor@sysoev.ru 92812Sigor@sysoev.ru 92912Sigor@sysoev.ru static void 93062Sigor@sysoev.ru nxt_kqueue_conn_io_accept(nxt_task_t *task, void *obj, void *data) 93112Sigor@sysoev.ru { 932*312Sigor@sysoev.ru socklen_t socklen; 93362Sigor@sysoev.ru nxt_conn_t *c; 93462Sigor@sysoev.ru nxt_socket_t s; 93562Sigor@sysoev.ru struct sockaddr *sa; 93662Sigor@sysoev.ru nxt_listen_event_t *lev; 93712Sigor@sysoev.ru 93862Sigor@sysoev.ru lev = obj; 93962Sigor@sysoev.ru c = lev->next; 94012Sigor@sysoev.ru 94162Sigor@sysoev.ru lev->ready--; 94262Sigor@sysoev.ru lev->socket.read_ready = (lev->ready != 0); 94312Sigor@sysoev.ru 94462Sigor@sysoev.ru lev->socket.kq_available--; 94562Sigor@sysoev.ru lev->socket.read_ready = (lev->socket.kq_available != 0); 94612Sigor@sysoev.ru 947*312Sigor@sysoev.ru sa = &c->remote->u.sockaddr; 948*312Sigor@sysoev.ru socklen = c->remote->socklen; 949*312Sigor@sysoev.ru /* 950*312Sigor@sysoev.ru * The returned socklen is ignored here, 951*312Sigor@sysoev.ru * see comment in nxt_conn_io_accept(). 952*312Sigor@sysoev.ru */ 953*312Sigor@sysoev.ru s = accept(lev->socket.fd, sa, &socklen); 95412Sigor@sysoev.ru 95512Sigor@sysoev.ru if (s != -1) { 95612Sigor@sysoev.ru c->socket.fd = s; 95712Sigor@sysoev.ru 95862Sigor@sysoev.ru nxt_debug(task, "accept(%d): %d", lev->socket.fd, s); 95912Sigor@sysoev.ru 96062Sigor@sysoev.ru nxt_conn_accept(task, lev, c); 96112Sigor@sysoev.ru return; 96212Sigor@sysoev.ru } 96312Sigor@sysoev.ru 96462Sigor@sysoev.ru nxt_conn_accept_error(task, lev, "accept", nxt_errno); 96512Sigor@sysoev.ru } 96612Sigor@sysoev.ru 96712Sigor@sysoev.ru 96812Sigor@sysoev.ru /* 96962Sigor@sysoev.ru * nxt_kqueue_conn_io_read() is just a wrapper to eliminate the 97012Sigor@sysoev.ru * readv() or recv() syscall if a remote side just closed connection. 97112Sigor@sysoev.ru */ 97212Sigor@sysoev.ru 97312Sigor@sysoev.ru static void 97462Sigor@sysoev.ru nxt_kqueue_conn_io_read(nxt_task_t *task, void *obj, void *data) 97512Sigor@sysoev.ru { 97662Sigor@sysoev.ru nxt_conn_t *c; 97712Sigor@sysoev.ru 97812Sigor@sysoev.ru c = obj; 97912Sigor@sysoev.ru 98062Sigor@sysoev.ru nxt_debug(task, "kqueue conn read fd:%d", c->socket.fd); 98112Sigor@sysoev.ru 98212Sigor@sysoev.ru if (c->socket.kq_available == 0 && c->socket.kq_eof) { 98312Sigor@sysoev.ru nxt_debug(task, "kevent fd:%d eof", c->socket.fd); 98412Sigor@sysoev.ru 98512Sigor@sysoev.ru c->socket.closed = 1; 98612Sigor@sysoev.ru nxt_work_queue_add(c->read_work_queue, c->read_state->close_handler, 98712Sigor@sysoev.ru task, c, data); 98812Sigor@sysoev.ru return; 98912Sigor@sysoev.ru } 99012Sigor@sysoev.ru 99162Sigor@sysoev.ru nxt_conn_io_read(task, c, data); 99212Sigor@sysoev.ru } 99312Sigor@sysoev.ru 99412Sigor@sysoev.ru 99512Sigor@sysoev.ru /* 99662Sigor@sysoev.ru * nxt_kqueue_conn_io_recvbuf() is just wrapper around standard 99762Sigor@sysoev.ru * nxt_conn_io_recvbuf() to eliminate the readv() or recv() syscalls 99812Sigor@sysoev.ru * if there is no pending data or a remote side closed connection. 99912Sigor@sysoev.ru */ 100012Sigor@sysoev.ru 100112Sigor@sysoev.ru static ssize_t 100262Sigor@sysoev.ru nxt_kqueue_conn_io_recvbuf(nxt_conn_t *c, nxt_buf_t *b) 100312Sigor@sysoev.ru { 100412Sigor@sysoev.ru ssize_t n; 100512Sigor@sysoev.ru 100612Sigor@sysoev.ru if (c->socket.kq_available == 0 && c->socket.kq_eof) { 100712Sigor@sysoev.ru c->socket.closed = 1; 100812Sigor@sysoev.ru return 0; 100912Sigor@sysoev.ru } 101012Sigor@sysoev.ru 101162Sigor@sysoev.ru n = nxt_conn_io_recvbuf(c, b); 101212Sigor@sysoev.ru 101312Sigor@sysoev.ru if (n > 0) { 101412Sigor@sysoev.ru c->socket.kq_available -= n; 101512Sigor@sysoev.ru 101612Sigor@sysoev.ru if (c->socket.kq_available < 0) { 101712Sigor@sysoev.ru c->socket.kq_available = 0; 101812Sigor@sysoev.ru } 101912Sigor@sysoev.ru 102012Sigor@sysoev.ru nxt_debug(c->socket.task, "kevent fd:%d avail:%D eof:%d", 102112Sigor@sysoev.ru c->socket.fd, c->socket.kq_available, c->socket.kq_eof); 102212Sigor@sysoev.ru 102312Sigor@sysoev.ru c->socket.read_ready = (c->socket.kq_available != 0 102412Sigor@sysoev.ru || c->socket.kq_eof); 102512Sigor@sysoev.ru } 102612Sigor@sysoev.ru 102712Sigor@sysoev.ru return n; 102812Sigor@sysoev.ru } 1029