fdev: Improve fdev handling with epoll 23/14323/1
authorJosé Bollo <jose.bollo@iot.bzh>
Fri, 23 Mar 2018 16:46:59 +0000 (17:46 +0100)
committerJosé Bollo <jose.bollo@iot.bzh>
Wed, 13 Jun 2018 15:14:00 +0000 (17:14 +0200)
Change-Id: I53c6eb394772e40f87000a0e5383be923f5d15f1
Signed-off-by: José Bollo <jose.bollo@iot.bzh>
src/fdev-epoll.c
src/fdev-epoll.h
src/fdev-systemd.c
src/fdev.c
src/fdev.h

index 80c037d..5043440 100644 (file)
 #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;
 }
 
index 53d02e7..4b81f86 100644 (file)
@@ -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);
 
index 0f4a03c..9115dd0 100644 (file)
@@ -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)
index 8ad79b5..a8f3695 100644 (file)
@@ -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);
        }
 }
 
index 9fbcb75..1e2f49f 100644 (file)
@@ -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);