diff options
author | Eric Wong <normalperson@yhbt.net> | 2013-02-10 11:37:34 +0000 |
---|---|---|
committer | Eric Wong <normalperson@yhbt.net> | 2013-02-11 00:39:16 +0000 |
commit | 5537c96848f483d403da1ed663809681e7b09f3b (patch) | |
tree | 6a1afef2cc6ac2af758cbad65385c7c8323ca2c2 | |
parent | 955991aae8c3da5a13e34e929188db3fd9216a0e (diff) | |
download | cmogstored-5537c96848f483d403da1ed663809681e7b09f3b.tar.gz |
eventfd uses fewer resources than a pipe, so create less overhead for our users by using eventfd instead of a pipe.
-rw-r--r-- | Makefile.am | 3 | ||||
-rw-r--r-- | cmogstored.h | 8 | ||||
-rw-r--r-- | configure.ac | 3 | ||||
-rw-r--r-- | notify.c | 69 | ||||
-rw-r--r-- | notify.h | 16 | ||||
-rw-r--r-- | selfwake.c | 40 | ||||
-rw-r--r-- | selfwake_eventfd.h | 36 | ||||
-rw-r--r-- | selfwake_pipe.h | 35 |
8 files changed, 151 insertions, 59 deletions
diff --git a/Makefile.am b/Makefile.am index 557ecca..8ec860c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -77,6 +77,9 @@ mog_src += queue_kqueue.c mog_src += queue_kqueue.h mog_src += queue_loop.c mog_src += queue_step.c +mog_src += selfwake_eventfd.h +mog_src += selfwake_pipe.h +mog_src += selfwake.c mog_src += sig.c mog_src += svc.c mog_src += svc_dev.c diff --git a/cmogstored.h b/cmogstored.h index 769825b..2fe0f05 100644 --- a/cmogstored.h +++ b/cmogstored.h @@ -246,8 +246,8 @@ enum mog_fd_type { MOG_FD_TYPE_HTTPGET, MOG_FD_TYPE_MGMT, MOG_FD_TYPE_IOSTAT, - MOG_FD_TYPE_NOTIFYRD, - MOG_FD_TYPE_NOTIFYWR, + MOG_FD_TYPE_SELFWAKE, + MOG_FD_TYPE_SELFPIPE, MOG_FD_TYPE_ACCEPT, MOG_FD_TYPE_FILE, MOG_FD_TYPE_QUEUE, @@ -264,8 +264,8 @@ struct mog_fd { struct mog_mgmt mgmt; struct mog_http http; struct mog_iostat iostat; - struct mog_notifyrd notifyrd; - struct mog_notifywr notifywr; + struct mog_selfwake selfwake; + struct mog_selfpipe selfpipe; struct mog_file file; struct mog_queue queue; struct mog_svc *svc; diff --git a/configure.ac b/configure.ac index b63ab40..ca202da 100644 --- a/configure.ac +++ b/configure.ac @@ -34,7 +34,8 @@ AC_C_FLEXIBLE_ARRAY_MEMBER dnl gnulib *at functions aren't thread-safe, ask for the real thing AC_CHECK_FUNCS([openat renameat mkdirat fstatat unlinkat]) -AC_CHECK_FUNCS([epoll_wait]) +AC_CHECK_HEADERS_ONCE([sys/eventfd.h]) +AC_CHECK_FUNCS([epoll_wait eventfd]) dnl libkqueue should work in the future AC_CHECK_FUNCS([kqueue]) @@ -4,8 +4,8 @@ */ #include "cmogstored.h" -static struct mog_fd *notifywr_mfd; -static struct mog_notifywr *notifywr; +static struct mog_fd *notify_mfd; +static struct mog_selfwake *notify; static time_t usage_file_updated_at; static time_t usage_file_interval = 10; struct mog_queue *mog_notify_queue; @@ -13,11 +13,6 @@ struct mog_queue *mog_notify_queue; void mog_notify_init(void) { const char *interval = getenv("MOG_DISK_USAGE_INTERVAL"); - struct mog_fd *mfd; - int self_pipe[2]; - - if (pipe2(self_pipe, O_NONBLOCK | O_CLOEXEC) < 0) - die_errno("failed to init self-pipe"); if (interval) { int i = atoi(interval); @@ -27,16 +22,16 @@ void mog_notify_init(void) } assert(mog_notify_queue == NULL && "notify queue already initialized"); - mog_notify_queue = mog_queue_new(); - - mfd = mog_fd_init(self_pipe[0], MOG_FD_TYPE_NOTIFYRD); - mfd->as.notifyrd.queue = mog_notify_queue; - mog_idleq_add(mog_notify_queue, mfd, MOG_QEV_RD); + assert(notify == NULL && "notify already initialized"); + assert(notify_mfd == NULL && "notify_mfd already initialized"); - notifywr_mfd = mfd = mog_fd_init(self_pipe[1], MOG_FD_TYPE_NOTIFYWR); - notifywr = &mfd->as.notifywr; - notifywr->queue = mog_notify_queue; - memset(notifywr->notes, 0, sizeof(notifywr->notes)); + mog_notify_queue = mog_queue_new(); + notify_mfd = mog_selfwake_new(); + notify = ¬ify_mfd->as.selfwake; + assert(notify->writer && "notify writer not initialized"); + notify->queue = mog_notify_queue; + mog_idleq_add(notify->queue, notify_mfd, MOG_QEV_RD); + memset(¬ify->as.notes, 0, sizeof(notify->as.notes)); } static void global_mkusage(void) @@ -47,22 +42,13 @@ static void global_mkusage(void) static inline bool note_xchg(enum mog_notification note, int from, int to) { - return __sync_bool_compare_and_swap(¬ifywr->notes[note], from, to); + return __sync_bool_compare_and_swap(¬ify->as.notes[note], from, to); } /* drain the pipe and process notifications */ -static void notifyrd_queue_step(struct mog_fd *mfd) +static void note_queue_step(struct mog_fd *mfd) { - char buf[128]; - ssize_t r; - struct mog_notifyrd *notifyrd = &mfd->as.notifyrd; - - do { - r = read(mfd->fd, buf, sizeof(buf)); - } while (r > 0); - assert(r < 0 && - (errno == EAGAIN || errno == EINTR) - && "self-pipe read failed"); + mog_selfwake_drain(mfd); if (note_xchg(MOG_NOTIFY_DEVICE_REFRESH, 1, 0)) global_mkusage(); @@ -70,13 +56,13 @@ static void notifyrd_queue_step(struct mog_fd *mfd) if (note_xchg(MOG_NOTIFY_SET_N_THREADS, 1, 0)) mog_thrpool_process_queue(); - mog_idleq_push(notifyrd->queue, mfd, MOG_QEV_RD); + mog_idleq_push(mfd->as.selfwake.queue, mfd, MOG_QEV_RD); } static void notify_queue_step(struct mog_fd *mfd) { switch (mfd->fd_type) { - case MOG_FD_TYPE_NOTIFYRD: notifyrd_queue_step(mfd); return; + case MOG_FD_TYPE_SELFWAKE: note_queue_step(mfd); return; case MOG_FD_TYPE_IOSTAT: mog_iostat_queue_step(mfd); return; default: assert(0 && mfd->fd_type && "bad fd_type in queue"); @@ -98,7 +84,7 @@ void mog_notify_wait(bool need_usage_file) * epoll_wait() with timeout==0 can avoid some slow paths, * so take anything that's already ready before sleeping */ - while ((mfd = mog_idleq_wait(notifywr->queue, 0))) + while ((mfd = mog_idleq_wait(notify->queue, 0))) notify_queue_step(mfd); if (need_usage_file == false) @@ -109,7 +95,7 @@ void mog_notify_wait(bool need_usage_file) timeout = 0; mog_intr_enable(); - mfd = mog_idleq_wait(notifywr->queue, timeout); + mfd = mog_idleq_wait(notify->queue, timeout); mog_intr_disable(); if (mfd) notify_queue_step(mfd); @@ -118,8 +104,6 @@ void mog_notify_wait(bool need_usage_file) /* this is async-signal safe */ void mog_notify(enum mog_notification note) { - ssize_t w; - switch (note) { case MOG_NOTIFY_DEVICE_REFRESH: case MOG_NOTIFY_SET_N_THREADS: @@ -128,20 +112,5 @@ void mog_notify(enum mog_notification note) case MOG_NOTIFY_SIGNAL: break; default: assert(0 && "bad note passed"); } - -retry: - w = write(notifywr_mfd->fd, "^", 1); - if (w >= 0) return; - - switch (errno) { - case_EAGAIN: return; /* somebody already woke this up */ - case EINTR: goto retry; /* just in case... */ - } - - /* - * we're screwed anyways, at least try this even though syslog() - * isn't safe inside a signal handler. - */ - syslog(LOG_CRIT, "mog_notify write() to pipe failed: %m"); - abort(); + mog_selfwake_trigger(notify_mfd); } @@ -9,13 +9,21 @@ enum mog_notification { MOG_NOTIFY_MAX }; -struct mog_notifyrd { +struct mog_selfwake { struct mog_queue *queue; + struct mog_fd *writer; + union { + int notes[MOG_NOTIFY_MAX]; + } as; }; -struct mog_notifywr { - struct mog_queue *queue; - int notes[MOG_NOTIFY_MAX]; +/* only for pipe */ +struct mog_selfpipe { + struct mog_fd *reader; /* points to mog_selfwake */ }; extern struct mog_queue *mog_notify_queue; + +struct mog_fd * mog_selfwake_new(void); +void mog_selfwake_trigger(struct mog_fd *); +void mog_selfwake_drain(struct mog_fd *); diff --git a/selfwake.c b/selfwake.c new file mode 100644 index 0000000..d0fbf44 --- /dev/null +++ b/selfwake.c @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2012-2013, Eric Wong <normalperson@yhbt.net> + * License: GPLv3 or later (see COPYING for details) + */ +#include "cmogstored.h" +#include "selfwake_eventfd.h" +#include "selfwake_pipe.h" + +/* this is async-signal safe (except in the case of bugs) */ +void mog_selfwake_trigger(struct mog_fd *mfd) +{ + ssize_t w; + +retry: + w = selfwake_write(mfd); + if (w >= 0) return; + + switch (errno) { + case_EAGAIN: return; /* somebody already woke this up */ + case EINTR: goto retry; /* just in case... */ + } + + /* + * we're screwed anyways, at least try this even though syslog() + * isn't safe inside a signal handler. + */ + syslog(LOG_CRIT, "mog_selfwake_trigger write() failed: %m"); + abort(); +} + +void mog_selfwake_drain(struct mog_fd *mfd) +{ + ssize_t r; + + do { + r = selfwake_drain(mfd); + } while (r > 0); + assert(r < 0 && (errno == EAGAIN || errno == EINTR) + && "selfwake read failed"); +} diff --git a/selfwake_eventfd.h b/selfwake_eventfd.h new file mode 100644 index 0000000..baca39f --- /dev/null +++ b/selfwake_eventfd.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2012-2013, Eric Wong <normalperson@yhbt.net> + * License: GPLv3 or later (see COPYING for details) + */ +#if defined(HAVE_SYS_EVENTFD_H) && defined(HAVE_EVENTFD) +#include <sys/eventfd.h> +#if defined(EFD_CLOEXEC) && defined(EFD_NONBLOCK) +static ssize_t selfwake_write(struct mog_fd *mfd) +{ + static const uint64_t buf = 1; + + return write(mfd->fd, &buf, sizeof(buf)); +} + +struct mog_fd * mog_selfwake_new(void) +{ + struct mog_fd *mfd; + int efd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK); + + if (efd < 0) + die_errno("failed to create eventfd"); + + mfd = mog_fd_init(efd, MOG_FD_TYPE_SELFWAKE); + mfd->as.selfwake.writer = mfd; + + return mfd; +} + +static ssize_t selfwake_drain(struct mog_fd *mfd) +{ + uint64_t buf; + + return read(mfd->fd, &buf, sizeof(buf)); +} +#endif /* EFD_CLOEXEC+EFD_NONBLOCK */ +#endif /* HAVE_SYS_EVENTFD_H */ diff --git a/selfwake_pipe.h b/selfwake_pipe.h new file mode 100644 index 0000000..763332a --- /dev/null +++ b/selfwake_pipe.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2012-2013, Eric Wong <normalperson@yhbt.net> + * License: GPLv3 or later (see COPYING for details) + */ +#ifndef HAVE_EVENTFD +static ssize_t selfwake_write(struct mog_fd *mfd) +{ + return write(mfd->as.selfwake.writer->fd, "", 1); +} + +struct mog_fd * mog_selfwake_new(void) +{ + struct mog_fd *reader, *writer; + struct mog_selfwake *selfwake; + int self_pipe[2]; + + if (pipe2(self_pipe, O_NONBLOCK | O_CLOEXEC) < 0) + die_errno("failed to init self-pipe"); + + reader = mog_fd_init(self_pipe[0], MOG_FD_TYPE_SELFWAKE); + selfwake = &reader->as.selfwake; + + writer = mog_fd_init(self_pipe[1], MOG_FD_TYPE_SELFPIPE); + writer->as.selfpipe.reader = reader; + selfwake->writer = writer; + + return reader; +} + +static ssize_t selfwake_drain(struct mog_fd *mfd) +{ + char buf[64]; + return read(mfd->fd, buf, sizeof(buf)); +} +#endif /* !HAVE_EVENTFD */ |