[nginx] Events: implemented epoll notification mechanism.
Valentin Bartenev
vbart at nginx.com
Wed Mar 18 15:57:58 UTC 2015
details: http://hg.nginx.org/nginx/rev/40e244e042a7
branches:
changeset: 6019:40e244e042a7
user: Valentin Bartenev <vbart at nginx.com>
date: Sat Mar 14 17:37:13 2015 +0300
description:
Events: implemented epoll notification mechanism.
diffstat:
auto/unix | 23 +++++
src/event/modules/ngx_epoll_module.c | 141 ++++++++++++++++++++++++++++++++++-
2 files changed, 162 insertions(+), 2 deletions(-)
diffs (253 lines):
diff -r 466bd63b63d1 -r 40e244e042a7 auto/unix
--- a/auto/unix Sat Mar 14 17:37:07 2015 +0300
+++ b/auto/unix Sat Mar 14 17:37:13 2015 +0300
@@ -450,6 +450,29 @@ Currently file AIO is supported on FreeB
END
exit 1
fi
+
+else
+
+ ngx_feature="eventfd()"
+ ngx_feature_name="NGX_HAVE_EVENTFD"
+ ngx_feature_run=no
+ ngx_feature_incs="#include <sys/eventfd.h>"
+ ngx_feature_path=
+ ngx_feature_libs=
+ ngx_feature_test="(void) eventfd(0, 0)"
+ . auto/feature
+
+ if [ $ngx_found = yes ]; then
+ have=NGX_HAVE_SYS_EVENTFD_H . auto/have
+ fi
+
+ if [ $ngx_found = no ]; then
+
+ ngx_feature="eventfd() (SYS_eventfd)"
+ ngx_feature_incs="#include <sys/syscall.h>"
+ ngx_feature_test="int n = SYS_eventfd"
+ . auto/feature
+ fi
fi
diff -r 466bd63b63d1 -r 40e244e042a7 src/event/modules/ngx_epoll_module.c
--- a/src/event/modules/ngx_epoll_module.c Sat Mar 14 17:37:07 2015 +0300
+++ b/src/event/modules/ngx_epoll_module.c Sat Mar 14 17:37:13 2015 +0300
@@ -70,12 +70,15 @@ int epoll_wait(int epfd, struct epoll_ev
return -1;
}
+#if (NGX_HAVE_EVENTFD)
+#define SYS_eventfd 323
+#endif
+
#if (NGX_HAVE_FILE_AIO)
#define SYS_io_setup 245
#define SYS_io_destroy 246
#define SYS_io_getevents 247
-#define SYS_eventfd 323
typedef u_int aio_context_t;
@@ -88,7 +91,7 @@ struct io_event {
#endif
-#endif
+#endif /* NGX_TEST_BUILD_EPOLL */
typedef struct {
@@ -98,6 +101,10 @@ typedef struct {
static ngx_int_t ngx_epoll_init(ngx_cycle_t *cycle, ngx_msec_t timer);
+#if (NGX_HAVE_EVENTFD)
+static ngx_int_t ngx_epoll_notify_init(ngx_log_t *log);
+static void ngx_epoll_notify_handler(ngx_event_t *ev);
+#endif
static void ngx_epoll_done(ngx_cycle_t *cycle);
static ngx_int_t ngx_epoll_add_event(ngx_event_t *ev, ngx_int_t event,
ngx_uint_t flags);
@@ -106,6 +113,9 @@ static ngx_int_t ngx_epoll_del_event(ngx
static ngx_int_t ngx_epoll_add_connection(ngx_connection_t *c);
static ngx_int_t ngx_epoll_del_connection(ngx_connection_t *c,
ngx_uint_t flags);
+#if (NGX_HAVE_EVENTFD)
+static ngx_int_t ngx_epoll_notify(ngx_event_handler_pt handler);
+#endif
static ngx_int_t ngx_epoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
ngx_uint_t flags);
@@ -120,6 +130,12 @@ static int ep = -1;
static struct epoll_event *event_list;
static ngx_uint_t nevents;
+#if (NGX_HAVE_EVENTFD)
+static int notify_fd = -1;
+static ngx_event_t notify_event;
+static ngx_connection_t notify_conn;
+#endif
+
#if (NGX_HAVE_FILE_AIO)
int ngx_eventfd = -1;
@@ -164,7 +180,11 @@ ngx_event_module_t ngx_epoll_module_ctx
ngx_epoll_del_event, /* disable an event */
ngx_epoll_add_connection, /* add an connection */
ngx_epoll_del_connection, /* delete an connection */
+#if (NGX_HAVE_EVENTFD)
+ ngx_epoll_notify, /* trigger a notify */
+#else
NULL, /* trigger a notify */
+#endif
NULL, /* process the changes */
ngx_epoll_process_events, /* process the events */
ngx_epoll_init, /* init the events */
@@ -308,6 +328,12 @@ ngx_epoll_init(ngx_cycle_t *cycle, ngx_m
return NGX_ERROR;
}
+#if (NGX_HAVE_EVENTFD)
+ if (ngx_epoll_notify_init(cycle->log) != NGX_OK) {
+ return NGX_ERROR;
+ }
+#endif
+
#if (NGX_HAVE_FILE_AIO)
ngx_epoll_aio_init(cycle, epcf);
@@ -345,6 +371,85 @@ ngx_epoll_init(ngx_cycle_t *cycle, ngx_m
}
+#if (NGX_HAVE_EVENTFD)
+
+static ngx_int_t
+ngx_epoll_notify_init(ngx_log_t *log)
+{
+ struct epoll_event ee;
+
+#if (NGX_HAVE_SYS_EVENTFD_H)
+ notify_fd = eventfd(0, 0);
+#else
+ notify_fd = syscall(SYS_eventfd, 0);
+#endif
+
+ if (notify_fd == -1) {
+ ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "eventfd() failed");
+ return NGX_ERROR;
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, log, 0,
+ "notify eventfd: %d", notify_fd);
+
+ notify_event.handler = ngx_epoll_notify_handler;
+ notify_event.log = log;
+ notify_event.active = 1;
+
+ notify_conn.fd = notify_fd;
+ notify_conn.read = ¬ify_event;
+ notify_conn.log = log;
+
+ ee.events = EPOLLIN|EPOLLET;
+ ee.data.ptr = ¬ify_conn;
+
+ if (epoll_ctl(ep, EPOLL_CTL_ADD, notify_fd, &ee) == -1) {
+ ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
+ "epoll_ctl(EPOLL_CTL_ADD, eventfd) failed");
+
+ if (close(notify_fd) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
+ "eventfd close() failed");
+ }
+
+ return NGX_ERROR;
+ }
+
+ return NGX_OK;
+}
+
+
+static void
+ngx_epoll_notify_handler(ngx_event_t *ev)
+{
+ ssize_t n;
+ uint64_t count;
+ ngx_err_t err;
+ ngx_event_handler_pt handler;
+
+ if (++ev->index == NGX_MAX_UINT32_VALUE) {
+ ev->index = 0;
+
+ n = read(notify_fd, &count, sizeof(uint64_t));
+
+ err = ngx_errno;
+
+ ngx_log_debug3(NGX_LOG_DEBUG_EVENT, ev->log, 0,
+ "read() eventfd %d: %z count:%uL", notify_fd, n, count);
+
+ if ((size_t) n != sizeof(uint64_t)) {
+ ngx_log_error(NGX_LOG_ALERT, ev->log, err,
+ "read() eventfd %d failed", notify_fd);
+ }
+ }
+
+ handler = ev->data;
+ handler(ev);
+}
+
+#endif
+
+
static void
ngx_epoll_done(ngx_cycle_t *cycle)
{
@@ -355,6 +460,17 @@ ngx_epoll_done(ngx_cycle_t *cycle)
ep = -1;
+#if (NGX_HAVE_EVENTFD)
+
+ if (close(notify_fd) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "eventfd close() failed");
+ }
+
+ notify_fd = -1;
+
+#endif
+
#if (NGX_HAVE_FILE_AIO)
if (ngx_eventfd != -1) {
@@ -561,6 +677,27 @@ ngx_epoll_del_connection(ngx_connection_
}
+#if (NGX_HAVE_EVENTFD)
+
+static ngx_int_t
+ngx_epoll_notify(ngx_event_handler_pt handler)
+{
+ static uint64_t inc = 1;
+
+ if ((size_t) write(notify_fd, &inc, sizeof(uint64_t)) != sizeof(uint64_t)) {
+ ngx_log_error(NGX_LOG_ALERT, notify_event.log, ngx_errno,
+ "write() to eventfd %d failed", notify_fd);
+ return NGX_ERROR;
+ }
+
+ notify_event.data = handler;
+
+ return NGX_OK;
+}
+
+#endif
+
+
static ngx_int_t
ngx_epoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags)
{
More information about the nginx-devel
mailing list