[libvirt] [PATCH 1/4] add a qemu-specific event register API, to passthough the new events come from qemu
ShaoHe Feng
shaohef at linux.vnet.ibm.com
Fri Dec 16 17:39:20 UTC 2011
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 at linux.vnet.ibm.com wrote:
> From: ShaoHe Feng <shaohef at 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 at 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;
More information about the libvir-list
mailing list