[Libvir] PATCH: Allow updating of timer & file handle event watches
Daniel P. Berrange
berrange at redhat.com
Tue Sep 18 01:56:35 UTC 2007
The forthcoming patch to add Avahi support requires a couple of enhancements
to our event loop to support integration with Avahi's event callback needs
- Ability to update the event mask for a pre-existing file handle watch
- Ability to change the frequency of a timer watch
- Ability to have a timer which fires immediately
- Ability to disable events on a timer watch
The first point was trivial - just change the 'events' flag we have recorded
in the virEventHandle struct.
The second point was also trivial - just change the period of the timer as
recorded in virEventTimer struct.
The last two points were more tricky, but doable. To fire a timer immediately
I tweaked the logic so that it allows a frequency of '0'. Obviously to avoid
spinning 100%, the app should unregister the timer once it has fired the
desired number of times (usually 1). To disable a timer temporarily I allow
the use of '-1' in the frequency.
THe code had a bad mix of terminology using a 'timer' and 'timeout' field
in the virEventTimer struct which confused me no end. So I renamed the
'timeout' field to 'frequency' which reflects its actual purpose.
Finally, when building with debugging, the event loop can generate alot of
data, so I added a EVENT_DEBUG macro to the file which prefixes EVENT: on
all debug output so allow easy filtering.
Dan.
--
|=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=|
|=- Perl modules: http://search.cpan.org/~danberr/ -=|
|=- Projects: http://freshmeat.net/~danielpb/ -=|
|=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|
-------------- next part --------------
diff -r 0f29c3c9425f qemud/event.c
--- a/qemud/event.c Mon Sep 17 05:23:04 2007 -0400
+++ b/qemud/event.c Mon Sep 17 13:29:46 2007 -0400
@@ -30,6 +30,8 @@
#include "internal.h"
#include "event.h"
+
+#define EVENT_DEBUG(fmt, ...) qemudDebug("EVENT: " fmt, __VA_ARGS__)
/* State for a single file handle being monitored */
struct virEventHandle {
@@ -43,7 +45,7 @@ struct virEventHandle {
/* State for a single timer being generated */
struct virEventTimeout {
int timer;
- int timeout;
+ int frequency;
unsigned long long expiresAt;
virEventTimeoutCallback cb;
void *opaque;
@@ -77,11 +79,11 @@ static int nextTimer = 0;
* For this reason we only ever append to existing list.
*/
int virEventAddHandleImpl(int fd, int events, virEventHandleCallback cb, void *opaque) {
- qemudDebug("Add handle %d %d %p %p\n", fd, events, cb, opaque);
+ EVENT_DEBUG("Add handle %d %d %p %p", fd, events, cb, opaque);
if (eventLoop.handlesCount == eventLoop.handlesAlloc) {
struct virEventHandle *tmp;
- qemudDebug("Used %d handle slots, adding %d more\n",
- eventLoop.handlesAlloc, EVENT_ALLOC_EXTENT);
+ EVENT_DEBUG("Used %d handle slots, adding %d more",
+ eventLoop.handlesAlloc, EVENT_ALLOC_EXTENT);
tmp = realloc(eventLoop.handles,
sizeof(struct virEventHandle) *
(eventLoop.handlesAlloc + EVENT_ALLOC_EXTENT));
@@ -103,6 +105,15 @@ int virEventAddHandleImpl(int fd, int ev
return 0;
}
+void virEventUpdateHandleImpl(int fd, int events) {
+ int i;
+ for (i = 0 ; i < eventLoop.handlesCount ; i++) {
+ if (eventLoop.handles[i].fd == fd) {
+ eventLoop.handles[i].events = events;
+ }
+ }
+}
+
/*
* Unregister a callback from a file handle
* NB, it *must* be safe to call this from within a callback
@@ -111,13 +122,13 @@ int virEventAddHandleImpl(int fd, int ev
*/
int virEventRemoveHandleImpl(int fd) {
int i;
- qemudDebug("Remove handle %d\n", fd);
+ EVENT_DEBUG("Remove handle %d", fd);
for (i = 0 ; i < eventLoop.handlesCount ; i++) {
if (eventLoop.handles[i].deleted)
continue;
if (eventLoop.handles[i].fd == fd) {
- qemudDebug("mark delete %d\n", i);
+ EVENT_DEBUG("mark delete %d", i);
eventLoop.handles[i].deleted = 1;
return 0;
}
@@ -131,17 +142,17 @@ int virEventRemoveHandleImpl(int fd) {
* NB, it *must* be safe to call this from within a callback
* For this reason we only ever append to existing list.
*/
-int virEventAddTimeoutImpl(int timeout, virEventTimeoutCallback cb, void *opaque) {
- struct timeval tv;
- qemudDebug("Adding timeout with %d ms period", timeout);
- if (gettimeofday(&tv, NULL) < 0) {
+int virEventAddTimeoutImpl(int frequency, virEventTimeoutCallback cb, void *opaque) {
+ struct timeval now;
+ EVENT_DEBUG("Adding timer %d with %d ms freq", nextTimer, frequency);
+ if (gettimeofday(&now, NULL) < 0) {
return -1;
}
if (eventLoop.timeoutsCount == eventLoop.timeoutsAlloc) {
struct virEventTimeout *tmp;
- qemudDebug("Used %d timeout slots, adding %d more\n",
- eventLoop.timeoutsAlloc, EVENT_ALLOC_EXTENT);
+ EVENT_DEBUG("Used %d timeout slots, adding %d more",
+ eventLoop.timeoutsAlloc, EVENT_ALLOC_EXTENT);
tmp = realloc(eventLoop.timeouts,
sizeof(struct virEventTimeout) *
(eventLoop.timeoutsAlloc + EVENT_ALLOC_EXTENT));
@@ -153,18 +164,37 @@ int virEventAddTimeoutImpl(int timeout,
}
eventLoop.timeouts[eventLoop.timeoutsCount].timer = nextTimer++;
- eventLoop.timeouts[eventLoop.timeoutsCount].timeout = timeout;
+ eventLoop.timeouts[eventLoop.timeoutsCount].frequency = frequency;
eventLoop.timeouts[eventLoop.timeoutsCount].cb = cb;
eventLoop.timeouts[eventLoop.timeoutsCount].opaque = opaque;
eventLoop.timeouts[eventLoop.timeoutsCount].deleted = 0;
eventLoop.timeouts[eventLoop.timeoutsCount].expiresAt =
- timeout +
- (((unsigned long long)tv.tv_sec)*1000) +
- (((unsigned long long)tv.tv_usec)/1000);
+ frequency >= 0 ? frequency +
+ (((unsigned long long)now.tv_sec)*1000) +
+ (((unsigned long long)now.tv_usec)/1000) : 0;
eventLoop.timeoutsCount++;
return nextTimer-1;
+}
+
+void virEventUpdateTimeoutImpl(int timer, int frequency) {
+ struct timeval tv;
+ int i;
+ EVENT_DEBUG("Updating timer %d timeout with %d ms freq", timer, frequency);
+ if (gettimeofday(&tv, NULL) < 0) {
+ return;
+ }
+
+ for (i = 0 ; i < eventLoop.timeoutsCount ; i++) {
+ if (eventLoop.timeouts[i].timer == timer) {
+ eventLoop.timeouts[i].frequency = frequency;
+ eventLoop.timeouts[i].expiresAt =
+ frequency >= 0 ? frequency +
+ (((unsigned long long)tv.tv_sec)*1000) +
+ (((unsigned long long)tv.tv_usec)/1000) : 0;
+ }
+ }
}
/*
@@ -175,6 +205,7 @@ int virEventAddTimeoutImpl(int timeout,
*/
int virEventRemoveTimeoutImpl(int timer) {
int i;
+ EVENT_DEBUG("Remove timer %d", timer);
for (i = 0 ; i < eventLoop.timeoutsCount ; i++) {
if (eventLoop.timeouts[i].deleted)
continue;
@@ -196,13 +227,13 @@ static int virEventCalculateTimeout(int
static int virEventCalculateTimeout(int *timeout) {
unsigned long long then = 0;
int i;
-
+ EVENT_DEBUG("Calculate expiry of %d timers", eventLoop.timeoutsCount);
/* Figure out if we need a timeout */
for (i = 0 ; i < eventLoop.timeoutsCount ; i++) {
- if (eventLoop.timeouts[i].deleted)
- continue;
-
- qemudDebug("Got a timeout scheduled for %llu", eventLoop.timeouts[i].expiresAt);
+ if (eventLoop.timeouts[i].deleted || eventLoop.timeouts[i].frequency < 0)
+ continue;
+
+ EVENT_DEBUG("Got a timeout scheduled for %llu", eventLoop.timeouts[i].expiresAt);
if (then == 0 ||
eventLoop.timeouts[i].expiresAt < then)
then = eventLoop.timeouts[i].expiresAt;
@@ -220,13 +251,13 @@ static int virEventCalculateTimeout(int
((((unsigned long long)tv.tv_sec)*1000) +
(((unsigned long long)tv.tv_usec)/1000));
- qemudDebug("Timeout at %llu due in %d ms", then, *timeout);
if (*timeout < 0)
- *timeout = 1;
+ *timeout = 0;
} else {
- qemudDebug("No timeout due");
*timeout = -1;
}
+
+ EVENT_DEBUG("Timeout at %llu due in %d ms", then, *timeout);
return 0;
}
@@ -256,7 +287,7 @@ static int virEventMakePollFDs(struct po
fds[nfds].fd = eventLoop.handles[i].fd;
fds[nfds].events = eventLoop.handles[i].events;
fds[nfds].revents = 0;
- qemudDebug("Wait for %d %d\n", eventLoop.handles[i].fd, eventLoop.handles[i].events);
+ //EVENT_DEBUG("Wait for %d %d", eventLoop.handles[i].fd, eventLoop.handles[i].events);
nfds++;
}
@@ -291,14 +322,14 @@ static int virEventDispatchTimeouts(void
(((unsigned long long)tv.tv_usec)/1000);
for (i = 0 ; i < ntimeouts ; i++) {
- if (eventLoop.timeouts[i].deleted)
+ if (eventLoop.timeouts[i].deleted || eventLoop.timeouts[i].frequency < 0)
continue;
if (eventLoop.timeouts[i].expiresAt <= now) {
(eventLoop.timeouts[i].cb)(eventLoop.timeouts[i].timer,
eventLoop.timeouts[i].opaque);
eventLoop.timeouts[i].expiresAt =
- now + eventLoop.timeouts[i].timeout;
+ now + eventLoop.timeouts[i].frequency;
}
}
return 0;
@@ -322,12 +353,12 @@ static int virEventDispatchHandles(struc
for (i = 0 ; i < nhandles ; i++) {
if (eventLoop.handles[i].deleted) {
- qemudDebug("Skip deleted %d\n", eventLoop.handles[i].fd);
+ EVENT_DEBUG("Skip deleted %d", eventLoop.handles[i].fd);
continue;
}
if (fds[i].revents) {
- qemudDebug("Dispatch %d %d %p\n", fds[i].fd, fds[i].revents, eventLoop.handles[i].opaque);
+ EVENT_DEBUG("Dispatch %d %d %p", fds[i].fd, fds[i].revents, eventLoop.handles[i].opaque);
(eventLoop.handles[i].cb)(fds[i].fd, fds[i].revents,
eventLoop.handles[i].opaque);
}
@@ -353,7 +384,7 @@ static int virEventCleanupTimeouts(void)
continue;
}
- qemudDebug("Purging timeout %d with id %d", i, eventLoop.timeouts[i].timer);
+ EVENT_DEBUG("Purging timeout %d with id %d", i, eventLoop.timeouts[i].timer);
if ((i+1) < eventLoop.timeoutsCount) {
memmove(eventLoop.timeouts+i,
eventLoop.timeouts+i+1,
@@ -365,7 +396,7 @@ static int virEventCleanupTimeouts(void)
/* Release some memory if we've got a big chunk free */
if ((eventLoop.timeoutsAlloc - EVENT_ALLOC_EXTENT) > eventLoop.timeoutsCount) {
struct virEventTimeout *tmp;
- qemudDebug("Releasing %d out of %d timeout slots used, releasing %d\n",
+ EVENT_DEBUG("Releasing %d out of %d timeout slots used, releasing %d",
eventLoop.timeoutsCount, eventLoop.timeoutsAlloc, EVENT_ALLOC_EXTENT);
tmp = realloc(eventLoop.timeouts,
sizeof(struct virEventTimeout) *
@@ -406,7 +437,7 @@ static int virEventCleanupHandles(void)
/* Release some memory if we've got a big chunk free */
if ((eventLoop.handlesAlloc - EVENT_ALLOC_EXTENT) > eventLoop.handlesCount) {
struct virEventHandle *tmp;
- qemudDebug("Releasing %d out of %d handles slots used, releasing %d\n",
+ EVENT_DEBUG("Releasing %d out of %d handles slots used, releasing %d",
eventLoop.handlesCount, eventLoop.handlesAlloc, EVENT_ALLOC_EXTENT);
tmp = realloc(eventLoop.handles,
sizeof(struct virEventHandle) *
@@ -437,9 +468,9 @@ int virEventRunOnce(void) {
}
retry:
- qemudDebug("Poll on %d handles %p timeout %d\n", nfds, fds, timeout);
+ EVENT_DEBUG("Poll on %d handles %p timeout %d", nfds, fds, timeout);
ret = poll(fds, nfds, timeout);
- qemudDebug("Poll got %d event\n", ret);
+ EVENT_DEBUG("Poll got %d event", ret);
if (ret < 0) {
if (errno == EINTR) {
goto retry;
diff -r 0f29c3c9425f qemud/event.h
--- a/qemud/event.h Mon Sep 17 05:23:04 2007 -0400
+++ b/qemud/event.h Mon Sep 17 13:29:46 2007 -0400
@@ -39,6 +39,16 @@ int virEventAddHandleImpl(int fd, int ev
int virEventAddHandleImpl(int fd, int events, virEventHandleCallback cb, void *opaque);
/**
+ * virEventUpdateHandleImpl: change event set for a monitored file handle
+ *
+ * @fd: file handle to monitor for events
+ * @events: bitset of events to wach from POLLnnn constants
+ *
+ * Will not fail if fd exists
+ */
+void virEventUpdateHandleImpl(int fd, int events);
+
+/**
* virEventRemoveHandleImpl: unregister a callback from a file handle
*
* @fd: file handle to stop monitoring for events
@@ -50,14 +60,30 @@ int virEventRemoveHandleImpl(int fd);
/**
* virEventAddTimeoutImpl: register a callback for a timer event
*
- * @timeout: timeout between events in milliseconds
+ * @frequency: time between events in milliseconds
* @cb: callback to invoke when an event occurrs
* @opaque: user data to pass to callback
+ *
+ * Setting frequency to -1 will disable the timer. Setting the frequency
+ * to zero will cause it to fire on every event loop iteration.
*
* returns -1 if the file handle cannot be registered, a positive
* integer timer id upon success
*/
-int virEventAddTimeoutImpl(int timeout, virEventTimeoutCallback cb, void *opaque);
+int virEventAddTimeoutImpl(int frequency, virEventTimeoutCallback cb, void *opaque);
+
+/**
+ * virEventUpdateTimeoutImpl: change frequency for a timer
+ *
+ * @timer: timer id to change
+ * @frequency: time between events in milliseconds
+ *
+ * Setting frequency to -1 will disable the timer. Setting the frequency
+ * to zero will cause it to fire on every event loop iteration.
+ *
+ * Will not fail if timer exists
+ */
+void virEventUpdateTimeoutImpl(int timer, int frequency);
/**
* virEventRemoveTimeoutImpl: unregister a callback for a timer
diff -r 0f29c3c9425f qemud/qemud.c
--- a/qemud/qemud.c Mon Sep 17 05:23:04 2007 -0400
+++ b/qemud/qemud.c Mon Sep 17 13:29:46 2007 -0400
@@ -688,8 +688,10 @@ static struct qemud_server *qemudInitial
goto cleanup;
__virEventRegisterImpl(virEventAddHandleImpl,
+ virEventUpdateHandleImpl,
virEventRemoveHandleImpl,
virEventAddTimeoutImpl,
+ virEventUpdateTimeoutImpl,
virEventRemoveTimeoutImpl);
virStateInitialize();
diff -r 0f29c3c9425f src/event.c
--- a/src/event.c Mon Sep 17 05:23:04 2007 -0400
+++ b/src/event.c Mon Sep 17 13:29:46 2007 -0400
@@ -27,8 +27,10 @@
#include <stdlib.h>
static virEventAddHandleFunc addHandleImpl = NULL;
+static virEventUpdateHandleFunc updateHandleImpl = NULL;
static virEventRemoveHandleFunc removeHandleImpl = NULL;
static virEventAddTimeoutFunc addTimeoutImpl = NULL;
+static virEventUpdateTimeoutFunc updateTimeoutImpl = NULL;
static virEventRemoveTimeoutFunc removeTimeoutImpl = NULL;
int virEventAddHandle(int fd, int events, virEventHandleCallback cb, void *opaque) {
@@ -36,6 +38,10 @@ int virEventAddHandle(int fd, int events
return -1;
return addHandleImpl(fd, events, cb, opaque);
+}
+
+void virEventUpdateHandle(int fd, int events) {
+ updateHandleImpl(fd, events);
}
int virEventRemoveHandle(int fd) {
@@ -52,6 +58,10 @@ int virEventAddTimeout(int timeout, virE
return addTimeoutImpl(timeout, cb, opaque);
}
+void virEventUpdateTimeout(int timer, int timeout) {
+ updateTimeoutImpl(timer, timeout);
+}
+
int virEventRemoveTimeout(int timer) {
if (!removeTimeoutImpl)
return -1;
@@ -60,12 +70,16 @@ int virEventRemoveTimeout(int timer) {
}
void __virEventRegisterImpl(virEventAddHandleFunc addHandle,
- virEventRemoveHandleFunc removeHandle,
- virEventAddTimeoutFunc addTimeout,
- virEventRemoveTimeoutFunc removeTimeout) {
+ virEventUpdateHandleFunc updateHandle,
+ virEventRemoveHandleFunc removeHandle,
+ virEventAddTimeoutFunc addTimeout,
+ virEventUpdateTimeoutFunc updateTimeout,
+ virEventRemoveTimeoutFunc removeTimeout) {
addHandleImpl = addHandle;
+ updateHandleImpl = updateHandle;
removeHandleImpl = removeHandle;
addTimeoutImpl = addTimeout;
+ updateTimeoutImpl = updateTimeout;
removeTimeoutImpl = removeTimeout;
}
diff -r 0f29c3c9425f src/event.h
--- a/src/event.h Mon Sep 17 05:23:04 2007 -0400
+++ b/src/event.h Mon Sep 17 13:29:46 2007 -0400
@@ -47,6 +47,16 @@ int virEventAddHandle(int fd, int events
int virEventAddHandle(int fd, int events, virEventHandleCallback cb, void *opaque);
/**
+ * virEventUpdateHandle: change event set for a monitored file handle
+ *
+ * @fd: file handle to monitor for events
+ * @events: bitset of events to wach from POLLnnn constants
+ *
+ * Will not fail if fd exists
+ */
+void virEventUpdateHandle(int fd, int events);
+
+/**
* virEventRemoveHandle: unregister a callback from a file handle
*
* @fd: file handle to stop monitoring for events
@@ -66,14 +76,30 @@ typedef void (*virEventTimeoutCallback)(
/**
* virEventAddTimeout: register a callback for a timer event
*
- * @timeout: timeout between events in milliseconds
+ * @frequency: time between events in milliseconds
* @cb: callback to invoke when an event occurrs
* @opaque: user data to pass to callback
+ *
+ * Setting frequency to -1 will disable the timer. Setting the frequency
+ * to zero will cause it to fire on every event loop iteration.
*
* returns -1 if the file handle cannot be registered, a positive
* integer timer id upon success
*/
-int virEventAddTimeout(int timeout, virEventTimeoutCallback cb, void *opaque);
+int virEventAddTimeout(int frequency, virEventTimeoutCallback cb, void *opaque);
+
+/**
+ * virEventUpdateTimeoutImpl: change frequency for a timer
+ *
+ * @timer: timer id to change
+ * @frequency: time between events in milliseconds
+ *
+ * Setting frequency to -1 will disable the timer. Setting the frequency
+ * to zero will cause it to fire on every event loop iteration.
+ *
+ * Will not fail if timer exists
+ */
+void virEventUpdateTimeout(int timer, int frequency);
/**
* virEventRemoveTimeout: unregister a callback for a timer
@@ -85,14 +111,18 @@ int virEventRemoveTimeout(int timer);
int virEventRemoveTimeout(int timer);
typedef int (*virEventAddHandleFunc)(int, int, virEventHandleCallback, void *);
+typedef void (*virEventUpdateHandleFunc)(int, int);
typedef int (*virEventRemoveHandleFunc)(int);
typedef int (*virEventAddTimeoutFunc)(int, virEventTimeoutCallback, void *);
+typedef void (*virEventUpdateTimeoutFunc)(int, int);
typedef int (*virEventRemoveTimeoutFunc)(int);
void __virEventRegisterImpl(virEventAddHandleFunc addHandle,
+ virEventUpdateHandleFunc updateHandle,
virEventRemoveHandleFunc removeHandle,
virEventAddTimeoutFunc addTimeout,
+ virEventUpdateTimeoutFunc updateTimeout,
virEventRemoveTimeoutFunc removeTimeout);
#define virEventRegisterImpl(ah,rh,at,rt) __virEventRegisterImpl(ah,rh,at,rt)
More information about the libvir-list
mailing list