/** * virObjectEventCallbackListRemoveID: * @conn: pointer to the connection * @cbList: the list * @callback: the callback to remove * * Internal function to remove a callback from a virObjectEventCallbackListPtr */ static int virObjectEventCallbackListRemoveID(virConnectPtr conn, virObjectEventCallbackListPtr cbList, int callbackID) { size_t i; for (i = 0; i < cbList->count; i++) { virObjectEventCallbackPtr cb = cbList->callbacks[i]; if (cb->callbackID == callbackID && cb->conn == conn) { int ret; ret = cb->filter ? 0 : (virObjectEventCallbackListCount(conn, cbList, cb->klass, cb->eventID, cb->key_filter ? cb->key : NULL, cb->remoteID >= 0) - 1); if (cb->freecb) (*cb->freecb)(cb->opaque); virObjectEventCallbackFree(cb); VIR_DELETE_ELEMENT(cbList->callbacks, i, cbList->count); return ret; } } virReportError(VIR_ERR_INVALID_ARG, _("could not find event callback %d for deletion"), callbackID); return -1; }
static int virObjectEventCallbackListPurgeMarked(virObjectEventCallbackListPtr cbList) { size_t n; for (n = 0; n < cbList->count; n++) { if (cbList->callbacks[n]->deleted) { virFreeCallback freecb = cbList->callbacks[n]->freecb; if (freecb) (*freecb)(cbList->callbacks[n]->opaque); virObjectEventCallbackFree(cbList->callbacks[n]); VIR_DELETE_ELEMENT(cbList->callbacks, n, cbList->count); n--; } } return 0; }
/** * virObjectEventCallbackListRemoveID: * @conn: pointer to the connection * @cbList: the list * @callback: the callback to remove * @doFreeCb: Inhibit calling the freecb * * Internal function to remove a callback from a virObjectEventCallbackListPtr */ static int virObjectEventCallbackListRemoveID(virConnectPtr conn, virObjectEventCallbackListPtr cbList, int callbackID, bool doFreeCb) { size_t i; for (i = 0; i < cbList->count; i++) { virObjectEventCallbackPtr cb = cbList->callbacks[i]; if (cb->callbackID == callbackID && cb->conn == conn) { int ret; ret = cb->filter ? 0 : (virObjectEventCallbackListCount(conn, cbList, cb->klass, cb->eventID, cb->key_filter ? cb->key : NULL, cb->remoteID >= 0) - 1); /* @doFreeCb inhibits calling @freecb from error paths in * register functions to ensure the caller of a failed register * function won't end up with a double free error */ if (doFreeCb && cb->freecb) (*cb->freecb)(cb->opaque); virObjectEventCallbackFree(cb); VIR_DELETE_ELEMENT(cbList->callbacks, i, cbList->count); return ret; } } virReportError(VIR_ERR_INVALID_ARG, _("could not find event callback %d for deletion"), callbackID); return -1; }
/** * virObjectEventCallbackListAddID: * @conn: pointer to the connection * @cbList: the list * @key: the optional key of the object to filter on * @filter: optional last-ditch filter callback * @filter_opaque: opaque data to pass to @filter * @klass: the base event class * @eventID: the event ID * @callback: the callback to add * @opaque: opaque data to pass to @callback * @freecb: callback to free @opaque * @legacy: true if callback is tracked by function instead of callbackID * @callbackID: filled with callback ID * @serverFilter: true if server supports object filtering * * Internal function to add a callback from a virObjectEventCallbackListPtr */ static int virObjectEventCallbackListAddID(virConnectPtr conn, virObjectEventCallbackListPtr cbList, const char *key, virObjectEventCallbackFilter filter, void *filter_opaque, virClassPtr klass, int eventID, virConnectObjectEventGenericCallback callback, void *opaque, virFreeCallback freecb, bool legacy, int *callbackID, bool serverFilter) { virObjectEventCallbackPtr cb; int ret = -1; int remoteID = -1; VIR_DEBUG("conn=%p cblist=%p key=%p filter=%p filter_opaque=%p " "klass=%p eventID=%d callback=%p opaque=%p " "legacy=%d callbackID=%p serverFilter=%d", conn, cbList, key, filter, filter_opaque, klass, eventID, callback, opaque, legacy, callbackID, serverFilter); /* Check incoming */ if (!cbList) return -1; /* If there is no additional filtering, then check if we already * have this callback on our list. */ if (!filter && virObjectEventCallbackLookup(conn, cbList, key, klass, eventID, callback, legacy, serverFilter ? &remoteID : NULL) != -1) { virReportError(VIR_ERR_INVALID_ARG, "%s", _("event callback already tracked")); return -1; } /* Allocate new cb */ if (VIR_ALLOC(cb) < 0) goto cleanup; cb->conn = virObjectRef(conn); *callbackID = cb->callbackID = cbList->nextID++; cb->cb = callback; cb->klass = klass; cb->eventID = eventID; cb->opaque = opaque; cb->freecb = freecb; cb->remoteID = remoteID; if (key) { cb->key_filter = true; if (VIR_STRDUP(cb->key, key) < 0) goto cleanup; } cb->filter = filter; cb->filter_opaque = filter_opaque; cb->legacy = legacy; if (VIR_APPEND_ELEMENT(cbList->callbacks, cbList->count, cb) < 0) goto cleanup; /* 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, key, serverFilter); if (serverFilter && remoteID < 0) ret++; } cleanup: virObjectEventCallbackFree(cb); return ret; }