[pypy-svn] r46639 - in pypy/dist/pypy: lib module/__builtin__ module/thread module/thread/test
arigo at codespeak.net
arigo at codespeak.net
Sat Sep 15 15:39:55 CEST 2007
Author: arigo
Date: Sat Sep 15 15:39:55 2007
New Revision: 46639
Modified:
pypy/dist/pypy/lib/imp.py
pypy/dist/pypy/module/__builtin__/importing.py
pypy/dist/pypy/module/thread/__init__.py
pypy/dist/pypy/module/thread/os_thread.py
pypy/dist/pypy/module/thread/test/test_import_lock.py
Log:
Move the import lock at interp-level. This is less of a hack,
and it also has the advantage that it can be slightly finer-grained.
Something easy to satisfy like 'import sys' should not block even if
another thread has acquired the import lock.
Modified: pypy/dist/pypy/lib/imp.py
==============================================================================
--- pypy/dist/pypy/lib/imp.py (original)
+++ pypy/dist/pypy/lib/imp.py Sat Sep 15 15:39:55 2007
@@ -140,73 +140,3 @@
def is_frozen(name):
return False
-
-
-# ____________________________________________________________
-
-try:
- # PyPy-specific interface: hint from the thread module to ask us to
- # provide an import lock
- from thread import _please_provide_import_lock
-except ImportError:
- def lock_held():
- """On platforms without threads, return False."""
- return False
- def acquire_lock():
- """On platforms without threads, this function does nothing."""
- def release_lock():
- """On platforms without threads, this function does nothing."""
-
-else:
- del _please_provide_import_lock
- import thread
-
- class _ImportLock:
- def __init__(self):
- self.lock = thread.allocate_lock()
- self.in_thread = None
- self.recursions = 0
-
- def held(self):
- """Return True if the import lock is currently held, else False."""
- return self.in_thread is not None
-
- def acquire(self):
- """Acquires the interpreter's import lock for the current thread.
- This lock should be used by import hooks to ensure thread-safety
- when importing modules.
- """
- myident = thread.get_ident()
- if self.in_thread == myident:
- self.recursions += 1
- else:
- self.lock.acquire()
- self.in_thread = myident
- self.recursions = 1
-
- def release(self):
- """Release the interpreter's import lock."""
- myident = thread.get_ident()
- if self.in_thread != myident:
- raise RuntimeError("not holding the import lock")
- self.recursions -= 1
- if self.recursions == 0:
- self.in_thread = None
- self.lock.release()
-
- _importlock = _ImportLock()
-
- lock_held = _importlock.held
- acquire_lock = _importlock.acquire
- release_lock = _importlock.release
-
- import __builtin__
- _original_import_hook = __builtin__.__import__
- def __lockedimport__(modulename, globals=None, locals=None, fromlist=None):
- acquire_lock()
- try:
- return _original_import_hook(modulename, globals, locals, fromlist)
- finally:
- release_lock()
- __builtin__.__import__ = __lockedimport__
- del __builtin__
Modified: pypy/dist/pypy/module/__builtin__/importing.py
==============================================================================
--- pypy/dist/pypy/module/__builtin__/importing.py (original)
+++ pypy/dist/pypy/module/__builtin__/importing.py Sat Sep 15 15:39:55 2007
@@ -196,6 +196,16 @@
importhook.unwrap_spec = [ObjSpace,str,W_Root,W_Root,W_Root]
def absolute_import(space, modulename, baselevel, w_fromlist, tentative):
+ lock = getimportlock(space)
+ acquired = lock.try_acquire_lock()
+ try:
+ return _absolute_import(space, modulename, baselevel,
+ w_fromlist, tentative)
+ finally:
+ if acquired:
+ lock.release_lock()
+
+def _absolute_import(space, modulename, baselevel, w_fromlist, tentative):
w = space.wrap
w_mod = None
@@ -286,6 +296,45 @@
# __________________________________________________________________
#
+# import lock, to prevent two threads from running module-level code in
+# parallel. This behavior is more or less part of the language specs,
+# as an attempt to avoid failure of 'from x import y' if module x is
+# still being executed in another thread.
+
+class ImportRLock:
+ def __init__(self, space):
+ self.space = space
+ self.lock = None
+ self.lockowner = None
+
+ def _freeze_(self):
+ # remove the lock object, which will be created again as need at
+ # run-time.
+ self.lock = None
+ assert self.lockowner is None
+ return False
+
+ def try_acquire_lock(self):
+ # this function runs with the GIL acquired so there is no race
+ # condition in the creation of the lock
+ if self.lock is None:
+ self.lock = self.space.allocate_lock()
+ me = self.space.getexecutioncontext() # used as thread ident
+ if self.lockowner is me:
+ return False # already acquired by the current thread
+ self.lock.acquire(True)
+ self.lockowner = me
+ return True
+
+ def release_lock(self):
+ self.lockowner = None
+ self.lock.release()
+
+def getimportlock(space):
+ return space.fromcache(ImportRLock)
+
+# __________________________________________________________________
+#
# .pyc file support
"""
Modified: pypy/dist/pypy/module/thread/__init__.py
==============================================================================
--- pypy/dist/pypy/module/thread/__init__.py (original)
+++ pypy/dist/pypy/module/thread/__init__.py Sat Sep 15 15:39:55 2007
@@ -17,7 +17,6 @@
'allocate': 'os_lock.allocate_lock', # obsolete synonym
'LockType': 'os_lock.getlocktype(space)',
'_local': 'os_local.getlocaltype(space)',
- '_please_provide_import_lock': '(space.w_True)', # for imp.py
}
def __init__(self, space, *args):
Modified: pypy/dist/pypy/module/thread/os_thread.py
==============================================================================
--- pypy/dist/pypy/module/thread/os_thread.py (original)
+++ pypy/dist/pypy/module/thread/os_thread.py Sat Sep 15 15:39:55 2007
@@ -52,11 +52,7 @@
def setup_threads(space):
- if space.threadlocals.setup_threads(space):
- # the import lock is in imp.py, which registers a custom import
- # hook with this lock.
- from pypy.module.__builtin__.importing import importhook
- importhook(space, 'imp')
+ space.threadlocals.setup_threads(space)
def start_new_thread(space, w_callable, w_args, w_kwargs=NoneNotWrapped):
Modified: pypy/dist/pypy/module/thread/test/test_import_lock.py
==============================================================================
--- pypy/dist/pypy/module/thread/test/test_import_lock.py (original)
+++ pypy/dist/pypy/module/thread/test/test_import_lock.py Sat Sep 15 15:39:55 2007
@@ -13,3 +13,7 @@
thread.start_new_thread(f, ())
self.waitfor(lambda: len(done) == 5)
assert len(done) == 5
+
+ def test_with_many_dependencies(self):
+ import thread
+ import re # -> causes nested imports
More information about the Pypy-commit
mailing list