[libvirt] [python PATCH 1/2] qemu: support arbitrary monitor events

Wrap the new virConnectDomainQemuMonitorEventRegister function being added in libvirt 1.2.2. This patch copies heavily from network events (commit 6ea5be0) and from event loop callbacks in libvirt-override.c, since in the libvirt_qemu module, we must expose top-level functions rather than class members. * generator.py (qemu_skip_function): Don't generate event code. (qemuBuildWrappers): Delay manual portion until after imports. * libvirt-qemu-override.py (qemuMonitorEventRegister) (qemuMonitorEventDeregister): New file. * libvirt-qemu-override.c (libvirt_qemu_virConnectDomainQemuMonitorEventFreeFunc) (libvirt_qemu_virConnectDomainQemuMonitorEventCallback) (libvirt_qemu_virConnectDomainQemuMonitorEventRegister) (libvirt_qemu_virConnectDomainQemuMonitorEventDeregister) (libvirt_qemu_lookupPythonFunc, getLibvirtQemuDictObject) (getLibvirtQemuModuleObject): New functions. Signed-off-by: Eric Blake <eblake@redhat.com> --- generator.py | 20 +++-- libvirt-qemu-override.c | 221 ++++++++++++++++++++++++++++++++++++++++++++++- libvirt-qemu-override.py | 36 ++++++++ 3 files changed, 268 insertions(+), 9 deletions(-) create mode 100644 libvirt-qemu-override.py diff --git a/generator.py b/generator.py index 42f3913..e2325b0 100755 --- a/generator.py +++ b/generator.py @@ -570,6 +570,8 @@ lxc_skip_function = ( ) qemu_skip_function = ( #"virDomainQemuAttach", + 'virConnectDomainQemuMonitorEventRegister', # overridden in -qemu.py + 'virConnectDomainQemuMonitorEventDeregister', # overridden in -qemu.py ) # Generate C code, but skip python impl @@ -1803,16 +1805,8 @@ def qemuBuildWrappers(module): fd.write("#\n") fd.write("# WARNING WARNING WARNING WARNING\n") fd.write("#\n") - if extra is not None: - fd.writelines(extra.readlines()) - fd.write("#\n") - fd.write("# WARNING WARNING WARNING WARNING\n") - fd.write("#\n") fd.write("# Automatically written part of python bindings for libvirt\n") fd.write("#\n") - fd.write("# WARNING WARNING WARNING WARNING\n") - if extra is not None: - extra.close() fd.write("try:\n") fd.write(" import libvirtmod_qemu\n") @@ -1826,6 +1820,16 @@ def qemuBuildWrappers(module): fd.write(" raise lib_e\n\n") fd.write("import libvirt\n\n") + fd.write("# WARNING WARNING WARNING WARNING\n") + fd.write("#\n") + if extra is not None: + fd.writelines(extra.readlines()) + fd.write("#\n") + if extra is not None: + extra.close() + + fd.write("# WARNING WARNING WARNING WARNING\n") + fd.write("#\n") fd.write("#\n# Functions from module %s\n#\n\n" % module) # # Generate functions directly, no classes diff --git a/libvirt-qemu-override.c b/libvirt-qemu-override.c index 480a7d3..0abcd3f 100644 --- a/libvirt-qemu-override.c +++ b/libvirt-qemu-override.c @@ -4,7 +4,7 @@ * entry points where an automatically generated stub is * unpractical * - * Copyright (C) 2011-2012 Red Hat, Inc. + * Copyright (C) 2011-2014 Red Hat, Inc. * * Daniel Veillard <veillard@redhat.com> */ @@ -54,6 +54,76 @@ extern void initcygvirtmod_qemu(void); #define VIR_PY_INT_FAIL (libvirt_intWrap(-1)) #define VIR_PY_INT_SUCCESS (libvirt_intWrap(0)) +/******************************************* + * Helper functions to avoid importing modules + * for every callback + *******************************************/ +#if LIBVIR_CHECK_VERSION(1, 2, 2) +static PyObject *libvirt_qemu_module; +static PyObject *libvirt_qemu_dict; + +static PyObject * +getLibvirtQemuModuleObject(void) +{ + if (libvirt_qemu_module) + return libvirt_qemu_module; + + // PyImport_ImportModule returns a new reference + /* Bogus (char *) cast for RHEL-5 python API brokenness */ + libvirt_qemu_module = PyImport_ImportModule((char *)"libvirt_qemu"); + if (!libvirt_qemu_module) { + DEBUG("%s Error importing libvirt_qemu module\n", __FUNCTION__); + PyErr_Print(); + return NULL; + } + + return libvirt_qemu_module; +} + +static PyObject * +getLibvirtQemuDictObject(void) +{ + if (libvirt_qemu_dict) + return libvirt_qemu_dict; + + // PyModule_GetDict returns a borrowed reference + libvirt_qemu_dict = PyModule_GetDict(getLibvirtQemuModuleObject()); + if (!libvirt_qemu_dict) { + DEBUG("%s Error importing libvirt_qemu dictionary\n", __FUNCTION__); + PyErr_Print(); + return NULL; + } + + Py_INCREF(libvirt_qemu_dict); + return libvirt_qemu_dict; +} + + +static PyObject * +libvirt_qemu_lookupPythonFunc(const char *funcname) +{ + PyObject *python_cb; + + /* Lookup the python callback */ + python_cb = PyDict_GetItemString(getLibvirtQemuDictObject(), funcname); + + if (!python_cb) { + DEBUG("%s: Error finding %s\n", __FUNCTION__, funcname); + PyErr_Print(); + PyErr_Clear(); + return NULL; + } + + if (!PyCallable_Check(python_cb)) { + DEBUG("%s: %s is not callable\n", __FUNCTION__, funcname); + return NULL; + } + + return python_cb; +} +#endif /* LIBVIR_CHECK_VERSION(1, 2, 2) */ + + /************************************************************************ * * * Statistics * @@ -122,6 +192,151 @@ libvirt_qemu_virDomainQemuAgentCommand(PyObject *self ATTRIBUTE_UNUSED, PyObject } #endif /* LIBVIR_CHECK_VERSION(0, 10, 0) */ + +#if LIBVIR_CHECK_VERSION(1, 2, 2) +static void +libvirt_qemu_virConnectDomainQemuMonitorEventFreeFunc(void *opaque) +{ + PyObject *pyobj_conn = (PyObject*)opaque; + LIBVIRT_ENSURE_THREAD_STATE; + Py_DECREF(pyobj_conn); + LIBVIRT_RELEASE_THREAD_STATE; +} + +static void +libvirt_qemu_virConnectDomainQemuMonitorEventCallback(virConnectPtr conn ATTRIBUTE_UNUSED, + virDomainPtr dom, + const char *event, + long long seconds, + unsigned int micros, + const char *details, + void *opaque) +{ + PyObject *pyobj_cbData = (PyObject*)opaque; + PyObject *pyobj_dom; + PyObject *pyobj_ret; + PyObject *pyobj_conn; + PyObject *dictKey; + PyObject *pyobj_cb; + + LIBVIRT_ENSURE_THREAD_STATE; + + pyobj_cb = libvirt_qemu_lookupPythonFunc("_dispatchQemuMonitorEventCallback"); + if (!pyobj_cb) { + goto cleanup; + } + + dictKey = libvirt_constcharPtrWrap("conn"); + if (!dictKey) + return; + pyobj_conn = PyDict_GetItem(pyobj_cbData, dictKey); + Py_DECREF(dictKey); + + /* Create a python instance of this virDomainPtr */ + virDomainRef(dom); + pyobj_dom = libvirt_virDomainPtrWrap(dom); + Py_INCREF(pyobj_cbData); + + /* Call the Callback Dispatcher */ + pyobj_ret = PyObject_CallFunction(pyobj_cb, + (char *)"OOsLIsO", + pyobj_conn, pyobj_dom, event, seconds, + micros, details, pyobj_cbData); + + Py_DECREF(pyobj_cbData); + Py_DECREF(pyobj_dom); + + if (!pyobj_ret) { + DEBUG("%s - ret:%p\n", __FUNCTION__, pyobj_ret); + PyErr_Print(); + } else { + Py_DECREF(pyobj_ret); + } + +cleanup: + LIBVIRT_RELEASE_THREAD_STATE; +} + + +static PyObject * +libvirt_qemu_virConnectDomainQemuMonitorEventRegister(PyObject *self ATTRIBUTE_UNUSED, + PyObject *args) +{ + PyObject *py_retval; + PyObject *pyobj_conn; + PyObject *pyobj_dom; + PyObject *pyobj_cbData; + const char *event; + virConnectPtr conn; + int ret = 0; + virConnectDomainQemuMonitorEventCallback cb = NULL; + virDomainPtr dom; + unsigned int flags; + + if (!PyArg_ParseTuple + (args, (char *) "OOzOI", + &pyobj_conn, &pyobj_dom, &event, &pyobj_cbData, &flags)) { + DEBUG("%s failed parsing tuple\n", __FUNCTION__); + return VIR_PY_INT_FAIL; + } + + DEBUG("libvirt_qemu_virConnectDomainQemuMonitorEventRegister(%p %p %s %p %x) called\n", + pyobj_conn, pyobj_dom, NULLSTR(event), pyobj_cbData, flags); + conn = PyvirConnect_Get(pyobj_conn); + if (pyobj_dom == Py_None) + dom = NULL; + else + dom = PyvirDomain_Get(pyobj_dom); + + cb = libvirt_qemu_virConnectDomainQemuMonitorEventCallback; + + Py_INCREF(pyobj_cbData); + + LIBVIRT_BEGIN_ALLOW_THREADS; + ret = virConnectDomainQemuMonitorEventRegister(conn, dom, event, + cb, pyobj_cbData, + libvirt_qemu_virConnectDomainQemuMonitorEventFreeFunc, + flags); + LIBVIRT_END_ALLOW_THREADS; + + if (ret < 0) + Py_DECREF(pyobj_cbData); + + py_retval = libvirt_intWrap(ret); + return py_retval; +} + + +static PyObject * +libvirt_qemu_virConnectDomainQemuMonitorEventDeregister(PyObject *self ATTRIBUTE_UNUSED, + PyObject *args) +{ + PyObject *py_retval; + PyObject *pyobj_conn; + int callbackID; + virConnectPtr conn; + int ret = 0; + + if (!PyArg_ParseTuple + (args, (char *) "Oi:virConnectDomainQemuMonitorEventDeregister", + &pyobj_conn, &callbackID)) + return NULL; + + DEBUG("libvirt_qemu_virConnectDomainQemuMonitorEventDeregister(%p) called\n", + pyobj_conn); + + conn = PyvirConnect_Get(pyobj_conn); + + LIBVIRT_BEGIN_ALLOW_THREADS; + + ret = virConnectDomainQemuMonitorEventDeregister(conn, callbackID); + + LIBVIRT_END_ALLOW_THREADS; + py_retval = libvirt_intWrap(ret); + return py_retval; +} +#endif /* LIBVIR_CHECK_VERSION(1, 2, 2) */ + /************************************************************************ * * * The registration stuff * @@ -133,6 +348,10 @@ static PyMethodDef libvirtQemuMethods[] = { #if LIBVIR_CHECK_VERSION(0, 10, 0) {(char *) "virDomainQemuAgentCommand", libvirt_qemu_virDomainQemuAgentCommand, METH_VARARGS, NULL}, #endif /* LIBVIR_CHECK_VERSION(0, 10, 0) */ +#if LIBVIR_CHECK_VERSION(1, 2, 2) + {(char *) "virConnectDomainQemuMonitorEventRegister", libvirt_qemu_virConnectDomainQemuMonitorEventRegister, METH_VARARGS, NULL}, + {(char *) "virConnectDomainQemuMonitorEventDeregister", libvirt_qemu_virConnectDomainQemuMonitorEventDeregister, METH_VARARGS, NULL}, +#endif /* LIBVIR_CHECK_VERSION(1, 2, 2) */ {NULL, NULL, 0, NULL} }; diff --git a/libvirt-qemu-override.py b/libvirt-qemu-override.py new file mode 100644 index 0000000..ab48bec --- /dev/null +++ b/libvirt-qemu-override.py @@ -0,0 +1,36 @@ +# Manually written part of python bindings for libvirt-qemu + +def _dispatchQemuMonitorEventCallback(conn, dom, event, seconds, micros, details, cbData): + """Dispatches events to python user qemu monitor event callbacks + """ + cb = cbData["cb"] + opaque = cbData["opaque"] + + cb(conn, libvirt.virDomain(conn, _obj=dom), event, seconds, micros, details, opaque) + return 0 + +def qemuMonitorEventDeregister(conn, callbackID): + """Removes a qemu monitor event callback. De-registering for a callback + will disable delivery of this event type""" + try: + ret = libvirtmod_qemu.virConnectDomainQemuMonitorEventDeregister(conn._o, callbackID) + if ret == -1: raise libvirt.libvirtError ('virConnectDomainQemuMonitorEventDeregister() failed') + del conn.qemuMonitorEventCallbackID[callbackID] + except AttributeError: + pass + +def qemuMonitorEventRegister(conn, dom, event, cb, opaque, flags=0): + """Adds a qemu monitor event callback. Registering for a monitor + callback will enable delivery of the events""" + if not hasattr(conn, 'qemuMonitorEventCallbackID'): + conn.qemuMonitorEventCallbackID = {} + cbData = { "cb": cb, "conn": conn, "opaque": opaque } + if dom is None: + ret = libvirtmod_qemu.virConnectDomainQemuMonitorEventRegister(conn._o, None, event, cbData, flags) + else: + ret = libvirtmod_qemu.virConnectDomainQemuMonitorEventRegister(conn._o, dom._o, event, cbData, flags) + if ret == -1: + raise libvirt.libvirtError ('virConnectDomainQemuMonitorEventRegister() failed') + conn.qemuMonitorEventCallbackID[ret] = opaque + return ret + -- 1.8.5.3

