Wrap the new virConnectDomainQemuMonitorEventRegister function
added in libvirt 1.2.3. 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(a)redhat.com>
---
generator.py | 20 +++--
libvirt-qemu-override.c | 223 ++++++++++++++++++++++++++++++++++++++++++++++-
libvirt-qemu-override.py | 35 ++++++++
3 files changed, 269 insertions(+), 9 deletions(-)
create mode 100644 libvirt-qemu-override.py
diff --git a/generator.py b/generator.py
index 0e9600f..d5aee22 100755
--- a/generator.py
+++ b/generator.py
@@ -569,6 +569,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
@@ -1812,16 +1814,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")
@@ -1835,6 +1829,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..05ead30 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(a)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, 3)
+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, 3) */
+
+
/************************************************************************
* *
* Statistics *
@@ -122,6 +192,153 @@ libvirt_qemu_virDomainQemuAgentCommand(PyObject *self
ATTRIBUTE_UNUSED, PyObject
}
#endif /* LIBVIR_CHECK_VERSION(0, 10, 0) */
+
+#if LIBVIR_CHECK_VERSION(1, 2, 3)
+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 = NULL;
+ 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)
+ goto cleanup;
+ pyobj_conn = PyDict_GetItem(pyobj_cbData, dictKey);
+ Py_DECREF(dictKey);
+
+ /* Create a python instance of this virDomainPtr */
+ virDomainRef(dom);
+ if (!(pyobj_dom = libvirt_virDomainPtrWrap(dom))) {
+ virDomainFree(dom);
+ goto cleanup;
+ }
+ 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);
+
+cleanup:
+ if (!pyobj_ret) {
+ DEBUG("%s - ret:%p\n", __FUNCTION__, pyobj_ret);
+ PyErr_Print();
+ } else {
+ Py_DECREF(pyobj_ret);
+ }
+
+ 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, 3) */
+
/************************************************************************
* *
* The registration stuff *
@@ -133,6 +350,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, 3)
+ {(char *) "virConnectDomainQemuMonitorEventRegister",
libvirt_qemu_virConnectDomainQemuMonitorEventRegister, METH_VARARGS, NULL},
+ {(char *) "virConnectDomainQemuMonitorEventDeregister",
libvirt_qemu_virConnectDomainQemuMonitorEventDeregister, METH_VARARGS, NULL},
+#endif /* LIBVIR_CHECK_VERSION(1, 2, 3) */
{NULL, NULL, 0, NULL}
};
diff --git a/libvirt-qemu-override.py b/libvirt-qemu-override.py
new file mode 100644
index 0000000..265a252
--- /dev/null
+++ b/libvirt-qemu-override.py
@@ -0,0 +1,35 @@
+# 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