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:
parent
fe5b180fbb
commit
42a6c76e28
140
src/eloop.c
140
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;
|
||||
|
14
src/eloop.h
14
src/eloop.h
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user