The event test is too useful to make it always drag in libvirt_qemu. So I don't want this applied. However, it makes testing my event addition much easier. --- examples/event-test.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/examples/event-test.py b/examples/event-test.py index 101dbc0..ab56299 100644 --- a/examples/event-test.py +++ b/examples/event-test.py @@ -10,6 +10,7 @@ import sys import getopt import os import libvirt +import libvirt_qemu import select import errno import time @@ -528,6 +529,16 @@ def myNetworkEventLifecycleCallback(conn, net, event, detail, opaque): netDetailToString(event, detail))) ########################################################################## +# qemu monitor events +########################################################################## +def myDomainQemuMonitorCallback(conn, dom, event, seconds, micros, details, opaque): + if details is None: + details = "" + print("myDomainQemuMonitorCallback: Domain %s(%s) %d.%06d %s %s" %(dom.name(), dom.ID(), + seconds, micros, + event, details)) + +########################################################################## # Set up and run the program ########################################################################## @@ -579,7 +590,7 @@ def main(): else: virEventLoopNativeStart() - vc = libvirt.openReadOnly(uri) + vc = libvirt.open(uri) # Close connection on exit (to test cleanup paths) old_exitfunc = getattr(sys, 'exitfunc', None) @@ -609,6 +620,8 @@ def main(): vc.networkEventRegisterAny(None, libvirt.VIR_NETWORK_EVENT_ID_LIFECYCLE, myNetworkEventLifecycleCallback, None) + libvirt_qemu.qemuMonitorEventRegister(vc, None, None, myDomainQemuMonitorCallback, None) + vc.setKeepAlive(5, 3) # The rest of your app would go here normally, but for sake -- 1.8.5.3

