Signals in Python without glib
Justin Mazzola Paluska
jmp at MIT.EDU
Thu Jul 27 02:53:16 PDT 2006
On Wed, Jul 26, 2006 at 10:30:43AM -0400, John (J5) Palmieri wrote:
> What would be nice is to wrap this in the lower level bindings
> directly and then add a method on the Bus class in _dbus.py.
> Perhaps even have something like
>
> connection = dbus.SessionBus()
> connection.generic_main_loop()
>
> Make sure the method is clear that a person shouldn't be using this
> if they can be using a real main loop.
I added a read_write_dispatch(timeout) method to the low-level
DBUSConnection bindings and then wrote the Bus.generic_main_loop()
function. Please see the attached patch. It seems to be working on
my machine with Python 2.4.4c0 and D-BUS 0.62.
The main complication in this basic version was remembering to release
the GIL when I call dbus_connection_read_write_dispatch.
There are improvements that can be made to it:
- make the read_write_dispatch method more "Pythonic", that is, take
in a float as a number of seconds to block, like time.sleep.
- make the system work on non-threaded Python systems. In the 'cdef
extern from "Python.h"' block of code, I include API only defined on
threaded Python systems.
<http://article.gmane.org/gmane.comp.python.pyrex/967> has the no-op
defs that should be used on non-threaded Pythons, but I don't know
how to do ifdefs with Pyrex.
- write tests. I see that the Python bindings include a tests
directory with some unittests that use the glib mainloop. Should I
extend the test file to use the brain-dead mainloop?
Let me know if you are amenable to the patch and my proposed changes
and make a new patch with the changes.
--Justin
-------------- next part --------------
diff --git a/dbus/_dbus.py b/dbus/_dbus.py
index 7e17d9f..8700963 100644
--- a/dbus/_dbus.py
+++ b/dbus/_dbus.py
@@ -240,6 +240,20 @@ class Bus(object):
def start_service_by_name(self, named_service):
return dbus_bindings.bus_start_service_by_name(self._connection, named_service)
+ def generic_main_loop(self):
+
+ """ Run a brain-dead simple mainloop.
+
+ If you can use a real mainloop, like the Glib one, you're best
+ off using that.
+
+ This function will return only after the bus has been
+ disconnected."""
+
+ while self._connection.read_write_dispatch():
+ pass
+ return
+
def __repr__(self):
if self._bus_type == self.TYPE_SESSION:
name = 'SESSION'
diff --git a/dbus/dbus_bindings.pyx b/dbus/dbus_bindings.pyx
index c29dea2..4e9045c 100644
--- a/dbus/dbus_bindings.pyx
+++ b/dbus/dbus_bindings.pyx
@@ -25,6 +25,9 @@ cdef extern from "Python.h":
void PyErr_Clear()
PyGILState_STATE PyGILState_Ensure()
void PyGILState_Release(PyGILState_STATE)
+ struct PyThreadState
+ PyThreadState* PyEval_SaveThread()
+ void PyEval_RestoreThread(PyThreadState *tstate)
ctypedef struct DBusError:
char *name
@@ -387,6 +390,27 @@ cdef class Connection:
def dispatch(self):
return dbus_connection_dispatch(self.conn)
+ def read_write_dispatch(self,
+ timeout=None):
+
+ # `read_write_dispatch blocks`, so we need to make sure that
+ # we *don't* hold the GIL. The cdefs force Pyrex to convert
+ # our Python objects before we release the GIL.
+
+ cdef int to, rval
+ cdef PyThreadState *_save
+
+ if timeout is None:
+ timeout = -1
+ to = timeout
+
+ _save = PyEval_SaveThread()
+ rval = dbus_connection_read_write_dispatch(self.conn,
+ to)
+ PyEval_RestoreThread(_save)
+
+ return rval
+
def send(self, Message message):
#cdef dbus_uint32_t client_serial
#if type(message) != Message:
More information about the dbus
mailing list