mirror of
https://github.com/systemd/systemd.git
synced 2025-03-01 08:58:29 +03:00
sd-event: add test for the new sd_event_add_inotify() API
This tests a couple of corner cases of the sd-event API including changing priorities of existing event sources, as well as overflow conditions of the inotify queue.
This commit is contained in:
parent
97ef539169
commit
41e09d62c5
@ -9,12 +9,19 @@
|
||||
|
||||
#include "sd-event.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "fs-util.h"
|
||||
#include "log.h"
|
||||
#include "macro.h"
|
||||
#include "signal-util.h"
|
||||
#include "util.h"
|
||||
#include "parse-util.h"
|
||||
#include "process-util.h"
|
||||
#include "rm-rf.h"
|
||||
#include "signal-util.h"
|
||||
#include "stdio-util.h"
|
||||
#include "string-util.h"
|
||||
#include "util.h"
|
||||
|
||||
static int prepare_handler(sd_event_source *s, void *userdata) {
|
||||
log_info("preparing %c", PTR_TO_INT(userdata));
|
||||
@ -342,6 +349,142 @@ static void test_rtqueue(void) {
|
||||
sd_event_unref(e);
|
||||
}
|
||||
|
||||
#define CREATE_EVENTS_MAX (70000U)
|
||||
|
||||
struct inotify_context {
|
||||
bool delete_self_handler_called;
|
||||
unsigned create_called[CREATE_EVENTS_MAX];
|
||||
unsigned create_overflow;
|
||||
unsigned n_create_events;
|
||||
};
|
||||
|
||||
static void maybe_exit(sd_event_source *s, struct inotify_context *c) {
|
||||
unsigned n;
|
||||
|
||||
assert(s);
|
||||
assert(c);
|
||||
|
||||
if (!c->delete_self_handler_called)
|
||||
return;
|
||||
|
||||
for (n = 0; n < 3; n++) {
|
||||
unsigned i;
|
||||
|
||||
if (c->create_overflow & (1U << n))
|
||||
continue;
|
||||
|
||||
for (i = 0; i < c->n_create_events; i++)
|
||||
if (!(c->create_called[i] & (1U << n)))
|
||||
return;
|
||||
}
|
||||
|
||||
sd_event_exit(sd_event_source_get_event(s), 0);
|
||||
}
|
||||
|
||||
static int inotify_handler(sd_event_source *s, const struct inotify_event *ev, void *userdata) {
|
||||
struct inotify_context *c = userdata;
|
||||
const char *description;
|
||||
unsigned bit, n;
|
||||
|
||||
assert_se(sd_event_source_get_description(s, &description) >= 0);
|
||||
assert_se(safe_atou(description, &n) >= 0);
|
||||
|
||||
assert_se(n <= 3);
|
||||
bit = 1U << n;
|
||||
|
||||
if (ev->mask & IN_Q_OVERFLOW) {
|
||||
log_info("inotify-handler <%s>: overflow", description);
|
||||
c->create_overflow |= bit;
|
||||
} else if (ev->mask & IN_CREATE) {
|
||||
unsigned i;
|
||||
|
||||
log_info("inotify-handler <%s>: create on %s", description, ev->name);
|
||||
|
||||
if (!streq(ev->name, "sub")) {
|
||||
assert_se(safe_atou(ev->name, &i) >= 0);
|
||||
|
||||
assert_se(i < c->n_create_events);
|
||||
c->create_called[i] |= bit;
|
||||
}
|
||||
} else if (ev->mask & IN_DELETE) {
|
||||
log_info("inotify-handler <%s>: delete of %s", description, ev->name);
|
||||
assert_se(streq(ev->name, "sub"));
|
||||
} else
|
||||
assert_not_reached("unexpected inotify event");
|
||||
|
||||
maybe_exit(s, c);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int delete_self_handler(sd_event_source *s, const struct inotify_event *ev, void *userdata) {
|
||||
struct inotify_context *c = userdata;
|
||||
|
||||
if (ev->mask & IN_Q_OVERFLOW) {
|
||||
log_info("delete-self-handler: overflow");
|
||||
c->delete_self_handler_called = true;
|
||||
} else if (ev->mask & IN_DELETE_SELF) {
|
||||
log_info("delete-self-handler: delete-self");
|
||||
c->delete_self_handler_called = true;
|
||||
} else if (ev->mask & IN_IGNORED) {
|
||||
log_info("delete-self-handler: ignore");
|
||||
} else
|
||||
assert_not_reached("unexpected inotify event (delete-self)");
|
||||
|
||||
maybe_exit(s, c);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void test_inotify(unsigned n_create_events) {
|
||||
_cleanup_(rm_rf_physical_and_freep) char *p = NULL;
|
||||
sd_event_source *a = NULL, *b = NULL, *c = NULL, *d = NULL;
|
||||
struct inotify_context context = {
|
||||
.n_create_events = n_create_events,
|
||||
};
|
||||
sd_event *e = NULL;
|
||||
const char *q;
|
||||
unsigned i;
|
||||
|
||||
assert_se(sd_event_default(&e) >= 0);
|
||||
|
||||
assert_se(mkdtemp_malloc("/tmp/test-inotify-XXXXXX", &p) >= 0);
|
||||
|
||||
assert_se(sd_event_add_inotify(e, &a, p, IN_CREATE|IN_ONLYDIR, inotify_handler, &context) >= 0);
|
||||
assert_se(sd_event_add_inotify(e, &b, p, IN_CREATE|IN_DELETE|IN_DONT_FOLLOW, inotify_handler, &context) >= 0);
|
||||
assert_se(sd_event_source_set_priority(b, SD_EVENT_PRIORITY_IDLE) >= 0);
|
||||
assert_se(sd_event_source_set_priority(b, SD_EVENT_PRIORITY_NORMAL) >= 0);
|
||||
assert_se(sd_event_add_inotify(e, &c, p, IN_CREATE|IN_DELETE|IN_EXCL_UNLINK, inotify_handler, &context) >= 0);
|
||||
assert_se(sd_event_source_set_priority(c, SD_EVENT_PRIORITY_IDLE) >= 0);
|
||||
|
||||
assert_se(sd_event_source_set_description(a, "0") >= 0);
|
||||
assert_se(sd_event_source_set_description(b, "1") >= 0);
|
||||
assert_se(sd_event_source_set_description(c, "2") >= 0);
|
||||
|
||||
q = strjoina(p, "/sub");
|
||||
assert_se(touch(q) >= 0);
|
||||
assert_se(sd_event_add_inotify(e, &d, q, IN_DELETE_SELF, delete_self_handler, &context) >= 0);
|
||||
|
||||
for (i = 0; i < n_create_events; i++) {
|
||||
char buf[DECIMAL_STR_MAX(unsigned)+1];
|
||||
_cleanup_free_ char *z;
|
||||
|
||||
xsprintf(buf, "%u", i);
|
||||
assert_se(z = strjoin(p, "/", buf));
|
||||
|
||||
assert_se(touch(z) >= 0);
|
||||
}
|
||||
|
||||
assert_se(unlink(q) >= 0);
|
||||
|
||||
assert_se(sd_event_loop(e) >= 0);
|
||||
|
||||
sd_event_source_unref(a);
|
||||
sd_event_source_unref(b);
|
||||
sd_event_source_unref(c);
|
||||
sd_event_source_unref(d);
|
||||
|
||||
sd_event_unref(e);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
log_set_max_level(LOG_DEBUG);
|
||||
@ -351,5 +494,8 @@ int main(int argc, char *argv[]) {
|
||||
test_sd_event_now();
|
||||
test_rtqueue();
|
||||
|
||||
test_inotify(100); /* should work without overflow */
|
||||
test_inotify(33000); /* should trigger a q overflow */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user