chiark / gitweb /
0b7e2e48c4396b541a9d2ba31e333a8be30cdad9
[elogind.git] / src / libsystemd / sd-event / test-event.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2013 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include "sd-event.h"
23 #include "log.h"
24 #include "util.h"
25
26 static int prepare_handler(sd_event_source *s, void *userdata) {
27         log_info("preparing %c", PTR_TO_INT(userdata));
28         return 1;
29 }
30
31 static bool got_a, got_b, got_c, got_unref;
32 static unsigned got_d;
33
34 static int unref_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
35         sd_event_source_unref(s);
36         got_unref = true;
37         return 0;
38 }
39
40 static int io_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
41
42         log_info("got IO on %c", PTR_TO_INT(userdata));
43
44         if (userdata == INT_TO_PTR('a')) {
45                 assert_se(sd_event_source_set_enabled(s, SD_EVENT_OFF) >= 0);
46                 assert_se(!got_a);
47                 got_a = true;
48         } else if (userdata == INT_TO_PTR('b')) {
49                 assert_se(!got_b);
50                 got_b = true;
51         } else if (userdata == INT_TO_PTR('d')) {
52                 got_d++;
53                 if (got_d < 2)
54                         assert_se(sd_event_source_set_enabled(s, SD_EVENT_ONESHOT) >= 0);
55                 else
56                         assert_se(sd_event_source_set_enabled(s, SD_EVENT_OFF) >= 0);
57         } else
58                 assert_not_reached("Yuck!");
59
60         return 1;
61 }
62
63 static int child_handler(sd_event_source *s, const siginfo_t *si, void *userdata) {
64
65         assert(s);
66         assert(si);
67
68         log_info("got child on %c", PTR_TO_INT(userdata));
69
70         assert(userdata == INT_TO_PTR('f'));
71
72         assert_se(sd_event_exit(sd_event_source_get_event(s), 0) >= 0);
73         sd_event_source_unref(s);
74
75         return 1;
76 }
77
78 static int signal_handler(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
79         sd_event_source *p = NULL;
80         sigset_t ss;
81         pid_t pid;
82
83         assert(s);
84         assert(si);
85
86         log_info("got signal on %c", PTR_TO_INT(userdata));
87
88         assert(userdata == INT_TO_PTR('e'));
89
90         assert_se(sigemptyset(&ss) >= 0);
91         assert_se(sigaddset(&ss, SIGCHLD) >= 0);
92         assert_se(sigprocmask(SIG_BLOCK, &ss, NULL) >= 0);
93
94         pid = fork();
95         assert_se(pid >= 0);
96
97         if (pid == 0)
98                 _exit(0);
99
100         assert_se(sd_event_add_child(sd_event_source_get_event(s), &p, pid, WEXITED, child_handler, INT_TO_PTR('f')) >= 0);
101         assert_se(sd_event_source_set_enabled(p, SD_EVENT_ONESHOT) >= 0);
102
103         sd_event_source_unref(s);
104
105         return 1;
106 }
107
108 static int defer_handler(sd_event_source *s, void *userdata) {
109         sd_event_source *p = NULL;
110         sigset_t ss;
111
112         assert(s);
113
114         log_info("got defer on %c", PTR_TO_INT(userdata));
115
116         assert(userdata == INT_TO_PTR('d'));
117
118         assert_se(sigemptyset(&ss) >= 0);
119         assert_se(sigaddset(&ss, SIGUSR1) >= 0);
120         assert_se(sigprocmask(SIG_BLOCK, &ss, NULL) >= 0);
121         assert_se(sd_event_add_signal(sd_event_source_get_event(s), &p, SIGUSR1, signal_handler, INT_TO_PTR('e')) >= 0);
122         assert_se(sd_event_source_set_enabled(p, SD_EVENT_ONESHOT) >= 0);
123         raise(SIGUSR1);
124
125         sd_event_source_unref(s);
126
127         return 1;
128 }
129
130 static bool do_quit = false;
131
132 static int time_handler(sd_event_source *s, uint64_t usec, void *userdata) {
133         log_info("got timer on %c", PTR_TO_INT(userdata));
134
135         if (userdata == INT_TO_PTR('c')) {
136
137                 if (do_quit) {
138                         sd_event_source *p;
139
140                         assert_se(sd_event_add_defer(sd_event_source_get_event(s), &p, defer_handler, INT_TO_PTR('d')) >= 0);
141                         assert_se(sd_event_source_set_enabled(p, SD_EVENT_ONESHOT) >= 0);
142                 } else {
143                         assert(!got_c);
144                         got_c = true;
145                 }
146         } else
147                 assert_not_reached("Huh?");
148
149         return 2;
150 }
151
152 static bool got_exit = false;
153
154 static int exit_handler(sd_event_source *s, void *userdata) {
155         log_info("got quit handler on %c", PTR_TO_INT(userdata));
156
157         got_exit = true;
158
159         return 3;
160 }
161
162 int main(int argc, char *argv[]) {
163         sd_event *e = NULL;
164         sd_event_source *w = NULL, *x = NULL, *y = NULL, *z = NULL, *q = NULL, *t = NULL;
165         static const char ch = 'x';
166         int a[2] = { -1, -1 }, b[2] = { -1, -1}, d[2] = { -1, -1}, k[2] = { -1, -1 };
167
168         assert_se(pipe(a) >= 0);
169         assert_se(pipe(b) >= 0);
170         assert_se(pipe(d) >= 0);
171         assert_se(pipe(k) >= 0);
172
173         assert_se(sd_event_default(&e) >= 0);
174
175         assert_se(sd_event_set_watchdog(e, true) >= 0);
176
177         /* Test whether we cleanly can destroy an io event source from its own handler */
178         got_unref = false;
179         assert_se(sd_event_add_io(e, &t, k[0], EPOLLIN, unref_handler, NULL) >= 0);
180         assert_se(write(k[1], &ch, 1) == 1);
181         assert_se(sd_event_run(e, (uint64_t) -1) >= 1);
182         assert_se(got_unref);
183
184         got_a = false, got_b = false, got_c = false, got_d = 0;
185
186         /* Add a oneshot handler, trigger it, re-enable it, and trigger
187          * it again. */
188         assert_se(sd_event_add_io(e, &w, d[0], EPOLLIN, io_handler, INT_TO_PTR('d')) >= 0);
189         assert_se(sd_event_source_set_enabled(w, SD_EVENT_ONESHOT) >= 0);
190         assert_se(write(d[1], &ch, 1) >= 0);
191         assert_se(sd_event_run(e, (uint64_t) -1) >= 1);
192         assert_se(got_d == 1);
193         assert_se(write(d[1], &ch, 1) >= 0);
194         assert_se(sd_event_run(e, (uint64_t) -1) >= 1);
195         assert_se(got_d == 2);
196
197         assert_se(sd_event_add_io(e, &x, a[0], EPOLLIN, io_handler, INT_TO_PTR('a')) >= 0);
198         assert_se(sd_event_add_io(e, &y, b[0], EPOLLIN, io_handler, INT_TO_PTR('b')) >= 0);
199         assert_se(sd_event_add_monotonic(e, &z, 0, 0, time_handler, INT_TO_PTR('c')) >= 0);
200         assert_se(sd_event_add_exit(e, &q, exit_handler, INT_TO_PTR('g')) >= 0);
201
202         assert_se(sd_event_source_set_priority(x, 99) >= 0);
203         assert_se(sd_event_source_set_enabled(y, SD_EVENT_ONESHOT) >= 0);
204         assert_se(sd_event_source_set_prepare(x, prepare_handler) >= 0);
205         assert_se(sd_event_source_set_priority(z, 50) >= 0);
206         assert_se(sd_event_source_set_enabled(z, SD_EVENT_ONESHOT) >= 0);
207         assert_se(sd_event_source_set_prepare(z, prepare_handler) >= 0);
208
209         assert_se(write(a[1], &ch, 1) >= 0);
210         assert_se(write(b[1], &ch, 1) >= 0);
211
212         assert_se(!got_a && !got_b && !got_c);
213
214         assert_se(sd_event_run(e, (uint64_t) -1) >= 1);
215
216         assert_se(!got_a && got_b && !got_c);
217
218         assert_se(sd_event_run(e, (uint64_t) -1) >= 1);
219
220         assert_se(!got_a && got_b && got_c);
221
222         assert_se(sd_event_run(e, (uint64_t) -1) >= 1);
223
224         assert_se(got_a && got_b && got_c);
225
226         sd_event_source_unref(x);
227         sd_event_source_unref(y);
228
229         do_quit = true;
230         assert_se(sd_event_source_set_time(z, now(CLOCK_MONOTONIC) + 200 * USEC_PER_MSEC) >= 0);
231         assert_se(sd_event_source_set_enabled(z, SD_EVENT_ONESHOT) >= 0);
232
233         assert_se(sd_event_loop(e) >= 0);
234
235         sd_event_source_unref(z);
236         sd_event_source_unref(q);
237
238         sd_event_source_unref(w);
239
240         sd_event_unref(e);
241
242         close_pipe(a);
243         close_pipe(b);
244         close_pipe(d);
245         close_pipe(k);
246
247         return 0;
248 }