[libvirt] PATCH: Misc fixes to events code

Daniel P. Berrange berrange at redhat.com
Tue Nov 4 19:56:05 UTC 2008


I'm trying out the new events code with virt-manager and stumbled on some
minor bugs

 - The python binding forgot to call LIBVIRT_BEGIN_ALLOW_THREADS,
   LIBVIRT_END_ALLOW_THREADS, LIBVIRT_ENSURE_THREAD_STATE or
   LIBVIRT_RELEASE_THREAD_STATE which meant virt-manager crashed
   and burned in a heap of python interpretor state corruption [1]

 - The API docs extracted assumes that enums without explicit value
   assignements started from 1 instead of 0.  This caused an off-by-1
   error for all the VIR_DOMAIN_EVENT_* constants in the generated python
   code.

I briefly toyed with fixing docs/apibuild.py enum handling but then instead
decided to just change libvirt.h to give explicit values.

With these two fixes and some hacks to virt-manager, I've got the
events triggering display state refreshes.

A couple more things I've not fixed but are on the todo list

 - THe QEMU driver doesn't emit the ADDED or REMOVED events for VMs
   which virt-manager requires in order to fully avoid polling.
 - The VIR_EVENT_* constants aren't included in python, because the
   API docs can't cope with enum value asignments looking like
   (1 << 0) (ie fails to parse the left-shifts)

Regards,
Daniel

[1] FYI, i'm using the libvirt-glib python binding in virt-manager
    http://libvirt.org/hg/libvirt-glib/ which is slightly bad too
    by not doing glib thread locking calls, but we're lucky because
    libvirt.so doesn't invoke any glib calls itself from the event
    callback context.


