backup: Wire up qemu full pull backup commands over QMP
[libvirt/ericb.git] / tests / eventtest.c
blobdf7570bac6ad0571f34981b1402b795702f20c49
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 HAVE_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 "virthread.h"
35 #include "virlog.h"
36 #include "virutil.h"
37 #include "vireventpoll.h"
39 VIR_LOG_INIT("tests.eventtest");
41 #define NUM_FDS 31
42 #define NUM_TIME 31
44 static struct handleInfo {
45 int pipeFD[2];
46 int fired;
47 int watch;
48 int error;
49 int delete;
50 } handles[NUM_FDS];
52 static struct timerInfo {
53 int timeout;
54 int timer;
55 int fired;
56 int error;
57 int delete;
58 } timers[NUM_TIME];
60 enum {
61 EV_ERROR_NONE,
62 EV_ERROR_WATCH,
63 EV_ERROR_FD,
64 EV_ERROR_EVENT,
65 EV_ERROR_DATA,
68 struct testEventResultData {
69 bool failed;
70 const char *msg;
73 static int
74 testEventResultCallback(const void *opaque)
76 const struct testEventResultData *data = opaque;
78 if (data->failed && data->msg)
79 fprintf(stderr, "%s", data->msg);
80 return data->failed;
83 static void
84 ATTRIBUTE_FMT_PRINTF(3, 4)
85 testEventReport(const char *name, bool failed, const char *msg, ...)
87 va_list vargs;
88 va_start(vargs, msg);
89 char *str = NULL;
90 struct testEventResultData data;
92 if (msg && virVasprintfQuiet(&str, msg, vargs) != 0)
93 failed = true;
95 data.failed = failed;
96 data.msg = str;
97 ignore_value(virTestRun(name, testEventResultCallback, &data));
99 va_end(vargs);
100 VIR_FREE(str);
103 static void
104 testPipeReader(int watch, int fd, int events, void *data)
106 struct handleInfo *info = data;
107 char one;
109 info->fired = 1;
111 if (watch != info->watch) {
112 info->error = EV_ERROR_WATCH;
113 return;
116 if (fd != info->pipeFD[0]) {
117 info->error = EV_ERROR_FD;
118 return;
121 if (!(events & VIR_EVENT_HANDLE_READABLE)) {
122 info->error = EV_ERROR_EVENT;
123 return;
125 if (read(fd, &one, 1) != 1) {
126 info->error = EV_ERROR_DATA;
127 return;
129 info->error = EV_ERROR_NONE;
131 if (info->delete != -1)
132 virEventPollRemoveHandle(info->delete);
136 static void
137 testTimer(int timer, void *data)
139 struct timerInfo *info = data;
141 info->fired = 1;
143 if (timer != info->timer) {
144 info->error = EV_ERROR_WATCH;
145 return;
148 info->error = EV_ERROR_NONE;
150 if (info->delete != -1)
151 virEventPollRemoveTimeout(info->delete);
154 static pthread_mutex_t eventThreadMutex = PTHREAD_MUTEX_INITIALIZER;
155 static pthread_cond_t eventThreadRunCond = PTHREAD_COND_INITIALIZER;
156 static int eventThreadRunOnce;
157 static pthread_cond_t eventThreadJobCond = PTHREAD_COND_INITIALIZER;
158 static int eventThreadJobDone;
161 ATTRIBUTE_NORETURN static void *eventThreadLoop(void *data ATTRIBUTE_UNUSED) {
162 while (1) {
163 pthread_mutex_lock(&eventThreadMutex);
164 while (!eventThreadRunOnce)
165 pthread_cond_wait(&eventThreadRunCond, &eventThreadMutex);
166 eventThreadRunOnce = 0;
167 pthread_mutex_unlock(&eventThreadMutex);
169 virEventPollRunOnce();
171 pthread_mutex_lock(&eventThreadMutex);
172 eventThreadJobDone = 1;
173 pthread_cond_signal(&eventThreadJobCond);
174 pthread_mutex_unlock(&eventThreadMutex);
179 static int
180 verifyFired(const char *name, int handle, int timer)
182 int handleFired = 0;
183 int timerFired = 0;
184 size_t i;
185 for (i = 0; i < NUM_FDS; i++) {
186 if (handles[i].fired) {
187 if (i != handle) {
188 testEventReport(name, 1,
189 "Handle %zu fired, but expected %d\n", i,
190 handle);
191 return EXIT_FAILURE;
192 } else {
193 if (handles[i].error != EV_ERROR_NONE) {
194 testEventReport(name, 1,
195 "Handle %zu fired, but had error %d\n", i,
196 handles[i].error);
197 return EXIT_FAILURE;
199 handleFired = 1;
201 } else {
202 if (i == handle) {
203 testEventReport(name, 1,
204 "Handle %d should have fired, but didn't\n",
205 handle);
206 return EXIT_FAILURE;
210 if (handleFired != 1 && handle != -1) {
211 testEventReport(name, 1,
212 "Something weird happened, expecting handle %d\n",
213 handle);
214 return EXIT_FAILURE;
218 for (i = 0; i < NUM_TIME; i++) {
219 if (timers[i].fired) {
220 if (i != timer) {
221 testEventReport(name, 1,
222 "Timer %zu fired, but expected %d\n", i, timer);
223 return EXIT_FAILURE;
224 } else {
225 if (timers[i].error != EV_ERROR_NONE) {
226 testEventReport(name, 1,
227 "Timer %zu fired, but had error %d\n", i,
228 timers[i].error);
229 return EXIT_FAILURE;
231 timerFired = 1;
233 } else {
234 if (i == timer) {
235 testEventReport(name, 1,
236 "Timer %d should have fired, but didn't\n",
237 timer);
238 return EXIT_FAILURE;
242 if (timerFired != 1 && timer != -1) {
243 testEventReport(name, 1,
244 "Something weird happened, expecting timer %d\n",
245 timer);
246 return EXIT_FAILURE;
248 return EXIT_SUCCESS;
251 static void
252 startJob(void)
254 eventThreadRunOnce = 1;
255 eventThreadJobDone = 0;
256 pthread_cond_signal(&eventThreadRunCond);
257 pthread_mutex_unlock(&eventThreadMutex);
258 sched_yield();
259 pthread_mutex_lock(&eventThreadMutex);
262 static int
263 finishJob(const char *name, int handle, int timer)
265 struct timespec waitTime;
266 int rc;
267 #if HAVE_MACH_CLOCK_ROUTINES
268 clock_serv_t cclock;
269 mach_timespec_t mts;
271 host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
272 clock_get_time(cclock, &mts);
273 mach_port_deallocate(mach_task_self(), cclock);
274 waitTime.tv_sec = mts.tv_sec;
275 waitTime.tv_nsec = mts.tv_nsec;
276 #else
277 clock_gettime(CLOCK_REALTIME, &waitTime);
278 #endif
279 waitTime.tv_sec += 5;
280 rc = 0;
281 while (!eventThreadJobDone && rc == 0)
282 rc = pthread_cond_timedwait(&eventThreadJobCond, &eventThreadMutex,
283 &waitTime);
284 if (rc != 0) {
285 testEventReport(name, 1, "Timed out waiting for pipe event\n");
286 return EXIT_FAILURE;
289 if (verifyFired(name, handle, timer) != EXIT_SUCCESS)
290 return EXIT_FAILURE;
292 testEventReport(name, 0, NULL);
293 return EXIT_SUCCESS;
296 static void
297 resetAll(void)
299 size_t i;
300 for (i = 0; i < NUM_FDS; i++) {
301 handles[i].fired = 0;
302 handles[i].error = EV_ERROR_NONE;
304 for (i = 0; i < NUM_TIME; i++) {
305 timers[i].fired = 0;
306 timers[i].error = EV_ERROR_NONE;
310 static int
311 mymain(void)
313 size_t i;
314 pthread_t eventThread;
315 char one = '1';
317 for (i = 0; i < NUM_FDS; i++) {
318 if (pipe(handles[i].pipeFD) < 0) {
319 fprintf(stderr, "Cannot create pipe: %d", errno);
320 return EXIT_FAILURE;
324 if (virThreadInitialize() < 0)
325 return EXIT_FAILURE;
326 char *debugEnv = getenv("LIBVIRT_DEBUG");
327 if (debugEnv && *debugEnv &&
328 (virLogSetDefaultPriority(virLogParseDefaultPriority(debugEnv)) < 0)) {
329 fprintf(stderr, "Invalid log level setting.\n");
330 return EXIT_FAILURE;
333 virEventPollInit();
335 for (i = 0; i < NUM_FDS; i++) {
336 handles[i].delete = -1;
337 handles[i].watch =
338 virEventPollAddHandle(handles[i].pipeFD[0],
339 VIR_EVENT_HANDLE_READABLE,
340 testPipeReader,
341 &handles[i], NULL);
344 for (i = 0; i < NUM_TIME; i++) {
345 timers[i].delete = -1;
346 timers[i].timeout = -1;
347 timers[i].timer =
348 virEventPollAddTimeout(timers[i].timeout,
349 testTimer,
350 &timers[i], NULL);
353 pthread_create(&eventThread, NULL, eventThreadLoop, NULL);
355 pthread_mutex_lock(&eventThreadMutex);
357 /* First time, is easy - just try triggering one of our
358 * registered handles */
359 startJob();
360 if (safewrite(handles[1].pipeFD[1], &one, 1) != 1)
361 return EXIT_FAILURE;
362 if (finishJob("Simple write", 1, -1) != EXIT_SUCCESS)
363 return EXIT_FAILURE;
365 resetAll();
367 /* Now lets delete one before starting poll(), and
368 * try triggering another handle */
369 virEventPollRemoveHandle(handles[0].watch);
370 startJob();
371 if (safewrite(handles[1].pipeFD[1], &one, 1) != 1)
372 return EXIT_FAILURE;
373 if (finishJob("Deleted before poll", 1, -1) != EXIT_SUCCESS)
374 return EXIT_FAILURE;
376 resetAll();
378 /* Next lets delete *during* poll, which should interrupt
379 * the loop with no event showing */
381 /* NB: this case is subject to a bit of a race condition.
382 * We yield & sleep, and pray that the other thread gets
383 * scheduled before we run EventRemoveHandle */
384 startJob();
385 pthread_mutex_unlock(&eventThreadMutex);
386 sched_yield();
387 usleep(100 * 1000);
388 pthread_mutex_lock(&eventThreadMutex);
389 virEventPollRemoveHandle(handles[1].watch);
390 if (finishJob("Interrupted during poll", -1, -1) != EXIT_SUCCESS)
391 return EXIT_FAILURE;
393 resetAll();
395 /* Getting more fun, lets delete a later handle during dispatch */
397 /* NB: this case is subject to a bit of a race condition.
398 * Only 1 time in 3 does the 2nd write get triggered by
399 * before poll() exits for the first safewrite(). We don't
400 * see a hard failure in other cases, so nothing to worry
401 * about */
402 startJob();
403 handles[2].delete = handles[3].watch;
404 if (safewrite(handles[2].pipeFD[1], &one, 1) != 1
405 || safewrite(handles[3].pipeFD[1], &one, 1) != 1)
406 return EXIT_FAILURE;
407 if (finishJob("Deleted during dispatch", 2, -1) != EXIT_SUCCESS)
408 return EXIT_FAILURE;
410 resetAll();
412 /* Extreme fun, lets delete ourselves during dispatch */
413 startJob();
414 handles[2].delete = handles[2].watch;
415 if (safewrite(handles[2].pipeFD[1], &one, 1) != 1)
416 return EXIT_FAILURE;
417 if (finishJob("Deleted during dispatch", 2, -1) != EXIT_SUCCESS)
418 return EXIT_FAILURE;
420 resetAll();
424 /* Run a timer on its own */
425 virEventPollUpdateTimeout(timers[1].timer, 100);
426 startJob();
427 if (finishJob("Firing a timer", -1, 1) != EXIT_SUCCESS)
428 return EXIT_FAILURE;
429 virEventPollUpdateTimeout(timers[1].timer, -1);
431 resetAll();
433 /* Now lets delete one before starting poll(), and
434 * try triggering another timer */
435 virEventPollUpdateTimeout(timers[1].timer, 100);
436 virEventPollRemoveTimeout(timers[0].timer);
437 startJob();
438 if (finishJob("Deleted before poll", -1, 1) != EXIT_SUCCESS)
439 return EXIT_FAILURE;
440 virEventPollUpdateTimeout(timers[1].timer, -1);
442 resetAll();
444 /* Next lets delete *during* poll, which should interrupt
445 * the loop with no event showing */
447 /* NB: this case is subject to a bit of a race condition.
448 * We yield & sleep, and pray that the other thread gets
449 * scheduled before we run EventRemoveTimeout */
450 startJob();
451 pthread_mutex_unlock(&eventThreadMutex);
452 sched_yield();
453 usleep(100 * 1000);
454 pthread_mutex_lock(&eventThreadMutex);
455 virEventPollRemoveTimeout(timers[1].timer);
456 if (finishJob("Interrupted during poll", -1, -1) != EXIT_SUCCESS)
457 return EXIT_FAILURE;
459 resetAll();
461 /* Getting more fun, lets delete a later timer during dispatch */
463 /* NB: this case is subject to a bit of a race condition.
464 * Only 1 time in 3 does the 2nd write get triggered by
465 * before poll() exits for the first safewrite(). We don't
466 * see a hard failure in other cases, so nothing to worry
467 * about */
468 virEventPollUpdateTimeout(timers[2].timer, 100);
469 virEventPollUpdateTimeout(timers[3].timer, 100);
470 startJob();
471 timers[2].delete = timers[3].timer;
472 if (finishJob("Deleted during dispatch", -1, 2) != EXIT_SUCCESS)
473 return EXIT_FAILURE;
474 virEventPollUpdateTimeout(timers[2].timer, -1);
476 resetAll();
478 /* Extreme fun, lets delete ourselves during dispatch */
479 virEventPollUpdateTimeout(timers[2].timer, 100);
480 startJob();
481 timers[2].delete = timers[2].timer;
482 if (finishJob("Deleted during dispatch", -1, 2) != EXIT_SUCCESS)
483 return EXIT_FAILURE;
485 for (i = 0; i < NUM_FDS - 1; i++)
486 virEventPollRemoveHandle(handles[i].watch);
487 for (i = 0; i < NUM_TIME - 1; i++)
488 virEventPollRemoveTimeout(timers[i].timer);
490 resetAll();
492 /* Make sure the last handle still works several times in a row. */
493 for (i = 0; i < 4; i++) {
494 startJob();
495 if (safewrite(handles[NUM_FDS - 1].pipeFD[1], &one, 1) != 1)
496 return EXIT_FAILURE;
497 if (finishJob("Simple write", NUM_FDS - 1, -1) != EXIT_SUCCESS)
498 return EXIT_FAILURE;
500 resetAll();
504 /* Final test, register same FD twice, once with no
505 * events, and make sure the right callback runs */
506 handles[0].pipeFD[0] = handles[1].pipeFD[0];
507 handles[0].pipeFD[1] = handles[1].pipeFD[1];
509 handles[0].watch = virEventPollAddHandle(handles[0].pipeFD[0],
511 testPipeReader,
512 &handles[0], NULL);
513 handles[1].watch = virEventPollAddHandle(handles[1].pipeFD[0],
514 VIR_EVENT_HANDLE_READABLE,
515 testPipeReader,
516 &handles[1], NULL);
517 startJob();
518 if (safewrite(handles[1].pipeFD[1], &one, 1) != 1)
519 return EXIT_FAILURE;
520 if (finishJob("Write duplicate", 1, -1) != EXIT_SUCCESS)
521 return EXIT_FAILURE;
523 /* pthread_kill(eventThread, SIGTERM); */
525 return EXIT_SUCCESS;
528 VIR_TEST_MAIN(mymain)