[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