From e7e42ce9196e865a2dfd5a460932b0357885e603 Mon Sep 17 00:00:00 2001 From: José Bollo Date: Fri, 23 Mar 2018 17:46:59 +0100 Subject: fdev: Improve fdev handling with epoll MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I53c6eb394772e40f87000a0e5383be923f5d15f1 Signed-off-by: José Bollo --- src/fdev-epoll.c | 79 +++++++++++++++++++++++++++++++++++++++++++++--------- src/fdev-epoll.h | 2 +- src/fdev-systemd.c | 3 ++- src/fdev.c | 5 ++-- src/fdev.h | 1 + 5 files changed, 74 insertions(+), 16 deletions(-) diff --git a/src/fdev-epoll.c b/src/fdev-epoll.c index 80c037d0..5043440c 100644 --- a/src/fdev-epoll.c +++ b/src/fdev-epoll.c @@ -23,15 +23,30 @@ #include "fdev.h" #include "fdev-epoll.h" +/* + * For sake of simplicity there is no struct fdev_epoll. + * Instead, the file descriptor of the internal epoll is used + * and wrapped in a pseudo pointer to a pseudo struct. + */ #define epollfd(fdev_epoll) ((int)(intptr_t)fdev_epoll) +/* + * disable callback for fdev + * + * refs to fdev must not be counted here + */ static void disable(void *closure, const struct fdev *fdev) { struct fdev_epoll *fdev_epoll = closure; epoll_ctl(epollfd(fdev_epoll), EPOLL_CTL_DEL, fdev_fd(fdev), 0); } -static void enable(void *closure, const struct fdev *fdev) +/* + * enable callback for fdev + * + * refs to fdev must not be counted here + */ +static void enable_or_update(void *closure, const struct fdev *fdev, int op, int err) { struct fdev_epoll *fdev_epoll = closure; struct epoll_event event; @@ -40,18 +55,45 @@ static void enable(void *closure, const struct fdev *fdev) fd = fdev_fd(fdev); event.events = fdev_events(fdev); event.data.ptr = (void*)fdev; - rc = epoll_ctl(epollfd(fdev_epoll), EPOLL_CTL_MOD, fd, &event); - if (rc < 0 && errno == ENOENT) - epoll_ctl(epollfd(fdev_epoll), EPOLL_CTL_ADD, fd, &event); + rc = epoll_ctl(epollfd(fdev_epoll), op, fd, &event); + if (rc < 0 && errno == err) + epoll_ctl(epollfd(fdev_epoll), (EPOLL_CTL_MOD + EPOLL_CTL_ADD) - op, fd, &event); +} + +/* + * enable callback for fdev + * + * refs to fdev must not be counted here + */ +static void enable(void *closure, const struct fdev *fdev) +{ + enable_or_update(closure, fdev, EPOLL_CTL_ADD, EEXIST); +} + +/* + * update callback for fdev + * + * refs to fdev must not be counted here + */ +static void update(void *closure, const struct fdev *fdev) +{ + enable_or_update(closure, fdev, EPOLL_CTL_MOD, ENOENT); } +/* + * unref is not handled here + */ static struct fdev_itf itf = { .unref = 0, .disable = disable, - .enable = enable + .enable = enable, + .update = update }; +/* + * create an fdev_epoll + */ struct fdev_epoll *fdev_epoll_create() { int fd = epoll_create1(EPOLL_CLOEXEC); @@ -62,16 +104,25 @@ struct fdev_epoll *fdev_epoll_create() return fd < 0 ? 0 : (struct fdev_epoll*)(intptr_t)fd; } +/* + * destroy the fdev_epoll + */ void fdev_epoll_destroy(struct fdev_epoll *fdev_epoll) { close(epollfd(fdev_epoll)); } +/* + * get pollable fd for the fdev_epoll + */ int fdev_epoll_fd(struct fdev_epoll *fdev_epoll) { return epollfd(fdev_epoll); } +/* + * create an fdev linked to the 'fdev_epoll' for 'fd' + */ struct fdev *fdev_epoll_add(struct fdev_epoll *fdev_epoll, int fd) { struct fdev *fdev; @@ -82,16 +133,20 @@ struct fdev *fdev_epoll_add(struct fdev_epoll *fdev_epoll, int fd) return fdev; } -void fdev_epoll_wait_and_dispatch(struct fdev_epoll *fdev_epoll, int timeout_ms) +/* + * get pollable fd for the fdev_epoll + */ +int fdev_epoll_wait_and_dispatch(struct fdev_epoll *fdev_epoll, int timeout_ms) { struct fdev *fdev; - struct epoll_event events[8]; - int rc, i; + struct epoll_event events; + int rc; - rc = epoll_wait(epollfd(fdev_epoll), events, sizeof events / sizeof *events, timeout_ms < 0 ? -1 : timeout_ms); - for (i = 0 ; i < rc ; i++) { - fdev = events[i].data.ptr; - fdev_dispatch(fdev, events[i].events); + rc = epoll_wait(epollfd(fdev_epoll), &events, 1, timeout_ms < 0 ? -1 : timeout_ms); + if (rc == 1) { + fdev = events.data.ptr; + fdev_dispatch(fdev, events.events); } + return rc; } diff --git a/src/fdev-epoll.h b/src/fdev-epoll.h index 53d02e72..4b81f86e 100644 --- a/src/fdev-epoll.h +++ b/src/fdev-epoll.h @@ -24,5 +24,5 @@ extern struct fdev_epoll *fdev_epoll_create(); extern void fdev_epoll_destroy(struct fdev_epoll *fdev_epoll); extern int fdev_epoll_fd(struct fdev_epoll *fdev_epoll); extern struct fdev *fdev_epoll_add(struct fdev_epoll *fdev_epoll, int fd); -extern void fdev_epoll_wait_and_dispatch(struct fdev_epoll *fdev_epoll, int timeout_ms); +extern int fdev_epoll_wait_and_dispatch(struct fdev_epoll *fdev_epoll, int timeout_ms); diff --git a/src/fdev-systemd.c b/src/fdev-systemd.c index 0f4a03cd..9115dd0d 100644 --- a/src/fdev-systemd.c +++ b/src/fdev-systemd.c @@ -53,7 +53,8 @@ static struct fdev_itf itf = { .unref = unref, .disable = disable, - .enable = enable + .enable = enable, + .update = enable }; struct fdev *fdev_systemd_create(struct sd_event *eloop, int fd) diff --git a/src/fdev.c b/src/fdev.c index 8ad79b5f..a8f36956 100644 --- a/src/fdev.c +++ b/src/fdev.c @@ -76,7 +76,8 @@ void fdev_unref(struct fdev *fdev) if (fdev && __atomic_sub_fetch(&fdev->refcount, 2, __ATOMIC_RELAXED) <= 1) { if (fdev->itf) { fdev->itf->disable(fdev->closure_itf, fdev); - fdev->itf->unref(fdev->closure_itf); + if (fdev->itf->unref) + fdev->itf->unref(fdev->closure_itf); } if (fdev->refcount) close(fdev->fd); @@ -135,7 +136,7 @@ void fdev_set_events(struct fdev *fdev, uint32_t events) if (events != fdev->events) { fdev->events = events; if (is_active(fdev)) - fdev->itf->enable(fdev->closure_itf, fdev); + fdev->itf->update(fdev->closure_itf, fdev); } } diff --git a/src/fdev.h b/src/fdev.h index 9fbcb759..1e2f49f6 100644 --- a/src/fdev.h +++ b/src/fdev.h @@ -27,6 +27,7 @@ struct fdev_itf void (*unref)(void *closure); void (*disable)(void *closure, const struct fdev *fdev); void (*enable)(void *closure, const struct fdev *fdev); + void (*update)(void *closure, const struct fdev *fdev); }; extern struct fdev *fdev_create(int fd); -- cgit 1.2.3-korg