From 42a6c76e281b8028e8ec0eddbf68ee633463a1ae Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Sat, 3 Dec 2011 12:04:29 +0100 Subject: [PATCH] Eloop: Add idle-event support 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 --- src/eloop.c | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/eloop.h | 14 ++++++ 2 files changed, 154 insertions(+) diff --git a/src/eloop.c b/src/eloop.c index be3b0c7..1b6168c 100644 --- a/src/eloop.c +++ b/src/eloop.c @@ -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; diff --git a/src/eloop.h b/src/eloop.h index 5372a13..c10db1c 100644 --- a/src/eloop.h +++ b/src/eloop.h @@ -37,9 +37,11 @@ #include 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);