Commit c13c591d authored by Arnaud Fontaine's avatar Arnaud Fontaine

ZODB Components: Fix deadlock between import lock and aq_method_lock.

parent 5ad424bf
...@@ -241,25 +241,6 @@ class ComponentDynamicPackage(ModuleType): ...@@ -241,25 +241,6 @@ class ComponentDynamicPackage(ModuleType):
As per PEP-302, raise an ImportError if the Loader could not load the As per PEP-302, raise an ImportError if the Loader could not load the
module for any reason... module for any reason...
""" """
# In Python < 3.3, the import lock is a global lock for all modules:
# http://bugs.python.org/issue9260
#
# So, release the import lock acquired by import statement on all hooks to
# load objects from ZODB. When an object is requested from ZEO, it sends a
# RPC request and lets the asyncore thread gets the reply. This reply may
# be a tuple (PICKLE, TID), sent directly to the first thread, or an
# Exception, which tries to import a ZODB module and thus creates a
# deadlock because of the global import lock
#
# Also, handle the case where find_module() may be called without import
# statement as it does change anything in sys.modules
import_lock_held = True
try:
imp.release_lock()
except RuntimeError:
import_lock_held = False
try:
site = getSite() site = getSite()
name = fullname[len(self._namespace_prefix):] name = fullname[len(self._namespace_prefix):]
...@@ -327,15 +308,8 @@ class ComponentDynamicPackage(ModuleType): ...@@ -327,15 +308,8 @@ class ComponentDynamicPackage(ModuleType):
source_code_str = component.getTextContent(validated_only=True) source_code_str = component.getTextContent(validated_only=True)
version_package = self._getVersionPackage(version) version_package = self._getVersionPackage(version)
finally:
# Internal release of import lock at the end of import machinery will
# fail if the hook is not acquired
if import_lock_held:
imp.acquire_lock()
# All the required objects have been loaded, acquire import lock to modify # All the required objects have been loaded, acquire import lock to modify
# sys.modules and execute PEP302 requisites # sys.modules and execute PEP302 requisites
if not import_lock_held:
imp.acquire_lock() imp.acquire_lock()
try: try:
# The module *must* be in sys.modules before executing the code in case # The module *must* be in sys.modules before executing the code in case
...@@ -393,10 +367,6 @@ class ComponentDynamicPackage(ModuleType): ...@@ -393,10 +367,6 @@ class ComponentDynamicPackage(ModuleType):
return module return module
finally: finally:
# load_module() can be called outside of import machinery, for example
# to check first if the module can be handled by Component and then try
# to load it without going through the same code again
if not import_lock_held:
imp.release_lock() imp.release_lock()
def load_module(self, fullname): def load_module(self, fullname):
...@@ -404,8 +374,34 @@ class ComponentDynamicPackage(ModuleType): ...@@ -404,8 +374,34 @@ class ComponentDynamicPackage(ModuleType):
Make sure that loading module is thread-safe using aq_method_lock to make Make sure that loading module is thread-safe using aq_method_lock to make
sure that modules do not disappear because of an ongoing reset sure that modules do not disappear because of an ongoing reset
""" """
with aq_method_lock: # In Python < 3.3, the import lock is a global lock for all modules:
# http://bugs.python.org/issue9260
#
# So, release the import lock acquired by import statement on all hooks to
# load objects from ZODB. When an object is requested from ZEO, it sends a
# RPC request and lets the asyncore thread gets the reply. This reply may
# be a tuple (PICKLE, TID), sent directly to the first thread, or an
# Exception, which tries to import a ZODB module and thus creates a
# deadlock because of the global import lock
#
# Also, handle the case where find_module() may be called without import
# statement as it does change anything in sys.modules
import_lock_held = True
try:
imp.release_lock()
except RuntimeError:
import_lock_held = False
aq_method_lock.acquire()
try:
return self.__load_module(fullname) return self.__load_module(fullname)
finally:
aq_method_lock.release()
# Internal release of import lock at the end of import machinery will
# fail if the hook is not acquired
if import_lock_held:
imp.acquire_lock()
def find_load_module(self, name): def find_load_module(self, name):
""" """
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment