chiark / gitweb /
util: split out signal-util.[ch] from util.[ch]
[elogind.git] / src / libelogind / 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         sigset_t ss;
83         pid_t pid;
84
85         assert_se(s);
86         assert_se(si);
87
88         log_info("got signal on %c", PTR_TO_INT(userdata));
89
90         assert_se(userdata == INT_TO_PTR('e'));
91
92         assert_se(sigemptyset(&ss) >= 0);
93         assert_se(sigaddset(&ss, SIGCHLD) >= 0);
94         assert_se(sigprocmask(SIG_BLOCK, &ss, NULL) >= 0);
95
96         pid = fork();
97         assert_se(pid >= 0);
98
99         if (pid == 0)
100                 _exit(0);
101
102         assert_se(sd_event_add_child(sd_event_source_get_event(s), &p, pid, WEXITED, child_handler, INT_TO_PTR('f')) >= 0);
103         assert_se(sd_event_source_set_enabled(p, SD_EVENT_ONESHOT) >= 0);
104
105         sd_event_source_unref(s);
106
107         return 1;
108 }
109
110 static int defer_handler(sd_event_source *s, void *userdata) {
111         sd_event_source *p = NULL;
112         sigset_t ss;
113
114         assert_se(s);
115
116         log_info("got defer on %c", PTR_TO_INT(userdata));
117
118         assert_se(userdata == INT_TO_PTR('d'));
119
120         assert_se(sigemptyset(&ss) >= 0);
121         assert_se(sigaddset(&ss, SIGUSR1) >= 0);
122         assert_se(sigprocmask(SIG_BLOCK, &ss, NULL) >= 0);
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 int main(int argc, char *argv[]) {
165         sd_event *e = NULL;
166         sd_event_source *w = NULL, *x = NULL, *y = NULL, *z = NULL, *q = NULL, *t = NULL;
167         static const char ch = 'x';
168         int a[2] = { -1, -1 }, b[2] = { -1, -1}, d[2] = { -1, -1}, k[2] = { -1, -1 };
169
170         assert_se(pipe(a) >= 0);
171         assert_se(pipe(b) >= 0);
172         assert_se(pipe(d) >= 0);
173         assert_se(pipe(k) >= 0);
174
175         assert_se(sd_event_default(&e) >= 0);
176
177         assert_se(sd_event_set_watchdog(e, true) >= 0);
178
179         /* Test whether we cleanly can destroy an io event source from its own handler */
180         got_unref = false;
181         assert_se(sd_event_add_io(e, &t, k[0], EPOLLIN, unref_handler, NULL) >= 0);
182         assert_se(write(k[1], &ch, 1) == 1);
183         assert_se(sd_event_run(e, (uint64_t) -1) >= 1);
184         assert_se(got_unref);
185
186         got_a = false, got_b = false, got_c = false, got_d = 0;
187
188         /* Add a oneshot handler, trigger it, re-enable it, and trigger
189          * it again. */
190         assert_se(sd_event_add_io(e, &w, d[0], EPOLLIN, io_handler, INT_TO_PTR('d')) >= 0);
191         assert_se(sd_event_source_set_enabled(w, SD_EVENT_ONESHOT) >= 0);
192         assert_se(write(d[1], &ch, 1) >= 0);
193         assert_se(sd_event_run(e, (uint64_t) -1) >= 1);
194         assert_se(got_d == 1);
195         assert_se(write(d[1], &ch, 1) >= 0);
196         assert_se(sd_event_run(e, (uint64_t) -1) >= 1);
197         assert_se(got_d == 2);
198
199         assert_se(sd_event_add_io(e, &x, a[0], EPOLLIN, io_handler, INT_TO_PTR('a')) >= 0);
200         assert_se(sd_event_add_io(e, &y, b[0], EPOLLIN, io_handler, INT_TO_PTR('b')) >= 0);
201         assert_se(sd_event_add_time(e, &z, CLOCK_MONOTONIC, 0, 0, time_handler, INT_TO_PTR('c')) >= 0);
202         assert_se(sd_event_add_exit(e, &q, exit_handler, INT_TO_PTR('g')) >= 0);
203
204         assert_se(sd_event_source_set_priority(x, 99) >= 0);
205         assert_se(sd_event_source_set_enabled(y, SD_EVENT_ONESHOT) >= 0);
206         assert_se(sd_event_source_set_prepare(x, prepare_handler) >= 0);
207         assert_se(sd_event_source_set_priority(z, 50) >= 0);
208         assert_se(sd_event_source_set_enabled(z, SD_EVENT_ONESHOT) >= 0);
209         assert_se(sd_event_source_set_prepare(z, prepare_handler) >= 0);
210
211         /* Test for floating event sources */
212         assert_se(sigprocmask_many(SIG_BLOCK, SIGRTMIN+1, -1) == 0);
213         assert_se(sd_event_add_signal(e, NULL, SIGRTMIN+1, NULL, NULL) >= 0);
214
215         assert_se(write(a[1], &ch, 1) >= 0);
216         assert_se(write(b[1], &ch, 1) >= 0);
217
218         assert_se(!got_a && !got_b && !got_c);
219
220         assert_se(sd_event_run(e, (uint64_t) -1) >= 1);
221
222         assert_se(!got_a && got_b && !got_c);
223
224         assert_se(sd_event_run(e, (uint64_t) -1) >= 1);
225
226         assert_se(!got_a && got_b && got_c);
227
228         assert_se(sd_event_run(e, (uint64_t) -1) >= 1);
229
230         assert_se(got_a && got_b && got_c);
231
232         sd_event_source_unref(x);
233         sd_event_source_unref(y);
234
235         do_quit = true;
236         assert_se(sd_event_source_set_time(z, now(CLOCK_MONOTONIC) + 200 * USEC_PER_MSEC) >= 0);
237         assert_se(sd_event_source_set_enabled(z, SD_EVENT_ONESHOT) >= 0);
238
239         assert_se(sd_event_loop(e) >= 0);
240
241         sd_event_source_unref(z);
242         sd_event_source_unref(q);
243
244         sd_event_source_unref(w);
245
246         sd_event_unref(e);
247
248         safe_close_pair(a);
249         safe_close_pair(b);
250         safe_close_pair(d);
251         safe_close_pair(k);
252
253         return 0;
254 }