Index: python/libvir.c
===================================================================
RCS file: /data/cvs/libvirt/python/libvir.c,v
retrieving revision 1.43
diff -u -p -r1.43 libvir.c
--- python/libvir.c	31 Oct 2008 10:13:45 -0000	1.43
+++ python/libvir.c	4 Nov 2008 19:45:42 -0000
@@ -1537,29 +1537,33 @@ libvirt_virConnectDomainEventCallback(vi
     PyObject *pyobj_ret;
 
     PyObject *pyobj_conn_inst = (PyObject*)opaque;
-    PyObject *pyobj_dom = libvirt_virDomainPtrWrap(dom);
+    PyObject *pyobj_dom;
 
     PyObject *pyobj_dom_args;
     PyObject *pyobj_dom_inst;
 
     PyObject *dom_class;
+    int ret = -1;
+
+    LIBVIRT_ENSURE_THREAD_STATE;
 
     /* Create a python instance of this virDomainPtr */
+    pyobj_dom = libvirt_virDomainPtrWrap(dom);
     pyobj_dom_args = PyTuple_New(2);
     if(PyTuple_SetItem(pyobj_dom_args, 0, pyobj_conn_inst)!=0) {
         printf("%s error creating tuple",__FUNCTION__);
-        return -1;
+        goto cleanup;
     }
     if(PyTuple_SetItem(pyobj_dom_args, 1, pyobj_dom)!=0) {
         printf("%s error creating tuple",__FUNCTION__);
-        return -1;
+        goto cleanup;
     }
     Py_INCREF(pyobj_conn_inst);
 
     dom_class = getLibvirtDomainClassObject();
     if(!PyClass_Check(dom_class)) {
         printf("%s dom_class is not a class!\n", __FUNCTION__);
-        return -1;
+        goto cleanup;
     }
 
     pyobj_dom_inst = PyInstance_New(dom_class,
@@ -1571,7 +1575,7 @@ libvirt_virConnectDomainEventCallback(vi
     if(!pyobj_dom_inst) {
         printf("%s Error creating a python instance of virDomain\n", __FUNCTION__);
         PyErr_Print();
-        return -1;
+        goto cleanup;
     }
 
     /* Call the Callback Dispatcher */
@@ -1586,12 +1590,15 @@ libvirt_virConnectDomainEventCallback(vi
     if(!pyobj_ret) {
         printf("%s - ret:%p\n", __FUNCTION__, pyobj_ret);
         PyErr_Print();
-        return -1;
     } else {
         Py_DECREF(pyobj_ret);
-        return 0;
+        ret = 0;
     }
 
+
+cleanup:
+    LIBVIRT_RELEASE_THREAD_STATE;
+    return -1;
 }
 
 static PyObject *
@@ -1620,10 +1627,14 @@ libvirt_virConnectDomainEventRegister(AT
 
     Py_INCREF(pyobj_conn_inst);
 
+    LIBVIRT_BEGIN_ALLOW_THREADS;
+
     ret = virConnectDomainEventRegister(conn,
                                         libvirt_virConnectDomainEventCallback,
                                         (void *)pyobj_conn_inst);
 
+    LIBVIRT_END_ALLOW_THREADS;
+
     py_retval = libvirt_intWrap(ret);
     return (py_retval);
 }
@@ -1650,8 +1661,12 @@ libvirt_virConnectDomainEventDeregister(
 
     conn   = (virConnectPtr) PyvirConnect_Get(pyobj_conn);
 
+    LIBVIRT_BEGIN_ALLOW_THREADS;
+
     ret = virConnectDomainEventDeregister(conn, libvirt_virConnectDomainEventCallback);
 
+    LIBVIRT_END_ALLOW_THREADS;
+
     Py_DECREF(pyobj_conn_inst);
     py_retval = libvirt_intWrap(ret);
     return (py_retval);
@@ -1679,13 +1694,15 @@ libvirt_virEventAddHandleFunc  (int fd A
     PyObject *cb_args;
     PyObject *pyobj_args;
 
+    LIBVIRT_ENSURE_THREAD_STATE;
+
     /* Lookup the python callback */
     python_cb = PyDict_GetItemString(getLibvirtDictObject(),
                                      "eventInvokeHandleCallback");
     if(!python_cb) {
         printf("%s Error finding eventInvokeHandleCallback\n", __FUNCTION__);
         PyErr_Print();
-        return -1;
+        goto cleanup;
     }
     Py_INCREF(python_cb);
 
@@ -1708,6 +1725,10 @@ libvirt_virEventAddHandleFunc  (int fd A
 
     Py_XDECREF(result);
     Py_DECREF(pyobj_args);
+
+cleanup:
+    LIBVIRT_RELEASE_THREAD_STATE;
+
     return 0;
 }
 
@@ -1715,7 +1736,11 @@ static void
 libvirt_virEventUpdateHandleFunc(int fd, int event)
 {
     PyObject *result = NULL;
-    PyObject *pyobj_args = PyTuple_New(2);
+    PyObject *pyobj_args;
+
+    LIBVIRT_ENSURE_THREAD_STATE;
+
+    pyobj_args = PyTuple_New(2);
     PyTuple_SetItem(pyobj_args, 0, libvirt_intWrap(fd));
     PyTuple_SetItem(pyobj_args, 1, libvirt_intWrap(event));
 
@@ -1724,13 +1749,20 @@ libvirt_virEventUpdateHandleFunc(int fd,
 
     Py_XDECREF(result);
     Py_DECREF(pyobj_args);
+
+    LIBVIRT_RELEASE_THREAD_STATE;
 }
 
+
 static int
 libvirt_virEventRemoveHandleFunc(int fd)
 {
     PyObject *result = NULL;
-    PyObject *pyobj_args = PyTuple_New(1);
+    PyObject *pyobj_args;
+
+    LIBVIRT_ENSURE_THREAD_STATE;
+
+    pyobj_args = PyTuple_New(1);
     PyTuple_SetItem(pyobj_args, 0, libvirt_intWrap(fd));
 
     if(removeHandleObj && PyCallable_Check(removeHandleObj))
@@ -1738,6 +1770,9 @@ libvirt_virEventRemoveHandleFunc(int fd)
 
     Py_XDECREF(result);
     Py_DECREF(pyobj_args);
+
+    LIBVIRT_RELEASE_THREAD_STATE;
+
     return 0;
 }
 
@@ -1754,13 +1789,15 @@ libvirt_virEventAddTimeoutFunc(int timeo
     PyObject *cb_args;
     PyObject *pyobj_args;
 
+    LIBVIRT_ENSURE_THREAD_STATE;
+
     /* Lookup the python callback */
     python_cb = PyDict_GetItemString(getLibvirtDictObject(),
                                      "eventInvokeTimeoutCallback");
     if(!python_cb) {
         printf("%s Error finding eventInvokeTimeoutCallback\n", __FUNCTION__);
         PyErr_Print();
-        return -1;
+        goto cleanup;
     }
     Py_INCREF(python_cb);
 
@@ -1783,6 +1820,9 @@ libvirt_virEventAddTimeoutFunc(int timeo
 
     Py_XDECREF(result);
     Py_DECREF(pyobj_args);
+
+cleanup:
+    LIBVIRT_RELEASE_THREAD_STATE;
     return 0;
 }
 
@@ -1790,7 +1830,11 @@ static void
 libvirt_virEventUpdateTimeoutFunc(int timer, int timeout)
 {
     PyObject *result = NULL;
-    PyObject *pyobj_args = PyTuple_New(2);
+    PyObject *pyobj_args;
+
+    LIBVIRT_ENSURE_THREAD_STATE;
+
+    pyobj_args = PyTuple_New(2);
     PyTuple_SetItem(pyobj_args, 0, libvirt_intWrap(timer));
     PyTuple_SetItem(pyobj_args, 1, libvirt_intWrap(timeout));
 
@@ -1799,13 +1843,19 @@ libvirt_virEventUpdateTimeoutFunc(int ti
 
     Py_XDECREF(result);
     Py_DECREF(pyobj_args);
+
+    LIBVIRT_RELEASE_THREAD_STATE;
 }
 
 static int
 libvirt_virEventRemoveTimeoutFunc(int timer)
 {
     PyObject *result = NULL;
-    PyObject *pyobj_args = PyTuple_New(1);
+    PyObject *pyobj_args;
+
+    LIBVIRT_ENSURE_THREAD_STATE;
+
+    pyobj_args = PyTuple_New(1);
     PyTuple_SetItem(pyobj_args, 0, libvirt_intWrap(timer));
 
     if(updateTimeoutObj && PyCallable_Check(updateTimeoutObj))
@@ -1813,6 +1863,9 @@ libvirt_virEventRemoveTimeoutFunc(int ti
 
     Py_XDECREF(result);
     Py_DECREF(pyobj_args);
+
+    LIBVIRT_RELEASE_THREAD_STATE;
+
     return 0;
 }
 
@@ -1845,6 +1898,8 @@ libvirt_virEventRegisterImpl(ATTRIBUTE_U
     Py_INCREF(updateTimeoutObj);
     Py_INCREF(removeTimeoutObj);
 
+    LIBVIRT_BEGIN_ALLOW_THREADS;
+
     virEventRegisterImpl(libvirt_virEventAddHandleFunc,
                          libvirt_virEventUpdateHandleFunc,
                          libvirt_virEventRemoveHandleFunc,
@@ -1852,6 +1907,8 @@ libvirt_virEventRegisterImpl(ATTRIBUTE_U
                          libvirt_virEventUpdateTimeoutFunc,
                          libvirt_virEventRemoveTimeoutFunc);
 
+    LIBVIRT_END_ALLOW_THREADS;
+
     return VIR_PY_INT_SUCCESS;
 }
 
Index: include/libvirt/libvirt.h.in
===================================================================
RCS file: /data/cvs/libvirt/include/libvirt/libvirt.h.in,v
retrieving revision 1.57
diff -u -p -r1.57 libvirt.h.in
--- include/libvirt/libvirt.h.in	24 Oct 2008 12:05:39 -0000	1.57
+++ include/libvirt/libvirt.h.in	4 Nov 2008 19:45:42 -0000
@@ -1004,14 +1004,14 @@ virDomainPtr            virDomainCreateL
  * a virDomainEventType is emitted during domain lifecycle events
  */
 typedef enum {
-      VIR_DOMAIN_EVENT_ADDED,
-      VIR_DOMAIN_EVENT_REMOVED,
-      VIR_DOMAIN_EVENT_STARTED,
-      VIR_DOMAIN_EVENT_SUSPENDED,
-      VIR_DOMAIN_EVENT_RESUMED,
-      VIR_DOMAIN_EVENT_STOPPED,
-      VIR_DOMAIN_EVENT_SAVED,
-      VIR_DOMAIN_EVENT_RESTORED,
+      VIR_DOMAIN_EVENT_ADDED = 0,
+      VIR_DOMAIN_EVENT_REMOVED = 1,
+      VIR_DOMAIN_EVENT_STARTED = 2,
+      VIR_DOMAIN_EVENT_SUSPENDED = 3,
+      VIR_DOMAIN_EVENT_RESUMED = 4,
+      VIR_DOMAIN_EVENT_STOPPED = 5,
+      VIR_DOMAIN_EVENT_SAVED = 6,
+      VIR_DOMAIN_EVENT_RESTORED = 7,
 } virDomainEventType;
 
 /**


-- 
|: Red Hat, Engineering, London   -o-   http://people.redhat.com/berrange/ :|
|: http://libvirt.org  -o-  http://virt-manager.org  -o-  http://ovirt.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505  -o-  F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|




More information about the libvir-list mailing list