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 -=|
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)
-- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list