[libvirt] add a qemu-specific event register API, to passthough the new events come from qemu
ShaoHe Feng
shaohef at linux.vnet.ibm.com
Tue Dec 13 06:13:36 UTC 2011
there are are some thing wrong with the formate of my last mail, so I
resent it again.
and In this patch, I add the the register callback
_dispatchDomainEventUnknown Callback function as an attribute of the
virConnect class in libvirt.py, not in the libvirt_qemu.py.
should I make it as an attribute of an new subclass that inherits from
virConnect class in libvirt_qemu.py?
now, there will come an "RESUME" events when qemu domains are started.
The attached 0002-for-testing-the-new-qemu-specific-regiater-API.patch
is used to start a qemu domain and to catch this event.
# ./tools/virsh -c qemu:///system
virsh# register-event RESUME
virsh# start domain
the attached python test case, is used to catch RESUME events, in order
to test the python register API.
, shaohef at linux.vnet.ibm.com wrote:
> From: Shao He 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.
> In order to test this patch, see the attached python test case. When domains are started, it will be able to catch RESUME events.
>
> Signed-off-by: Shao He Feng <shaohef at linux.vnet.ibm.com>
> ---
> daemon/libvirtd.h | 12 +-
> daemon/remote.c | 195 ++++++++++++++++++-
> include/libvirt/libvirt-qemu.h | 11 +
> include/libvirt/libvirt.h.in | 17 ++-
> python/generator.py | 26 ++-
> python/libvirt-override-virConnect.py | 14 ++-
> python/libvirt-qemu-override.c | 140 +++++++++++++
> python/libvirt-qemu-override.py | 41 ++++
> src/conf/domain_event.c | 347 +++++++++++++++++++++++++++++++--
> src/conf/domain_event.h | 49 +++++-
> src/driver.h | 14 ++
> src/libvirt-qemu.c | 190 ++++++++++++++++++
> src/libvirt_private.syms | 6 +
> src/libvirt_qemu.syms | 5 +
> src/qemu/qemu_driver.c | 42 ++++
> src/qemu/qemu_monitor.c | 10 +
> src/qemu/qemu_monitor.h | 8 +
> src/qemu/qemu_monitor_json.c | 36 ++++
> src/qemu/qemu_process.c | 24 +++
> src/remote/qemu_protocol.x | 33 +++-
> src/remote/remote_driver.c | 153 ++++++++++++++-
> src/remote/remote_protocol.x | 9 +-
> src/remote_protocol-structs | 5 +
> 23 files changed, 1353 insertions(+), 34 deletions(-)
> mode change 100644 => 100755 python/libvirt-override-virConnect.py
> mode change 100644 => 100755 python/libvirt-override-virStream.py
> mode change 100644 => 100755 python/libvirt-override.py
> create mode 100644 python/libvirt-qemu-override.py
>
> diff --git a/daemon/libvirtd.h b/daemon/libvirtd.h
> index c8d3ca2..e3e1c40 100644
> --- a/daemon/libvirtd.h
> +++ b/daemon/libvirtd.h
> @@ -38,6 +38,16 @@
> # endif
> # include "virnetserverprogram.h"
>
> +/* limit the number unknow event of an conncet can register */
> +#define VIR_DOMAIN_EVENT_NAME_LAST 512
> +struct domainEventNameCallBackStatus {
> + /* counter the number of unknow event registered */
> + int eventNameCallBackCounter;
> + /* Stores the ID of the unknow event registered */
> + int eventNameCallback[VIR_DOMAIN_EVENT_NAME_LAST];
> +};
> +typedef struct domainEventNameCallBackStatus domainEventNameCallBackStatus;
> +
> typedef struct daemonClientStream daemonClientStream;
> typedef daemonClientStream *daemonClientStreamPtr;
> typedef struct daemonClientPrivate daemonClientPrivate;
> @@ -49,7 +59,7 @@ struct daemonClientPrivate {
> virMutex lock;
>
> int domainEventCallbackID[VIR_DOMAIN_EVENT_ID_LAST];
> -
> + domainEventNameCallBackStatus domainEventNameCallBack;
> # if HAVE_SASL
> virNetSASLSessionPtr sasl;
> # endif
> diff --git a/daemon/remote.c b/daemon/remote.c
> index e1d208c..bc8455d 100644
> --- a/daemon/remote.c
> +++ b/daemon/remote.c
> @@ -421,6 +421,54 @@ mem_error:
> return -1;
> }
>
> +static int remoteRelayDomainEventUnknown(virConnectPtr conn ATTRIBUTE_UNUSED,
> + virDomainPtr dom,
> + const char *eventName, /* The JSON event name */
> + const char *eventArgs, /* The JSON string of args */
> + void *opaque)
> +{
> + virNetServerClientPtr client = opaque;
> + remote_domain_event_default_event_msg data;
> +
> + if (!client)
> + return -1;
> +
> + VIR_DEBUG("Relaying domain: %s id: %d, unknown event: %s arguments: %s",
> + dom->name, dom->id, eventName, eventArgs);
> +
> + /* build return data */
> + memset(&data, 0, sizeof data);
> + if (eventName == NULL)
> + goto mem_error3;
> + data.eventName = (char *)strdup(eventName);
> + if (data.eventName == NULL)
> + goto mem_error2;
> + if (eventArgs != NULL) {
> + data.eventArgs = (char *)strdup(eventArgs);
> + if (data.eventArgs == NULL)
> + goto mem_error1;
> + }
> + else {
> + data.eventArgs = (char *)strdup("NULL");
> + if (data.eventArgs == NULL)
> + goto mem_error1;
> + }
> + make_nonnull_domain(&data.dom, dom);
> + remoteDispatchDomainEventSend(client, remoteProgram,
> + REMOTE_PROC_QEMU_DOMAIN_EVENT_UNKNOWN_EVENT,
> + (xdrproc_t)xdr_remote_domain_event_default_event_msg, &data);
> +
> + return 0;
> +
> +mem_error1:
> + VIR_FREE(data.eventArgs);
> +mem_error2:
> + VIR_FREE(data.eventName);
> +mem_error3:
> + virReportOOMError();
> + return -1;
> +}
> +
>
> static int remoteRelayDomainEventControlError(virConnectPtr conn ATTRIBUTE_UNUSED,
> virDomainPtr dom,
> @@ -509,6 +557,7 @@ static virConnectDomainEventGenericCallback domainEventCallbacks[] = {
> VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventControlError),
> VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventBlockJob),
> VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventDiskChange),
> + VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventUnknown),
> };
>
> verify(ARRAY_CARDINALITY(domainEventCallbacks) == VIR_DOMAIN_EVENT_ID_LAST);
> @@ -526,10 +575,21 @@ static void remoteClientFreeFunc(void *data)
>
> /* Deregister event delivery callback */
> if (priv->conn) {
> - int i;
> + int i, j;
>
> for (i = 0 ; i < VIR_DOMAIN_EVENT_ID_LAST ; i++) {
> - if (priv->domainEventCallbackID[i] != -1) {
> + if (i == VIR_QEMU_DOMAIN_EVENT_ID_UNKNOWN && priv->domainEventCallbackID[i] != -1) {
> + for (j = 0 ; j < VIR_DOMAIN_EVENT_NAME_LAST ; j++){
> + if (priv->domainEventNameCallBack.eventNameCallback[j] != -1) {
> + VIR_DEBUG("Deregistering to relay remote events %d", i);
> + virConnectDomainQemuEventDeregister(priv->conn,
> + priv->domainEventNameCallBack.eventNameCallback[j]);
> + }
> + priv->domainEventNameCallBack.eventNameCallback[j] == -1;
> + }
> + priv->domainEventNameCallBack.eventNameCallBackCounter = 0;
> + }
> + else if (priv->domainEventCallbackID[i] != -1) {
> VIR_DEBUG("Deregistering to relay remote events %d", i);
> virConnectDomainEventDeregisterAny(priv->conn,
> priv->domainEventCallbackID[i]);
> @@ -572,6 +632,10 @@ int remoteClientInitHook(virNetServerPtr srv ATTRIBUTE_UNUSED,
> for (i = 0 ; i < VIR_DOMAIN_EVENT_ID_LAST ; i++)
> priv->domainEventCallbackID[i] = -1;
>
> + priv->domainEventNameCallBack.eventNameCallBackCounter = 0;
> + for (i = 0 ; i < VIR_DOMAIN_EVENT_NAME_LAST ; i++)
> + priv->domainEventNameCallBack.eventNameCallback[i] = -1;
> +
> virNetServerClientSetPrivateData(client, priv,
> remoteClientFreeFunc);
> virNetServerClientSetCloseHook(client, remoteClientCloseFunc);
> @@ -2991,6 +3055,133 @@ cleanup:
> }
>
> static int
> +qemuDispatchDomainEventsRegister(virNetServerPtr server ATTRIBUTE_UNUSED,
> + virNetServerClientPtr client ATTRIBUTE_UNUSED,
> + virNetMessagePtr msg ATTRIBUTE_UNUSED,
> + virNetMessageErrorPtr rerr,
> + qemu_domain_events_register_args *args,
> + qemu_domain_events_register_ret *ret ATTRIBUTE_UNUSED)
> +{
> + int callbackID = -1;
> + int rv = -1;
> + int eventIdx = 0;
> + struct daemonClientPrivate *priv =
> + virNetServerClientGetPrivateData(client);
> + if (!priv->conn) {
> + virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
> + goto cleanup;
> + }
> +
> + virMutexLock(&priv->lock);
> +
> + if (args->eventName == NULL) {
> + virNetError(VIR_ERR_INTERNAL_ERROR, _("event Name is NULL"));
> + goto cleanup;
> + }
> + if (priv->domainEventNameCallBack.eventNameCallBackCounter >= VIR_DOMAIN_EVENT_NAME_LAST) {
> + virNetError(VIR_ERR_INTERNAL_ERROR,
> + _("domain event %s is not registered, the register number has exceeded limit number %d"),
> + args->eventName,
> + VIR_DOMAIN_EVENT_NAME_LAST);
> + goto cleanup;
> + }
> +
> + if ((callbackID = virConnectDomainQemuEventRegister(priv->conn,
> + NULL,
> + args->eventName,
> + (virConnectDomainQemuEventCallback)remoteRelayDomainEventUnknown,
> + client,
> + NULL)) < 0)
> + goto cleanup;
> +
> + for (eventIdx = 0 ; eventIdx < VIR_DOMAIN_EVENT_NAME_LAST ; eventIdx++) {
> + if (priv->domainEventNameCallBack.eventNameCallback[eventIdx] == -1) {
> + priv->domainEventNameCallBack.eventNameCallback[eventIdx] = callbackID;
> + priv->domainEventNameCallBack.eventNameCallBackCounter++;
> + ret->callbackID = eventIdx;
> + break;
> + }
> + }
> + priv->domainEventCallbackID[VIR_QEMU_DOMAIN_EVENT_ID_UNKNOWN] = callbackID;
> +
> + rv = 0;
> +
> +cleanup:
> + if (rv < 0)
> + virNetMessageSaveError(rerr);
> + virMutexUnlock(&priv->lock);
> + return rv;
> +}
> +
> +static int
> +remoteDispatchQemuDomainEventUnknownEvent(virNetServerPtr server,
> + virNetServerClientPtr client,
> + virNetMessagePtr msg,
> + virNetMessageErrorPtr rerr)
> +{
> + int rv = -1;
> + return rv;
> +}
> +
> +static int
> +qemuDispatchDomainEventsUnknownEvent(virNetServerPtr server,
> + virNetServerClientPtr client,
> + virNetMessagePtr msg,
> + virNetMessageErrorPtr rerr,
> + qemu_domain_events_unknown_event_args *args,
> + qemu_domain_events_unknown_event_ret *ret)
> +{
> + int rv = -1;
> + return rv;
> +}
> +
> +static int
> +qemuDispatchDomainEventsDeregister(virNetServerPtr server ATTRIBUTE_UNUSED,
> + virNetServerClientPtr client ATTRIBUTE_UNUSED,
> + virNetMessagePtr msg ATTRIBUTE_UNUSED,
> + virNetMessageErrorPtr rerr,
> + qemu_domain_events_deregister_args *args,
> + qemu_domain_events_deregister_ret *ret ATTRIBUTE_UNUSED)
> +{
> + int callbackID = -1;
> + int rv = -1;
> + int eventIdx = args->callbackID;
> + struct daemonClientPrivate *priv =
> + virNetServerClientGetPrivateData(client);
> +
> + if (!priv->conn) {
> + virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
> + goto cleanup;
> + }
> +
> + virMutexLock(&priv->lock);
> +
> + if (eventIdx >= VIR_DOMAIN_EVENT_NAME_LAST ||
> + (callbackID = priv->domainEventNameCallBack.eventNameCallback[eventIdx]) < 0) {
> +
> + virNetError(VIR_ERR_INTERNAL_ERROR, _("callbakcID %d is not register"), eventIdx);
> + goto cleanup;
> + }
> +
> + if (virConnectDomainQemuEventDeregister(priv->conn, callbackID) < 0)
> + goto cleanup;
> + ret->cb_deregistered = callbackID;
> +
> + priv->domainEventNameCallBack.eventNameCallback[eventIdx] = -1;
> + priv->domainEventNameCallBack.eventNameCallBackCounter--;
> + if (priv->domainEventNameCallBack.eventNameCallBackCounter == 0)
> + priv->domainEventCallbackID[VIR_QEMU_DOMAIN_EVENT_ID_UNKNOWN] = -1;
> +
> + rv = 0;
> +
> +cleanup:
> + if (rv < 0)
> + virNetMessageSaveError(rerr);
> + virMutexUnlock(&priv->lock);
> + return rv;
> +}
> +
> +static int
> qemuDispatchMonitorCommand(virNetServerPtr server ATTRIBUTE_UNUSED,
> virNetServerClientPtr client ATTRIBUTE_UNUSED,
> virNetMessagePtr msg ATTRIBUTE_UNUSED,
> diff --git a/include/libvirt/libvirt-qemu.h b/include/libvirt/libvirt-qemu.h
> index 7f12e4f..74efe79 100644
> --- a/include/libvirt/libvirt-qemu.h
> +++ b/include/libvirt/libvirt-qemu.h
> @@ -32,6 +32,17 @@ virDomainPtr virDomainQemuAttach(virConnectPtr domain,
> unsigned int pid,
> unsigned int flags);
>
> +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..99e1c5d 100644
> --- a/include/libvirt/libvirt.h.in
> +++ b/include/libvirt/libvirt.h.in
> @@ -3207,7 +3207,21 @@ typedef void (*virConnectDomainEventBlockJobCallback)(virConnectPtr conn,
> int type,
> int status,
> void *opaque);
> -
> +/**
> + * 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);
> /**
> * virConnectDomainEventDiskChangeReason:
> *
> @@ -3263,6 +3277,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/python/generator.py b/python/generator.py
> index 88c52b9..3d13622 100755
> --- a/python/generator.py
> +++ b/python/generator.py
> @@ -234,6 +234,7 @@ skipped_types = {
> # 'int *': "usually a return type",
> 'virConnectDomainEventCallback': "No function types in python",
> 'virConnectDomainEventGenericCallback': "No function types in python",
> + 'virConnectDomainQemuEventCallback': "No function types in python",
> 'virConnectDomainEventRTCChangeCallback': "No function types in python",
> 'virConnectDomainEventWatchdogCallback': "No function types in python",
> 'virConnectDomainEventIOErrorCallback': "No function types in python",
> @@ -476,6 +477,8 @@ skip_function = (
>
> qemu_skip_function = (
> #"virDomainQemuAttach",
> + 'virConnectDomainQemuEventRegister', # overridden in libvirt_qemu_override.py
> + 'virConnectDomainQemuEventDeregister', # overridden in libvirt_qemu_override.py
> )
>
> # Generate C code, but skip python impl
> @@ -1656,17 +1659,18 @@ def qemuBuildWrappers(module):
> if extra != None:
> extra.close()
>
> - fd.write("try:\n")
> - fd.write(" import libvirtmod_qemu\n")
> - fd.write("except ImportError, lib_e:\n")
> - fd.write(" try:\n")
> - fd.write(" import cygvirtmod_qemu as libvirtmod_qemu\n")
> - fd.write(" except ImportError, cyg_e:\n")
> - fd.write(" if str(cyg_e).count(\"No module named\"):\n")
> - fd.write(" raise lib_e\n\n")
> -
> - fd.write("import libvirt\n\n");
> - fd.write("#\n# Functions from module %s\n#\n\n" % module)
> + if extra == None:
> + fd.write("try:\n")
> + fd.write(" import libvirtmod_qemu\n")
> + fd.write("except ImportError, lib_e:\n")
> + fd.write(" try:\n")
> + fd.write(" import cygvirtmod_qemu as libvirtmod_qemu\n")
> + fd.write(" except ImportError, cyg_e:\n")
> + fd.write(" if str(cyg_e).count(\"No module named\"):\n")
> + fd.write(" raise lib_e\n\n")
> +
> + fd.write("import libvirt\n\n");
> + fd.write("#\n# Functions from module %s\n#\n\n" % module)
> #
> # Generate functions directly, no classes
> #
> diff --git a/python/libvirt-override-virConnect.py b/python/libvirt-override-virConnect.py
> old mode 100644
> new mode 100755
> index b908b32..ce34bcf
> --- a/python/libvirt-override-virConnect.py
> +++ b/python/libvirt-override-virConnect.py
> @@ -134,8 +134,20 @@
> cb(self, virDomain(self, _obj=dom), oldSrcPath, newSrcPath, devAlias, reason, opaque)
> return 0;
>
> + def _dispatchDomainEventUnknownCallback(self, dom, eventName, eventArgs, cbData):
> + """Dispatches events to python user unknown event callbacks
> + """
> + try:
> + cb = cbData["cb"]
> + opaque = cbData["opaque"]
> +
> + cb(self, virDomain(self, _obj=dom), eventName, eventArgs, opaque)
> + return 0
> + except AttributeError:
> + pass
> +
> def domainEventDeregisterAny(self, callbackID):
> - """Removes a Domain Event Callback. De-registering for a
> + """Removes a QEMU Domain Event Callback. De-registering for a
> domain callback will disable delivery of this event type """
> try:
> ret = libvirtmod.virConnectDomainEventDeregisterAny(self._o, callbackID)
> diff --git a/python/libvirt-override-virStream.py b/python/libvirt-override-virStream.py
> old mode 100644
> new mode 100755
> diff --git a/python/libvirt-override.py b/python/libvirt-override.py
> old mode 100644
> new mode 100755
> diff --git a/python/libvirt-qemu-override.c b/python/libvirt-qemu-override.c
> index 485c809..f5a8c09 100644
> --- a/python/libvirt-qemu-override.c
> +++ b/python/libvirt-qemu-override.c
> @@ -18,6 +18,7 @@
>
> #include <Python.h>
> #include "libvirt/libvirt-qemu.h"
> +#include "libvirt/libvirt.h"
> #include "libvirt/virterror.h"
> #include "typewrappers.h"
> #include "libvirt-qemu.h"
> @@ -96,6 +97,143 @@ libvirt_qemu_virDomainQemuMonitorCommand(PyObject *self ATTRIBUTE_UNUSED,
> return(py_retval);
> }
>
> +static void
> +libvirt_qemu_virConnectDomainEventFreeFunc(void *opaque)
> +{
> + PyObject *pyobj_conn = (PyObject*)opaque;
> + LIBVIRT_ENSURE_THREAD_STATE;
> + Py_DECREF(pyobj_conn);
> + LIBVIRT_RELEASE_THREAD_STATE;
> +}
> +
> +static int
> +libvirt_qemu_virConnectDomainEventUnknownCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
> + virDomainPtr dom,
> + const char *eventName,
> + const char *eventArgs,
> + void *opaque)
> +{
> + PyObject *pyobj_cbData = (PyObject*)opaque;
> + PyObject *pyobj_dom;
> + PyObject *pyobj_ret;
> + PyObject *pyobj_conn;
> + PyObject *dictKey;
> + int ret = -1;
> +
> + LIBVIRT_ENSURE_THREAD_STATE;
> +
> + /* Create a python instance of this virDomainPtr */
> + virDomainRef(dom);
> + pyobj_dom = libvirt_virDomainPtrWrap(dom);
> + Py_INCREF(pyobj_cbData);
> +
> + dictKey = libvirt_constcharPtrWrap("conn");
> + pyobj_conn = PyDict_GetItem(pyobj_cbData, dictKey);
> + Py_DECREF(dictKey);
> +
> + /* Call the Callback Dispatcher */
> + pyobj_ret = PyObject_CallMethod(pyobj_conn,
> + (char*)"_dispatchDomainEventUnknownCallback",
> + (char*)"OssO",
> + pyobj_dom, eventName, eventArgs, pyobj_cbData);
> +
> + Py_DECREF(pyobj_cbData);
> + Py_DECREF(pyobj_dom);
> +
> + if (!pyobj_ret) {
> +#if DEBUG_ERROR
> + printf("%s - ret:%p\n", __FUNCTION__, pyobj_ret);
> +#endif
> + PyErr_Print();
> + } else {
> + Py_DECREF(pyobj_ret);
> + ret = 0;
> + }
> +
> + LIBVIRT_RELEASE_THREAD_STATE;
> + return ret;
> +}
> +
> +static PyObject *
> +libvirt_qemu_virConnectDomainQemuEventRegister(ATTRIBUTE_UNUSED PyObject * self,
> + PyObject * args)
> +{
> + PyObject *py_retval; /* return value */
> + PyObject *pyobj_conn; /* virConnectPtr */
> + PyObject *pyobj_dom;
> + PyObject *pyobj_cbData; /* hash of callback data */
> + char *eventName;
> + virConnectPtr conn;
> + int ret = 0;
> +
> + virConnectDomainQemuEventCallback cb = NULL;
> + virDomainPtr dom;
> +
> + if (!PyArg_ParseTuple
> + (args, (char *) "OOsO:virConnectDomainQemuEventRegister",
> + &pyobj_conn, &pyobj_dom, &eventName, &pyobj_cbData)) {
> + DEBUG("%s failed parsing tuple\n", __FUNCTION__);
> + return VIR_PY_INT_FAIL;
> + }
> +
> + if (eventName == NULL)
> + return VIR_PY_INT_FAIL;
> +
> + DEBUG("libvirt_qemu_virConnectDomainQemuEventRegister(%p %p %s %p) called\n",
> + pyobj_conn, pyobj_dom, eventName, pyobj_cbData);
> + conn = PyvirConnect_Get(pyobj_conn);
> + if (pyobj_dom == Py_None)
> + dom = NULL;
> + else
> + dom = PyvirDomain_Get(pyobj_dom);
> +
> + cb = (virConnectDomainQemuEventCallback)(libvirt_qemu_virConnectDomainEventUnknownCallback);
> + if (!cb) {
> + return VIR_PY_INT_FAIL;
> + }
> +
> + Py_INCREF(pyobj_cbData);
> +
> + LIBVIRT_BEGIN_ALLOW_THREADS;
> + ret = virConnectDomainQemuEventRegister(conn, dom, eventName,
> + cb, pyobj_cbData,
> + libvirt_qemu_virConnectDomainEventFreeFunc);
> + LIBVIRT_END_ALLOW_THREADS;
> + if (ret < 0) {
> + Py_DECREF(pyobj_cbData);
> + }
> + py_retval = libvirt_intWrap(ret);
> + return (py_retval);
> +}
> +
> +static PyObject *
> +libvirt_qemu_virConnectDomainQemuEventDeregister(ATTRIBUTE_UNUSED PyObject * self,
> + PyObject * args)
> +{
> + PyObject *py_retval;
> + PyObject *pyobj_conn;
> + int callbackID;
> + virConnectPtr conn;
> + int ret = 0;
> +
> + if (!PyArg_ParseTuple
> + (args, (char *) "Oi:virConnectDomainQemuEventDeregister",
> + &pyobj_conn, &callbackID))
> + return (NULL);
> +
> + DEBUG("libvirt_qemu_virConnectDomainQemuEventDeregister(%p) called\n", pyobj_conn);
> +
> + conn = (virConnectPtr) PyvirConnect_Get(pyobj_conn);
> +
> + LIBVIRT_BEGIN_ALLOW_THREADS;
> +
> + ret = virConnectDomainQemuEventDeregister(conn, callbackID);
> +
> + LIBVIRT_END_ALLOW_THREADS;
> + py_retval = libvirt_intWrap(ret);
> + return (py_retval);
> +}
> +
> /************************************************************************
> * *
> * The registration stuff *
> @@ -104,6 +242,8 @@ libvirt_qemu_virDomainQemuMonitorCommand(PyObject *self ATTRIBUTE_UNUSED,
> static PyMethodDef libvirtQemuMethods[] = {
> #include "libvirt-qemu-export.c"
> {(char *) "virDomainQemuMonitorCommand", libvirt_qemu_virDomainQemuMonitorCommand, METH_VARARGS, NULL},
> + {(char *) "virConnectDomainQemuEventRegister", libvirt_qemu_virConnectDomainQemuEventRegister, METH_VARARGS, NULL},
> + {(char *) "virConnectDomainQemuEventDeregister", libvirt_qemu_virConnectDomainQemuEventDeregister, METH_VARARGS, NULL},
> {NULL, NULL, 0, NULL}
> };
>
> diff --git a/python/libvirt-qemu-override.py b/python/libvirt-qemu-override.py
> new file mode 100644
> index 0000000..0f5694c
> --- /dev/null
> +++ b/python/libvirt-qemu-override.py
> @@ -0,0 +1,41 @@
> +#
> +# Manually written part of python bindings for libvirt_qemu
> +#
> +
> +# On cygwin, the DLL is called cygvirtmod.dll
> +try:
> + import libvirtmod_qemu
> +except ImportError, lib_e:
> + try:
> + import cygvirtmod_qemu as libvirtmod_qemu
> + except ImportError, cyg_e:
> + if str(cyg_e).count("No module named"):
> + raise lib_e
> +
> +import libvirt
> +import types
> +
> +def domainQemuEventDeregister(conn, callbackID):
> + """Removes a Domain Event Callback. De-registering for a
> + domain callback will disable delivery of this event type """
> + try:
> + ret = libvirtmod_qemu.virConnectDomainQemuEventDeregister(conn._o, callbackID)
> + if ret == -1: raise libvirt.libvirtError ('virConnectDomainQemuEventDeregister() failed', conn)
> + del conn.domainEventCallbackID[callbackID]
> + except AttributeError:
> + pass
> +
> +def domainQemuEventRegister(conn, dom, eventName, cb, opaque):
> + """Adds a Domain Event Callback. Registering for a domain
> + callback will enable delivery of the events """
> + if not hasattr(conn, 'domainEventCallbackID'):
> + conn.domainEventCallbackID = {}
> + cbData = { "cb": cb, "conn": conn, "opaque": opaque }
> + if dom is None:
> + ret = libvirtmod_qemu.virConnectDomainQemuEventRegister(conn._o, None, eventName, cbData)
> + else:
> + ret = libvirtmod_qemu.virConnectDomainQemuEventRegister(conn._o, dom._o, eventName, cbData)
> + if ret == -1:
> + raise libvirt.libvirtError ('virConnectDomainQemuEventRegister() failed', conn)
> + conn.domainEventCallbackID[ret] = opaque
> + return ret
> diff --git a/src/conf/domain_event.c b/src/conf/domain_event.c
> index 614ab97..b6a763a 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,8 @@ virDomainEventCallbackListFree(virDomainEventCallbackListPtr list)
>
> for (i=0; i<list->count; i++) {
> virFreeCallback freecb = list->callbacks[i]->freecb;
> + if (list->callbacks[i]->eventName)
> + VIR_FREE(list->callbacks[i]->eventName);
> if (freecb)
> (*freecb)(list->callbacks[i]->opaque);
> VIR_FREE(list->callbacks[i]);
> @@ -143,7 +151,6 @@ virDomainEventCallbackListRemove(virConnectPtr conn,
> (*freecb)(cbList->callbacks[i]->opaque);
> virUnrefConnect(cbList->callbacks[i]->conn);
> VIR_FREE(cbList->callbacks[i]);
> -
> if (i < (cbList->count - 1))
> memmove(cbList->callbacks + i,
> cbList->callbacks + i + 1,
> @@ -187,8 +194,11 @@ 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) {
> + if (cbList->callbacks[i]->eventName)
> + VIR_FREE(cbList->callbacks[i]->eventName);
> + }
> VIR_FREE(cbList->callbacks[i]);
> -
> if (i < (cbList->count - 1))
> memmove(cbList->callbacks + i,
> cbList->callbacks + i + 1,
> @@ -212,6 +222,52 @@ virDomainEventCallbackListRemoveID(virConnectPtr conn,
>
>
> /**
> + * virDomainQemuEventCallbackListRemoveID:
> + * @conn: pointer to the connection
> + * @cbList: the list
> + * @callback: the callback to remove
> + *
> + * Internal function to remove a callback from a virDomainEventCallbackListPtr
> + */
> +int
> +virDomainQemuEventCallbackListRemoveID(virConnectPtr conn,
> + virDomainEventCallbackListPtr cbList,
> + int callbackID)
> +{
> + int i;
> + for (i = 0 ; i < cbList->count ; i++) {
> + if (cbList->callbacks[i]->callbackID == callbackID &&
> + cbList->callbacks[i]->conn == conn &&
> + cbList->callbacks[i]->eventID == VIR_QEMU_DOMAIN_EVENT_ID_UNKNOWN) {
> + virFreeCallback freecb = cbList->callbacks[i]->freecb;
> + if (freecb)
> + (*freecb)(cbList->callbacks[i]->opaque);
> + VIR_FREE(cbList->callbacks[i]->eventName);
> + virUnrefConnect(cbList->callbacks[i]->conn);
> + VIR_FREE(cbList->callbacks[i]);
> +
> + if (i < (cbList->count - 1))
> + memmove(cbList->callbacks + i,
> + cbList->callbacks + i + 1,
> + sizeof(*(cbList->callbacks)) *
> + (cbList->count - (i + 1)));
> +
> + if (VIR_REALLOC_N(cbList->callbacks,
> + cbList->count - 1) < 0) {
> + ; /* Failure to reduce memory allocation isn't fatal */
> + }
> + cbList->count--;
> + return 0;
> + }
> + }
> +
> + eventReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> + _("could not find event callback for removal"));
> + return -1;
> +}
> +
> +
> +/**
> * virDomainEventCallbackListRemoveConn:
> * @conn: pointer to the connection
> * @cbList: the list
> @@ -231,8 +287,11 @@ 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) {
> + if (cbList->callbacks[i]->eventName)
> + VIR_FREE(cbList->callbacks[i]->eventName);
> + }
> VIR_FREE(cbList->callbacks[i]);
> -
> if (i < (cbList->count - 1))
> memmove(cbList->callbacks + i,
> cbList->callbacks + i + 1,
> @@ -299,8 +358,11 @@ 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) {
> + if (cbList->callbacks[i]->eventName)
> + VIR_FREE(cbList->callbacks[i]->eventName);
> + }
> VIR_FREE(cbList->callbacks[i]);
> -
> if (i < (cbList->count - 1))
> memmove(cbList->callbacks + i,
> cbList->callbacks + i + 1,
> @@ -404,7 +466,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) &&
> + !strcmp(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: %d",
> + _("not suport this kind of eventID"), 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 +569,41 @@ no_memory:
> if (event->dom)
> VIR_FREE(event->dom->name);
> VIR_FREE(event->dom);
> + if (event->eventName)
> + 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 +625,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 (!strcmp(cbList->callbacks[i]->eventName,eventName) &&
> + cbList->callbacks[i]->conn == conn)
> + count++;
> + }
> +
> + return count;
> +}
> +
> +
> int virDomainEventCallbackListEventID(virConnectPtr conn,
> virDomainEventCallbackListPtr cbList,
> int callbackID)
> @@ -461,6 +665,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 +763,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 +1203,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 +1387,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 +1473,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 +1489,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 +1499,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 ||
> + strcmp(cb->eventName, event->data.qemuUnknownEvent.eventName) != 0)
> + return 0;
> + }
> if (cb->dom) {
> /* Deliberately ignoring 'id' for matching, since that
> * will cause problems when a domain switches between
> @@ -1341,3 +1647,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 = virDomainQemuEventCallbackListRemoveID(conn,
> + state->callbacks, callbackID);
> + virDomainEventStateUnlock(state);
> + return ret;
> +}
> diff --git a/src/conf/domain_event.h b/src/conf/domain_event.h
> index 3ba418e..c0edfac 100644
> --- a/src/conf/domain_event.h
> +++ b/src/conf/domain_event.h
> @@ -26,7 +26,6 @@
> # define __DOMAIN_EVENT_H__
>
> # include "domain_conf.h"
> -
> typedef struct _virDomainEventCallback virDomainEventCallback;
> typedef virDomainEventCallback *virDomainEventCallbackPtr;
>
> @@ -83,6 +82,15 @@ 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,
> @@ -92,6 +100,10 @@ int virDomainEventCallbackListRemoveID(virConnectPtr conn,
> virDomainEventCallbackListPtr cbList,
> int callbackID)
> ATTRIBUTE_NONNULL(1);
> +int virDomainQemuEventCallbackListRemoveID(virConnectPtr conn,
> + virDomainEventCallbackListPtr cbList,
> + int callbackID)
> + ATTRIBUTE_NONNULL(1);
> int virDomainEventCallbackListRemoveConn(virConnectPtr conn,
> virDomainEventCallbackListPtr cbList)
> ATTRIBUTE_NONNULL(1);
> @@ -106,9 +118,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 +136,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 +222,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 +285,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..c84375c 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,122 @@ 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__);
> + virLibConnError(conn, VIR_ERR_INVALID_CONN, "my_test_fuction");
> + 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 a81c230..b92ce71 100644
> --- a/src/libvirt_private.syms
> +++ b/src/libvirt_private.syms
> @@ -470,11 +470,16 @@ virDomainWatchdogModelTypeToString;
> # domain_event.h
> virDomainEventBlockJobNewFromObj;
> virDomainEventBlockJobNewFromDom;
> +virDomainEventUnknownNewFromObj;
> +virDomainEventunknownNewFromDom;
> virDomainEventCallbackListAdd;
> virDomainEventCallbackListAddID;
> +virDomainEventCallbackListAddName;
> virDomainEventCallbackListCount;
> virDomainEventCallbackListCountID;
> +virDomainEventCallbackListCountName;
> virDomainEventCallbackListEventID;
> +virDomainEventCallbackListEventName;
> virDomainEventCallbackListFree;
> virDomainEventCallbackListMarkDelete;
> virDomainEventCallbackListMarkDeleteID;
> @@ -511,6 +516,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;
> diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
> index ceb9f47..31fe966 100644
> --- a/src/qemu/qemu_driver.c
> +++ b/src/qemu/qemu_driver.c
> @@ -8217,6 +8217,46 @@ qemuDomainEventDeregisterAny(virConnectPtr conn,
> }
>
>
> +static int
> +qemuDomainQemuEventRegister(virConnectPtr conn,
> + virDomainPtr dom,
> + const char *eventName,
> + virConnectDomainEventGenericCallback callback,
> + void *opaque,
> + virFreeCallback freecb)
> +{
> + struct qemud_driver *driver = conn->privateData;
> + int ret;
> +
> + qemuDriverLock(driver);
> + ret = virDomainEventCallbackListAddName(conn,
> + driver->domainEventState->callbacks,
> + dom, eventName,
> + VIR_QEMU_DOMAIN_EVENT_ID_UNKNOWN,
> + callback, opaque, freecb);
> + qemuDriverUnlock(driver);
> +
> + return ret;
> +}
> +
> +
> +static int
> +qemuDomainQemuEventDeregister(virConnectPtr conn,
> + int callbackID)
> +{
> + struct qemud_driver *driver = conn->privateData;
> + int ret;
> +
> + qemuDriverLock(driver);
> + ret = virDomainQemuEventStateDeregister(conn,
> + driver->domainEventState,
> + callbackID);
> + qemuDriverUnlock(driver);
> +
> + return ret;
> +}
> +
> +
> /*******************************************************************
> * Migration Protocol Version 2
> *******************************************************************/
> @@ -11564,6 +11604,8 @@ static virDriver qemuDriver = {
> .domainMigrateGetMaxSpeed = qemuDomainMigrateGetMaxSpeed, /* 0.9.5 */
> .domainEventRegisterAny = qemuDomainEventRegisterAny, /* 0.8.0 */
> .domainEventDeregisterAny = qemuDomainEventDeregisterAny, /* 0.8.0 */
> + .qemuDomainQemuEventRegister = qemuDomainQemuEventRegister, /* 0.9.9 */
> + .qemuDomainQemuEventDeregister = qemuDomainQemuEventDeregister, /* 0.9.9 */
> .domainManagedSave = qemuDomainManagedSave, /* 0.8.0 */
> .domainHasManagedSaveImage = qemuDomainHasManagedSaveImage, /* 0.8.0 */
> .domainManagedSaveRemove = qemuDomainManagedSaveRemove, /* 0.8.0 */
> diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
> index 4141fb7..e6cd39c 100644
> --- a/src/qemu/qemu_monitor.c
> +++ b/src/qemu/qemu_monitor.c
> @@ -959,6 +959,16 @@ int qemuMonitorEmitBlockJob(qemuMonitorPtr mon,
> return ret;
> }
>
> +int qemuMonitorEmitUnknownEvent(qemuMonitorPtr mon,
> + const char *eventName,
> + const char *eventArgs)
> +{
> + int ret = -1;
> + VIR_DEBUG("mon=%p", mon);
> + QEMU_MONITOR_CALLBACK(mon, ret, domainUnknownEvent, mon->vm,
> + eventName, eventArgs);
> + return ret;
> +}
>
>
> int qemuMonitorSetCapabilities(qemuMonitorPtr mon)
> diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
> index 15acf8b..d3685b4 100644
> --- a/src/qemu/qemu_monitor.h
> +++ b/src/qemu/qemu_monitor.h
> @@ -123,6 +123,10 @@ struct _qemuMonitorCallbacks {
> const char *diskAlias,
> int type,
> int status);
> + int (*domainUnknownEvent)(qemuMonitorPtr mon,
> + virDomainObjPtr vm,
> + const char *eventName,
> + const char *eventArgs);
> };
>
>
> @@ -193,6 +197,10 @@ int qemuMonitorEmitBlockJob(qemuMonitorPtr mon,
> int type,
> int status);
>
> +int qemuMonitorEmitUnknownEvent(qemuMonitorPtr mon,
> + const char *eventName,
> + const char *eventArgs);
> +
>
>
> int qemuMonitorStartCPUs(qemuMonitorPtr mon,
> diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
> index 1ef3e84..a5fc1e6 100644
> --- a/src/qemu/qemu_monitor_json.c
> +++ b/src/qemu/qemu_monitor_json.c
> @@ -58,6 +58,7 @@ static void qemuMonitorJSONHandleVNCConnect(qemuMonitorPtr mon, virJSONValuePtr
> static void qemuMonitorJSONHandleVNCInitialize(qemuMonitorPtr mon, virJSONValuePtr data);
> static void qemuMonitorJSONHandleVNCDisconnect(qemuMonitorPtr mon, virJSONValuePtr data);
> static void qemuMonitorJSONHandleBlockJob(qemuMonitorPtr mon, virJSONValuePtr data);
> +static void qemuMonitorJSONHandleUnmatchedEvent(qemuMonitorPtr mon, virJSONValuePtr obj);
>
> struct {
> const char *type;
> @@ -74,6 +75,7 @@ struct {
> { "VNC_INITIALIZED", qemuMonitorJSONHandleVNCInitialize, },
> { "VNC_DISCONNECTED", qemuMonitorJSONHandleVNCDisconnect, },
> { "BLOCK_JOB_COMPLETED", qemuMonitorJSONHandleBlockJob, },
> + { "DEFAULT_UNKNOW_EVENT", qemuMonitorJSONHandleUnmatchedEvent, },
> };
>
>
> @@ -83,6 +85,7 @@ qemuMonitorJSONIOProcessEvent(qemuMonitorPtr mon,
> {
> const char *type;
> int i;
> + int findEventFlag = -1;
> VIR_DEBUG("mon=%p obj=%p", mon, obj);
>
> type = virJSONValueObjectGetString(obj, "event");
> @@ -98,9 +101,24 @@ qemuMonitorJSONIOProcessEvent(qemuMonitorPtr mon,
> VIR_DEBUG("handle %s handler=%p data=%p", type,
> eventHandlers[i].handler, data);
> (eventHandlers[i].handler)(mon, data);
> + findEventFlag = 0;
> break;
> }
> }
> + if (findEventFlag != 0) {
> + if (!STREQ(eventHandlers[ARRAY_CARDINALITY(eventHandlers)-1].type, "DEFAULT_UNKNOW_EVENT")) {
> + VIR_ERROR("the last element is not the default event handler");
> + }
> + else {
> + char *event = NULL;
> + event = virJSONValueToString(obj);
> + if (event != NULL) {
> + VIR_DEBUG("Unknow event,call default event handler %s",event);
> + free(event);
> + }
> + (eventHandlers[ARRAY_CARDINALITY(eventHandlers)-1].handler)(mon, obj);
> + }
> + }
> return 0;
> }
>
> @@ -724,6 +742,24 @@ out:
> }
>
>
> +static void
> +qemuMonitorJSONHandleUnmatchedEvent(qemuMonitorPtr mon, virJSONValuePtr obj)
> +{
> + const char *eventArgsStr = NULL;
> + const char *type = NULL;
> + virJSONValuePtr data = NULL;
> + type = virJSONValueObjectGetString(obj, "event");
> + data = virJSONValueObjectGet(obj, "data");
> + if (data) {
> + eventArgsStr = virJSONValueToString(data);
> + }
> + if (eventArgsStr == NULL) {
> + VIR_ERROR("no data string from JSONValue");
> + }
> + qemuMonitorEmitUnknownEvent(mon, type, eventArgsStr);
> +}
> +
> +
> int
> qemuMonitorJSONHumanCommandWithFd(qemuMonitorPtr mon,
> const char *cmd_str,
> diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
> index 9123f4c..55e5464 100644
> --- a/src/qemu/qemu_process.c
> +++ b/src/qemu/qemu_process.c
> @@ -755,6 +755,29 @@ qemuProcessHandleBlockJob(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
> }
>
> static int
> +qemuProcessHandleUnknownEvent(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
> + virDomainObjPtr vm,
> + const char *eventName,
> + const char *eventArgs)
> +{
> + struct qemud_driver *driver = qemu_driver;
> + virDomainEventPtr event = NULL;
> +
> + virDomainObjLock(vm);
> + event = virDomainEventUnknownNewFromObj(vm, eventName, eventArgs);
> +
> + virDomainObjUnlock(vm);
> +
> + if (event) {
> + qemuDriverLock(driver);
> + qemuDomainEventQueue(driver, event);
> + qemuDriverUnlock(driver);
> + }
> +
> + return 0;
> +}
> +
> +static int
> qemuProcessHandleGraphics(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
> virDomainObjPtr vm,
> int phase,
> @@ -871,6 +894,7 @@ static qemuMonitorCallbacks monitorCallbacks = {
> .domainIOError = qemuProcessHandleIOError,
> .domainGraphics = qemuProcessHandleGraphics,
> .domainBlockJob = qemuProcessHandleBlockJob,
> + .domainUnknownEvent = qemuProcessHandleUnknownEvent,
> };
>
> static int
> diff --git a/src/remote/qemu_protocol.x b/src/remote/qemu_protocol.x
> index 39f9adf..5f4ed61 100644
> --- a/src/remote/qemu_protocol.x
> +++ b/src/remote/qemu_protocol.x
> @@ -47,6 +47,34 @@ struct qemu_domain_attach_ret {
> remote_nonnull_domain dom;
> };
>
> +struct qemu_domain_events_register_args {
> + remote_nonnull_string eventName;
> +};
> +
> +struct qemu_domain_events_deregister_args {
> + remote_nonnull_string eventName;
> + int callbackID;
> +};
> +
> +struct qemu_domain_events_register_ret {
> + int callbackID;
> +};
> +
> +struct qemu_domain_events_deregister_ret {
> + int cb_deregistered;
> +};
> +
> +struct qemu_domain_events_unknown_event_args {
> + remote_nonnull_domain dom;
> + remote_nonnull_string eventName;
> + remote_nonnull_string eventArgs;
> +};
> +
> +struct qemu_domain_events_unknown_event_ret {
> + int event_ret;
> +};
> +
> +
> /* Define the program number, protocol version and procedure numbers here. */
> const QEMU_PROGRAM = 0x20008087;
> const QEMU_PROTOCOL_VERSION = 1;
> @@ -61,5 +89,8 @@ enum qemu_procedure {
> * are some exceptions to this rule, e.g. domainDestroy. Other APIs MAY
> * be marked as high priority. If in doubt, it's safe to choose low. */
> QEMU_PROC_MONITOR_COMMAND = 1, /* skipgen skipgen priority:low */
> - QEMU_PROC_DOMAIN_ATTACH = 2 /* autogen autogen priority:low */
> + QEMU_PROC_DOMAIN_ATTACH = 2, /* autogen autogen priority:low */
> + QEMU_PROC_DOMAIN_EVENTS_REGISTER = 3, /* skipgen skipgen priority:low */
> + QEMU_PROC_DOMAIN_EVENTS_DEREGISTER = 4, /* skipgen skipgen priority:low */
> + QEMU_PROC_DOMAIN_EVENTS_UNKNOWN_EVENT = 5 /* skipgen skipgen priority:low */
> };
> diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
> index ff2d4b4..1f7b25d 100644
> --- a/src/remote/remote_driver.c
> +++ b/src/remote/remote_driver.c
> @@ -238,6 +238,10 @@ static void
> remoteDomainBuildEventDiskChange(virNetClientProgramPtr prog,
> virNetClientPtr client,
> void *evdata, void *opaque);
> +static void
> +remoteQemuDomainBuildEventDefaultEvent(virNetClientProgramPtr prog,
> + virNetClientPtr client,
> + void *evdata, void *opaque);
>
> static virNetClientProgramEvent remoteDomainEvents[] = {
> { REMOTE_PROC_DOMAIN_EVENT_RTC_CHANGE,
> @@ -280,6 +284,10 @@ static virNetClientProgramEvent remoteDomainEvents[] = {
> remoteDomainBuildEventDiskChange,
> sizeof(remote_domain_event_disk_change_msg),
> (xdrproc_t)xdr_remote_domain_event_disk_change_msg },
> + { REMOTE_PROC_QEMU_DOMAIN_EVENT_UNKNOWN_EVENT,
> + remoteQemuDomainBuildEventDefaultEvent,
> + sizeof(remote_domain_event_default_event_msg),
> + (xdrproc_t)xdr_remote_domain_event_default_event_msg },
> };
>
> enum virDrvOpenRemoteFlags {
> @@ -3345,6 +3353,28 @@ remoteDomainBuildEventBlockJob(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
> }
>
> static void
> +remoteQemuDomainBuildEventDefaultEvent(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
> + virNetClientPtr client ATTRIBUTE_UNUSED,
> + void *evdata, void *opaque)
> +{
> + virConnectPtr conn = opaque;
> + struct private_data *priv = conn->privateData;
> + remote_domain_event_default_event_msg *msg = evdata;
> + virDomainPtr dom;
> + virDomainEventPtr event = NULL;
> +
> + dom = get_nonnull_domain(conn, msg->dom);
> + if (!dom)
> + return;
> +
> + event = virDomainEventUnknownNewFromDom(dom, msg->eventName, msg->eventArgs);
> +
> + virDomainFree(dom);
> +
> + remoteDomainEventQueue(priv, event);
> +}
> +
> +static void
> remoteDomainBuildEventGraphics(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
> virNetClientPtr client ATTRIBUTE_UNUSED,
> void *evdata, void *opaque)
> @@ -3800,7 +3830,6 @@ done:
> return rv;
> }
>
> -
> static int remoteDomainEventDeregisterAny(virConnectPtr conn,
> int callbackID)
> {
> @@ -3843,6 +3872,126 @@ done:
> return rv;
> }
>
> +static int
> +remoteDomainQemuEventRegister(virConnectPtr conn,
> + virDomainPtr dom,
> + const char *eventName,
> + virConnectDomainEventGenericCallback callback,
> + void *opaque,
> + virFreeCallback freecb)
> +{
> + int rv = -1;
> + struct private_data *priv = conn->privateData;
> + qemu_domain_events_register_args args;
> + qemu_domain_events_register_ret ret;
> + int callbackID;
> +
> + remoteDriverLock(priv);
> +
> + if (priv->domainEventState->timer < 0) {
> + remoteError(VIR_ERR_NO_SUPPORT, "%s", _("no event support"));
> + goto done;
> + }
> +
> + if ((callbackID = virDomainEventCallbackListAddName(conn,
> + priv->domainEventState->callbacks,
> + dom, eventName,
> + VIR_QEMU_DOMAIN_EVENT_ID_UNKNOWN,
> + callback, opaque, freecb)) < 0) {
> + remoteError(VIR_ERR_RPC, "%s", _("adding cb to list"));
> + goto done;
> + }
> +
> + /* If this is the first callback for this eventID, we need to enable
> + * events on the server */
> + if (virDomainEventCallbackListCountName(conn,
> + priv->domainEventState->callbacks,
> + eventName) == 1) {
> + args.eventName= (char *)eventName;
> +
> + if (call (conn, priv, REMOTE_CALL_QEMU, QEMU_PROC_DOMAIN_EVENTS_REGISTER,
> + (xdrproc_t) xdr_qemu_domain_events_register_args, (char *) &args,
> + (xdrproc_t) xdr_qemu_domain_events_register_ret, (char *) &ret) == -1) {
> + virDomainEventCallbackListRemoveID(conn,
> + priv->domainEventState->callbacks,
> + callbackID);
> + goto done;
> + }
> + }
> + virDomainEventCallbackListAddQemuCallbackID(conn,
> + priv->domainEventState->callbacks,
> + callbackID,
> + ret.callbackID);
> + rv = callbackID;
> +
> +done:
> + remoteDriverUnlock(priv);
> + return rv;
> +}
> +
> +static int remoteDomainQemuEventDeregister(virConnectPtr conn,
> + int callbackID)
> +{
> + struct private_data *priv = conn->privateData;
> + int rv = -1;
> + qemu_domain_events_deregister_args args;
> + qemu_domain_events_deregister_ret ret;
> + char *eventName = NULL;
> + ret.cb_deregistered = -1;
> +
> + remoteDriverLock(priv);
> +
> + if ((eventName = (char *)virDomainEventCallbackListEventName(conn,
> + priv->domainEventState->callbacks,
> + callbackID)) == NULL) {
> + remoteError(VIR_ERR_RPC, _("unable to find callback ID %d"), callbackID);
> + goto done;
> + }
> + eventName = strdup(eventName);
> + if (eventName == NULL)
> + goto done;
> +
> + if ((args.callbackID = virDomainEventCallbackListEventQemuCallbackID(conn,
> + priv->domainEventState->callbacks,
> + callbackID)) == -1) {
> + remoteError(VIR_ERR_RPC, _("unable to find callback ID %d"), callbackID);
> + goto done;
> + }
> +
> + if (virDomainQemuEventStateDeregister(conn,
> + priv->domainEventState,
> + callbackID) < 0)
> + goto done;
> +
> + /* If that was the last callback for this eventName, we need to disable
> + * events on the server */
> + if (virDomainEventCallbackListCountName(conn,
> + priv->domainEventState->callbacks,
> + eventName) == 0) {
> + args.eventName = eventName;
> +
> + if (call (conn, priv, REMOTE_CALL_QEMU, QEMU_PROC_DOMAIN_EVENTS_DEREGISTER,
> + (xdrproc_t) xdr_qemu_domain_events_deregister_args, (char *) &args,
> + (xdrproc_t) xdr_qemu_domain_events_deregister_ret, (char *) &ret) == -1) {
> + goto done;
> + }
> +
> + if ( ret.cb_deregistered == -1 ) {
> + remoteError(VIR_ERR_RPC, _("remote sever deregeiter remote callbackID:%d, and the client callbackID%d"),
> + args.callbackID,
> + callbackID);
> + goto done;
> + }
> + rv = ret.cb_deregistered;
> + }
> +
> +
> +done:
> + remoteDriverUnlock(priv);
> + if (eventName != NULL)
> + VIR_FREE(eventName);
> + return rv;
> +}
>
> /*----------------------------------------------------------------------*/
>
> @@ -4627,6 +4776,8 @@ static virDriver remote_driver = {
> .nodeGetFreeMemory = remoteNodeGetFreeMemory, /* 0.3.3 */
> .domainEventRegister = remoteDomainEventRegister, /* 0.5.0 */
> .domainEventDeregister = remoteDomainEventDeregister, /* 0.5.0 */
> + .qemuDomainQemuEventRegister = remoteDomainQemuEventRegister, /* 0.9.9 */
> + .qemuDomainQemuEventDeregister = remoteDomainQemuEventDeregister, /* 0.9.9 */
> .domainMigratePrepare2 = remoteDomainMigratePrepare2, /* 0.5.0 */
> .domainMigrateFinish2 = remoteDomainMigrateFinish2, /* 0.5.0 */
> .nodeDeviceDettach = remoteNodeDeviceDettach, /* 0.6.1 */
> diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x
> index 509a20b..4239db8 100644
> --- a/src/remote/remote_protocol.x
> +++ b/src/remote/remote_protocol.x
> @@ -2049,6 +2049,12 @@ struct remote_domain_event_disk_change_msg {
> int reason;
> };
>
> +struct remote_domain_event_default_event_msg {
> + remote_nonnull_domain dom;
> + remote_nonnull_string eventName;
> + remote_nonnull_string eventArgs;
> +};
> +
> struct remote_domain_managed_save_args {
> remote_nonnull_domain dom;
> unsigned int flags;
> @@ -2605,7 +2611,8 @@ enum remote_procedure {
>
> REMOTE_PROC_DOMAIN_BLOCK_RESIZE = 251, /* autogen autogen */
> REMOTE_PROC_DOMAIN_SET_BLOCK_IO_TUNE = 252, /* autogen autogen */
> - REMOTE_PROC_DOMAIN_GET_BLOCK_IO_TUNE = 253 /* skipgen skipgen */
> + REMOTE_PROC_DOMAIN_GET_BLOCK_IO_TUNE = 253, /* skipgen skipgen */
> + REMOTE_PROC_QEMU_DOMAIN_EVENT_UNKNOWN_EVENT = 254 /* skipgen skipgen */
>
> /*
> * Notice how the entries are grouped in sets of 10 ?
> diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs
> index a9d4296..17b3896 100644
> --- a/src/remote_protocol-structs
> +++ b/src/remote_protocol-structs
> @@ -1546,6 +1546,10 @@ struct remote_domain_event_disk_change_msg {
> remote_nonnull_string devAlias;
> int reason;
> };
> +struct remote_domain_event_default_event_msg {
> + remote_nonnull_domain dom;
> + remote_nonnull_string rawEvent;
> +};
> struct remote_domain_managed_save_args {
> remote_nonnull_domain dom;
> u_int flags;
> @@ -2044,4 +2048,5 @@ enum remote_procedure {
> REMOTE_PROC_DOMAIN_BLOCK_RESIZE = 251,
> REMOTE_PROC_DOMAIN_SET_BLOCK_IO_TUNE = 252,
> REMOTE_PROC_DOMAIN_GET_BLOCK_IO_TUNE = 253,
> + REMOTE_PROC_QEMU_DOMAIN_EVENT_UNKNOWN_EVENT = 254,
> };
-------------- next part --------------
A non-text attachment was scrubbed...
Name: unknown-event-test.py
Type: text/x-python
Size: 2314 bytes
Desc: not available
URL: <http://listman.redhat.com/archives/libvir-list/attachments/20111213/fd90a92e/attachment-0001.py>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0002-for-testing-the-new-qemu-specific-regiater-API.patch
Type: text/x-patch
Size: 4745 bytes
Desc: not available
URL: <http://listman.redhat.com/archives/libvir-list/attachments/20111213/fd90a92e/attachment-0001.bin>
More information about the libvir-list
mailing list