On 02/04/2014 07:01 PM, Eric Blake wrote:
Wrap the new virConnectDomainQemuMonitorEventRegister function being added in libvirt 1.2.2. This patch copies heavily from network events (commit 6ea5be0) and from event loop callbacks in libvirt-override.c, since in the libvirt_qemu module, we must expose top-level functions rather than class members.
Just realized I need to tweak this to say 1.2.3, since the new API missed 1.2. -- Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

On 05.02.2014 03:01, Eric Blake wrote:
Wrap the new virConnectDomainQemuMonitorEventRegister function being added in libvirt 1.2.2. This patch copies heavily from network events (commit 6ea5be0) and from event loop callbacks in libvirt-override.c, since in the libvirt_qemu module, we must expose top-level functions rather than class members.
* generator.py (qemu_skip_function): Don't generate event code. (qemuBuildWrappers): Delay manual portion until after imports. * libvirt-qemu-override.py (qemuMonitorEventRegister) (qemuMonitorEventDeregister): New file. * libvirt-qemu-override.c (libvirt_qemu_virConnectDomainQemuMonitorEventFreeFunc) (libvirt_qemu_virConnectDomainQemuMonitorEventCallback) (libvirt_qemu_virConnectDomainQemuMonitorEventRegister) (libvirt_qemu_virConnectDomainQemuMonitorEventDeregister) (libvirt_qemu_lookupPythonFunc, getLibvirtQemuDictObject) (getLibvirtQemuModuleObject): New functions.
Signed-off-by: Eric Blake <eblake@redhat.com> --- generator.py | 20 +++-- libvirt-qemu-override.c | 221 ++++++++++++++++++++++++++++++++++++++++++++++- libvirt-qemu-override.py | 36 ++++++++ 3 files changed, 268 insertions(+), 9 deletions(-) create mode 100644 libvirt-qemu-override.py
diff --git a/libvirt-qemu-override.c b/libvirt-qemu-override.c index 480a7d3..0abcd3f 100644 --- a/libvirt-qemu-override.c +++ b/libvirt-qemu-override.c
@@ -122,6 +192,151 @@ libvirt_qemu_virDomainQemuAgentCommand(PyObject *self ATTRIBUTE_UNUSED, PyObject } #endif /* LIBVIR_CHECK_VERSION(0, 10, 0) */
+ +#if LIBVIR_CHECK_VERSION(1, 2, 2) +static void +libvirt_qemu_virConnectDomainQemuMonitorEventFreeFunc(void *opaque) +{ + PyObject *pyobj_conn = (PyObject*)opaque; + LIBVIRT_ENSURE_THREAD_STATE; + Py_DECREF(pyobj_conn); + LIBVIRT_RELEASE_THREAD_STATE; +} + +static void +libvirt_qemu_virConnectDomainQemuMonitorEventCallback(virConnectPtr conn ATTRIBUTE_UNUSED, + virDomainPtr dom, + const char *event, + long long seconds, + unsigned int micros, + const char *details, + void *opaque) +{ + PyObject *pyobj_cbData = (PyObject*)opaque; + PyObject *pyobj_dom; + PyObject *pyobj_ret; + PyObject *pyobj_conn; + PyObject *dictKey; + PyObject *pyobj_cb; + + LIBVIRT_ENSURE_THREAD_STATE; + + pyobj_cb = libvirt_qemu_lookupPythonFunc("_dispatchQemuMonitorEventCallback"); + if (!pyobj_cb) { + goto cleanup; + } + + dictKey = libvirt_constcharPtrWrap("conn"); + if (!dictKey) + return; + pyobj_conn = PyDict_GetItem(pyobj_cbData, dictKey); + Py_DECREF(dictKey); + + /* Create a python instance of this virDomainPtr */ + virDomainRef(dom);
1: ^^^
+ pyobj_dom = libvirt_virDomainPtrWrap(dom); + Py_INCREF(pyobj_cbData); + + /* Call the Callback Dispatcher */ + pyobj_ret = PyObject_CallFunction(pyobj_cb, + (char *)"OOsLIsO", + pyobj_conn, pyobj_dom, event, seconds, + micros, details, pyobj_cbData); + + Py_DECREF(pyobj_cbData); + Py_DECREF(pyobj_dom);
I'd expect counterpart of [1] here.
+ + if (!pyobj_ret) { + DEBUG("%s - ret:%p\n", __FUNCTION__, pyobj_ret); + PyErr_Print(); + } else { + Py_DECREF(pyobj_ret); + } + +cleanup: + LIBVIRT_RELEASE_THREAD_STATE; +} + +
Besides that, the code looks okay. ACK. Michal

