From 9c63dab390521999d8afb55c55168d0eba53d41d Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Wed, 25 Jul 2012 11:29:33 +0200 Subject: [PATCH] Use a synchronizing decorator for the dynamic control methods. --- src/calibre/devices/interface.py | 25 ++++++++++++++------- src/calibre/gui2/device.py | 38 +++++++++----------------------- 2 files changed, 28 insertions(+), 35 deletions(-) diff --git a/src/calibre/devices/interface.py b/src/calibre/devices/interface.py index 1466732169..c9e62bcfca 100644 --- a/src/calibre/devices/interface.py +++ b/src/calibre/devices/interface.py @@ -514,8 +514,11 @@ class DevicePlugin(Plugin): ''' pass - # Dynamic control interface - # All of these methods are called on the device_manager thread + # Dynamic control interface. + # The following methods are probably called on the GUI thread. Any driver + # that implements these methods must take pains to be thread safe, because + # the device_manager might be using the driver at the same time that one of + # these methods is called. def is_dynamically_controllable(self): ''' @@ -523,7 +526,8 @@ class DevicePlugin(Plugin): a string, then a) it supports the device manager's dynamic control interface, and b) that name is to be used when talking to the plugin. - This method must be called from the device_manager thread. + This method can be called on the GUI thread. A driver that implements + this method must be thread safe. ''' return None @@ -533,7 +537,8 @@ class DevicePlugin(Plugin): to accept device connections however it does that. If the plugin is already accepting connections, then do nothing. - This method must be called from the device_manager thread. + This method can be called on the GUI thread. A driver that implements + this method must be thread safe. ''' pass @@ -544,7 +549,8 @@ class DevicePlugin(Plugin): this method should call shutdown. If the plugin is already not accepting connections, then do nothing. - This method must be called from the device_manager thread. + This method can be called on the GUI thread. A driver that implements + this method must be thread safe. ''' pass @@ -554,7 +560,8 @@ class DevicePlugin(Plugin): be called when the plugin is not started. Return None if the option does not exist. - This method must be called from the device_manager thread. + This method can be called on the GUI thread. A driver that implements + this method must be thread safe. ''' return default @@ -563,7 +570,8 @@ class DevicePlugin(Plugin): Set the value of the option indicated by opt_string. This method can be called when the plugin is not started. - This method must be called from the device_manager thread. + This method can be called on the GUI thread. A driver that implements + this method must be thread safe. ''' pass @@ -571,7 +579,8 @@ class DevicePlugin(Plugin): ''' Return True if the plugin is started, otherwise false - This method must be called from the device_manager thread. + This method can be called on the GUI thread. A driver that implements + this method must be thread safe. ''' return False diff --git a/src/calibre/gui2/device.py b/src/calibre/gui2/device.py index f08f87bf80..d4b8aa0e9b 100644 --- a/src/calibre/gui2/device.py +++ b/src/calibre/gui2/device.py @@ -148,8 +148,6 @@ class DeviceManager(Thread): # {{{ self.call_shutdown_on_disconnect = False self.devices_initialized = Event() self.dynamic_plugins = {} - self.dynamic_plugin_requests = Queue.Queue(0) - self.dynamic_plugin_responses = Queue.Queue(0) def report_progress(self, *args): pass @@ -329,15 +327,8 @@ class DeviceManager(Thread): # {{{ self.current_job = None else: break - while True: - dynamic_method = None - try: - (dynamic_method, args, kwargs) = \ - self.dynamic_plugin_requests.get(timeout=self.sleep_time) - res = dynamic_method(*args, **kwargs) - self.dynamic_plugin_responses.put(res) - except Queue.Empty: - break + time.sleep(self.sleep_time) + # We are exiting. Call the shutdown method for each plugin for p in self.devices: try: @@ -528,36 +519,29 @@ class DeviceManager(Thread): # {{{ # dynamic plugin interface # This is a helper function that handles queueing with the device manager - def _queue_request(self, name, method, *args, **kwargs): - if not is_gui_thread(): - raise ValueError( - 'The device_manager dynamic plugin methods must be called from the GUI thread') - try: - d = self.dynamic_plugins.get(name, None) - if d: - self.dynamic_plugin_requests.put((getattr(d, method), args, kwargs)) - return self.dynamic_plugin_responses.get() - except: - traceback.print_exc() + def _call_request(self, name, method, *args, **kwargs): + d = self.dynamic_plugins.get(name, None) + if d: + return getattr(d, method)(*args, **kwargs) return kwargs.get('default', None) # The dynamic plugin methods below must be called on the GUI thread. They # will switch to the device thread before calling the plugin. def start_plugin(self, name): - self._queue_request(name, 'start_plugin') + self._call_request(name, 'start_plugin') def stop_plugin(self, name): - self._queue_request(name, 'stop_plugin') + self._call_request(name, 'stop_plugin') def get_option(self, name, opt_string, default=None): - return self._queue_request(name, 'get_option', opt_string, default=default) + return self._call_request(name, 'get_option', opt_string, default=default) def set_option(self, name, opt_string, opt_value): - self._queue_request(name, 'set_option', opt_string, opt_value) + self._call_request(name, 'set_option', opt_string, opt_value) def is_running(self, name): - if self._queue_request(name, 'is_running'): + if self._call_request(name, 'is_running'): return True return False