[pypy-svn] r46589 - in pypy/dist/pypy/module/thread: . test

arigo at codespeak.net arigo at codespeak.net
Fri Sep 14 20:29:04 CEST 2007


Author: arigo
Date: Fri Sep 14 20:29:04 2007
New Revision: 46589

Added:
   pypy/dist/pypy/module/thread/error.py   (contents, props changed)
Modified:
   pypy/dist/pypy/module/thread/gil.py
   pypy/dist/pypy/module/thread/ll_thread.py
   pypy/dist/pypy/module/thread/os_lock.py
   pypy/dist/pypy/module/thread/os_thread.py
   pypy/dist/pypy/module/thread/test/test_thread.py
Log:
Fix error handling (at least, attempt to).
Note that there is a race condition somewhere on top of py.py
making test_local crash but very rarely :-((


Added: pypy/dist/pypy/module/thread/error.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/module/thread/error.py	Fri Sep 14 20:29:04 2007
@@ -0,0 +1,6 @@
+from pypy.interpreter.error import OperationError
+
+def reraise_thread_error(space, msg):
+    w_module = space.getbuiltinmodule('thread')
+    w_error = space.getattr(w_module, space.wrap('error'))
+    raise OperationError(w_error, space.wrap(msg))

Modified: pypy/dist/pypy/module/thread/gil.py
==============================================================================
--- pypy/dist/pypy/module/thread/gil.py	(original)
+++ pypy/dist/pypy/module/thread/gil.py	Fri Sep 14 20:29:04 2007
@@ -8,6 +8,7 @@
 # from time to time, using the executioncontext's XXX
 
 from pypy.module.thread import ll_thread as thread
+from pypy.module.thread.error import reraise_thread_error
 from pypy.interpreter.miscutils import Action
 from pypy.module.thread.threadlocals import OSThreadLocals
 from pypy.rlib.objectmodel import invoke_around_extcall
@@ -19,7 +20,10 @@
     def setup_threads(self, space):
         """Enable threads in the object space, if they haven't already been."""
         if self.GIL is None:
-            self.GIL = thread.allocate_lock_NOAUTO()
+            try:
+                self.GIL = thread.allocate_lock_NOAUTO()
+            except thread.error:
+                reraise_thread_error(space, "can't allocate GIL")
             self.enter_thread(space)   # setup the main thread
             # add the GIL-releasing callback as an action on the space
             space.pending_actions.append(GILReleaseAction(self))

Modified: pypy/dist/pypy/module/thread/ll_thread.py
==============================================================================
--- pypy/dist/pypy/module/thread/ll_thread.py	(original)
+++ pypy/dist/pypy/module/thread/ll_thread.py	Fri Sep 14 20:29:04 2007
@@ -11,11 +11,8 @@
 from pypy.annotation import model as annmodel
 from pypy.rpython.lltypesystem.lltype import typeOf
 from pypy.rlib.objectmodel import debug_assert
-from pypy.rlib.nonconst import NonConstant
 
-class error(Exception):
-    def __init__(self, msg):
-        self.msg = msg
+error = thread.error
 
 from pypy.tool.autopath import pypydir
 pypydir = py.path.local(pypydir)
@@ -138,7 +135,7 @@
         # Sanity check: the lock must be locked
         if self.acquire(False):
             c_thread_releaselock(self._lock)
-            raise error(NonConstant("bad lock"))
+            raise error("bad lock")
         else:
             c_thread_releaselock(self._lock)
 

Modified: pypy/dist/pypy/module/thread/os_lock.py
==============================================================================
--- pypy/dist/pypy/module/thread/os_lock.py	(original)
+++ pypy/dist/pypy/module/thread/os_lock.py	Fri Sep 14 20:29:04 2007
@@ -3,7 +3,7 @@
 """
 
 from pypy.module.thread import ll_thread as thread
-from pypy.interpreter.error import OperationError
+from pypy.module.thread.error import reraise_thread_error
 from pypy.interpreter.baseobjspace import Wrappable
 from pypy.interpreter.gateway import ObjSpace, interp2app
 from pypy.interpreter.typedef import TypeDef
@@ -29,9 +29,11 @@
 class Lock(Wrappable):
     "A wrappable box around an interp-level lock object."
 
-    def __init__(self):
-        # XXX catch thread.error!
-        self.lock = thread.allocate_lock()
+    def __init__(self, space):
+        try:
+            self.lock = thread.allocate_lock()
+        except thread.error:
+            reraise_thread_error(space, "out of resources")
 
     def descr_lock_acquire(self, space, waitflag=1):
         """Lock the lock.  Without argument, this blocks if the lock is already
@@ -51,9 +53,7 @@
         try:
             self.lock.release()
         except thread.error:
-            w_module = space.getbuiltinmodule('thread')
-            w_error = space.getattr(w_module, space.wrap('error'))
-            raise OperationError(w_error, space.wrap("release unlocked lock"))
+            reraise_thread_error(space, "release unlocked lock")
 
     def descr_lock_locked(self, space):
         """Return whether the lock is in the locked state."""
@@ -96,7 +96,7 @@
 def allocate_lock(space):
     """Create a new lock object.  (allocate() is an obsolete synonym.)
 See LockType.__doc__ for information about locks."""
-    return space.wrap(Lock())
+    return space.wrap(Lock(space))
 
 def getlocktype(space):
     return space.gettypeobject(Lock.typedef)

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	Fri Sep 14 20:29:04 2007
@@ -3,6 +3,7 @@
 """
 
 from pypy.module.thread import ll_thread as thread
+from pypy.module.thread.error import reraise_thread_error
 from pypy.interpreter.error import OperationError
 from pypy.interpreter.gateway import NoneNotWrapped
 from pypy.interpreter.gateway import ObjSpace, W_Root, Arguments
@@ -81,7 +82,10 @@
     boot.space      = space
     boot.w_callable = w_callable
     boot.args       = args
-    ident = thread.start_new_thread(Bootstrapper.bootstrap, (boot,))
+    try:
+        ident = thread.start_new_thread(Bootstrapper.bootstrap, (boot,))
+    except thread.error:
+        reraise_thread_error(space, "can't start new thread")
     return space.wrap(ident)
 
 

Modified: pypy/dist/pypy/module/thread/test/test_thread.py
==============================================================================
--- pypy/dist/pypy/module/thread/test/test_thread.py	(original)
+++ pypy/dist/pypy/module/thread/test/test_thread.py	Fri Sep 14 20:29:04 2007
@@ -1,7 +1,31 @@
+import thread, time
 from pypy.module.thread.test.support import GenericTestThread
 
 class AppTestThread(GenericTestThread):
 
+    def setup_class(cls):
+        GenericTestThread.setup_class.im_func(cls)
+        # if we cannot start more than, say, 1000 threads on this OS, then
+        # we can check that we get the proper error at app-level
+        space = cls.space
+        lock = thread.allocate_lock()
+        lock.acquire()
+        def f():
+            lock.acquire()
+            lock.release()
+        try:
+            try:
+                for i in range(1000):
+                    thread.start_new_thread(f, ())
+            finally:
+                lock.release()
+                # wait a bit to allow most threads to finish now
+                time.sleep(0.5)
+        except (thread.error, MemoryError):
+            cls.w_can_start_many_threads = space.w_False
+        else:
+            cls.w_can_start_many_threads = space.w_True
+
     def test_start_new_thread(self):
         import thread
         feedback = []
@@ -141,3 +165,25 @@
             self.waitfor(lambda: done, delay=3)
             assert done    # see stderr for failures in threads
         assert sorted(lst) == range(120)
+
+    def test_many_threads(self):
+        import thread, time
+        if self.can_start_many_threads:
+            skip("this OS supports too many threads to check (> 1000)")
+        lock = thread.allocate_lock()
+        lock.acquire()
+        def f():
+            lock.acquire()
+            lock.release()
+        try:
+            try:
+                for i in range(1000):
+                    thread.start_new_thread(f, ())
+            finally:
+                lock.release()
+                # wait a bit to allow most threads to finish now
+                self.busywait(2.0)
+        except (thread.error, MemoryError):
+            pass
+        else:
+            raise Exception("could unexpectedly start 1000 threads")



More information about the Pypy-commit mailing list