]> git.proxmox.com Git - systemd.git/blob - src/libsystemd/sd-event/test-event.c
Imported Upstream version 226
[systemd.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 #include "macro.h"
26 #include "signal-util.h"
27
28 static int prepare_handler(sd_event_source *s, void *userdata) {
29 log_info("preparing %c", PTR_TO_INT(userdata));
30 return 1;
31 }
32
33 static bool got_a, got_b, got_c, got_unref;
34 static unsigned got_d;
35
36 static int unref_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
37 sd_event_source_unref(s);
38 got_unref = true;
39 return 0;
40 }
41
42 static int io_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
43
44 log_info("got IO on %c", PTR_TO_INT(userdata));
45
46 if (userdata == INT_TO_PTR('a')) {
47 assert_se(sd_event_source_set_enabled(s, SD_EVENT_OFF) >= 0);
48 assert_se(!got_a);
49 got_a = true;
50 } else if (userdata == INT_TO_PTR('b')) {
51 assert_se(!got_b);
52 got_b = true;
53 } else if (userdata == INT_TO_PTR('d')) {
54 got_d++;
55 if (got_d < 2)
56 assert_se(sd_event_source_set_enabled(s, SD_EVENT_ONESHOT) >= 0);
57 else
58 assert_se(sd_event_source_set_enabled(s, SD_EVENT_OFF) >= 0);
59 } else
60 assert_not_reached("Yuck!");
61
62 return 1;
63 }
64
65 static int child_handler(sd_event_source *s, const siginfo_t *si, void *userdata) {
66
67 assert_se(s);
68 assert_se(si);
69
70 log_info("got child on %c", PTR_TO_INT(userdata));
71
72 assert_se(userdata == INT_TO_PTR('f'));
73
74 assert_se(sd_event_exit(sd_event_source_get_event(s), 0) >= 0);
75 sd_event_source_unref(s);
76
77 return 1;
78 }
79
80 static int signal_handler(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
81 sd_event_source *p = NULL;
82 pid_t pid;
83
84 assert_se(s);
85 assert_se(si);
86
87 log_info("got signal on %c", PTR_TO_INT(userdata));
88
89 assert_se(userdata == INT_TO_PTR('e'));
90
91 assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, -1) >= 0);
92
93 pid = fork();
94 assert_se(pid >= 0);
95
96 if (pid == 0)
97 _exit(0);
98
99 assert_se(sd_event_add_child(sd_event_source_get_event(s), &p, pid, WEXITED, child_handler, INT_TO_PTR('f')) >= 0);
100 assert_se(sd_event_source_set_enabled(p, SD_EVENT_ONESHOT) >= 0);
101
102 sd_event_source_unref(s);
103
104 return 1;
105 }
106
107 static int defer_handler(sd_event_source *s, void *userdata) {
108 sd_event_source *p = NULL;
109
110 assert_se(s);
111
112 log_info("got defer on %c", PTR_TO_INT(userdata));
113
114 assert_se(userdata == INT_TO_PTR('d'));
115
116 assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGUSR1, -1) >= 0);
117
118 assert_se(sd_event_add_signal(sd_event_source_get_event(s), &p, SIGUSR1, signal_handler, INT_TO_PTR('e')) >= 0);
119 assert_se(sd_event_source_set_enabled(p, SD_EVENT_ONESHOT) >= 0);
120 raise(SIGUSR1);
121
122 sd_event_source_unref(s);
123
124 return 1;
125 }
126
127 static bool do_quit = false;
128
129 static int time_handler(sd_event_source *s, uint64_t usec, void *userdata) {
130 log_info("got timer on %c", PTR_TO_INT(userdata));
131
132 if (userdata == INT_TO_PTR('c')) {
133
134 if (do_quit) {
135 sd_event_source *p;
136
137 assert_se(sd_event_add_defer(sd_event_source_get_event(s), &p, defer_handler, INT_TO_PTR('d')) >= 0);
138 assert_se(sd_event_source_set_enabled(p, SD_EVENT_ONESHOT) >= 0);
139 } else {
140 assert_se(!got_c);
141 got_c = true;
142 }
143 } else
144 assert_not_reached("Huh?");
145
146 return 2;
147 }
148
149 static bool got_exit = false;
150
151 static int exit_handler(sd_event_source *s, void *userdata) {
152 log_info("got quit handler on %c", PTR_TO_INT(userdata));
153
154 got_exit = true;
155
156 return 3;
157 }
158
159 static void test_basic(void) {
160 sd_event *e = NULL;
161 sd_event_source *w = NULL, *x = NULL, *y = NULL, *z = NULL, *q = NULL, *t = NULL;
162 static const char ch = 'x';
163 int a[2] = { -1, -1 }, b[2] = { -1, -1}, d[2] = { -1, -1}, k[2] = { -1, -1 };
164
165 assert_se(pipe(a) >= 0);
166 assert_se(pipe(b) >= 0);
167 assert_se(pipe(d) >= 0);
168 assert_se(pipe(k) >= 0);
169
170 assert_se(sd_event_default(&e) >= 0);
171
172 assert_se(sd_event_set_watchdog(e, true) >= 0);
173
174 /* Test whether we cleanly can destroy an io event source from its own handler */
175 got_unref = false;
176 assert_se(sd_event_add_io(e, &t, k[0], EPOLLIN, unref_handler, NULL) >= 0);
177 assert_se(write(k[1], &ch, 1) == 1);
178 assert_se(sd_event_run(e, (uint64_t) -1) >= 1);
179 assert_se(got_unref);
180
181 got_a = false, got_b = false, got_c = false, got_d = 0;
182
183 /* Add a oneshot handler, trigger it, re-enable it, and trigger
184 * it again. */
185 assert_se(sd_event_add_io(e, &w, d[0], EPOLLIN, io_handler, INT_TO_PTR('d')) >= 0);
186 assert_se(sd_event_source_set_enabled(w, SD_EVENT_ONESHOT) >= 0);
187 assert_se(write(d[1], &ch, 1) >= 0);
188 assert_se(sd_event_run(e, (uint64_t) -1) >= 1);
189 assert_se(got_d == 1);
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 == 2);
193
194 assert_se(sd_event_add_io(e, &x, a[0], EPOLLIN, io_handler, INT_TO_PTR('a')) >= 0);
195 assert_se(sd_event_add_io(e, &y, b[0], EPOLLIN, io_handler, INT_TO_PTR('b')) >= 0);
196 assert_se(sd_event_add_time(e, &z, CLOCK_MONOTONIC, 0, 0, time_handler, INT_TO_PTR('c')) >= 0);
197 assert_se(sd_event_add_exit(e, &q, exit_handler, INT_TO_PTR('g')) >= 0);
198
199 assert_se(sd_event_source_set_priority(x, 99) >= 0);
200 assert_se(sd_event_source_set_enabled(y, SD_EVENT_ONESHOT) >= 0);
201 assert_se(sd_event_source_set_prepare(x, prepare_handler) >= 0);
202 assert_se(sd_event_source_set_priority(z, 50) >= 0);
203 assert_se(sd_event_source_set_enabled(z, SD_EVENT_ONESHOT) >= 0);
204 assert_se(sd_event_source_set_prepare(z, prepare_handler) >= 0);
205
206 /* Test for floating event sources */
207 assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGRTMIN+1, -1) >= 0);
208 assert_se(sd_event_add_signal(e, NULL, SIGRTMIN+1, NULL, NULL) >= 0);
209
210 assert_se(write(a[1], &ch, 1) >= 0);
211 assert_se(write(b[1], &ch, 1) >= 0);
212
213 assert_se(!got_a && !got_b && !got_c);
214
215 assert_se(sd_event_run(e, (uint64_t) -1) >= 1);
216
217 assert_se(!got_a && got_b && !got_c);
218
219 assert_se(sd_event_run(e, (uint64_t) -1) >= 1);
220
221 assert_se(!got_a && got_b && got_c);
222
223 assert_se(sd_event_run(e, (uint64_t) -1) >= 1);
224
225 assert_se(got_a && got_b && got_c);
226
227 sd_event_source_unref(x);
228 sd_event_source_unref(y);
229
230 do_quit = true;
231 assert_se(sd_event_source_set_time(z, now(CLOCK_MONOTONIC) + 200 * USEC_PER_MSEC) >= 0);
232 assert_se(sd_event_source_set_enabled(z, SD_EVENT_ONESHOT) >= 0);
233
234 assert_se(sd_event_loop(e) >= 0);
235
236 sd_event_source_unref(z);
237 sd_event_source_unref(q);
238
239 sd_event_source_unref(w);
240
241 sd_event_unref(e);
242
243 safe_close_pair(a);
244 safe_close_pair(b);
245 safe_close_pair(d);
246 safe_close_pair(k);
247 }
248
249 static int last_rtqueue_sigval = 0;
250 static int n_rtqueue = 0;
251
252 static int rtqueue_handler(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
253 last_rtqueue_sigval = si->ssi_int;
254 n_rtqueue ++;
255 return 0;
256 }
257
258 static void test_rtqueue(void) {
259 sd_event_source *u = NULL, *v = NULL, *s = NULL;
260 sd_event *e = NULL;
261
262 assert_se(sd_event_default(&e) >= 0);
263
264 assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGRTMIN+2, SIGRTMIN+3, SIGUSR2, -1) >= 0);
265 assert_se(sd_event_add_signal(e, &u, SIGRTMIN+2, rtqueue_handler, NULL) >= 0);
266 assert_se(sd_event_add_signal(e, &v, SIGRTMIN+3, rtqueue_handler, NULL) >= 0);
267 assert_se(sd_event_add_signal(e, &s, SIGUSR2, rtqueue_handler, NULL) >= 0);
268
269 assert_se(sd_event_source_set_priority(v, -10) >= 0);
270
271 assert(sigqueue(getpid(), SIGRTMIN+2, (union sigval) { .sival_int = 1 }) >= 0);
272 assert(sigqueue(getpid(), SIGRTMIN+3, (union sigval) { .sival_int = 2 }) >= 0);
273 assert(sigqueue(getpid(), SIGUSR2, (union sigval) { .sival_int = 3 }) >= 0);
274 assert(sigqueue(getpid(), SIGRTMIN+3, (union sigval) { .sival_int = 4 }) >= 0);
275 assert(sigqueue(getpid(), SIGUSR2, (union sigval) { .sival_int = 5 }) >= 0);
276
277 assert_se(n_rtqueue == 0);
278 assert_se(last_rtqueue_sigval == 0);
279
280 assert_se(sd_event_run(e, (uint64_t) -1) >= 1);
281 assert_se(n_rtqueue == 1);
282 assert_se(last_rtqueue_sigval == 2); /* first SIGRTMIN+3 */
283
284 assert_se(sd_event_run(e, (uint64_t) -1) >= 1);
285 assert_se(n_rtqueue == 2);
286 assert_se(last_rtqueue_sigval == 4); /* second SIGRTMIN+3 */
287
288 assert_se(sd_event_run(e, (uint64_t) -1) >= 1);
289 assert_se(n_rtqueue == 3);
290 assert_se(last_rtqueue_sigval == 3); /* first SIGUSR2 */
291
292 assert_se(sd_event_run(e, (uint64_t) -1) >= 1);
293 assert_se(n_rtqueue == 4);
294 assert_se(last_rtqueue_sigval == 1); /* SIGRTMIN+2 */
295
296 assert_se(sd_event_run(e, 0) == 0); /* the other SIGUSR2 is dropped, because the first one was still queued */
297 assert_se(n_rtqueue == 4);
298 assert_se(last_rtqueue_sigval == 1);
299
300 sd_event_source_unref(u);
301 sd_event_source_unref(v);
302 sd_event_source_unref(s);
303
304 sd_event_unref(e);
305 }
306
307 int main(int argc, char *argv[]) {
308
309 test_basic();
310 test_rtqueue();
311
312 return 0;
313 }