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 <dh.herrmann@googlemail.com>
This commit is contained in:
David Herrmann 2011-12-03 12:04:29 +01:00
parent fe5b180fbb
commit 42a6c76e28
2 changed files with 154 additions and 0 deletions

View 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;

View File

@ -37,9 +37,11 @@
#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);