}
+/* In order to filter by event name, we need to store a copy of the
+ * name to filter on. By wrapping the caller's freecb, we can
+ * piggyback our cleanup to happen at the same time the caller
+ * deregisters. */
+struct virDomainQemuMonitorEventData {
+ char *event;
+ void *opaque;
+ virFreeCallback freecb;
+};
+typedef struct virDomainQemuMonitorEventData virDomainQemuMonitorEventData;
+
+
static void
virDomainQemuMonitorEventDispatchFunc(virConnectPtr conn,
virObjectEventPtr event,
{
virDomainPtr dom = virGetDomain(conn, event->meta.name, event->meta.uuid);
virDomainQemuMonitorEventPtr qemuMonitorEvent;
+ virDomainQemuMonitorEventData *data = cbopaque;
if (!dom)
return;
qemuMonitorEvent->seconds,
qemuMonitorEvent->micros,
qemuMonitorEvent->details,
- cbopaque);
+ data->opaque);
virDomainFree(dom);
}
}
+/**
+ * virDomainQemuMonitorEventFilter:
+ * @conn: the connection pointer
+ * @event: the event about to be dispatched
+ * @opaque: the opaque data registered with the filter
+ *
+ * Callback for filtering based on event names. Returns true if the
+ * event should be dispatched.
+ */
+static bool
+virDomainQemuMonitorEventFilter(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virObjectEventPtr event,
+ void *opaque)
+{
+ virDomainQemuMonitorEventData *data = opaque;
+ virDomainQemuMonitorEventPtr monitorEvent;
+
+ monitorEvent = (virDomainQemuMonitorEventPtr) event;
+
+ return STREQ(monitorEvent->event, data->event);
+}
+
+
+static void
+virDomainQemuMonitorEventCleanup(void *opaque)
+{
+ virDomainQemuMonitorEventData *data = opaque;
+
+ VIR_FREE(data->event);
+ if (data->freecb)
+ (data->freecb)(data->opaque);
+ VIR_FREE(data);
+}
+
+
/**
* virDomainQemuMonitorEventStateRegisterID:
* @conn: connection to associate with callback
unsigned int flags,
int *callbackID)
{
+ virDomainQemuMonitorEventData *data = NULL;
+ virObjectEventCallbackFilter filter = NULL;
+
if (virDomainEventsInitialize() < 0)
return -1;
- /* FIXME support event filtering */
if (flags != -1)
virCheckFlags(0, -1);
- if (event) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("event filtering on '%s' not implemented yet"),
- event);
+ if (VIR_ALLOC(data) < 0)
+ return -1;
+ if (VIR_STRDUP(data->event, event) < 0) {
+ VIR_FREE(data);
return -1;
}
+ data->opaque = opaque;
+ data->freecb = freecb;
+ if (event)
+ filter = virDomainQemuMonitorEventFilter;
+ freecb = virDomainQemuMonitorEventCleanup;
return virObjectEventStateRegisterID(conn, state, dom ? dom->uuid : NULL,
- NULL, NULL,
+ filter, data,
virDomainQemuMonitorEventClass, 0,
VIR_OBJECT_EVENT_CALLBACK(cb),
- opaque, freecb,
+ data, freecb,
false, callbackID, false);
}
for (i = 0; i < cbList->count; i++) {
virObjectEventCallbackPtr cb = cbList->callbacks[i];
+ if (cb->filter)
+ continue;
if (cb->klass == klass &&
cb->eventID == eventID &&
cb->conn == conn &&
if (cb->callbackID == callbackID && cb->conn == conn) {
int ret;
- ret = virObjectEventCallbackListCount(conn, cbList, cb->klass,
- cb->eventID,
- cb->uuid_filter ? cb->uuid : NULL,
- cb->remoteID >= 0) - 1;
+ ret = cb->filter ? 0 :
+ (virObjectEventCallbackListCount(conn, cbList, cb->klass,
+ cb->eventID,
+ cb->uuid_filter ? cb->uuid : NULL,
+ cb->remoteID >= 0) - 1);
if (cb->freecb)
(*cb->freecb)(cb->opaque);
if (cb->callbackID == callbackID && cb->conn == conn) {
cb->deleted = true;
- return virObjectEventCallbackListCount(conn, cbList, cb->klass,
- cb->eventID,
- cb->uuid_filter ? cb->uuid : NULL,
- cb->remoteID >= 0);
+ return cb->filter ? 0 :
+ virObjectEventCallbackListCount(conn, cbList, cb->klass,
+ cb->eventID,
+ cb->uuid_filter ? cb->uuid : NULL,
+ cb->remoteID >= 0);
}
}
return -1;
}
- /* check if we already have this callback on our list */
- if (virObjectEventCallbackLookup(conn, cbList, uuid,
+ /* If there is no additional filtering, then check if we already
+ * have this callback on our list. */
+ if (!filter &&
+ virObjectEventCallbackLookup(conn, cbList, uuid,
klass, eventID, callback, legacy,
serverFilter ? &remoteID : NULL) != -1) {
virReportError(VIR_ERR_INVALID_ARG, "%s",
if (VIR_APPEND_ELEMENT(cbList->callbacks, cbList->count, event) < 0)
goto cleanup;
- ret = virObjectEventCallbackListCount(conn, cbList, klass, eventID,
- uuid, serverFilter);
- if (serverFilter && remoteID < 0)
- ret++;
+ /* When additional filtering is being done, every client callback
+ * is matched to exactly one server callback. */
+ if (filter) {
+ ret = 1;
+ } else {
+ ret = virObjectEventCallbackListCount(conn, cbList, klass, eventID,
+ uuid, serverFilter);
+ if (serverFilter && remoteID < 0)
+ ret++;
+ }
cleanup:
if (event)