chiark / gitweb /
tree-wide: use EXIT_SUCCESS/EXIT_FAILURE in exit() where we can
[elogind.git] / src / libelogind / sd-event / test-event.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3   This file is part of systemd.
4
5   Copyright 2013 Lennart Poettering
6
7   systemd is free software; you can redistribute it and/or modify it
8   under the terms of the GNU Lesser General Public License as published by
9   the Free Software Foundation; either version 2.1 of the License, or
10   (at your option) any later version.
11
12   systemd is distributed in the hope that it will be useful, but
13   WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15   Lesser General Public License for more details.
16
17   You should have received a copy of the GNU Lesser General Public License
18   along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #include <sys/wait.h>
22
23 #include "sd-event.h"
24
25 #include "fd-util.h"
26 #include "log.h"
27 #include "macro.h"
28 #include "signal-util.h"
29 #include "util.h"
30 /// Additional includes needed by elogind
31 #include "process-util.h"
32
33 static int prepare_handler(sd_event_source *s, void *userdata) {
34         log_info("preparing %c", PTR_TO_INT(userdata));
35         return 1;
36 }
37
38 static bool got_a, got_b, got_c, got_unref;
39 static unsigned got_d;
40
41 static int unref_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
42         sd_event_source_unref(s);
43         got_unref = true;
44         return 0;
45 }
46
47 static int io_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
48
49         log_info("got IO on %c", PTR_TO_INT(userdata));
50
51         if (userdata == INT_TO_PTR('a')) {
52                 assert_se(sd_event_source_set_enabled(s, SD_EVENT_OFF) >= 0);
53                 assert_se(!got_a);
54                 got_a = true;
55         } else if (userdata == INT_TO_PTR('b')) {
56                 assert_se(!got_b);
57                 got_b = true;
58         } else if (userdata == INT_TO_PTR('d')) {
59                 got_d++;
60                 if (got_d < 2)
61                         assert_se(sd_event_source_set_enabled(s, SD_EVENT_ONESHOT) >= 0);
62                 else
63                         assert_se(sd_event_source_set_enabled(s, SD_EVENT_OFF) >= 0);
64         } else
65                 assert_not_reached("Yuck!");
66
67         return 1;
68 }
69
70 static int child_handler(sd_event_source *s, const siginfo_t *si, void *userdata) {
71
72         assert_se(s);
73         assert_se(si);
74
75         log_info("got child on %c", PTR_TO_INT(userdata));
76
77         assert_se(userdata == INT_TO_PTR('f'));
78
79         assert_se(sd_event_exit(sd_event_source_get_event(s), 0) >= 0);
80         sd_event_source_unref(s);
81
82         return 1;
83 }
84
85 static int signal_handler(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
86         sd_event_source *p = NULL;
87         pid_t pid;
88
89         assert_se(s);
90         assert_se(si);
91
92         log_info("got signal on %c", PTR_TO_INT(userdata));
93
94         assert_se(userdata == INT_TO_PTR('e'));
95
96         assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, -1) >= 0);
97
98         pid = fork();
99         assert_se(pid >= 0);
100
101         if (pid == 0)
102                 _exit(EXIT_SUCCESS);
103
104         assert_se(sd_event_add_child(sd_event_source_get_event(s), &p, pid, WEXITED, child_handler, INT_TO_PTR('f')) >= 0);
105         assert_se(sd_event_source_set_enabled(p, SD_EVENT_ONESHOT) >= 0);
106
107         sd_event_source_unref(s);
108
109         return 1;
110 }
111
112 static int defer_handler(sd_event_source *s, void *userdata) {
113         sd_event_source *p = NULL;
114
115         assert_se(s);
116
117         log_info("got defer on %c", PTR_TO_INT(userdata));
118
119         assert_se(userdata == INT_TO_PTR('d'));
120
121         assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGUSR1, -1) >= 0);
122
123         assert_se(sd_event_add_signal(sd_event_source_get_event(s), &p, SIGUSR1, signal_handler, INT_TO_PTR('e')) >= 0);
124         assert_se(sd_event_source_set_enabled(p, SD_EVENT_ONESHOT) >= 0);
125         raise(SIGUSR1);
126
127         sd_event_source_unref(s);
128
129         return 1;
130 }
131
132 static bool do_quit = false;
133
134 static int time_handler(sd_event_source *s, uint64_t usec, void *userdata) {
135         log_info("got timer on %c", PTR_TO_INT(userdata));
136
137         if (userdata == INT_TO_PTR('c')) {
138
139                 if (do_quit) {
140                         sd_event_source *p;
141
142                         assert_se(sd_event_add_defer(sd_event_source_get_event(s), &p, defer_handler, INT_TO_PTR('d')) >= 0);
143                         assert_se(sd_event_source_set_enabled(p, SD_EVENT_ONESHOT) >= 0);
144                 } else {
145                         assert_se(!got_c);
146                         got_c = true;
147                 }
148         } else
149                 assert_not_reached("Huh?");
150
151         return 2;
152 }
153
154 static bool got_exit = false;
155
156 static int exit_handler(sd_event_source *s, void *userdata) {
157         log_info("got quit handler on %c", PTR_TO_INT(userdata));
158
159         got_exit = true;
160
161         return 3;
162 }
163
164 static bool got_post = false;
165
166 static int post_handler(sd_event_source *s, void *userdata) {
167         log_info("got post handler");
168
169         got_post = true;
170
171         return 2;
172 }
173
174 static void test_basic(void) {
175         sd_event *e = NULL;
176         sd_event_source *w = NULL, *x = NULL, *y = NULL, *z = NULL, *q = NULL, *t = NULL;
177         static const char ch = 'x';
178         int a[2] = { -1, -1 }, b[2] = { -1, -1}, d[2] = { -1, -1}, k[2] = { -1, -1 };
179         uint64_t event_now;
180         int64_t priority;
181
182         assert_se(pipe(a) >= 0);
183         assert_se(pipe(b) >= 0);
184         assert_se(pipe(d) >= 0);
185         assert_se(pipe(k) >= 0);
186
187         assert_se(sd_event_default(&e) >= 0);
188         assert_se(sd_event_now(e, CLOCK_MONOTONIC, &event_now) > 0);
189
190         assert_se(sd_event_set_watchdog(e, true) >= 0);
191
192         /* Test whether we cleanly can destroy an io event source from its own handler */
193         got_unref = false;
194         assert_se(sd_event_add_io(e, &t, k[0], EPOLLIN, unref_handler, NULL) >= 0);
195         assert_se(write(k[1], &ch, 1) == 1);
196         assert_se(sd_event_run(e, (uint64_t) -1) >= 1);
197         assert_se(got_unref);
198
199         got_a = false, got_b = false, got_c = false, got_d = 0;
200
201         /* Add a oneshot handler, trigger it, re-enable it, and trigger
202          * it again. */
203         assert_se(sd_event_add_io(e, &w, d[0], EPOLLIN, io_handler, INT_TO_PTR('d')) >= 0);
204         assert_se(sd_event_source_set_enabled(w, SD_EVENT_ONESHOT) >= 0);
205         assert_se(write(d[1], &ch, 1) >= 0);
206         assert_se(sd_event_run(e, (uint64_t) -1) >= 1);
207         assert_se(got_d == 1);
208         assert_se(write(d[1], &ch, 1) >= 0);
209         assert_se(sd_event_run(e, (uint64_t) -1) >= 1);
210         assert_se(got_d == 2);
211
212         assert_se(sd_event_add_io(e, &x, a[0], EPOLLIN, io_handler, INT_TO_PTR('a')) >= 0);
213         assert_se(sd_event_add_io(e, &y, b[0], EPOLLIN, io_handler, INT_TO_PTR('b')) >= 0);
214         assert_se(sd_event_add_time(e, &z, CLOCK_MONOTONIC, 0, 0, time_handler, INT_TO_PTR('c')) >= 0);
215         assert_se(sd_event_add_exit(e, &q, exit_handler, INT_TO_PTR('g')) >= 0);
216
217         assert_se(sd_event_source_set_priority(x, 99) >= 0);
218         assert_se(sd_event_source_get_priority(x, &priority) >= 0);
219         assert_se(priority == 99);
220         assert_se(sd_event_source_set_enabled(y, SD_EVENT_ONESHOT) >= 0);
221         assert_se(sd_event_source_set_prepare(x, prepare_handler) >= 0);
222         assert_se(sd_event_source_set_priority(z, 50) >= 0);
223         assert_se(sd_event_source_set_enabled(z, SD_EVENT_ONESHOT) >= 0);
224         assert_se(sd_event_source_set_prepare(z, prepare_handler) >= 0);
225
226         /* Test for floating event sources */
227         assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGRTMIN+1, -1) >= 0);
228         assert_se(sd_event_add_signal(e, NULL, SIGRTMIN+1, NULL, NULL) >= 0);
229
230         assert_se(write(a[1], &ch, 1) >= 0);
231         assert_se(write(b[1], &ch, 1) >= 0);
232
233         assert_se(!got_a && !got_b && !got_c);
234
235         assert_se(sd_event_run(e, (uint64_t) -1) >= 1);
236
237         assert_se(!got_a && got_b && !got_c);
238
239         assert_se(sd_event_run(e, (uint64_t) -1) >= 1);
240
241         assert_se(!got_a && got_b && got_c);
242
243         assert_se(sd_event_run(e, (uint64_t) -1) >= 1);
244
245         assert_se(got_a && got_b && got_c);
246
247         sd_event_source_unref(x);
248         sd_event_source_unref(y);
249
250         do_quit = true;
251         assert_se(sd_event_add_post(e, NULL, post_handler, NULL) >= 0);
252         assert_se(sd_event_now(e, CLOCK_MONOTONIC, &event_now) == 0);
253         assert_se(sd_event_source_set_time(z, event_now + 200 * USEC_PER_MSEC) >= 0);
254         assert_se(sd_event_source_set_enabled(z, SD_EVENT_ONESHOT) >= 0);
255
256         assert_se(sd_event_loop(e) >= 0);
257         assert_se(got_post);
258         assert_se(got_exit);
259
260         sd_event_source_unref(z);
261         sd_event_source_unref(q);
262
263         sd_event_source_unref(w);
264
265         sd_event_unref(e);
266
267         safe_close_pair(a);
268         safe_close_pair(b);
269         safe_close_pair(d);
270         safe_close_pair(k);
271 }
272
273 static void test_sd_event_now(void) {
274         _cleanup_(sd_event_unrefp) sd_event *e = NULL;
275         uint64_t event_now;
276
277         assert_se(sd_event_new(&e) >= 0);
278         assert_se(sd_event_now(e, CLOCK_MONOTONIC, &event_now) > 0);
279         assert_se(sd_event_now(e, CLOCK_REALTIME, &event_now) > 0);
280         assert_se(sd_event_now(e, CLOCK_REALTIME_ALARM, &event_now) > 0);
281         if (clock_boottime_supported()) {
282                 assert_se(sd_event_now(e, CLOCK_BOOTTIME, &event_now) > 0);
283                 assert_se(sd_event_now(e, CLOCK_BOOTTIME_ALARM, &event_now) > 0);
284         }
285         assert_se(sd_event_now(e, -1, &event_now) == -EOPNOTSUPP);
286         assert_se(sd_event_now(e, 900 /* arbitrary big number */, &event_now) == -EOPNOTSUPP);
287
288         assert_se(sd_event_run(e, 0) == 0);
289
290         assert_se(sd_event_now(e, CLOCK_MONOTONIC, &event_now) == 0);
291         assert_se(sd_event_now(e, CLOCK_REALTIME, &event_now) == 0);
292         assert_se(sd_event_now(e, CLOCK_REALTIME_ALARM, &event_now) == 0);
293         if (clock_boottime_supported()) {
294                 assert_se(sd_event_now(e, CLOCK_BOOTTIME, &event_now) == 0);
295                 assert_se(sd_event_now(e, CLOCK_BOOTTIME_ALARM, &event_now) == 0);
296         }
297         assert_se(sd_event_now(e, -1, &event_now) == -EOPNOTSUPP);
298         assert_se(sd_event_now(e, 900 /* arbitrary big number */, &event_now) == -EOPNOTSUPP);
299 }
300
301 static int last_rtqueue_sigval = 0;
302 static int n_rtqueue = 0;
303
304 static int rtqueue_handler(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
305         last_rtqueue_sigval = si->ssi_int;
306         n_rtqueue++;
307         return 0;
308 }
309
310 static void test_rtqueue(void) {
311         sd_event_source *u = NULL, *v = NULL, *s = NULL;
312         sd_event *e = NULL;
313
314         assert_se(sd_event_default(&e) >= 0);
315
316         assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGRTMIN+2, SIGRTMIN+3, SIGUSR2, -1) >= 0);
317         assert_se(sd_event_add_signal(e, &u, SIGRTMIN+2, rtqueue_handler, NULL) >= 0);
318         assert_se(sd_event_add_signal(e, &v, SIGRTMIN+3, rtqueue_handler, NULL) >= 0);
319         assert_se(sd_event_add_signal(e, &s, SIGUSR2, rtqueue_handler, NULL) >= 0);
320
321         assert_se(sd_event_source_set_priority(v, -10) >= 0);
322
323         assert_se(sigqueue(getpid_cached(), SIGRTMIN+2, (union sigval) { .sival_int = 1 }) >= 0);
324         assert_se(sigqueue(getpid_cached(), SIGRTMIN+3, (union sigval) { .sival_int = 2 }) >= 0);
325         assert_se(sigqueue(getpid_cached(), SIGUSR2, (union sigval) { .sival_int = 3 }) >= 0);
326         assert_se(sigqueue(getpid_cached(), SIGRTMIN+3, (union sigval) { .sival_int = 4 }) >= 0);
327         assert_se(sigqueue(getpid_cached(), SIGUSR2, (union sigval) { .sival_int = 5 }) >= 0);
328
329         assert_se(n_rtqueue == 0);
330         assert_se(last_rtqueue_sigval == 0);
331
332         assert_se(sd_event_run(e, (uint64_t) -1) >= 1);
333         assert_se(n_rtqueue == 1);
334         assert_se(last_rtqueue_sigval == 2); /* first SIGRTMIN+3 */
335
336         assert_se(sd_event_run(e, (uint64_t) -1) >= 1);
337         assert_se(n_rtqueue == 2);
338         assert_se(last_rtqueue_sigval == 4); /* second SIGRTMIN+3 */
339
340         assert_se(sd_event_run(e, (uint64_t) -1) >= 1);
341         assert_se(n_rtqueue == 3);
342         assert_se(last_rtqueue_sigval == 3); /* first SIGUSR2 */
343
344         assert_se(sd_event_run(e, (uint64_t) -1) >= 1);
345         assert_se(n_rtqueue == 4);
346         assert_se(last_rtqueue_sigval == 1); /* SIGRTMIN+2 */
347
348         assert_se(sd_event_run(e, 0) == 0); /* the other SIGUSR2 is dropped, because the first one was still queued */
349         assert_se(n_rtqueue == 4);
350         assert_se(last_rtqueue_sigval == 1);
351
352         sd_event_source_unref(u);
353         sd_event_source_unref(v);
354         sd_event_source_unref(s);
355
356         sd_event_unref(e);
357 }
358
359 int main(int argc, char *argv[]) {
360
361         log_set_max_level(LOG_DEBUG);
362         log_parse_environment();
363
364         test_basic();
365         test_sd_event_now();
366         test_rtqueue();
367
368         return 0;
369 }