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@xxxxxxxxxx> --- 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@xxxxxxxxxx> */ @@ -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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list