event: add new kind of event source called "post"

This new event source is triggered by the dispatching of any non-post
event source. It can thus be used to do clean-up or recheck work,
triggered by any other event source having been executed.

This is different from "defer" event source which are unconditionally
triggered as long as they are enabled. A "defer" event source that does
nothing will result in the event loop busy looping unless it is turned
off eventually. This is different for "post" event sources that will be
only triggered when some other non-post ran, and will thus not keep the
event loop busy on its own.
This commit is contained in:
Lennart Poettering 2014-02-21 21:06:09 +01:00
parent d7c9a162f1
commit 6e9feda30d
2 changed files with 73 additions and 0 deletions

View File

@ -32,6 +32,7 @@
#include "util.h"
#include "time-util.h"
#include "missing.h"
#include "set.h"
#include "sd-event.h"
@ -45,6 +46,7 @@ typedef enum EventSourceType {
SOURCE_SIGNAL,
SOURCE_CHILD,
SOURCE_DEFER,
SOURCE_POST,
SOURCE_EXIT,
SOURCE_WATCHDOG
} EventSourceType;
@ -95,6 +97,9 @@ struct sd_event_source {
struct {
sd_event_handler_t callback;
} defer;
struct {
sd_event_handler_t callback;
} post;
struct {
sd_event_handler_t callback;
unsigned prioq_index;
@ -134,6 +139,8 @@ struct sd_event {
Hashmap *child_sources;
unsigned n_enabled_child_sources;
Set *post_sources;
Prioq *exit;
pid_t original_pid;
@ -350,6 +357,7 @@ static void event_free(sd_event *e) {
free(e->signal_sources);
hashmap_free(e->child_sources);
set_free(e->post_sources);
free(e);
}
@ -524,6 +532,10 @@ static void source_free(sd_event_source *s) {
/* nothing */
break;
case SOURCE_POST:
set_remove(s->event->post_sources, s);
break;
case SOURCE_EXIT:
prioq_remove(s->event->exit, s, &s->exit.prioq_index);
break;
@ -957,6 +969,43 @@ _public_ int sd_event_add_defer(
return 0;
}
_public_ int sd_event_add_post(
sd_event *e,
sd_event_source **ret,
sd_event_handler_t callback,
void *userdata) {
sd_event_source *s;
int r;
assert_return(e, -EINVAL);
assert_return(callback, -EINVAL);
assert_return(ret, -EINVAL);
assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
assert_return(!event_pid_changed(e), -ECHILD);
r = set_ensure_allocated(&e->post_sources, trivial_hash_func, trivial_compare_func);
if (r < 0)
return r;
s = source_new(e, SOURCE_POST);
if (!s)
return -ENOMEM;
s->post.callback = callback;
s->userdata = userdata;
s->enabled = SD_EVENT_ON;
r = set_put(e->post_sources, s);
if (r < 0) {
source_free(s);
return r;
}
*ret = s;
return 0;
}
_public_ int sd_event_add_exit(
sd_event *e,
sd_event_source **ret,
@ -1246,6 +1295,7 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) {
break;
case SOURCE_DEFER:
case SOURCE_POST:
s->enabled = m;
break;
@ -1304,6 +1354,7 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) {
break;
case SOURCE_DEFER:
case SOURCE_POST:
s->enabled = m;
break;
@ -1779,6 +1830,23 @@ static int source_dispatch(sd_event_source *s) {
return r;
}
if (s->type != SOURCE_POST) {
sd_event_source *z;
Iterator i;
/* If we execute a non-post source, let's mark all
* post sources as pending */
SET_FOREACH(z, s->event->post_sources, i) {
if (z->enabled == SD_EVENT_OFF)
continue;
r = source_set_pending(z, true);
if (r < 0)
return r;
}
}
if (s->enabled == SD_EVENT_ONESHOT) {
r = sd_event_source_set_enabled(s, SD_EVENT_OFF);
if (r < 0)
@ -1825,6 +1893,10 @@ static int source_dispatch(sd_event_source *s) {
r = s->defer.callback(s, s->userdata);
break;
case SOURCE_POST:
r = s->post.callback(s, s->userdata);
break;
case SOURCE_EXIT:
r = s->exit.callback(s, s->userdata);
break;

View File

@ -82,6 +82,7 @@ int sd_event_add_realtime(sd_event *e, sd_event_source **s, uint64_t usec, uint6
int sd_event_add_signal(sd_event *e, sd_event_source **s, int sig, sd_event_signal_handler_t callback, void *userdata);
int sd_event_add_child(sd_event *e, sd_event_source **s, pid_t pid, int options, sd_event_child_handler_t callback, void *userdata);
int sd_event_add_defer(sd_event *e, sd_event_source **s, sd_event_handler_t callback, void *userdata);
int sd_event_add_post(sd_event *e, sd_event_source **s, sd_event_handler_t callback, void *userdata);
int sd_event_add_exit(sd_event *e, sd_event_source **s, sd_event_handler_t callback, void *userdata);
int sd_event_run(sd_event *e, uint64_t timeout);