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/>.
26 #if HAVE_MACH_CLOCK_ROUTINES
27 # include <mach/clock.h>
28 # include <mach/mach.h>
31 #include "testutils.h"
34 #include "virthread.h"
37 #include "vireventpoll.h"
39 VIR_LOG_INIT("tests.eventtest");
44 static struct handleInfo
{
52 static struct timerInfo
{
68 struct testEventResultData
{
74 testEventResultCallback(const void *opaque
)
76 const struct testEventResultData
*data
= opaque
;
78 if (data
->failed
&& data
->msg
)
79 fprintf(stderr
, "%s", data
->msg
);
84 ATTRIBUTE_FMT_PRINTF(3, 4)
85 testEventReport(const char *name
, bool failed
, const char *msg
, ...)
90 struct testEventResultData data
;
92 if (msg
&& virVasprintfQuiet(&str
, msg
, vargs
) != 0)
97 ignore_value(virTestRun(name
, testEventResultCallback
, &data
));
104 testPipeReader(int watch
, int fd
, int events
, void *data
)
106 struct handleInfo
*info
= data
;
111 if (watch
!= info
->watch
) {
112 info
->error
= EV_ERROR_WATCH
;
116 if (fd
!= info
->pipeFD
[0]) {
117 info
->error
= EV_ERROR_FD
;
121 if (!(events
& VIR_EVENT_HANDLE_READABLE
)) {
122 info
->error
= EV_ERROR_EVENT
;
125 if (read(fd
, &one
, 1) != 1) {
126 info
->error
= EV_ERROR_DATA
;
129 info
->error
= EV_ERROR_NONE
;
131 if (info
->delete != -1)
132 virEventPollRemoveHandle(info
->delete);
137 testTimer(int timer
, void *data
)
139 struct timerInfo
*info
= data
;
143 if (timer
!= info
->timer
) {
144 info
->error
= EV_ERROR_WATCH
;
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
) {
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
);
180 verifyFired(const char *name
, int handle
, int timer
)
185 for (i
= 0; i
< NUM_FDS
; i
++) {
186 if (handles
[i
].fired
) {
188 testEventReport(name
, 1,
189 "Handle %zu fired, but expected %d\n", i
,
193 if (handles
[i
].error
!= EV_ERROR_NONE
) {
194 testEventReport(name
, 1,
195 "Handle %zu fired, but had error %d\n", i
,
203 testEventReport(name
, 1,
204 "Handle %d should have fired, but didn't\n",
210 if (handleFired
!= 1 && handle
!= -1) {
211 testEventReport(name
, 1,
212 "Something weird happened, expecting handle %d\n",
218 for (i
= 0; i
< NUM_TIME
; i
++) {
219 if (timers
[i
].fired
) {
221 testEventReport(name
, 1,
222 "Timer %zu fired, but expected %d\n", i
, timer
);
225 if (timers
[i
].error
!= EV_ERROR_NONE
) {
226 testEventReport(name
, 1,
227 "Timer %zu fired, but had error %d\n", i
,
235 testEventReport(name
, 1,
236 "Timer %d should have fired, but didn't\n",
242 if (timerFired
!= 1 && timer
!= -1) {
243 testEventReport(name
, 1,
244 "Something weird happened, expecting timer %d\n",
254 eventThreadRunOnce
= 1;
255 eventThreadJobDone
= 0;
256 pthread_cond_signal(&eventThreadRunCond
);
257 pthread_mutex_unlock(&eventThreadMutex
);
259 pthread_mutex_lock(&eventThreadMutex
);
263 finishJob(const char *name
, int handle
, int timer
)
265 struct timespec waitTime
;
267 #if HAVE_MACH_CLOCK_ROUTINES
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
;
277 clock_gettime(CLOCK_REALTIME
, &waitTime
);
279 waitTime
.tv_sec
+= 5;
281 while (!eventThreadJobDone
&& rc
== 0)
282 rc
= pthread_cond_timedwait(&eventThreadJobCond
, &eventThreadMutex
,
285 testEventReport(name
, 1, "Timed out waiting for pipe event\n");
289 if (verifyFired(name
, handle
, timer
) != EXIT_SUCCESS
)
292 testEventReport(name
, 0, NULL
);
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
++) {
306 timers
[i
].error
= EV_ERROR_NONE
;
314 pthread_t eventThread
;
317 for (i
= 0; i
< NUM_FDS
; i
++) {
318 if (pipe(handles
[i
].pipeFD
) < 0) {
319 fprintf(stderr
, "Cannot create pipe: %d", errno
);
324 if (virThreadInitialize() < 0)
326 char *debugEnv
= getenv("LIBVIRT_DEBUG");
327 if (debugEnv
&& *debugEnv
&&
328 (virLogSetDefaultPriority(virLogParseDefaultPriority(debugEnv
)) < 0)) {
329 fprintf(stderr
, "Invalid log level setting.\n");
335 for (i
= 0; i
< NUM_FDS
; i
++) {
336 handles
[i
].delete = -1;
338 virEventPollAddHandle(handles
[i
].pipeFD
[0],
339 VIR_EVENT_HANDLE_READABLE
,
344 for (i
= 0; i
< NUM_TIME
; i
++) {
345 timers
[i
].delete = -1;
346 timers
[i
].timeout
= -1;
348 virEventPollAddTimeout(timers
[i
].timeout
,
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 */
360 if (safewrite(handles
[1].pipeFD
[1], &one
, 1) != 1)
362 if (finishJob("Simple write", 1, -1) != EXIT_SUCCESS
)
367 /* Now lets delete one before starting poll(), and
368 * try triggering another handle */
369 virEventPollRemoveHandle(handles
[0].watch
);
371 if (safewrite(handles
[1].pipeFD
[1], &one
, 1) != 1)
373 if (finishJob("Deleted before poll", 1, -1) != EXIT_SUCCESS
)
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 */
385 pthread_mutex_unlock(&eventThreadMutex
);
388 pthread_mutex_lock(&eventThreadMutex
);
389 virEventPollRemoveHandle(handles
[1].watch
);
390 if (finishJob("Interrupted during poll", -1, -1) != EXIT_SUCCESS
)
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
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)
407 if (finishJob("Deleted during dispatch", 2, -1) != EXIT_SUCCESS
)
412 /* Extreme fun, lets delete ourselves during dispatch */
414 handles
[2].delete = handles
[2].watch
;
415 if (safewrite(handles
[2].pipeFD
[1], &one
, 1) != 1)
417 if (finishJob("Deleted during dispatch", 2, -1) != EXIT_SUCCESS
)
424 /* Run a timer on its own */
425 virEventPollUpdateTimeout(timers
[1].timer
, 100);
427 if (finishJob("Firing a timer", -1, 1) != EXIT_SUCCESS
)
429 virEventPollUpdateTimeout(timers
[1].timer
, -1);
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
);
438 if (finishJob("Deleted before poll", -1, 1) != EXIT_SUCCESS
)
440 virEventPollUpdateTimeout(timers
[1].timer
, -1);
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 */
451 pthread_mutex_unlock(&eventThreadMutex
);
454 pthread_mutex_lock(&eventThreadMutex
);
455 virEventPollRemoveTimeout(timers
[1].timer
);
456 if (finishJob("Interrupted during poll", -1, -1) != EXIT_SUCCESS
)
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
468 virEventPollUpdateTimeout(timers
[2].timer
, 100);
469 virEventPollUpdateTimeout(timers
[3].timer
, 100);
471 timers
[2].delete = timers
[3].timer
;
472 if (finishJob("Deleted during dispatch", -1, 2) != EXIT_SUCCESS
)
474 virEventPollUpdateTimeout(timers
[2].timer
, -1);
478 /* Extreme fun, lets delete ourselves during dispatch */
479 virEventPollUpdateTimeout(timers
[2].timer
, 100);
481 timers
[2].delete = timers
[2].timer
;
482 if (finishJob("Deleted during dispatch", -1, 2) != EXIT_SUCCESS
)
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
);
492 /* Make sure the last handle still works several times in a row. */
493 for (i
= 0; i
< 4; i
++) {
495 if (safewrite(handles
[NUM_FDS
- 1].pipeFD
[1], &one
, 1) != 1)
497 if (finishJob("Simple write", NUM_FDS
- 1, -1) != EXIT_SUCCESS
)
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],
513 handles
[1].watch
= virEventPollAddHandle(handles
[1].pipeFD
[0],
514 VIR_EVENT_HANDLE_READABLE
,
518 if (safewrite(handles
[1].pipeFD
[1], &one
, 1) != 1)
520 if (finishJob("Write duplicate", 1, -1) != EXIT_SUCCESS
)
523 /* pthread_kill(eventThread, SIGTERM); */
528 VIR_TEST_MAIN(mymain
)