there are still some questions: In my code the add new libvirt_qemu specific events and the former libvirt events share the same event queue. so in libvirtd, the qemuDomainEventFlush will dispatch these two kinds of event. so should I add new event queue for the new libvirt_qemu specific events, in order to isolate them from the rest events of libvirt? I think the qemuMonitorJSONIOProcessEvent has better to filter the register event names, but I did not know the best way to add these register event names list. , shaohef@xxxxxxxxxxxxxxxxxx wrote: > From: ShaoHe Feng <shaohef@xxxxxxxxxxxxxxxxxx> > > Basically, this feature can go along with qemu monitor passthrough. > That way, if we use new commands in the monitor that generate new events, we want some way to receive those new events too. > > Signed-off-by: ShaoHe Feng <shaohef@xxxxxxxxxxxxxxxxxx> > --- > include/libvirt/libvirt-qemu.h | 27 ++++ > include/libvirt/libvirt.h.in | 2 +- > src/conf/domain_event.c | 293 ++++++++++++++++++++++++++++++++++++++-- > src/conf/domain_event.h | 50 ++++++- > src/driver.h | 14 ++ > src/libvirt-qemu.c | 189 ++++++++++++++++++++++++++ > src/libvirt_private.syms | 6 + > src/libvirt_qemu.syms | 5 + > 8 files changed, 571 insertions(+), 15 deletions(-) > > diff --git a/include/libvirt/libvirt-qemu.h b/include/libvirt/libvirt-qemu.h > index 7f12e4f..3aa944a 100644 > --- a/include/libvirt/libvirt-qemu.h > +++ b/include/libvirt/libvirt-qemu.h > @@ -32,6 +32,33 @@ virDomainPtr virDomainQemuAttach(virConnectPtr domain, > unsigned int pid, > unsigned int flags); > > +/** > + * virConnectDomainQemuEventCallback: > + * @conn: connection object > + * @dom: domain on which the event occurred > + * @eventName : the name of the unknow or un-implementation event > + * @eventArgs: the content of the unknow or un-implementation event > + * > + * The callback signature to use when registering for an event of type > + * VIR_QEMU_DOMAIN_EVENT_ID_UNKNOWN with virConnectDomainQemuEventRegister() > + */ > +typedef void (*virConnectDomainQemuEventCallback)(virConnectPtr conn, > + virDomainPtr dom, > + const char *eventName, /* The JSON event name */ > + const char *eventArgs, /* The JSON string of args */ > + void *opaque); > + > +int > +virConnectDomainQemuEventRegister(virConnectPtr conn, > + virDomainPtr dom, /* option to filter */ > + const char *eventName, /* JSON event name */ > + virConnectDomainQemuEventCallback cb, > + void *opaque, > + virFreeCallback freecb); > +int > +virConnectDomainQemuEventDeregister(virConnectPtr conn, > + int callbackID); > + > # ifdef __cplusplus > } > # endif > diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in > index 2480add..9fcb400 100644 > --- a/include/libvirt/libvirt.h.in > +++ b/include/libvirt/libvirt.h.in > @@ -3207,7 +3207,6 @@ typedef void (*virConnectDomainEventBlockJobCallback)(virConnectPtr conn, > int type, > int status, > void *opaque); > - > /** > * virConnectDomainEventDiskChangeReason: > * > @@ -3263,6 +3262,7 @@ typedef enum { > VIR_DOMAIN_EVENT_ID_CONTROL_ERROR = 7, /* virConnectDomainEventGenericCallback */ > VIR_DOMAIN_EVENT_ID_BLOCK_JOB = 8, /* virConnectDomainEventBlockJobCallback */ > VIR_DOMAIN_EVENT_ID_DISK_CHANGE = 9, /* virConnectDomainEventDiskChangeCallback */ > + VIR_QEMU_DOMAIN_EVENT_ID_UNKNOWN = 10, /* virConnectDomainEventDefaultCallback */ > > /* > * NB: this enum value will increase over time as new events are > diff --git a/src/conf/domain_event.c b/src/conf/domain_event.c > index 614ab97..0388a66 100644 > --- a/src/conf/domain_event.c > +++ b/src/conf/domain_event.c > @@ -45,7 +45,9 @@ typedef virDomainMeta *virDomainMetaPtr; > > struct _virDomainEventCallback { > int callbackID; > + int qemuCallbackID; > int eventID; > + char *eventName; > virConnectPtr conn; > virDomainMetaPtr dom; > virConnectDomainEventGenericCallback cb; > @@ -94,6 +96,10 @@ struct _virDomainEvent { > char *devAlias; > int reason; > } diskChange; > + struct { > + char *eventName; > + char *eventArgs; > + }qemuUnknownEvent; > } data; > }; > > @@ -112,6 +118,7 @@ virDomainEventCallbackListFree(virDomainEventCallbackListPtr list) > > for (i=0; i<list->count; i++) { > virFreeCallback freecb = list->callbacks[i]->freecb; > + VIR_FREE(list->callbacks[i]->eventName); > if (freecb) > (*freecb)(list->callbacks[i]->opaque); > VIR_FREE(list->callbacks[i]); > @@ -187,8 +194,10 @@ virDomainEventCallbackListRemoveID(virConnectPtr conn, > if (freecb) > (*freecb)(cbList->callbacks[i]->opaque); > virUnrefConnect(cbList->callbacks[i]->conn); > + if (cbList->callbacks[i]->eventID == VIR_QEMU_DOMAIN_EVENT_ID_UNKNOWN) { > + VIR_FREE(cbList->callbacks[i]->eventName); > + } > VIR_FREE(cbList->callbacks[i]); > - > if (i < (cbList->count - 1)) > memmove(cbList->callbacks + i, > cbList->callbacks + i + 1, > @@ -231,6 +240,9 @@ virDomainEventCallbackListRemoveConn(virConnectPtr conn, > if (freecb) > (*freecb)(cbList->callbacks[i]->opaque); > virUnrefConnect(cbList->callbacks[i]->conn); > + if (cbList->callbacks[i]->eventID == VIR_QEMU_DOMAIN_EVENT_ID_UNKNOWN) { > + VIR_FREE(cbList->callbacks[i]->eventName); > + } > VIR_FREE(cbList->callbacks[i]); > > if (i < (cbList->count - 1)) > @@ -299,6 +311,9 @@ int virDomainEventCallbackListPurgeMarked(virDomainEventCallbackListPtr cbList) > if (freecb) > (*freecb)(cbList->callbacks[i]->opaque); > virUnrefConnect(cbList->callbacks[i]->conn); > + if (cbList->callbacks[i]->eventID == VIR_QEMU_DOMAIN_EVENT_ID_UNKNOWN) { > + VIR_FREE(cbList->callbacks[i]->eventName); > + } > VIR_FREE(cbList->callbacks[i]); > > if (i < (cbList->count - 1)) > @@ -404,7 +419,98 @@ virDomainEventCallbackListAddID(virConnectPtr conn, > > cbList->callbacks[cbList->count] = event; > cbList->count++; > + event->callbackID = cbList->nextID++; > + > + return event->callbackID; > + > +no_memory: > + virReportOOMError(); > + > + if (event) { > + if (event->dom) > + VIR_FREE(event->dom->name); > + VIR_FREE(event->dom); > + } > + VIR_FREE(event); > + return -1; > +} > + > + > + > +/** > + * virDomainEventCallbackListAddName: > + * @conn: pointer to the connection > + * @cbList: the list > + * @eventName: the event eventName > + * @callback: the callback to add > + * @eventID: the specific eventID > + * @opaque: opaque data tio pass to callback > + * > + * Internal function to add a callback from a virDomainEventCallbackListPtr > + */ > +int > +virDomainEventCallbackListAddName(virConnectPtr conn, > + virDomainEventCallbackListPtr cbList, > + virDomainPtr dom, > + const char* eventName, > + int eventID, > + virConnectDomainEventGenericCallback callback, > + void *opaque, > + virFreeCallback freecb) > +{ > + virDomainEventCallbackPtr event; > + int i; > + > + /* Check incoming */ > + if ( !cbList ) { > + return -1; > + } > + > + /* check if we already have this callback on our list */ > + for (i = 0 ; i < cbList->count ; i++) { > + if (cbList->callbacks[i]->cb == VIR_DOMAIN_EVENT_CALLBACK(callback) && > + STREQ(cbList->callbacks[i]->eventName, eventName) && > + cbList->callbacks[i]->eventID == eventID && > + cbList->callbacks[i]->conn == conn) { > + eventReportError(VIR_ERR_INTERNAL_ERROR, "%s", > + _("event callback already tracked")); > + return -1; > + } > + } > + if (eventID > VIR_DOMAIN_EVENT_ID_LAST || eventID < VIR_DOMAIN_EVENT_ID_LIFECYCLE) { > + eventReportError(VIR_ERR_INTERNAL_ERROR, "%s", > + _("not suport this kind of eventID: %d"), eventID); > + } > + /* Allocate new event */ > + if (VIR_ALLOC(event) < 0) > + goto no_memory; > + event->conn = conn; > + event->cb = callback; > + if (eventName == NULL) > + goto no_memory; > + event->eventName = strdup(eventName); > + if ( event->eventName == NULL) > + goto no_memory; > + event->opaque = opaque; > + event->freecb = freecb; > + event->eventID = eventID; > + if (dom) { > + if (VIR_ALLOC(event->dom) < 0) > + goto no_memory; > + if (!(event->dom->name = strdup(dom->name))) > + goto no_memory; > + memcpy(event->dom->uuid, dom->uuid, VIR_UUID_BUFLEN); > + event->dom->id = dom->id; > + } > > + /* Make space on list */ > + if (VIR_REALLOC_N(cbList->callbacks, cbList->count + 1) < 0) > + goto no_memory; > + > + event->conn->refs++; > + > + cbList->callbacks[cbList->count] = event; > + cbList->count++; > event->callbackID = cbList->nextID++; > > return event->callbackID; > @@ -416,11 +522,40 @@ no_memory: > if (event->dom) > VIR_FREE(event->dom->name); > VIR_FREE(event->dom); > + VIR_FREE(event->eventName); > } > VIR_FREE(event); > return -1; > } > > +/** > + * virDomainEventCallbackListAddQemuCallbackID: > + * @conn: pointer to the connection > + * @cbList: the list > + * @callbackID: the libvirt callback ID > + * @qemuCallbackID: the libvirtd callback ID to add > + * > + * Internal function to add a Daemon libvirtd callbackID > + */ > +int > +virDomainEventCallbackListAddQemuCallbackID(virConnectPtr conn, > + virDomainEventCallbackListPtr cbList, > + int callbackID, > + int qemuCallbackID) > +{ > + int i; > + for (i = 0 ; i < cbList->count ; i++) { > + if (cbList->callbacks[i]->callbackID == callbackID && > + cbList->callbacks[i]->conn == conn) { > + cbList->callbacks[i]->qemuCallbackID = qemuCallbackID; > + return 0; > + } > + } > + > + eventReportError(VIR_ERR_INTERNAL_ERROR, "%s", > + _("could not find event callback for deletion")); > + return -1; > +} > > int virDomainEventCallbackListCountID(virConnectPtr conn, > virDomainEventCallbackListPtr cbList, > @@ -442,6 +577,27 @@ int virDomainEventCallbackListCountID(virConnectPtr conn, > } > > > +int > +virDomainEventCallbackListCountName(virConnectPtr conn, > + virDomainEventCallbackListPtr cbList, > + const char *eventName) > +{ > + int i; > + int count = 0; > + > + for (i = 0 ; i < cbList->count ; i++) { > + if (cbList->callbacks[i]->deleted) > + continue; > + > + if (STREQ(cbList->callbacks[i]->eventName,eventName) && > + cbList->callbacks[i]->conn == conn) > + count++; > + } > + > + return count; > +} > + > + > int virDomainEventCallbackListEventID(virConnectPtr conn, > virDomainEventCallbackListPtr cbList, > int callbackID) > @@ -461,6 +617,44 @@ int virDomainEventCallbackListEventID(virConnectPtr conn, > } > > > +const char* > +virDomainEventCallbackListEventName(virConnectPtr conn, > + virDomainEventCallbackListPtr cbList, > + int callbackID) > +{ > + int i; > + > + for (i = 0 ; i < cbList->count ; i++) { > + if (cbList->callbacks[i]->deleted) > + continue; > + > + if (cbList->callbacks[i]->callbackID == callbackID && > + cbList->callbacks[i]->conn == conn) > + return cbList->callbacks[i]->eventName; > + } > + > + return NULL; > +} > + > +int > +virDomainEventCallbackListEventQemuCallbackID(virConnectPtr conn, > + virDomainEventCallbackListPtr cbList, > + int callbackID) > +{ > + int i; > + > + for (i = 0 ; i < cbList->count ; i++) { > + if (cbList->callbacks[i]->deleted) > + continue; > + > + if (cbList->callbacks[i]->callbackID == callbackID && > + cbList->callbacks[i]->conn == conn) > + return cbList->callbacks[i]->qemuCallbackID; > + } > + > + return -1; > +} > + > int virDomainEventCallbackListCount(virDomainEventCallbackListPtr cbList) > { > int i; > @@ -521,6 +715,11 @@ void virDomainEventFree(virDomainEventPtr event) > VIR_FREE(event->data.diskChange.newSrcPath); > VIR_FREE(event->data.diskChange.devAlias); > break; > + > + case VIR_QEMU_DOMAIN_EVENT_ID_UNKNOWN: > + VIR_FREE(event->data.qemuUnknownEvent.eventName); > + VIR_FREE(event->data.qemuUnknownEvent.eventArgs); > + break; > } > > VIR_FREE(event->dom.name); > @@ -956,6 +1155,51 @@ virDomainEventPtr virDomainEventBlockJobNewFromDom(virDomainPtr dom, > path, type, status); > } > > +static virDomainEventPtr > +virDomainEventUnknownNew(int id, const char *name, unsigned char *uuid, > + const char *eventName, const char *eventArgs) > +{ > + virDomainEventPtr ev = > + virDomainEventNewInternal(VIR_QEMU_DOMAIN_EVENT_ID_UNKNOWN, > + id, name, uuid); > + if (ev) { > + if (!(ev->data.qemuUnknownEvent.eventName = strdup(eventName))) { > + virReportOOMError(); > + VIR_FREE(ev->dom.name); > + VIR_FREE(ev); > + return NULL; > + } > + if (eventArgs) { > + if (!(ev->data.qemuUnknownEvent.eventArgs = strdup(eventArgs))) { > + virReportOOMError(); > + VIR_FREE(ev->data.qemuUnknownEvent.eventName); > + VIR_FREE(ev->dom.name); > + VIR_FREE(ev); > + return NULL; > + } > + } > + } > + > + return ev; > +} > + > +virDomainEventPtr virDomainEventUnknownNewFromObj(virDomainObjPtr obj, > + const char *eventName, > + const char *eventArgs) > +{ > + > + return virDomainEventUnknownNew(obj->def->id, obj->def->name, > + obj->def->uuid, eventName, eventArgs); > +} > + > +virDomainEventPtr virDomainEventUnknownNewFromDom(virDomainPtr dom, > + const char *eventName, > + const char *eventArgs) > +{ > + return virDomainEventUnknownNew(dom->id, dom->name, dom->uuid, > + eventName, eventArgs); > +} > + > virDomainEventPtr virDomainEventControlErrorNewFromDom(virDomainPtr dom) > { > virDomainEventPtr ev = > @@ -1095,11 +1339,12 @@ virDomainEventQueuePush(virDomainEventQueuePtr evtQueue, > } > > > -void virDomainEventDispatchDefaultFunc(virConnectPtr conn, > - virDomainEventPtr event, > - virConnectDomainEventGenericCallback cb, > - void *cbopaque, > - void *opaque ATTRIBUTE_UNUSED) > +void > +virDomainEventDispatchDefaultFunc(virConnectPtr conn, > + virDomainEventPtr event, > + virConnectDomainEventGenericCallback cb, > + void *cbopaque, > + void *opaque ATTRIBUTE_UNUSED) > { > virDomainPtr dom = virGetDomain(conn, event->dom.name, event->dom.uuid); > if (!dom) > @@ -1180,6 +1425,13 @@ void virDomainEventDispatchDefaultFunc(virConnectPtr conn, > cbopaque); > break; > > + case VIR_QEMU_DOMAIN_EVENT_ID_UNKNOWN: > + ((virConnectDomainQemuEventCallback)cb)(conn, dom, > + event->data.qemuUnknownEvent.eventName, > + event->data.qemuUnknownEvent.eventArgs, > + cbopaque); > + break; > + > default: > VIR_WARN("Unexpected event ID %d", event->eventID); > break; > @@ -1189,8 +1441,9 @@ void virDomainEventDispatchDefaultFunc(virConnectPtr conn, > } > > > -static int virDomainEventDispatchMatchCallback(virDomainEventPtr event, > - virDomainEventCallbackPtr cb) > +static int > +virDomainEventDispatchMatchCallback(virDomainEventPtr event, > + virDomainEventCallbackPtr cb) > { > if (!cb) > return 0; > @@ -1198,7 +1451,12 @@ static int virDomainEventDispatchMatchCallback(virDomainEventPtr event, > return 0; > if (cb->eventID != event->eventID) > return 0; > - > + if (event->eventID == VIR_QEMU_DOMAIN_EVENT_ID_UNKNOWN) { > + if (event->data.qemuUnknownEvent.eventName == NULL || > + cb->eventName == NULL || > + STRNEQ(cb->eventName, event->data.qemuUnknownEvent.eventName)) > + return 0; > + } > if (cb->dom) { > /* Deliberately ignoring 'id' for matching, since that > * will cause problems when a domain switches between > @@ -1341,3 +1599,20 @@ virDomainEventStateDeregisterAny(virConnectPtr conn, > virDomainEventStateUnlock(state); > return ret; > } > +int > +virDomainQemuEventStateDeregister(virConnectPtr conn, > + virDomainEventStatePtr state, > + int callbackID) > +{ > + int ret; > + > + virDomainEventStateLock(state); > + if (state->isDispatching) > + ret = virDomainEventCallbackListMarkDeleteID(conn, > + state->callbacks, callbackID); > + else > + ret = virDomainEventCallbackListRemoveID(conn, > + state->callbacks, callbackID); > + virDomainEventStateUnlock(state); > + return ret; > +} > diff --git a/src/conf/domain_event.h b/src/conf/domain_event.h > index 3ba418e..f2fe847 100644 > --- a/src/conf/domain_event.h > +++ b/src/conf/domain_event.h > @@ -83,14 +83,23 @@ int virDomainEventCallbackListAddID(virConnectPtr conn, > virFreeCallback freecb) > ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(5); > > +int virDomainEventCallbackListAddName(virConnectPtr conn, > + virDomainEventCallbackListPtr cbList, > + virDomainPtr dom, > + const char* eventName, > + int eventID, > + virConnectDomainEventGenericCallback callback, > + void *opaque, > + virFreeCallback freecb) > + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(4) ATTRIBUTE_NONNULL(6); > > int virDomainEventCallbackListRemove(virConnectPtr conn, > virDomainEventCallbackListPtr cbList, > virConnectDomainEventCallback callback) > ATTRIBUTE_NONNULL(1); > -int virDomainEventCallbackListRemoveID(virConnectPtr conn, > - virDomainEventCallbackListPtr cbList, > - int callbackID) > +int virDomainQemuEventCallbackListRemoveID(virConnectPtr conn, > + virDomainEventCallbackListPtr cbList, > + int callbackID) > ATTRIBUTE_NONNULL(1); > int virDomainEventCallbackListRemoveConn(virConnectPtr conn, > virDomainEventCallbackListPtr cbList) > @@ -106,9 +115,14 @@ int virDomainEventCallbackListMarkDeleteID(virConnectPtr conn, > int callbackID) > ATTRIBUTE_NONNULL(1); > > - > int virDomainEventCallbackListPurgeMarked(virDomainEventCallbackListPtr cbList); > > +int virDomainEventCallbackListAddQemuCallbackID(virConnectPtr conn, > + virDomainEventCallbackListPtr cbList, > + int callbackID, > + int qemuCallbackID) > + ATTRIBUTE_NONNULL(1); > + > int virDomainEventCallbackListCount(virDomainEventCallbackListPtr cbList); > int virDomainEventCallbackListCountID(virConnectPtr conn, > virDomainEventCallbackListPtr cbList, > @@ -119,6 +133,21 @@ int virDomainEventCallbackListEventID(virConnectPtr conn, > int callbackID) > ATTRIBUTE_NONNULL(1); > > +int virDomainEventCallbackListCountName(virConnectPtr conn, > + virDomainEventCallbackListPtr cbList, > + const char *eventName) > + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3); > + > +int virDomainEventCallbackListEventQemuCallbackID(virConnectPtr conn, > + virDomainEventCallbackListPtr cbList, > + int callbackID) > + ATTRIBUTE_NONNULL(1); > + > +const char* virDomainEventCallbackListEventName(virConnectPtr conn, > + virDomainEventCallbackListPtr cbList, > + int callbackID) > + ATTRIBUTE_NONNULL(1); > + > virDomainEventQueuePtr virDomainEventQueueNew(void); > > virDomainEventPtr virDomainEventNew(int id, const char *name, const unsigned char *uuid, int type, int detail); > @@ -190,6 +219,13 @@ virDomainEventPtr virDomainEventDiskChangeNewFromDom(virDomainPtr dom, > const char *devAlias, > int reason); > > +virDomainEventPtr virDomainEventUnknownNewFromObj(virDomainObjPtr obj, > + const char *eventName, > + const char *eventArgs); > +virDomainEventPtr virDomainEventUnknownNewFromDom(virDomainPtr dom, > + const char *eventName, > + const char *eventArgs); > + > int virDomainEventQueuePush(virDomainEventQueuePtr evtQueue, > virDomainEventPtr event); > > @@ -246,5 +282,9 @@ virDomainEventStateDeregisterAny(virConnectPtr conn, > virDomainEventStatePtr state, > int callbackID) > ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); > - > +int > +virDomainQemuEventStateDeregister(virConnectPtr conn, > + virDomainEventStatePtr state, > + int callbackID) > + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); > #endif > diff --git a/src/driver.h b/src/driver.h > index 941ff51..51164a9 100644 > --- a/src/driver.h > +++ b/src/driver.h > @@ -635,6 +635,18 @@ typedef virDomainPtr > unsigned int flags); > > typedef int > + (*virDrvDomainQemuEventRegister)(virConnectPtr conn, > + virDomainPtr dom, /* option to filter */ > + const char *eventName, /* JSON event name */ > + virConnectDomainEventGenericCallback cb, > + void *opaque, > + virFreeCallback freecb); > + > +typedef int > + (*virDrvDomainQemuEventDeregister)(virConnectPtr conn, > + int callbackID); > + > +typedef int > (*virDrvDomainOpenConsole)(virDomainPtr dom, > const char *dev_name, > virStreamPtr st, > @@ -915,6 +927,8 @@ struct _virDriver { > virDrvDomainSnapshotDelete domainSnapshotDelete; > virDrvDomainQemuMonitorCommand qemuDomainMonitorCommand; > virDrvDomainQemuAttach qemuDomainAttach; > + virDrvDomainQemuEventRegister qemuDomainQemuEventRegister; > + virDrvDomainQemuEventDeregister qemuDomainQemuEventDeregister; > virDrvDomainOpenConsole domainOpenConsole; > virDrvDomainOpenGraphics domainOpenGraphics; > virDrvDomainInjectNMI domainInjectNMI; > diff --git a/src/libvirt-qemu.c b/src/libvirt-qemu.c > index 248cc33..7722b7b 100644 > --- a/src/libvirt-qemu.c > +++ b/src/libvirt-qemu.c > @@ -36,6 +36,77 @@ > virReportErrorHelper(VIR_FROM_DOM, error, NULL, __FUNCTION__, \ > __LINE__, info) > > +/* Helper macros to implement VIR_DOMAIN_DEBUG using just C99. This > + * assumes you pass fewer than 15 arguments to VIR_DOMAIN_DEBUG, but > + * can easily be expanded if needed. > + * > + * Note that gcc provides extensions of "define a(b...) b" or > + * "define a(b,...) b,##__VA_ARGS__" as a means of eliding a comma > + * when no var-args are present, but we don't want to require gcc. > + */ > +#define VIR_ARG15(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, ...) _15 > +#define VIR_HAS_COMMA(...) VIR_ARG15(__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0) > + > +/* Form the name VIR_DOMAIN_DEBUG_[01], then call that macro, > + * according to how many arguments are present. Two-phase due to > + * macro expansion rules. */ > +#define VIR_DOMAIN_DEBUG_EXPAND(a, b, ...) \ > + VIR_DOMAIN_DEBUG_PASTE(a, b, __VA_ARGS__) > +#define VIR_DOMAIN_DEBUG_PASTE(a, b, ...) \ > + a##b(__VA_ARGS__) > + > +/* Internal use only, when VIR_DOMAIN_DEBUG has one argument. */ > +#define VIR_DOMAIN_DEBUG_0(dom) \ > + VIR_DOMAIN_DEBUG_2(dom, "%s", "") > + > +/* Internal use only, when VIR_DOMAIN_DEBUG has three or more arguments. */ > +#define VIR_DOMAIN_DEBUG_1(dom, fmt, ...) \ > + VIR_DOMAIN_DEBUG_2(dom, ", " fmt, __VA_ARGS__) > + > +/* Internal use only, with final format. */ > +#define VIR_DOMAIN_DEBUG_2(dom, fmt, ...) \ > + do { \ > + char _uuidstr[VIR_UUID_STRING_BUFLEN]; \ > + const char *_domname = NULL; \ > + \ > + if (!VIR_IS_DOMAIN(dom)) { \ > + memset(_uuidstr, 0, sizeof(_uuidstr)); \ > + } else { \ > + virUUIDFormat((dom)->uuid, _uuidstr); \ > + _domname = (dom)->name; \ > + } \ > + \ > + VIR_DEBUG("dom=%p, (VM: name=%s, uuid=%s)" fmt, \ > + dom, NULLSTR(_domname), _uuidstr, __VA_ARGS__); \ > + } while (0) > + > +/** > + * VIR_DOMAIN_DEBUG: > + * @dom: domain > + * @fmt: optional format for additional information > + * @...: optional arguments corresponding to @fmt. > + */ > +#define VIR_DOMAIN_DEBUG(...) \ > + VIR_DOMAIN_DEBUG_EXPAND(VIR_DOMAIN_DEBUG_, \ > + VIR_HAS_COMMA(__VA_ARGS__), \ > + __VA_ARGS__) > + > +/** > + * VIR_UUID_DEBUG: > + * @conn: connection > + * @uuid: possibly null UUID array > + */ > +#define VIR_UUID_DEBUG(conn, uuid) \ > + do { \ > + if (uuid) { \ > + char _uuidstr[VIR_UUID_STRING_BUFLEN]; \ > + virUUIDFormat(uuid, _uuidstr); \ > + VIR_DEBUG("conn=%p, uuid=%s", conn, _uuidstr); \ > + } else { \ > + VIR_DEBUG("conn=%p, uuid=(null)", conn); \ > + } \ > + } while (0) > + > /** > * virDomainQemuMonitorCommand: > * @domain: a domain object > @@ -178,3 +249,121 @@ error: > virDispatchError(conn); > return NULL; > } > + > +/** > + * virConnectDomainQemuEventRegister: > + * @conn: pointer to the connection > + * @dom: pointer to the domain > + * @eventName: the event Name to receive > + * @cb: callback to the function handling domain events > + * @opaque: opaque data to pass on to the callback > + * @freecb: optional function to deallocate opaque when not used anymore > + * > + * Adds a callback to receive notifications of arbitrary qemu domain events > + * occurring on a domain. > + * > + * If dom is NULL, then events will be monitored for any domain. If dom > + * is non-NULL, then only the specific domain will be monitored > + * > + * Most types of event have a callback providing a custom set of parameters > + * for the event. When registering an event, it is thus neccessary to use > + * the VIR_DOMAIN_EVENT_CALLBACK() macro to cast the supplied function pointer > + * to match the signature of this method. > + * > + * The virDomainPtr object handle passed into the callback upon delivery > + * of an event is only valid for the duration of execution of the callback. > + * If the callback wishes to keep the domain object after the callback returns, > + * it shall take a reference to it, by calling virDomainRef. > + * The reference can be released once the object is no longer required > + * by calling virDomainFree. > + * > + * The return value from this method is a positive integer identifier > + * for the callback. To unregister a callback, this callback ID should > + * be passed to the virConnectDomainQemuEventDeregister method > + * > + * Returns a callback identifier on success, -1 on failure > + */ > +int > +virConnectDomainQemuEventRegister(virConnectPtr conn, > + virDomainPtr dom, /* option to filter */ > + const char *eventName, /* JSON event name */ > + virConnectDomainQemuEventCallback cb, > + void *opaque, > + virFreeCallback freecb) > +{ > + VIR_DOMAIN_DEBUG(dom, "conn=%p, eventName=%s, cb=%p, opaque=%p, freecb=%p", > + conn, eventName, cb, opaque, freecb); > + > + virResetLastError(); > + > + if (!VIR_IS_CONNECT(conn)) { > + virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__); > + virDispatchError(NULL); > + return -1; > + } > + if (dom != NULL && > + !(VIR_IS_CONNECTED_DOMAIN(dom) && dom->conn == conn)) { > + virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__); > + virDispatchError(conn); > + return -1; > + } > + if (eventName == NULL || cb == NULL) { > + virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); > + goto error; > + } > + > + if ((conn->driver) && (conn->driver->qemuDomainQemuEventRegister)) { > + int ret; > + ret = conn->driver->qemuDomainQemuEventRegister(conn, dom, eventName, cb, opaque, freecb); > + if (ret < 0) > + goto error; > + return ret; > + } > + > + virLibConnError(conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); > +error: > + virDispatchError(conn); > + return -1; > +} > + > +/** > + * virConnectDomainQemuEventDeregister: > + * @conn: pointer to the connection > + * @callbackID: the callback identifier > + * > + * Removes an event callback. The callbackID parameter should be the > + * vaule obtained from a previous virConnectDomainQemuEventDeregister method. > + * > + * Returns 0 on success, -1 on failure > + */ > +int > +virConnectDomainQemuEventDeregister(virConnectPtr conn, > + int callbackID) > +{ > + > + VIR_DEBUG("conn=%p, callbackID=%d", conn, callbackID); > + > + virResetLastError(); > + > + if (!VIR_IS_CONNECT(conn)) { > + virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__); > + virDispatchError(NULL); > + return -1; > + } > + if (callbackID < 0) { > + virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); > + goto error; > + } > + if ((conn->driver) && (conn->driver->qemuDomainQemuEventDeregister)) { > + int ret; > + ret = conn->driver->qemuDomainQemuEventDeregister(conn, callbackID); > + if (ret < 0) > + goto error; > + return ret; > + } > + > + virLibConnError(conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); > +error: > + virDispatchError(conn); > + return -1; > +} > diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms > index 48ffdf2..75e544a 100644 > --- a/src/libvirt_private.syms > +++ b/src/libvirt_private.syms > @@ -471,11 +471,16 @@ virDomainWatchdogModelTypeToString; > # domain_event.h > virDomainEventBlockJobNewFromObj; > virDomainEventBlockJobNewFromDom; > +virDomainEventUnknownNewFromObj; > +virDomainEventunknownNewFromDom; > virDomainEventCallbackListAdd; > virDomainEventCallbackListAddID; > +virDomainEventCallbackListAddName; > virDomainEventCallbackListCount; > virDomainEventCallbackListCountID; > +virDomainEventCallbackListCountName; > virDomainEventCallbackListEventID; > +virDomainEventCallbackListEventName; > virDomainEventCallbackListFree; > virDomainEventCallbackListMarkDelete; > virDomainEventCallbackListMarkDeleteID; > @@ -512,6 +517,7 @@ virDomainEventRebootNewFromDom; > virDomainEventRebootNewFromObj; > virDomainEventStateDeregister; > virDomainEventStateDeregisterAny; > +virDomainQemuEventStateDeregister; > virDomainEventStateFlush; > virDomainEventStateFree; > virDomainEventStateNew; > diff --git a/src/libvirt_qemu.syms b/src/libvirt_qemu.syms > index 8447730..a17e387 100644 > --- a/src/libvirt_qemu.syms > +++ b/src/libvirt_qemu.syms > @@ -19,3 +19,8 @@ LIBVIRT_QEMU_0.9.4 { > global: > virDomainQemuAttach; > } LIBVIRT_QEMU_0.8.3; > +LIBVIRT_QEMU_0.9.9 { > + global: > + virConnectDomainQemuEventRegister; > + virConnectDomainQemuEventDeregister; > +} LIBVIRT_QEMU_0.9.4; -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list