On 03/21/2014 10:22 AM, Michal Privoznik wrote:
On 05.02.2014 03:01, Eric Blake wrote:
Wrap the new virConnectDomainQemuMonitorEventRegister function being added in libvirt 1.2.2. This patch copies heavily from network events (commit 6ea5be0) and from event loop callbacks in libvirt-override.c, since in the libvirt_qemu module, we must expose top-level functions rather than class members.
+ LIBVIRT_ENSURE_THREAD_STATE; + + pyobj_cb = libvirt_qemu_lookupPythonFunc("_dispatchQemuMonitorEventCallback"); + if (!pyobj_cb) { + goto cleanup; + } + + dictKey = libvirt_constcharPtrWrap("conn"); + if (!dictKey) + return;
This return needs to be 'goto cleanup' to restore thread state.
+ pyobj_conn = PyDict_GetItem(pyobj_cbData, dictKey); + Py_DECREF(dictKey); + + /* Create a python instance of this virDomainPtr */ + virDomainRef(dom);
1: ^^^
+ pyobj_dom = libvirt_virDomainPtrWrap(dom); + Py_INCREF(pyobj_cbData); + + /* Call the Callback Dispatcher */ + pyobj_ret = PyObject_CallFunction(pyobj_cb, + (char *)"OOsLIsO", + pyobj_conn, pyobj_dom, event, seconds, + micros, details, pyobj_cbData); + + Py_DECREF(pyobj_cbData); + Py_DECREF(pyobj_dom);
I'd expect counterpart of [1] here.
If pyobj_dom was successfully created, then the python object cleanup calls virDomainFree of the dom that got wrapped. But you are correct that if libvirt_virDomainPtrWrap fails, then we've leaked a reference. I'll post a v2. -- Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

