Eloop: Add idle-event support
authorDavid Herrmann <dh.herrmann@googlemail.com>
Sat, 3 Dec 2011 11:04:29 +0000 (12:04 +0100)
committerDavid Herrmann <dh.herrmann@googlemail.com>
Sat, 3 Dec 2011 11:04:29 +0000 (12:04 +0100)
Idle events are dispatched everytime kmscon_eloop_dispatch() is called. To allow
the callbacks to add/remove/modify all current idle events (including themself),
we need to keep a pointer to the currently dispatched event.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
src/eloop.c
src/eloop.h

index be3b0c7..1b6168c 100644 (file)
@@ -47,10 +47,23 @@ struct kmscon_eloop {
        int efd;
        unsigned long ref;
 
+       struct kmscon_idle *idle_list;
+       struct kmscon_idle *cur_idle;
+
        struct epoll_event *cur_fds;
        size_t cur_fds_cnt;
 };
 
+struct kmscon_idle {
+       unsigned long ref;
+       struct kmscon_eloop *loop;
+       struct kmscon_idle *next;
+       struct kmscon_idle *prev;
+
+       kmscon_idle_cb cb;
+       void *data;
+};
+
 struct kmscon_fd {
        unsigned long ref;
        struct kmscon_eloop *loop;
@@ -68,6 +81,124 @@ struct kmscon_signal {
        void *data;
 };
 
+int kmscon_idle_new(struct kmscon_idle **out)
+{
+       struct kmscon_idle *idle;
+
+       if (!out)
+               return -EINVAL;
+
+       idle = malloc(sizeof(*idle));
+       if (!idle)
+               return -ENOMEM;
+
+       memset(idle, 0, sizeof(*idle));
+       idle->ref = 1;
+
+       *out = idle;
+       return 0;
+}
+
+void kmscon_idle_ref(struct kmscon_idle *idle)
+{
+       if (!idle)
+               return;
+
+       ++idle->ref;
+}
+
+void kmscon_idle_unref(struct kmscon_idle *idle)
+{
+       if (!idle || !idle->ref)
+               return;
+
+       if (--idle->ref)
+               return;
+
+       free(idle);
+}
+
+int kmscon_eloop_new_idle(struct kmscon_eloop *loop, struct kmscon_idle **out,
+                                               kmscon_idle_cb cb, void *data)
+{
+       struct kmscon_idle *idle;
+       int ret;
+
+       if (!out)
+               return -EINVAL;
+
+       ret = kmscon_idle_new(&idle);
+       if (ret)
+               return ret;
+
+       ret = kmscon_eloop_add_idle(loop, idle, cb, data);
+       if (ret) {
+               kmscon_idle_unref(idle);
+               return ret;
+       }
+
+       kmscon_idle_unref(idle);
+       *out = idle;
+       return 0;
+}
+
+int kmscon_eloop_add_idle(struct kmscon_eloop *loop, struct kmscon_idle *idle,
+                                               kmscon_idle_cb cb, void *data)
+{
+       if (!loop || !idle || !cb)
+               return -EINVAL;
+
+       if (idle->next || idle->prev || idle->loop)
+               return -EALREADY;
+
+       idle->next = loop->idle_list;
+       if (idle->next)
+               idle->next->prev = idle;
+       loop->idle_list = idle;
+
+       idle->loop = loop;
+       idle->cb = cb;
+       idle->data = data;
+
+       kmscon_idle_ref(idle);
+       kmscon_eloop_ref(loop);
+
+       return 0;
+}
+
+void kmsocn_eloop_rm_idle(struct kmscon_idle *idle)
+{
+       struct kmscon_eloop *loop;
+
+       if (!idle || !idle->loop)
+               return;
+
+       loop = idle->loop;
+
+       /*
+        * If the loop is currently dispatching, we need to check whether we are
+        * the current element and correctly set it to the next element.
+        */
+       if (loop->cur_idle == idle)
+               loop->cur_idle = idle->next;
+
+       if (idle->prev)
+               idle->prev->next = idle->next;
+       if (idle->next)
+               idle->next->prev = idle->prev;
+       if (loop->idle_list == idle)
+               loop->idle_list = idle->next;
+
+       idle->next = NULL;
+       idle->prev = NULL;
+       idle->loop = NULL;
+       idle->cb = NULL;
+       idle->data = NULL;
+
+       kmscon_idle_unref(idle);
+       kmscon_eloop_unref(loop);
+}
+
 int kmscon_fd_new(struct kmscon_fd **out)
 {
        struct kmscon_fd *fd;
@@ -401,6 +532,15 @@ int kmscon_eloop_dispatch(struct kmscon_eloop *loop, int timeout)
        if (!loop)
                return -EINVAL;
 
+       /* dispatch idle events */
+       loop->cur_idle = loop->idle_list;
+       while (loop->cur_idle) {
+               loop->cur_idle->cb(loop->cur_idle, loop->cur_idle->data);
+               if (loop->cur_idle)
+                       loop->cur_idle = loop->cur_idle->next;
+       }
+
+       /* dispatch fd events */
        count = epoll_wait(loop->efd, ep, 32, timeout);
        if (count < 0)
                return -errno;
index 5372a13..c10db1c 100644 (file)
 #include <stdlib.h>
 
 struct kmscon_eloop;
+struct kmscon_idle;
 struct kmscon_fd;
 struct kmscon_signal;
 
+typedef void (*kmscon_idle_cb) (struct kmscon_idle *idle, void *data);
 typedef void (*kmscon_fd_cb) (struct kmscon_fd *fd, void *data);
 typedef void (*kmscon_signal_cb)
                        (struct kmscon_signal *sig, int signum, void *data);
@@ -57,6 +59,18 @@ void kmscon_eloop_unref(struct kmscon_eloop *loop);
 int kmscon_eloop_get_fd(struct kmscon_eloop *loop);
 int kmscon_eloop_dispatch(struct kmscon_eloop *loop, int timeout);
 
+/* idle sources */
+
+int kmscon_idle_new(struct kmscon_idle **out);
+void kmscon_idle_ref(struct kmscon_idle *idle);
+void kmscon_idle_unref(struct kmscon_idle *idle);
+
+int kmscon_eloop_new_idle(struct kmscon_eloop *loop, struct kmscon_idle **out,
+                                               kmscon_idle_cb cb, void *data);
+int kmscon_eloop_add_idle(struct kmscon_eloop *loop, struct kmscon_idle *idle,
+                                               kmscon_idle_cb cb, void *data);
+void kmsocn_eloop_rm_idle(struct kmscon_idle *idle);
+
 /* fd sources */
 
 int kmscon_fd_new(struct kmscon_fd **out);