remote: add sysusers file to create 'libvirt' group
[libvirt.git] / tests / eventtest.c
blob470de4c6304945629daeab888eda3859a9d21bfe
1 /*
2 * eventtest.c: Test the libvirtd event loop impl
4 * Copyright (C) 2009, 2011-2014 Red Hat, Inc.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library. If not, see
18 * <http://www.gnu.org/licenses/>.
21 #include <config.h>
23 #include <signal.h>
24 #include <time.h>
26 #if WITH_MACH_CLOCK_ROUTINES
27 # include <mach/clock.h>
28 # include <mach/mach.h>
29 #endif
31 #include "testutils.h"
32 #include "internal.h"
33 #include "virfile.h"
34 #include "virlog.h"
35 #include "virutil.h"
37 VIR_LOG_INIT("tests.eventtest");
39 #define NUM_FDS 31
40 #define NUM_TIME 31
42 static pthread_mutex_t eventThreadMutex = PTHREAD_MUTEX_INITIALIZER;
43 static pthread_cond_t eventThreadCond = PTHREAD_COND_INITIALIZER;
44 static bool eventThreadSignaled;
46 static struct handleInfo {
47 int pipeFD[2];
48 int fired;
49 int watch;
50 int error;
51 int delete;
52 } handles[NUM_FDS];
54 static struct timerInfo {
55 int timeout;
56 int timer;
57 int fired;
58 int error;
59 int delete;
60 } timers[NUM_TIME];
62 enum {
63 EV_ERROR_NONE,
64 EV_ERROR_WATCH,
65 EV_ERROR_FD,
66 EV_ERROR_EVENT,
67 EV_ERROR_DATA,
70 struct testEventResultData {
71 bool failed;
72 const char *msg;
75 static int
76 testEventResultCallback(const void *opaque)
78 const struct testEventResultData *data = opaque;
80 if (data->failed && data->msg)
81 fprintf(stderr, "%s", data->msg);
82 return data->failed;
85 static void
86 G_GNUC_PRINTF(3, 4)
87 testEventReport(const char *name, bool failed, const char *msg, ...)
89 va_list vargs;
90 g_autofree char *str = NULL;
91 struct testEventResultData data;
93 va_start(vargs, msg);
95 if (msg)
96 str = g_strdup_vprintf(msg, vargs);
98 data.failed = failed;
99 data.msg = str;
100 ignore_value(virTestRun(name, testEventResultCallback, &data));
102 va_end(vargs);
105 static void
106 testPipeReader(int watch, int fd, int events, void *data)
108 struct handleInfo *info = data;
109 char one;
111 VIR_DEBUG("Handle callback watch=%d fd=%d ev=%d", watch, fd, events);
112 pthread_mutex_lock(&eventThreadMutex);
114 info->fired = 1;
116 if (watch != info->watch) {
117 info->error = EV_ERROR_WATCH;
118 goto cleanup;
121 if (fd != info->pipeFD[0]) {
122 info->error = EV_ERROR_FD;
123 goto cleanup;
126 if (!(events & VIR_EVENT_HANDLE_READABLE)) {
127 info->error = EV_ERROR_EVENT;
128 goto cleanup;
130 if (read(fd, &one, 1) != 1) {
131 info->error = EV_ERROR_DATA;
132 goto cleanup;
134 info->error = EV_ERROR_NONE;
136 if (info->delete != -1)
137 virEventRemoveHandle(info->delete);
139 cleanup:
140 pthread_cond_signal(&eventThreadCond);
141 eventThreadSignaled = true;
142 pthread_mutex_unlock(&eventThreadMutex);
146 static void
147 testTimer(int timer, void *data)
149 struct timerInfo *info = data;
151 VIR_DEBUG("Timer callback timer=%d", timer);
152 pthread_mutex_lock(&eventThreadMutex);
154 info->fired = 1;
156 if (timer != info->timer) {
157 info->error = EV_ERROR_WATCH;
158 goto cleanup;
161 info->error = EV_ERROR_NONE;
163 if (info->delete != -1)
164 virEventRemoveTimeout(info->delete);
166 cleanup:
167 pthread_cond_signal(&eventThreadCond);
168 eventThreadSignaled = true;
169 pthread_mutex_unlock(&eventThreadMutex);
172 G_GNUC_NORETURN static void *eventThreadLoop(void *data G_GNUC_UNUSED) {
173 while (1)
174 virEventRunDefaultImpl();
175 abort();
179 static void
180 waitEvents(int nhandle, int ntimer)
182 int ngothandle = 0;
183 int ngottimer = 0;
184 size_t i;
186 VIR_DEBUG("Wait events nhandle %d ntimer %d",
187 nhandle, ntimer);
188 while (ngothandle != nhandle || ngottimer != ntimer) {
189 while (!eventThreadSignaled)
190 pthread_cond_wait(&eventThreadCond, &eventThreadMutex);
192 eventThreadSignaled = false;
194 ngothandle = ngottimer = 0;
195 for (i = 0; i < NUM_FDS; i++) {
196 if (handles[i].fired)
197 ngothandle++;
199 for (i = 0; i < NUM_TIME; i++) {
200 if (timers[i].fired)
201 ngottimer++;
204 VIR_DEBUG("Wait events ngothandle %d ngottimer %d",
205 ngothandle, ngottimer);
211 static int
212 verifyFired(const char *name, int handle, int timer)
214 int handleFired = 0;
215 int timerFired = 0;
216 size_t i;
217 VIR_DEBUG("Verify fired handle %d timer %d", handle, timer);
218 for (i = 0; i < NUM_FDS; i++) {
219 if (handles[i].fired) {
220 if (i != handle) {
221 testEventReport(name, 1,
222 "Handle %zu fired, but expected %d\n", i,
223 handle);
224 return EXIT_FAILURE;
225 } else {
226 if (handles[i].error != EV_ERROR_NONE) {
227 testEventReport(name, 1,
228 "Handle %zu fired, but had error %d\n", i,
229 handles[i].error);
230 return EXIT_FAILURE;
232 handleFired = 1;
234 } else {
235 if (i == handle) {
236 testEventReport(name, 1,
237 "Handle %d should have fired, but didn't\n",
238 handle);
239 return EXIT_FAILURE;
243 if (handleFired != 1 && handle != -1) {
244 testEventReport(name, 1,
245 "Something weird happened, expecting handle %d\n",
246 handle);
247 return EXIT_FAILURE;
251 for (i = 0; i < NUM_TIME; i++) {
252 if (timers[i].fired) {
253 if (i != timer) {
254 testEventReport(name, 1,
255 "Timer %zu fired, but expected %d\n", i, timer);
256 return EXIT_FAILURE;
257 } else {
258 if (timers[i].error != EV_ERROR_NONE) {
259 testEventReport(name, 1,
260 "Timer %zu fired, but had error %d\n", i,
261 timers[i].error);
262 return EXIT_FAILURE;
264 timerFired = 1;
266 } else {
267 if (i == timer) {
268 testEventReport(name, 1,
269 "Timer %d should have fired, but didn't\n",
270 timer);
271 return EXIT_FAILURE;
275 if (timerFired != 1 && timer != -1) {
276 testEventReport(name, 1,
277 "Something weird happened, expecting timer %d\n",
278 timer);
279 return EXIT_FAILURE;
281 return EXIT_SUCCESS;
285 static int
286 finishJob(const char *name, int handle, int timer)
288 pthread_mutex_lock(&eventThreadMutex);
290 waitEvents(handle == -1 ? 0 : 1,
291 timer == -1 ? 0 : 1);
293 if (verifyFired(name, handle, timer) != EXIT_SUCCESS) {
294 pthread_mutex_unlock(&eventThreadMutex);
295 return EXIT_FAILURE;
298 testEventReport(name, 0, NULL);
300 pthread_mutex_unlock(&eventThreadMutex);
301 return EXIT_SUCCESS;
304 static void
305 resetAll(void)
307 size_t i;
308 pthread_mutex_lock(&eventThreadMutex);
309 for (i = 0; i < NUM_FDS; i++) {
310 handles[i].fired = 0;
311 handles[i].error = EV_ERROR_NONE;
313 for (i = 0; i < NUM_TIME; i++) {
314 timers[i].fired = 0;
315 timers[i].error = EV_ERROR_NONE;
317 pthread_mutex_unlock(&eventThreadMutex);
320 static int
321 mymain(void)
323 size_t i;
324 pthread_t eventThread;
325 char one = '1';
326 char *debugEnv = getenv("LIBVIRT_DEBUG");
328 for (i = 0; i < NUM_FDS; i++) {
329 if (virPipeQuiet(handles[i].pipeFD) < 0) {
330 fprintf(stderr, "Cannot create pipe: %d", errno);
331 return EXIT_FAILURE;
335 if (debugEnv && *debugEnv &&
336 (virLogSetDefaultPriority(virLogParseDefaultPriority(debugEnv)) < 0)) {
337 fprintf(stderr, "Invalid log level setting.\n");
338 return EXIT_FAILURE;
341 virEventRegisterDefaultImpl();
343 for (i = 0; i < NUM_FDS; i++) {
344 handles[i].delete = -1;
345 handles[i].watch =
346 virEventAddHandle(handles[i].pipeFD[0],
347 VIR_EVENT_HANDLE_READABLE,
348 testPipeReader,
349 &handles[i], NULL);
352 for (i = 0; i < NUM_TIME; i++) {
353 timers[i].delete = -1;
354 timers[i].timeout = -1;
355 timers[i].timer =
356 virEventAddTimeout(timers[i].timeout,
357 testTimer,
358 &timers[i], NULL);
361 pthread_create(&eventThread, NULL, eventThreadLoop, NULL);
363 /* First time, is easy - just try triggering one of our
364 * registered handles */
365 if (safewrite(handles[1].pipeFD[1], &one, 1) != 1)
366 return EXIT_FAILURE;
367 if (finishJob("Simple write", 1, -1) != EXIT_SUCCESS)
368 return EXIT_FAILURE;
370 resetAll();
372 /* Now lets delete one before starting poll(), and
373 * try triggering another handle */
374 virEventRemoveHandle(handles[0].watch);
375 if (safewrite(handles[1].pipeFD[1], &one, 1) != 1)
376 return EXIT_FAILURE;
377 if (finishJob("Deleted before poll", 1, -1) != EXIT_SUCCESS)
378 return EXIT_FAILURE;
380 resetAll();
382 /* Next lets delete *during* poll, which should interrupt
383 * the loop with no event showing */
385 virEventRemoveHandle(handles[1].watch);
386 if (finishJob("Interrupted during poll", -1, -1) != EXIT_SUCCESS)
387 return EXIT_FAILURE;
389 resetAll();
391 /* Getting more fun, lets delete a later handle during dispatch */
393 handles[2].delete = handles[3].watch;
394 if (safewrite(handles[2].pipeFD[1], &one, 1) != 1
395 || safewrite(handles[3].pipeFD[1], &one, 1) != 1)
396 return EXIT_FAILURE;
397 if (finishJob("Deleted during dispatch", 2, -1) != EXIT_SUCCESS)
398 return EXIT_FAILURE;
400 resetAll();
402 /* Extreme fun, lets delete ourselves during dispatch */
403 handles[2].delete = handles[2].watch;
404 if (safewrite(handles[2].pipeFD[1], &one, 1) != 1)
405 return EXIT_FAILURE;
406 if (finishJob("Deleted during dispatch", 2, -1) != EXIT_SUCCESS)
407 return EXIT_FAILURE;
409 resetAll();
413 /* Run a timer on its own */
414 virEventUpdateTimeout(timers[1].timer, 100);
415 if (finishJob("Firing a timer", -1, 1) != EXIT_SUCCESS)
416 return EXIT_FAILURE;
417 virEventUpdateTimeout(timers[1].timer, -1);
419 resetAll();
421 /* Now lets delete one before starting poll(), and
422 * try triggering another timer */
423 virEventUpdateTimeout(timers[1].timer, 100);
424 virEventRemoveTimeout(timers[0].timer);
425 if (finishJob("Deleted before poll", -1, 1) != EXIT_SUCCESS)
426 return EXIT_FAILURE;
427 virEventUpdateTimeout(timers[1].timer, -1);
429 resetAll();
431 /* Next lets delete *during* poll, which should interrupt
432 * the loop with no event showing */
434 virEventRemoveTimeout(timers[1].timer);
435 if (finishJob("Interrupted during poll", -1, -1) != EXIT_SUCCESS)
436 return EXIT_FAILURE;
438 resetAll();
440 /* Getting more fun, lets delete a later timer during dispatch */
442 virEventUpdateTimeout(timers[2].timer, 100);
443 virEventUpdateTimeout(timers[3].timer, 100);
444 timers[2].delete = timers[3].timer;
445 if (finishJob("Deleted during dispatch", -1, 2) != EXIT_SUCCESS)
446 return EXIT_FAILURE;
447 virEventUpdateTimeout(timers[2].timer, -1);
449 resetAll();
451 /* Extreme fun, lets delete ourselves during dispatch */
452 virEventUpdateTimeout(timers[2].timer, 100);
453 timers[2].delete = timers[2].timer;
454 if (finishJob("Deleted during dispatch", -1, 2) != EXIT_SUCCESS)
455 return EXIT_FAILURE;
457 for (i = 0; i < NUM_FDS - 1; i++)
458 virEventRemoveHandle(handles[i].watch);
459 for (i = 0; i < NUM_TIME - 1; i++)
460 virEventRemoveTimeout(timers[i].timer);
462 resetAll();
464 /* Make sure the last handle still works several times in a row. */
465 for (i = 0; i < 4; i++) {
466 if (safewrite(handles[NUM_FDS - 1].pipeFD[1], &one, 1) != 1)
467 return EXIT_FAILURE;
468 if (finishJob("Simple write", NUM_FDS - 1, -1) != EXIT_SUCCESS)
469 return EXIT_FAILURE;
471 resetAll();
475 /* Final test, register same FD twice, once with no
476 * events, and make sure the right callback runs */
477 handles[0].pipeFD[0] = handles[1].pipeFD[0];
478 handles[0].pipeFD[1] = handles[1].pipeFD[1];
480 handles[0].watch = virEventAddHandle(handles[0].pipeFD[0],
482 testPipeReader,
483 &handles[0], NULL);
484 handles[1].watch = virEventAddHandle(handles[1].pipeFD[0],
485 VIR_EVENT_HANDLE_READABLE,
486 testPipeReader,
487 &handles[1], NULL);
489 if (safewrite(handles[1].pipeFD[1], &one, 1) != 1)
490 return EXIT_FAILURE;
491 if (finishJob("Write duplicate", 1, -1) != EXIT_SUCCESS)
492 return EXIT_FAILURE;
494 /* pthread_kill(eventThread, SIGTERM); */
496 return EXIT_SUCCESS;
499 VIR_TEST_MAIN(mymain)