#define NUM_FDS 31
#define NUM_TIME 31
+static pthread_mutex_t eventThreadMutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t eventThreadCond = PTHREAD_COND_INITIALIZER;
+
static struct handleInfo {
int pipeFD[2];
int fired;
struct handleInfo *info = data;
char one;
+ VIR_DEBUG("Handle callback watch=%d fd=%d ev=%d", watch, fd, events);
+ pthread_mutex_lock(&eventThreadMutex);
+
info->fired = 1;
if (watch != info->watch) {
info->error = EV_ERROR_WATCH;
- return;
+ goto cleanup;
}
if (fd != info->pipeFD[0]) {
info->error = EV_ERROR_FD;
- return;
+ goto cleanup;
}
if (!(events & VIR_EVENT_HANDLE_READABLE)) {
info->error = EV_ERROR_EVENT;
- return;
+ goto cleanup;
}
if (read(fd, &one, 1) != 1) {
info->error = EV_ERROR_DATA;
- return;
+ goto cleanup;
}
info->error = EV_ERROR_NONE;
if (info->delete != -1)
virEventRemoveHandle(info->delete);
+
+ cleanup:
+ pthread_mutex_unlock(&eventThreadMutex);
+ pthread_cond_signal(&eventThreadCond);
}
{
struct timerInfo *info = data;
+ VIR_DEBUG("Timer callback timer=%d", timer);
+ pthread_mutex_lock(&eventThreadMutex);
+
info->fired = 1;
if (timer != info->timer) {
info->error = EV_ERROR_WATCH;
- return;
+ goto cleanup;
}
info->error = EV_ERROR_NONE;
if (info->delete != -1)
virEventRemoveTimeout(info->delete);
+
+ cleanup:
+ pthread_mutex_unlock(&eventThreadMutex);
+ pthread_cond_signal(&eventThreadCond);
}
-static pthread_mutex_t eventThreadMutex = PTHREAD_MUTEX_INITIALIZER;
-static pthread_cond_t eventThreadRunCond = PTHREAD_COND_INITIALIZER;
-static int eventThreadRunOnce;
-static pthread_cond_t eventThreadJobCond = PTHREAD_COND_INITIALIZER;
-static int eventThreadJobDone;
+G_GNUC_NORETURN static void *eventThreadLoop(void *data G_GNUC_UNUSED) {
+ while (1)
+ virEventRunDefaultImpl();
+ abort();
+}
-G_GNUC_NORETURN static void *eventThreadLoop(void *data G_GNUC_UNUSED) {
- while (1) {
- pthread_mutex_lock(&eventThreadMutex);
- while (!eventThreadRunOnce)
- pthread_cond_wait(&eventThreadRunCond, &eventThreadMutex);
- eventThreadRunOnce = 0;
- pthread_mutex_unlock(&eventThreadMutex);
+static void
+waitEvents(int nhandle, int ntimer)
+{
+ int ngothandle = 0;
+ int ngottimer = 0;
+ size_t i;
- virEventRunDefaultImpl();
+ VIR_DEBUG("Wait events nhandle %d ntimer %d",
+ nhandle, ntimer);
+ while (ngothandle != nhandle || ngottimer != ntimer) {
+ pthread_cond_wait(&eventThreadCond, &eventThreadMutex);
- pthread_mutex_lock(&eventThreadMutex);
- eventThreadJobDone = 1;
- pthread_cond_signal(&eventThreadJobCond);
- pthread_mutex_unlock(&eventThreadMutex);
+ ngothandle = ngottimer = 0;
+ for (i = 0; i < NUM_FDS; i++) {
+ if (handles[i].fired)
+ ngothandle++;
+ }
+ for (i = 0; i < NUM_TIME; i++) {
+ if (timers[i].fired)
+ ngottimer++;
+ }
+
+ VIR_DEBUG("Wait events ngothandle %d ngottimer %d",
+ ngothandle, ngottimer);
}
+
}
int handleFired = 0;
int timerFired = 0;
size_t i;
+ VIR_DEBUG("Verify fired handle %d timer %d", handle, timer);
for (i = 0; i < NUM_FDS; i++) {
if (handles[i].fired) {
if (i != handle) {
return EXIT_SUCCESS;
}
-static void
-startJob(void)
-{
- eventThreadRunOnce = 1;
- eventThreadJobDone = 0;
- pthread_cond_signal(&eventThreadRunCond);
- pthread_mutex_unlock(&eventThreadMutex);
- sched_yield();
- pthread_mutex_lock(&eventThreadMutex);
-}
static int
finishJob(const char *name, int handle, int timer)
{
- unsigned long long now_us;
- struct timespec waitTime;
- int rc;
-
- now_us = g_get_real_time();
- waitTime.tv_sec = now_us / (1000*1000);
- waitTime.tv_nsec = (now_us % ((now_us / (1000*1000)))) * 1000;
-
- waitTime.tv_sec += 5;
- rc = 0;
- while (!eventThreadJobDone && rc == 0)
- rc = pthread_cond_timedwait(&eventThreadJobCond, &eventThreadMutex,
- &waitTime);
- if (rc != 0) {
- testEventReport(name, 1, "Timed out waiting for pipe event\n");
- return EXIT_FAILURE;
- }
+ pthread_mutex_lock(&eventThreadMutex);
- if (verifyFired(name, handle, timer) != EXIT_SUCCESS)
+ waitEvents(handle == -1 ? 0 : 1,
+ timer == -1 ? 0 : 1);
+
+ if (verifyFired(name, handle, timer) != EXIT_SUCCESS) {
+ pthread_mutex_unlock(&eventThreadMutex);
return EXIT_FAILURE;
+ }
testEventReport(name, 0, NULL);
+
+ pthread_mutex_unlock(&eventThreadMutex);
return EXIT_SUCCESS;
}
resetAll(void)
{
size_t i;
+ pthread_mutex_lock(&eventThreadMutex);
for (i = 0; i < NUM_FDS; i++) {
handles[i].fired = 0;
handles[i].error = EV_ERROR_NONE;
timers[i].fired = 0;
timers[i].error = EV_ERROR_NONE;
}
+ pthread_mutex_unlock(&eventThreadMutex);
}
static int
pthread_create(&eventThread, NULL, eventThreadLoop, NULL);
- pthread_mutex_lock(&eventThreadMutex);
-
/* First time, is easy - just try triggering one of our
* registered handles */
- startJob();
if (safewrite(handles[1].pipeFD[1], &one, 1) != 1)
return EXIT_FAILURE;
if (finishJob("Simple write", 1, -1) != EXIT_SUCCESS)
/* Now lets delete one before starting poll(), and
* try triggering another handle */
virEventRemoveHandle(handles[0].watch);
- startJob();
if (safewrite(handles[1].pipeFD[1], &one, 1) != 1)
return EXIT_FAILURE;
if (finishJob("Deleted before poll", 1, -1) != EXIT_SUCCESS)
/* Next lets delete *during* poll, which should interrupt
* the loop with no event showing */
- /* NB: this case is subject to a bit of a race condition.
- * We yield & sleep, and pray that the other thread gets
- * scheduled before we run EventRemoveHandle */
- startJob();
- pthread_mutex_unlock(&eventThreadMutex);
- sched_yield();
- g_usleep(100 * 1000);
- pthread_mutex_lock(&eventThreadMutex);
virEventRemoveHandle(handles[1].watch);
if (finishJob("Interrupted during poll", -1, -1) != EXIT_SUCCESS)
return EXIT_FAILURE;
/* Getting more fun, lets delete a later handle during dispatch */
- /* NB: this case is subject to a bit of a race condition.
- * Only 1 time in 3 does the 2nd write get triggered by
- * before poll() exits for the first safewrite(). We don't
- * see a hard failure in other cases, so nothing to worry
- * about */
- startJob();
handles[2].delete = handles[3].watch;
if (safewrite(handles[2].pipeFD[1], &one, 1) != 1
|| safewrite(handles[3].pipeFD[1], &one, 1) != 1)
resetAll();
/* Extreme fun, lets delete ourselves during dispatch */
- startJob();
handles[2].delete = handles[2].watch;
if (safewrite(handles[2].pipeFD[1], &one, 1) != 1)
return EXIT_FAILURE;
/* Run a timer on its own */
virEventUpdateTimeout(timers[1].timer, 100);
- startJob();
if (finishJob("Firing a timer", -1, 1) != EXIT_SUCCESS)
return EXIT_FAILURE;
virEventUpdateTimeout(timers[1].timer, -1);
* try triggering another timer */
virEventUpdateTimeout(timers[1].timer, 100);
virEventRemoveTimeout(timers[0].timer);
- startJob();
if (finishJob("Deleted before poll", -1, 1) != EXIT_SUCCESS)
return EXIT_FAILURE;
virEventUpdateTimeout(timers[1].timer, -1);
/* Next lets delete *during* poll, which should interrupt
* the loop with no event showing */
- /* NB: this case is subject to a bit of a race condition.
- * We yield & sleep, and pray that the other thread gets
- * scheduled before we run EventRemoveTimeout */
- startJob();
- pthread_mutex_unlock(&eventThreadMutex);
- sched_yield();
- g_usleep(100 * 1000);
- pthread_mutex_lock(&eventThreadMutex);
virEventRemoveTimeout(timers[1].timer);
if (finishJob("Interrupted during poll", -1, -1) != EXIT_SUCCESS)
return EXIT_FAILURE;
/* Getting more fun, lets delete a later timer during dispatch */
- /* NB: this case is subject to a bit of a race condition.
- * Only 1 time in 3 does the 2nd write get triggered by
- * before poll() exits for the first safewrite(). We don't
- * see a hard failure in other cases, so nothing to worry
- * about */
virEventUpdateTimeout(timers[2].timer, 100);
virEventUpdateTimeout(timers[3].timer, 100);
- startJob();
timers[2].delete = timers[3].timer;
if (finishJob("Deleted during dispatch", -1, 2) != EXIT_SUCCESS)
return EXIT_FAILURE;
/* Extreme fun, lets delete ourselves during dispatch */
virEventUpdateTimeout(timers[2].timer, 100);
- startJob();
timers[2].delete = timers[2].timer;
if (finishJob("Deleted during dispatch", -1, 2) != EXIT_SUCCESS)
return EXIT_FAILURE;
/* Make sure the last handle still works several times in a row. */
for (i = 0; i < 4; i++) {
- startJob();
if (safewrite(handles[NUM_FDS - 1].pipeFD[1], &one, 1) != 1)
return EXIT_FAILURE;
if (finishJob("Simple write", NUM_FDS - 1, -1) != EXIT_SUCCESS)
VIR_EVENT_HANDLE_READABLE,
testPipeReader,
&handles[1], NULL);
- startJob();
+
if (safewrite(handles[1].pipeFD[1], &one, 1) != 1)
return EXIT_FAILURE;
if (finishJob("Write duplicate", 1, -1) != EXIT_SUCCESS)