I want to improve this patch.
Is it the right place that I add an event name list as an attribute of
_virDomainEventState.
if the virConnectDomainQemuEventRegister() registers an eventName, then
I add the eventName to this name list.
and if virConnectDomainQemuEventDeregister() deregisters an eventName,
then I delete the eventName from this name list.
Different connects may register the same eventName. Yes, I should mark
the times of the eventName registered.
when an qemu monitor receives an event, so it can traversal this event
name list. if it can find the event name list, then it can add to the
qemu_driver event queue.
should I also add the dom to this event name list to filter the event,
for the dom argument of virConnectDomainQemuEventRegister may not be NULL.
And should I limit the times of the event name registered. for user may
register an event name that does not exist in qemu at all.
there is the two API, that we have discussed before.
virConnectDomainQemuEventRegister(virConnectPtr conn,
virDomainPtr dom, /* option to filter */
const char *eventName, /* JSON event name */
virConnectDomainQemuEventCallback cb,
void *opaque,
virFreeCallback freecb);
virConnectDomainQemuEventDeregister(virConnectPtr conn,
int callbackID);
, ShaoHe Feng wrote:
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(a)linux.vnet.ibm.com wrote:
> From: ShaoHe Feng <shaohef(a)linux.vnet.ibm.com>
>
> 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(a)linux.vnet.ibm.com>
> ---
> 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;