[pyatspi2] Add thread safety around main loop invocations
- From: Mike Gorse <mgorse src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [pyatspi2] Add thread safety around main loop invocations
- Date: Fri, 30 Jul 2010 14:49:38 +0000 (UTC)
commit a120558880f43f0be148ff3f2e8fc2ad779659ff
Author: Mike Gorse <mgorse novell com>
Date: Fri Jul 30 10:48:53 2010 -0400
Add thread safety around main loop invocations
Avoid running a main loop in two separate threads. Prevents deadlock in, ie,
Strongwind tests with listeners that start the registry in a separate thread
while making calls in the main thread.
pyatspi/accessible.py | 3 +++
pyatspi/appevent.py | 2 +-
pyatspi/busutils/bus.py | 11 ++++++-----
pyatspi/busutils/proxy.py | 30 ++++++++++++++++++++++++------
pyatspi/cache.py | 4 ++--
pyatspi/deviceevent.py | 3 ++-
pyatspi/factory.py | 3 ++-
pyatspi/registry.py | 28 +++++++++++++++++++++++++++-
pyatspi/selection.py | 6 +++++-
9 files changed, 72 insertions(+), 18 deletions(-)
---
diff --git a/pyatspi/accessible.py b/pyatspi/accessible.py
index 61515b6..0c7e633 100644
--- a/pyatspi/accessible.py
+++ b/pyatspi/accessible.py
@@ -428,6 +428,9 @@ class Accessible(BaseProxy):
@return : a StateSet encapsulating the currently true states
of the object.
"""
+ if self.getRole() == 78:
+ print "embedded"
+ return self[0].getState()
if self.cached:
return _marshal_state_set(self._cached_data.state)
else:
diff --git a/pyatspi/appevent.py b/pyatspi/appevent.py
index fcc63be..304c585 100644
--- a/pyatspi/appevent.py
+++ b/pyatspi/appevent.py
@@ -306,7 +306,7 @@ class Event(object):
class _ApplicationEventRegister (object):
def __init__ (self, factory):
- self._bus = AsyncAccessibilityBus ()
+ self._bus = AsyncAccessibilityBus (registry.Registry())
self._factory = factory
self._event_listeners = {}
diff --git a/pyatspi/busutils/bus.py b/pyatspi/busutils/bus.py
index ddbe42c..00652f7 100644
--- a/pyatspi/busutils/bus.py
+++ b/pyatspi/busutils/bus.py
@@ -24,7 +24,6 @@ import gobject
from proxy import AccessibilityProxy
import sys
-import traceback
def _get_accessibility_bus_address ():
@@ -114,7 +113,7 @@ class AsyncAccessibilityBus (_AccessibilityBus):
_shared_instance = None
- def __new__ (cls):
+ def __new__ (cls, registry):
if AsyncAccessibilityBus._shared_instance:
return AsyncAccessibilityBus._shared_instance
else:
@@ -127,11 +126,12 @@ class AsyncAccessibilityBus (_AccessibilityBus):
return AsyncAccessibilityBus._shared_instance
- def __init__ (self):
+ def __init__ (self, registry):
try:
_AccessibilityBus.__init__ (self, _get_accessibility_bus_address(), None)
except Exception:
_AccessibilityBus.__init__ (self, _bus.BusConnection.TYPE_SESSION, None)
+ self.registry = registry
class SyncAccessibilityBus (_bus.BusConnection):
"""
@@ -140,7 +140,7 @@ class SyncAccessibilityBus (_bus.BusConnection):
_shared_instance = None
- def __new__ (cls):
+ def __new__ (cls, registry):
if SyncAccessibilityBus._shared_instance:
return SyncAccessibilityBus._shared_instance
else:
@@ -153,8 +153,9 @@ class SyncAccessibilityBus (_bus.BusConnection):
return SyncAccessibilityBus._shared_instance
- def __init__ (self):
+ def __init__ (self, registry):
try:
_bus.BusConnection.__init__ (self, _get_accessibility_bus_address(), None)
except Exception:
_bus.BusConnection.__init__ (self, _bus.BusConnection.TYPE_SESSION, None)
+ self.registry = registry
diff --git a/pyatspi/busutils/proxy.py b/pyatspi/busutils/proxy.py
index 6f84160..9bff254 100644
--- a/pyatspi/busutils/proxy.py
+++ b/pyatspi/busutils/proxy.py
@@ -14,6 +14,7 @@
import dbus.connection as _connection
import gobject
+import threading
import Queue
@@ -39,10 +40,15 @@ class AccessibilityProxy (_connection.ProxyObject):
_main_loop_pool = _MainLoopPool ()
class DBusMethodCallbackData (object):
- def __init__ (self):
+ def __init__ (self, proxy):
# Will raise the Empty exception if we have hit
# The re-entrancy limit
- self.loop = AccessibilityProxy._main_loop_pool.get_nowait ()
+ if proxy._bus.registry.has_implementations == False or proxy._bus.registry.started == False or threading.currentThread() == proxy._bus.registry.thread:
+ self.event = None
+ self.loop = AccessibilityProxy._main_loop_pool.get_nowait ()
+ else:
+ self.event = threading.Event()
+ self.loop = None
self.error = None
self.args = None
@@ -58,14 +64,18 @@ class AccessibilityProxy (_connection.ProxyObject):
#print ("\t" * depth) + "Depth=" + str(gobject.main_depth())
#print
- data = AccessibilityProxy.DBusMethodCallbackData()
+ self._bus.registry.acquireLock()
+ data = AccessibilityProxy.DBusMethodCallbackData(self)
def method_error_callback (e):
data.error = e
def main_quit ():
data.loop.quit()
return False
- gobject.idle_add (main_quit)
+ if data.event is not None:
+ data.event.set()
+ else:
+ gobject.idle_add (main_quit)
def method_reply_callback (*jargs):
@@ -79,7 +89,11 @@ class AccessibilityProxy (_connection.ProxyObject):
def main_quit ():
data.loop.quit()
return False
- gobject.idle_add (main_quit)
+
+ if data.event is not None:
+ data.event.set()
+ else:
+ gobject.idle_add (main_quit)
method (reply_handler=method_reply_callback,
error_handler=method_error_callback,
@@ -87,9 +101,13 @@ class AccessibilityProxy (_connection.ProxyObject):
**ikwargs)
self._bus.freezeEvents()
- data.loop.run ()
+ if data.event is not None:
+ data.event.wait()
+ else:
+ data.loop.run ()
AccessibilityProxy._main_loop_pool.put_nowait (data.loop)
self._bus.thawEvents()
+ self._bus.registry.releaseLock()
#depth = gobject.main_depth()
#print ("\t" * depth) + "Post-recurse"
diff --git a/pyatspi/cache.py b/pyatspi/cache.py
index 507a657..207a8d4 100644
--- a/pyatspi/cache.py
+++ b/pyatspi/cache.py
@@ -84,7 +84,7 @@ class DesktopCacheManager (object):
"""
def __init__(self, cache):
- bus = SyncAccessibilityBus ()
+ bus = SyncAccessibilityBus (registry.Registry())
self._cache = cache
self._application_list = {}
@@ -215,7 +215,7 @@ class ApplicationCacheManager (object):
"""
# It is important that this bus is async as registered signals may
# come from orca itself.
- bus = AsyncAccessibilityBus()
+ bus = AsyncAccessibilityBus(registry.Registry())
self._cache = cache
self._bus_name = bus_name
diff --git a/pyatspi/deviceevent.py b/pyatspi/deviceevent.py
index 719af11..081bc39 100644
--- a/pyatspi/deviceevent.py
+++ b/pyatspi/deviceevent.py
@@ -13,6 +13,7 @@
#Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
from interfaces import *
+import registry
import dbus as _dbus
import dbus.service as _service
@@ -534,7 +535,7 @@ class KeyboardDeviceEventListener(_service.Object):
class _DeviceEventRegister (object):
def __init__ (self):
- self._bus = SyncAccessibilityBus ()
+ self._bus = SyncAccessibilityBus (registry.Registry())
self.dev = DeviceEventController (self._bus)
self.deviceClients = {}
diff --git a/pyatspi/factory.py b/pyatspi/factory.py
index 9b31b15..1a4d783 100644
--- a/pyatspi/factory.py
+++ b/pyatspi/factory.py
@@ -13,6 +13,7 @@
#Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
import interfaces
+import registry
from accessible import *
from action import *
@@ -47,7 +48,7 @@ class AccessibleFactory (object):
def __init__ (self, cache):
- self._connection = AsyncAccessibilityBus()
+ self._connection = AsyncAccessibilityBus(registry.Registry())
self._interfaces = {
interfaces.ATSPI_ACCESSIBLE:Accessible,
diff --git a/pyatspi/registry.py b/pyatspi/registry.py
index 4f58307..3d3eaf5 100644
--- a/pyatspi/registry.py
+++ b/pyatspi/registry.py
@@ -24,6 +24,8 @@
import dbus
import os as _os
import Queue
+import threading
+import time
import traceback
from busutils import *
@@ -136,7 +138,7 @@ class Registry(object):
_os.environ["AT_SPI_CLIENT"] = "1"
# Set up the device event controllers
- _connection = SyncAccessibilityBus ()
+ _connection = SyncAccessibilityBus (self)
_bus_object = _connection.get_object("org.freedesktop.DBus", "/org/freedesktop/DBus")
if app_name:
@@ -174,8 +176,16 @@ class Registry(object):
"""
if not self.has_implementations:
self._set_default_registry ()
+ self.acquireLock()
+ self.thread = threading.currentThread()
self.started = True
+
+ def idleReleaseLock():
+ self.releaseLock()
+ return False
+
try:
+ gobject.idle_add(idleReleaseLock)
self.main_loop.run()
except KeyboardInterrupt:
pass
@@ -392,6 +402,22 @@ class Registry(object):
self._set_default_registry ()
self.device_event_register.generateMouseEvent (x, y, name)
+ def acquireLock(self):
+ """
+ Acquire a lock, creating the registry irst if needed.
+ """
+ try:
+ self.lock.acquire()
+ except AttributeError:
+ self.lock = threading.Lock()
+ self.lock.acquire()
+
+ def releaseLock(self):
+ """
+ Release the lock
+ """
+ self.lock.release()
+
#------------------------------------------------------------------------------
def set_default_registry (main_loop, app_name=None):
diff --git a/pyatspi/selection.py b/pyatspi/selection.py
index ef8a25f..b52d962 100644
--- a/pyatspi/selection.py
+++ b/pyatspi/selection.py
@@ -119,8 +119,12 @@ class Selection(Accessible):
be selected.
@return True if the child was successfully selected, False otherwise.
"""
+ print "calling selectChild"
func = self.get_dbus_method("SelectChild", dbus_interface=ATSPI_SELECTION)
- return func(index)
+ print "calling"
+ val = func(index)
+ print "called"
+ return val
def get_nSelectedChildren(self):
return dbus.Int32(self._pgetter(ATSPI_SELECTION, "NSelectedChildren"))
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]