Skip to content

Commit

Permalink
qemu: support arbitrary monitor events
Browse files Browse the repository at this point in the history
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@redhat.com>
  • Loading branch information
ebblake committed Mar 25, 2014
1 parent 493ca08 commit e3da8f1
Show file tree
Hide file tree
Showing 3 changed files with 269 additions and 9 deletions.
20 changes: 12 additions & 8 deletions generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -570,6 +570,8 @@ def qemu_enum(type, name, value):
)
qemu_skip_function = (
#"virDomainQemuAttach",
'virConnectDomainQemuMonitorEventRegister', # overridden in -qemu.py
'virConnectDomainQemuMonitorEventDeregister', # overridden in -qemu.py
)

# Generate C code, but skip python impl
Expand Down Expand Up @@ -1813,16 +1815,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")
Expand All @@ -1836,6 +1830,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
Expand Down
223 changes: 222 additions & 1 deletion libvirt-qemu-override.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
*/
Expand Down Expand Up @@ -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 *
Expand Down Expand Up @@ -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 *
Expand All @@ -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}
};

Expand Down
35 changes: 35 additions & 0 deletions libvirt-qemu-override.py
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit e3da8f1

Please sign in to comment.