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@xxxxxxxxxxxxxxxxxx wrote: > From: Shao He Feng <shaohef@xxxxxxxxxxxxxxxxxx> > > Basically, this feature can go along with qemu monitor passthrough. > That way, if we use new commands in the monitor that generate new events, we want some way to receive those new events too. > 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@xxxxxxxxxxxxxxxxxx> > --- > 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, > };
#!/usr/bin/env python import libvirt import libvirt_qemu import threading import time import signal import os import sys eventLoopThread = None def eventLoopRun(): while True: libvirt.virEventRunDefaultImpl() def eventLoopStart(): global eventLoopThread libvirt.virEventRegisterDefaultImpl() eventLoopThread = threading.Thread(target=eventLoopRun, name="libvirtEventLoop") eventLoopThread.setDaemon(True) eventLoopThread.start() def reportDefault(conn, dom, eventName,eventArgs,opaque): print "DEFAULT EVENT: Domain %s(%s), pass the unknown event:%s, arguments is: %s" % (dom.name(), dom.ID(), eventName, eventArgs) eventStrings = ( "RESUME", "VNC_CONNECTED", "VNC_DISCONNECTED", "VNC_INITIALIZED", "RESET", "SHUTDOWN", "HELLO" ); conn = libvirt.virConnect(); eventID = {}; def signal_handler(signal, frame): #print conn.getURI() if conn != None: print conn for i in eventID: print "deregister event: %d" %(i) #libvirt_qemu.domainQemuEventDeregister(conn1, i) print "test safely exit" else: print "conn is None" sys.exit(0) def main(): eventLoopStart() signal.signal(signal.SIGINT, signal_handler) conn = libvirt.openReadOnly('qemu:///system') eventID[0] = libvirt_qemu.domainQemuEventRegister(conn, None, eventStrings[0], reportDefault, None) #eventID[1] = libvirt_qemu.domainQemuEventRegister(conn, None, eventStrings[1], reportDefault, None) #eventID[2] = libvirt_qemu.domainQemuEventRegister(conn, None, eventStrings[2], reportDefault, None) #eventID[3] = libvirt_qemu.domainQemuEventRegister(conn, None, eventStrings[3], reportDefault, None) #eventID[4] = libvirt_qemu.domainQemuEventRegister(conn, None, eventStrings[4], reportDefault, None) #eventID[5] = libvirt_qemu.domainQemuEventRegister(conn, None, eventStrings[5], reportDefault, None) #eventID[6] = libvirt_qemu.domainQemuEventRegister(conn, None, eventStrings[6], reportDefault, None) #eventID[7] = libvirt_qemu.domainQemuEventRegister(conn, None, 'SHUTDOWN', reportDefault, None) while 1: time.sleep(1) if __name__ == "__main__": main()
>From 5454587749040dd028f7255259b28dce22253531 Mon Sep 17 00:00:00 2001 From: Shao He Feng <shaohef@xxxxxxxxxxxxxxxxxx> Date: Tue, 13 Dec 2011 04:33:18 +0800 Subject: for testing the new qemu specific regiater API Signed-off-by: Shao He Feng <shaohef@xxxxxxxxxxxxxxxxxx> --- tools/virsh.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 107 insertions(+), 0 deletions(-) diff --git a/tools/virsh.c b/tools/virsh.c index d58b827..4c9a69d 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -36,6 +36,7 @@ #include <libxml/parser.h> #include <libxml/tree.h> +#include <libxml/uri.h> #include <libxml/xpath.h> #include <libxml/xmlsave.h> @@ -53,6 +54,8 @@ #include "memory.h" #include "xml.h" #include "libvirt/libvirt-qemu.h" +#include "libvirt/libvirt.h" +#include "datatypes.h" #include "virfile.h" #include "event_poll.h" #include "configmake.h" @@ -11790,6 +11793,108 @@ cmdVNCDisplay(vshControl *ctl, const vshCmd *cmd) return ret; } +static const vshCmdInfo info_deregevent[] = { + {"help", N_("deregister an qemu event")}, + {"desc", N_("you please input you eventID, that the register-event returns.")}, + {NULL, NULL} +}; +static const vshCmdOptDef opts_deregevent[] = { + {"eventID", VSH_OT_INT, VSH_OFLAG_REQ, N_("deregister qemu spici eventID ")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdDeregisterEvent(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom; + bool ret = false; + int eventID = -1; + int retEventID = -1; + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (vshCommandOptInt(cmd, "eventID", &eventID) < 0) { + vshError(ctl, "%s", _("Please specify valid eventID")); + return false; + } + if (eventID < 0) { + fprintf(stdout, "please input a positive Int\n"); + return false; + } + + if ((retEventID = virConnectDomainQemuEventDeregister(ctl->conn, eventID)) < 0) { + fprintf(stdout, "eventID: %d Deregister error.\n", eventID); + return false; + } + fprintf(stdout, "event Deregister successi, the remote callbackID is %d.\n", retEventID); + ret = true; + cleanup: + return ret; +} + +static const vshCmdInfo info_regevent[] = { + {"help", N_("register an qemu event")}, + {"desc", N_("you please input you event name.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_regevent[] = { + {"event", VSH_OT_DATA, VSH_OFLAG_REQ, N_("register qemu spici event ")}, + {NULL, 0, 0, NULL} +}; + +void printRegistEvent(virConnectPtr conn, + virDomainPtr dom, + const char *eventName, /* The JSON event name */ + const char *eventArgs, /* The JSON string of args */ + void *opaque){ + char *uriName = virConnectGetURI (conn); + fputc('\n', stdout); + if (uriName != NULL) + fprintf(stdout, "connect URI: %s, ",uriName); + //xmlPrintURI(stdout, conn->uri); + + if (dom != NULL) + fprintf(stdout, "dom: %s(%d) receive an event:\n", dom->name, dom->id); + + if (eventName != NULL) + fprintf(stdout, "{ event: %s", eventName); + if (eventArgs != NULL) + fprintf(stdout, ", data: %s }\n", eventArgs); + else + fprintf(stdout, " }\n"); + fprintf(stdout, "----------------------------------------------"); + fputc('\n', stdout); +} + +static bool +cmdRegisterEvent(vshControl *ctl, const vshCmd *cmd) +{ + const char *name = NULL; + virDomainPtr dom; + bool ret = false; + int eventID = -1; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (vshCommandOptString(cmd, "event", &name) < 0) { + vshError(ctl, "%s", _("Please specify valid event name")); + return false; + } + + dom = vshCommandOptDomain(ctl, cmd, NULL); + eventID = virConnectDomainQemuEventRegister(ctl->conn, dom, name, printRegistEvent, NULL, NULL); + if (eventID < 0) { + fprintf(stdout, "%s event register error.\n", name); + return false; + } + fprintf(stdout, "%s event call back ID is %d, you can use it to deregister the event.\n", name, eventID); + ret = true; + cleanup: + return ret; +} + /* * "ttyconsole" command */ @@ -15172,6 +15277,8 @@ static const vshCmdDef domManagementCmds[] = { {"vcpupin", cmdVcpuPin, opts_vcpupin, info_vcpupin, 0}, {"version", cmdVersion, opts_version, info_version, 0}, {"vncdisplay", cmdVNCDisplay, opts_vncdisplay, info_vncdisplay, 0}, + {"register-event", cmdRegisterEvent, opts_regevent, info_regevent, 0}, + {"deregister-event", cmdDeregisterEvent, opts_deregevent, info_deregevent, 0}, {NULL, NULL, NULL, NULL, 0} }; -- 1.7.5.4
-- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list