On 5.2.2014 03:01, Eric Blake wrote:
Wrap the new virConnectDomainQemuMonitorEventRegister function being added in libvirt 1.2.2. This patch copies heavily from network events (commit 6ea5be0) and from event loop callbacks in libvirt-override.c, since in the libvirt_qemu module, we must expose top-level functions rather than class members.
* generator.py (qemu_skip_function): Don't generate event code. (qemuBuildWrappers): Delay manual portion until after imports. * libvirt-qemu-override.py (qemuMonitorEventRegister) (qemuMonitorEventDeregister): New file. * libvirt-qemu-override.c (libvirt_qemu_virConnectDomainQemuMonitorEventFreeFunc) (libvirt_qemu_virConnectDomainQemuMonitorEventCallback) (libvirt_qemu_virConnectDomainQemuMonitorEventRegister) (libvirt_qemu_virConnectDomainQemuMonitorEventDeregister) (libvirt_qemu_lookupPythonFunc, getLibvirtQemuDictObject) (getLibvirtQemuModuleObject): New functions.
Signed-off-by: Eric Blake <eblake@redhat.com> ---
diff --git a/libvirt-qemu-override.py b/libvirt-qemu-override.py new file mode 100644 index 0000000..ab48bec --- /dev/null +++ b/libvirt-qemu-override.py @@ -0,0 +1,36 @@ +# Manually written part of python bindings for libvirt-qemu + +def _dispatchQemuMonitorEventCallback(conn, dom, event, seconds, micros, details, cbData): + """Dispatches events to python user qemu monitor event callbacks + """ + cb = cbData["cb"] + opaque = cbData["opaque"] + + cb(conn, libvirt.virDomain(conn, _obj=dom), event, seconds, micros, details, opaque) + return 0 + +def qemuMonitorEventDeregister(conn, callbackID): + """Removes a qemu monitor event callback. De-registering for a callback + will disable delivery of this event type""" + try: + ret = libvirtmod_qemu.virConnectDomainQemuMonitorEventDeregister(conn._o, callbackID) + if ret == -1: raise libvirt.libvirtError ('virConnectDomainQemuMonitorEventDeregister() failed') + del conn.qemuMonitorEventCallbackID[callbackID] + except AttributeError: + pass + +def qemuMonitorEventRegister(conn, dom, event, cb, opaque, flags=0): + """Adds a qemu monitor event callback. Registering for a monitor + callback will enable delivery of the events""" + if not hasattr(conn, 'qemuMonitorEventCallbackID'): + conn.qemuMonitorEventCallbackID = {} + cbData = { "cb": cb, "conn": conn, "opaque": opaque } + if dom is None: + ret = libvirtmod_qemu.virConnectDomainQemuMonitorEventRegister(conn._o, None, event, cbData, flags) + else: + ret = libvirtmod_qemu.virConnectDomainQemuMonitorEventRegister(conn._o, dom._o, event, cbData, flags) + if ret == -1: + raise libvirt.libvirtError ('virConnectDomainQemuMonitorEventRegister() failed') + conn.qemuMonitorEventCallbackID[ret] = opaque + return ret +
Also remove the blank line. And please try to fix it and push it asap as Jenkins tests depend on this patch, thanks. Pavel

On 03/24/2014 08:32 AM, Pavel Hrdina wrote:
On 5.2.2014 03:01, Eric Blake wrote:
Wrap the new virConnectDomainQemuMonitorEventRegister function being added in libvirt 1.2.2. This patch copies heavily from network events (commit 6ea5be0) and from event loop callbacks in libvirt-override.c, since in the libvirt_qemu module, we must expose top-level functions rather than class members.
Also remove the blank line. And please try to fix it and push it asap as Jenkins tests depend on this patch, thanks.
I've posted a v2... -- Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org
participants (3)
-
Eric Blake
-
Michal Privoznik
-
Pavel Hrdina