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 WITH_MACH_CLOCK_ROUTINES
27 # include <mach/clock.h>
28 # include <mach/mach.h>
31 #include "testutils.h"
37 VIR_LOG_INIT("tests.eventtest");
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
{
54 static struct timerInfo
{
70 struct testEventResultData
{
76 testEventResultCallback(const void *opaque
)
78 const struct testEventResultData
*data
= opaque
;
80 if (data
->failed
&& data
->msg
)
81 fprintf(stderr
, "%s", data
->msg
);
87 testEventReport(const char *name
, bool failed
, const char *msg
, ...)
90 g_autofree
char *str
= NULL
;
91 struct testEventResultData data
;
96 str
= g_strdup_vprintf(msg
, vargs
);
100 ignore_value(virTestRun(name
, testEventResultCallback
, &data
));
106 testPipeReader(int watch
, int fd
, int events
, void *data
)
108 struct handleInfo
*info
= data
;
111 VIR_DEBUG("Handle callback watch=%d fd=%d ev=%d", watch
, fd
, events
);
112 pthread_mutex_lock(&eventThreadMutex
);
116 if (watch
!= info
->watch
) {
117 info
->error
= EV_ERROR_WATCH
;
121 if (fd
!= info
->pipeFD
[0]) {
122 info
->error
= EV_ERROR_FD
;
126 if (!(events
& VIR_EVENT_HANDLE_READABLE
)) {
127 info
->error
= EV_ERROR_EVENT
;
130 if (read(fd
, &one
, 1) != 1) {
131 info
->error
= EV_ERROR_DATA
;
134 info
->error
= EV_ERROR_NONE
;
136 if (info
->delete != -1)
137 virEventRemoveHandle(info
->delete);
140 pthread_cond_signal(&eventThreadCond
);
141 eventThreadSignaled
= true;
142 pthread_mutex_unlock(&eventThreadMutex
);
147 testTimer(int timer
, void *data
)
149 struct timerInfo
*info
= data
;
151 VIR_DEBUG("Timer callback timer=%d", timer
);
152 pthread_mutex_lock(&eventThreadMutex
);
156 if (timer
!= info
->timer
) {
157 info
->error
= EV_ERROR_WATCH
;
161 info
->error
= EV_ERROR_NONE
;
163 if (info
->delete != -1)
164 virEventRemoveTimeout(info
->delete);
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
) {
174 virEventRunDefaultImpl();
180 waitEvents(int nhandle
, int ntimer
)
186 VIR_DEBUG("Wait events nhandle %d ntimer %d",
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
)
199 for (i
= 0; i
< NUM_TIME
; i
++) {
204 VIR_DEBUG("Wait events ngothandle %d ngottimer %d",
205 ngothandle
, ngottimer
);
212 verifyFired(const char *name
, int handle
, int timer
)
217 VIR_DEBUG("Verify fired handle %d timer %d", handle
, timer
);
218 for (i
= 0; i
< NUM_FDS
; i
++) {
219 if (handles
[i
].fired
) {
221 testEventReport(name
, 1,
222 "Handle %zu fired, but expected %d\n", i
,
226 if (handles
[i
].error
!= EV_ERROR_NONE
) {
227 testEventReport(name
, 1,
228 "Handle %zu fired, but had error %d\n", i
,
236 testEventReport(name
, 1,
237 "Handle %d should have fired, but didn't\n",
243 if (handleFired
!= 1 && handle
!= -1) {
244 testEventReport(name
, 1,
245 "Something weird happened, expecting handle %d\n",
251 for (i
= 0; i
< NUM_TIME
; i
++) {
252 if (timers
[i
].fired
) {
254 testEventReport(name
, 1,
255 "Timer %zu fired, but expected %d\n", i
, timer
);
258 if (timers
[i
].error
!= EV_ERROR_NONE
) {
259 testEventReport(name
, 1,
260 "Timer %zu fired, but had error %d\n", i
,
268 testEventReport(name
, 1,
269 "Timer %d should have fired, but didn't\n",
275 if (timerFired
!= 1 && timer
!= -1) {
276 testEventReport(name
, 1,
277 "Something weird happened, expecting timer %d\n",
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
);
298 testEventReport(name
, 0, NULL
);
300 pthread_mutex_unlock(&eventThreadMutex
);
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
++) {
315 timers
[i
].error
= EV_ERROR_NONE
;
317 pthread_mutex_unlock(&eventThreadMutex
);
324 pthread_t eventThread
;
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
);
335 if (debugEnv
&& *debugEnv
&&
336 (virLogSetDefaultPriority(virLogParseDefaultPriority(debugEnv
)) < 0)) {
337 fprintf(stderr
, "Invalid log level setting.\n");
341 virEventRegisterDefaultImpl();
343 for (i
= 0; i
< NUM_FDS
; i
++) {
344 handles
[i
].delete = -1;
346 virEventAddHandle(handles
[i
].pipeFD
[0],
347 VIR_EVENT_HANDLE_READABLE
,
352 for (i
= 0; i
< NUM_TIME
; i
++) {
353 timers
[i
].delete = -1;
354 timers
[i
].timeout
= -1;
356 virEventAddTimeout(timers
[i
].timeout
,
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)
367 if (finishJob("Simple write", 1, -1) != EXIT_SUCCESS
)
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)
377 if (finishJob("Deleted before poll", 1, -1) != EXIT_SUCCESS
)
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
)
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)
397 if (finishJob("Deleted during dispatch", 2, -1) != EXIT_SUCCESS
)
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)
406 if (finishJob("Deleted during dispatch", 2, -1) != EXIT_SUCCESS
)
413 /* Run a timer on its own */
414 virEventUpdateTimeout(timers
[1].timer
, 100);
415 if (finishJob("Firing a timer", -1, 1) != EXIT_SUCCESS
)
417 virEventUpdateTimeout(timers
[1].timer
, -1);
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
)
427 virEventUpdateTimeout(timers
[1].timer
, -1);
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
)
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
)
447 virEventUpdateTimeout(timers
[2].timer
, -1);
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
)
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
);
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)
468 if (finishJob("Simple write", NUM_FDS
- 1, -1) != EXIT_SUCCESS
)
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],
484 handles
[1].watch
= virEventAddHandle(handles
[1].pipeFD
[0],
485 VIR_EVENT_HANDLE_READABLE
,
489 if (safewrite(handles
[1].pipeFD
[1], &one
, 1) != 1)
491 if (finishJob("Write duplicate", 1, -1) != EXIT_SUCCESS
)
494 /* pthread_kill(eventThread, SIGTERM); */
499 VIR_TEST_MAIN(mymain
)