eloop: use counter source for idle events

epoll has the great feature that the poll object is an fd itself. However,
if we want to use idle-sources, we couldn't add them to the epoll set.
Now, we use a counter source for all idle sources so if we add a single
event-loop as source to another event loop, the idle sources will get
dispatched correctly. Furthermore, we now longer block after handling idle
sources but instead now correctly run idle sources every next round
without sleeping for fd events in between.
Unregister idle sources to avoid hogging the CPU.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
This commit is contained in:
David Herrmann 2012-05-19 13:07:12 +02:00
parent f0b92a1366
commit 2eb172acb4

View File

@ -55,6 +55,7 @@ struct ev_eloop {
int efd;
unsigned long ref;
struct ev_fd *fd;
struct ev_counter *cnt;
struct kmscon_dlist sig_list;
struct kmscon_hook *idlers;
@ -233,6 +234,24 @@ static void eloop_event(struct ev_fd *fd, int mask, void *data)
log_warn("HUP/ERR on eloop source");
}
static void eloop_cnt_event(struct ev_counter *cnt, uint64_t num, void *data)
{
struct ev_eloop *eloop = data;
int ret;
if (!num) {
log_warning("HUP/ERR on eloop idle-counter");
return;
}
kmscon_hook_call(eloop->idlers, eloop, NULL);
if (kmscon_hook_num(eloop->idlers) > 0) {
ret = ev_counter_inc(eloop->cnt, 1);
if (ret)
log_warning("cannot increase eloop idle-counter");
}
}
int ev_eloop_new(struct ev_eloop **out)
{
struct ev_eloop *loop;
@ -263,10 +282,16 @@ int ev_eloop_new(struct ev_eloop **out)
if (ret)
goto err_close;
ret = ev_eloop_new_counter(loop, &loop->cnt, eloop_cnt_event, loop);
if (ret)
goto err_fd;
log_debug("new eloop object %p", loop);
*out = loop;
return 0;
err_fd:
ev_fd_unref(loop->fd);
err_close:
close(loop->efd);
err_idlers:
@ -300,6 +325,7 @@ void ev_eloop_unref(struct ev_eloop *loop)
signal_free(sig);
}
ev_eloop_rm_counter(loop->cnt);
ev_fd_unref(loop->fd);
close(loop->efd);
kmscon_hook_free(loop->idlers);
@ -328,9 +354,6 @@ int ev_eloop_dispatch(struct ev_eloop *loop, int timeout)
if (!loop || loop->exit)
return -EINVAL;
/* dispatch idle events */
kmscon_hook_call(loop->idlers, loop, NULL);
/* dispatch fd events */
count = epoll_wait(loop->efd, ep, 32, timeout);
if (count < 0) {
@ -1230,10 +1253,20 @@ void ev_eloop_unregister_signal_cb(struct ev_eloop *loop, int signum,
int ev_eloop_register_idle_cb(struct ev_eloop *eloop, ev_idle_cb cb,
void *data)
{
int ret;
if (!eloop)
return -EINVAL;
return kmscon_hook_add_cast(eloop->idlers, cb, data);
ret = kmscon_hook_add_cast(eloop->idlers, cb, data);
if (ret)
return ret;
ret = ev_counter_inc(eloop->cnt, 1);
if (ret)
log_warning("cannot increase eloop idle-counter");
return 0;
}
void ev_eloop_unregister_idle_cb(struct ev_eloop *eloop, ev_idle_cb cb,