+Wed Nov 19 16:22:00 GMT 2008 Daniel Berrange <berrange@redhat.com>
+
+ Add virFreeCallback to event loop APIs.
+ * include/libvirt/libvirt.h.in: Add a virFreeCallback arg
+ to the virEventAddHandle and virEventAddTimeout methods.
+ * qemud/event.c: Invoke the virFreeCallback when releasing
+ a handle/timer event
+ * qemud/event.h, qemud/qemud.c, qemud/mdns.c,
+ src/event.h, src/event.c, src/lxc_driver.c,
+ src/qemu_driver.c, src/remote_internal.c: Update to pass
+ around the virFreeCallback where needed
+
Wed Nov 19 16:15:00 GMT 2008 Daniel Berrange <berrange@redhat.com>
* include/libvirt/libvirt.h.in: Change semantics of AddHandle
int h_fd = 0;
virEventHandleType h_event = 0;
virEventHandleCallback h_cb = NULL;
+virFreeCallback h_ff = NULL;
void *h_opaque = NULL;
/* timeout globals */
int t_active = 0;
int t_timeout = -1;
virEventTimeoutCallback t_cb = NULL;
+virFreeCallback t_ff = NULL;
void *t_opaque = NULL;
int myDomainEventCallback2 (virConnectPtr conn, virDomainPtr dom,
int event, int detail, void *opaque);
int myEventAddHandleFunc (int fd, int event,
- virEventHandleCallback cb, void *opaque);
+ virEventHandleCallback cb,
+ void *opaque,
+ virFreeCallback ff);
void myEventUpdateHandleFunc(int watch, int event);
int myEventRemoveHandleFunc(int watch);
-int myEventAddTimeoutFunc(int timeout, virEventTimeoutCallback cb,
- void *opaque);
+int myEventAddTimeoutFunc(int timeout,
+ virEventTimeoutCallback cb,
+ void *opaque,
+ virFreeCallback ff);
void myEventUpdateTimeoutFunc(int timer, int timout);
int myEventRemoveTimeoutFunc(int timer);
}
int myEventAddHandleFunc(int fd, int event,
- virEventHandleCallback cb, void *opaque)
+ virEventHandleCallback cb,
+ void *opaque,
+ virFreeCallback ff)
{
DEBUG("Add handle %d %d %p %p", fd, event, cb, opaque);
h_fd = fd;
h_event = myEventHandleTypeToPollEvent(event);
h_cb = cb;
+ h_ff = ff;
h_opaque = opaque;
return 0;
}
{
DEBUG("Removed Handle %d", fd);
h_fd = 0;
+ if (h_ff)
+ (h_ff)(h_opaque);
return 0;
}
-int myEventAddTimeoutFunc(int timeout, virEventTimeoutCallback cb,
- void *opaque)
+int myEventAddTimeoutFunc(int timeout,
+ virEventTimeoutCallback cb,
+ void *opaque,
+ virFreeCallback ff)
{
DEBUG("Adding Timeout %d %p %p", timeout, cb, opaque);
t_active = 1;
t_timeout = timeout;
t_cb = cb;
+ t_ff = ff;
t_opaque = opaque;
return 0;
}
{
DEBUG("Timeout removed %d", timer);
t_active = 0;
+ if (t_ff)
+ (t_ff)(t_opaque);
return 0;
}
* virEventAddHandleFunc:
* @fd: file descriptor to listen on
* @event: bitset of events on which to fire the callback
- * @cb: the callback to be called
+ * @cb: the callback to be called when an event occurrs
* @opaque: user data to pass to the callback
+ * @ff: the callback invoked to free opaque data blob
*
* Part of the EventImpl, this callback Adds a file handle callback to
* listen for specific events. The same file handle can be registered
* multiple times provided the requested event sets are non-overlapping
*
+ * If the opaque user data requires free'ing when the handle
+ * is unregistered, then a 2nd callback can be supplied for
+ * this purpose.
+ *
* Returns a handle watch number to be used for updating
* and unregistering for events
*/
typedef int (*virEventAddHandleFunc)(int fd, int event,
- virEventHandleCallback cb, void *opaque);
+ virEventHandleCallback cb,
+ void *opaque,
+ virFreeCallback ff);
/**
* virEventUpdateHandleFunc:
* @watch: file descriptor watch to stop listening on
*
* Part of the EventImpl, this user-provided callback is notified when
- * an fd is no longer being listened on
+ * an fd is no longer being listened on.
+ *
+ * If a virEventHandleFreeFunc was supplied when the handle was
+ * registered, it will be invoked some time during, or after this
+ * function call, when it is safe to release the user data.
*/
typedef int (*virEventRemoveHandleFunc)(int watch);
* @timeout: The timeout to monitor
* @cb: the callback to call when timeout has expired
* @opaque: user data to pass to the callback
+ * @ff: the callback invoked to free opaque data blob
*
* Part of the EventImpl, this user-defined callback handles adding an
* event timeout.
*
+ * If the opaque user data requires free'ing when the handle
+ * is unregistered, then a 2nd callback can be supplied for
+ * this purpose.
+ *
* Returns a timer value
*/
-typedef int (*virEventAddTimeoutFunc)(int timeout, virEventTimeoutCallback cb,
- void *opaque);
+typedef int (*virEventAddTimeoutFunc)(int timeout,
+ virEventTimeoutCallback cb,
+ void *opaque,
+ virFreeCallback ff);
/**
* virEventUpdateTimeoutFunc:
*
* Part of the EventImpl, this user-defined callback removes a timer
*
+ * If a virEventTimeoutFreeFunc was supplied when the handle was
+ * registered, it will be invoked some time during, or after this
+ * function call, when it is safe to release the user data.
+ *
* Returns 0 on success, -1 on failure
*/
typedef int (*virEventRemoveTimeoutFunc)(int timer);
* virEventAddHandleFunc:
* @fd: file descriptor to listen on
* @event: bitset of events on which to fire the callback
- * @cb: the callback to be called
+ * @cb: the callback to be called when an event occurrs
* @opaque: user data to pass to the callback
+ * @ff: the callback invoked to free opaque data blob
*
* Part of the EventImpl, this callback Adds a file handle callback to
* listen for specific events. The same file handle can be registered
* multiple times provided the requested event sets are non-overlapping
*
+ * If the opaque user data requires free'ing when the handle
+ * is unregistered, then a 2nd callback can be supplied for
+ * this purpose.
+ *
* Returns a handle watch number to be used for updating
* and unregistering for events
*/
typedef int (*virEventAddHandleFunc)(int fd, int event,
- virEventHandleCallback cb, void *opaque);
+ virEventHandleCallback cb,
+ void *opaque,
+ virFreeCallback ff);
/**
* virEventUpdateHandleFunc:
* @watch: file descriptor watch to stop listening on
*
* Part of the EventImpl, this user-provided callback is notified when
- * an fd is no longer being listened on
+ * an fd is no longer being listened on.
+ *
+ * If a virEventHandleFreeFunc was supplied when the handle was
+ * registered, it will be invoked some time during, or after this
+ * function call, when it is safe to release the user data.
*/
typedef int (*virEventRemoveHandleFunc)(int watch);
* @timeout: The timeout to monitor
* @cb: the callback to call when timeout has expired
* @opaque: user data to pass to the callback
+ * @ff: the callback invoked to free opaque data blob
*
* Part of the EventImpl, this user-defined callback handles adding an
* event timeout.
*
+ * If the opaque user data requires free'ing when the handle
+ * is unregistered, then a 2nd callback can be supplied for
+ * this purpose.
+ *
* Returns a timer value
*/
-typedef int (*virEventAddTimeoutFunc)(int timeout, virEventTimeoutCallback cb,
- void *opaque);
+typedef int (*virEventAddTimeoutFunc)(int timeout,
+ virEventTimeoutCallback cb,
+ void *opaque,
+ virFreeCallback ff);
/**
* virEventUpdateTimeoutFunc:
*
* Part of the EventImpl, this user-defined callback removes a timer
*
+ * If a virEventTimeoutFreeFunc was supplied when the handle was
+ * registered, it will be invoked some time during, or after this
+ * function call, when it is safe to release the user data.
+ *
* Returns 0 on success, -1 on failure
*/
typedef int (*virEventRemoveTimeoutFunc)(int timer);
static int
-libvirt_virEventAddHandleFunc (int fd ATTRIBUTE_UNUSED, int event ATTRIBUTE_UNUSED,
- virEventHandleCallback cb, void *opaque)
+libvirt_virEventAddHandleFunc (int fd,
+ int event,
+ virEventHandleCallback cb,
+ void *opaque,
+ virFreeCallback ff)
{
PyObject *result = NULL;
PyObject *python_cb;
PyObject *cb_obj;
+ PyObject *ff_obj;
PyObject *opaque_obj;
PyObject *cb_args;
PyObject *pyobj_args;
/* create tuple for cb */
cb_obj = libvirt_virEventHandleCallbackWrap(cb);
+ ff_obj = libvirt_virFreeCallbackWrap(ff);
opaque_obj = libvirt_virVoidPtrWrap(opaque);
- cb_args = PyTuple_New(2);
+ cb_args = PyTuple_New(3);
PyTuple_SetItem(cb_args, 0, cb_obj);
PyTuple_SetItem(cb_args, 1, opaque_obj);
+ PyTuple_SetItem(cb_args, 2, ff_obj);
pyobj_args = PyTuple_New(4);
PyTuple_SetItem(pyobj_args, 0, libvirt_intWrap(fd));
}
static int
-libvirt_virEventAddTimeoutFunc(int timeout, virEventTimeoutCallback cb,
- void *opaque)
+libvirt_virEventAddTimeoutFunc(int timeout,
+ virEventTimeoutCallback cb,
+ void *opaque,
+ virFreeCallback ff)
{
PyObject *result = NULL;
PyObject *python_cb;
PyObject *cb_obj;
+ PyObject *ff_obj;
PyObject *opaque_obj;
PyObject *cb_args;
PyObject *pyobj_args;
/* create tuple for cb */
cb_obj = libvirt_virEventTimeoutCallbackWrap(cb);
+ ff_obj = libvirt_virFreeCallbackWrap(ff);
opaque_obj = libvirt_virVoidPtrWrap(opaque);
- cb_args = PyTuple_New(2);
+ cb_args = PyTuple_New(3);
PyTuple_SetItem(cb_args, 0, cb_obj);
PyTuple_SetItem(cb_args, 1, opaque_obj);
+ PyTuple_SetItem(cb_args, 2, ff_obj);
pyobj_args = PyTuple_New(3);
PyObject * libvirt_virStorageVolPtrWrap(virStorageVolPtr node);
PyObject * libvirt_virEventHandleCallbackWrap(virEventHandleCallback node);
PyObject * libvirt_virEventTimeoutCallbackWrap(virEventTimeoutCallback node);
+PyObject * libvirt_virFreeCallbackWrap(virFreeCallback node);
PyObject * libvirt_virVoidPtrWrap(void* node);
/* Provide simple macro statement wrappers (adapted from GLib, in turn from Perl):
return (ret);
}
+PyObject *
+libvirt_virFreeCallbackWrap(virFreeCallback node)
+{
+ PyObject *ret;
+
+ if (node == NULL) {
+ printf("%s: WARNING - Wrapping None\n", __FUNCTION__);
+ Py_INCREF(Py_None);
+ return (Py_None);
+ }
+ ret =
+ PyCObject_FromVoidPtrAndDesc((void *) node, (char *) "virFreeCallback",
+ NULL);
+ return (ret);
+}
+
PyObject *
libvirt_virVoidPtrWrap(void* node)
{
int fd;
int events;
virEventHandleCallback cb;
+ virFreeCallback ff;
void *opaque;
int deleted;
};
int frequency;
unsigned long long expiresAt;
virEventTimeoutCallback cb;
+ virFreeCallback ff;
void *opaque;
int deleted;
};
* NB, it *must* be safe to call this from within a callback
* For this reason we only ever append to existing list.
*/
-int virEventAddHandleImpl(int fd, int events, virEventHandleCallback cb,
- void *opaque) {
+int virEventAddHandleImpl(int fd, int events,
+ virEventHandleCallback cb,
+ void *opaque,
+ virFreeCallback ff) {
EVENT_DEBUG("Add handle %d %d %p %p", fd, events, cb, opaque);
if (eventLoop.handlesCount == eventLoop.handlesAlloc) {
EVENT_DEBUG("Used %d handle slots, adding %d more",
eventLoop.handles[eventLoop.handlesCount].events =
virEventHandleTypeToPollEvent(events);
eventLoop.handles[eventLoop.handlesCount].cb = cb;
+ eventLoop.handles[eventLoop.handlesCount].ff = ff;
eventLoop.handles[eventLoop.handlesCount].opaque = opaque;
eventLoop.handles[eventLoop.handlesCount].deleted = 0;
* 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 frequency, virEventTimeoutCallback cb, void *opaque) {
+int virEventAddTimeoutImpl(int frequency,
+ virEventTimeoutCallback cb,
+ void *opaque,
+ virFreeCallback ff) {
struct timeval now;
EVENT_DEBUG("Adding timer %d with %d ms freq", nextTimer, frequency);
if (gettimeofday(&now, NULL) < 0) {
eventLoop.timeouts[eventLoop.timeoutsCount].timer = nextTimer++;
eventLoop.timeouts[eventLoop.timeoutsCount].frequency = frequency;
eventLoop.timeouts[eventLoop.timeoutsCount].cb = cb;
+ eventLoop.timeouts[eventLoop.timeoutsCount].ff = ff;
eventLoop.timeouts[eventLoop.timeoutsCount].opaque = opaque;
eventLoop.timeouts[eventLoop.timeoutsCount].deleted = 0;
eventLoop.timeouts[eventLoop.timeoutsCount].expiresAt =
}
EVENT_DEBUG("Purging timeout %d with id %d", i, eventLoop.timeouts[i].timer);
+ if (eventLoop.timeouts[i].ff)
+ (eventLoop.timeouts[i].ff)(eventLoop.timeouts[i].opaque);
+
if ((i+1) < eventLoop.timeoutsCount) {
memmove(eventLoop.timeouts+i,
eventLoop.timeouts+i+1,
continue;
}
+ if (eventLoop.handles[i].ff)
+ (eventLoop.handles[i].ff)(eventLoop.handles[i].opaque);
+
if ((i+1) < eventLoop.handlesCount) {
memmove(eventLoop.handles+i,
eventLoop.handles+i+1,
*
* returns -1 if the file handle cannot be registered, 0 upon success
*/
-int virEventAddHandleImpl(int fd, int events, virEventHandleCallback cb,
- void *opaque);
+int virEventAddHandleImpl(int fd, int events,
+ virEventHandleCallback cb,
+ void *opaque,
+ virFreeCallback ff);
/**
* virEventUpdateHandleImpl: change event set for a monitored file handle
* returns -1 if the file handle cannot be registered, a positive
* integer timer id upon success
*/
-int virEventAddTimeoutImpl(int frequency, virEventTimeoutCallback cb, void *opaque);
+int virEventAddTimeoutImpl(int frequency,
+ virEventTimeoutCallback cb,
+ void *opaque,
+ virFreeCallback ff);
/**
* virEventUpdateTimeoutImpl: change frequency for a timer
w->callback(w, fd, fd_events, w->userdata);
}
+static void libvirtd_mdns_watch_dofree(void *w)
+{
+ VIR_FREE(w);
+}
+
+
static AvahiWatch *libvirtd_mdns_watch_new(const AvahiPoll *api ATTRIBUTE_UNUSED,
int fd, AvahiWatchEvent event,
AvahiWatchCallback cb, void *userdata) {
AVAHI_DEBUG("New handle %p FD %d Event %d", w, w->fd, event);
hEvents = virPollEventToEventHandleType(event);
if ((w->watch = virEventAddHandleImpl(fd, hEvents,
- libvirtd_mdns_watch_dispatch, w)) < 0) {
+ libvirtd_mdns_watch_dispatch,
+ w,
+ libvirtd_mdns_watch_dofree)) < 0) {
VIR_FREE(w);
return NULL;
}
{
AVAHI_DEBUG("Free handle %p %d", w, w->fd);
virEventRemoveHandleImpl(w->watch);
- VIR_FREE(w);
}
static void libvirtd_mdns_timeout_dispatch(int timer ATTRIBUTE_UNUSED, void *opaque)
t->callback(t, t->userdata);
}
+static void libvirtd_mdns_timeout_dofree(void *t)
+{
+ VIR_FREE(t);
+}
+
static AvahiTimeout *libvirtd_mdns_timeout_new(const AvahiPoll *api ATTRIBUTE_UNUSED,
const struct timeval *tv,
AvahiTimeoutCallback cb,
timeout = -1;
}
- t->timer = virEventAddTimeoutImpl(timeout, libvirtd_mdns_timeout_dispatch, t);
+ t->timer = virEventAddTimeoutImpl(timeout,
+ libvirtd_mdns_timeout_dispatch,
+ t,
+ libvirtd_mdns_timeout_dofree);
t->callback = cb;
t->userdata = userdata;
{
AVAHI_DEBUG("Free timeout %p", t);
virEventRemoveTimeoutImpl(t->timer);
- VIR_FREE(t);
}
VIR_EVENT_HANDLE_ERROR |
VIR_EVENT_HANDLE_HANGUP,
qemudDispatchServerEvent,
- server)) < 0) {
+ server, NULL)) < 0) {
qemudLog(QEMUD_ERR, "%s",
_("Failed to add server event callback"));
goto cleanup;
VIR_EVENT_HANDLE_ERROR |
VIR_EVENT_HANDLE_HANGUP,
qemudDispatchServerEvent,
- server)) < 0) {
+ server, NULL)) < 0) {
qemudLog(QEMUD_ERR, "%s", _("Failed to add server event callback"));
goto cleanup;
}
mode | VIR_EVENT_HANDLE_ERROR |
VIR_EVENT_HANDLE_HANGUP,
qemudDispatchClientEvent,
- server)) < 0)
+ server, NULL)) < 0)
return -1;
return 0;
* shutdown after timeout seconds
*/
if (timeout > 0 && !virStateActive() && !server->clients) {
- timerid = virEventAddTimeoutImpl(timeout*1000, qemudInactiveTimer, server);
+ timerid = virEventAddTimeoutImpl(timeout*1000,
+ qemudInactiveTimer,
+ server, NULL);
qemudDebug("Scheduling shutdown timer %d", timerid);
}
if (virEventAddHandleImpl(sigpipe[0],
VIR_EVENT_HANDLE_READABLE,
qemudDispatchSignalEvent,
- server) < 0) {
+ server, NULL) < 0) {
qemudLog(QEMUD_ERR,
"%s", _("Failed to register callback for signal pipe"));
ret = 3;
static virEventUpdateTimeoutFunc updateTimeoutImpl = NULL;
static virEventRemoveTimeoutFunc removeTimeoutImpl = NULL;
-int virEventAddHandle(int fd, int events, virEventHandleCallback cb,
- void *opaque) {
+int virEventAddHandle(int fd,
+ int events,
+ virEventHandleCallback cb,
+ void *opaque,
+ virFreeCallback ff) {
if (!addHandleImpl)
return -1;
- return addHandleImpl(fd, events, cb, opaque);
+ return addHandleImpl(fd, events, cb, opaque, ff);
}
void virEventUpdateHandle(int watch, int events) {
return removeHandleImpl(watch);
}
-int virEventAddTimeout(int timeout, virEventTimeoutCallback cb, void *opaque) {
+int virEventAddTimeout(int timeout,
+ virEventTimeoutCallback cb,
+ void *opaque,
+ virFreeCallback ff) {
if (!addTimeoutImpl)
return -1;
- return addTimeoutImpl(timeout, cb, opaque);
+ return addTimeoutImpl(timeout, cb, opaque, ff);
}
void virEventUpdateTimeout(int timer, int timeout) {
*
* returns -1 if the file handle cannot be registered, 0 upon success
*/
-int virEventAddHandle(int fd, int events, virEventHandleCallback cb,
- void *opaque);
+int virEventAddHandle(int fd, int events,
+ virEventHandleCallback cb,
+ void *opaque,
+ virFreeCallback ff);
/**
* virEventUpdateHandle: change event set for a monitored file handle
* returns -1 if the file handle cannot be registered, a positive
* integer timer id upon success
*/
-int virEventAddTimeout(int frequency, virEventTimeoutCallback cb, void *opaque);
+int virEventAddTimeout(int frequency,
+ virEventTimeoutCallback cb,
+ void *opaque,
+ virFreeCallback ff);
/**
* virEventUpdateTimeoutImpl: change frequency for a timer
vm->monitor,
VIR_EVENT_HANDLE_ERROR | VIR_EVENT_HANDLE_HANGUP,
lxcMonitorEvent,
- driver)) < 0) {
+ driver, NULL)) < 0) {
lxcVmTerminate(conn, driver, vm, 0);
goto cleanup;
}
if (ret == 0) {
if (((vm->stdout_watch = virEventAddHandle(vm->stdout_fd,
- VIR_EVENT_HANDLE_READABLE |
- VIR_EVENT_HANDLE_ERROR |
- VIR_EVENT_HANDLE_HANGUP,
- qemudDispatchVMEvent,
- driver)) < 0) ||
+ VIR_EVENT_HANDLE_READABLE |
+ VIR_EVENT_HANDLE_ERROR |
+ VIR_EVENT_HANDLE_HANGUP,
+ qemudDispatchVMEvent,
+ driver, NULL)) < 0) ||
((vm->stderr_watch = virEventAddHandle(vm->stderr_fd,
VIR_EVENT_HANDLE_READABLE |
VIR_EVENT_HANDLE_ERROR |
VIR_EVENT_HANDLE_HANGUP,
qemudDispatchVMEvent,
- driver)) < 0) ||
+ driver, NULL)) < 0) ||
(qemudWaitForMonitor(conn, driver, vm) < 0) ||
(qemudDetectVcpuPIDs(conn, driver, vm) < 0) ||
(qemudInitCpus(conn, driver, vm, migrateFrom) < 0)) {
VIR_EVENT_HANDLE_ERROR |
VIR_EVENT_HANDLE_HANGUP,
remoteDomainEventFired,
- conn)) < 0) {
+ conn, NULL)) < 0) {
DEBUG0("virEventAddHandle failed: No addHandleImpl defined."
" continuing without events.");
} else {
DEBUG0("Adding Timeout for remote event queue flushing");
if ( (priv->eventFlushTimer = virEventAddTimeout(-1,
- remoteDomainEventQueueFlush,
- conn)) < 0) {
+ remoteDomainEventQueueFlush,
+ conn, NULL)) < 0) {
DEBUG0("virEventAddTimeout failed: No addTimeoutImpl defined. "
"continuing without events.");
}