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

arigo at codespeak.net arigo at codespeak.net
Thu Aug 25 19:30:18 CEST 2005


Author: arigo
Date: Thu Aug 25 19:30:16 2005
New Revision: 16534

Modified:
   pypy/dist/pypy/module/thread/gil.py
   pypy/dist/pypy/module/thread/os_thread.py
   pypy/dist/pypy/module/thread/test/support.py
   pypy/dist/pypy/module/thread/test/test_thread.py
Log:
(pedronis, arigo)

For the translated PyPy, we need to be extra super careful about making
thread.start_new_thread() thread-safe (argh).


Modified: pypy/dist/pypy/module/thread/gil.py
==============================================================================
--- pypy/dist/pypy/module/thread/gil.py	(original)
+++ pypy/dist/pypy/module/thread/gil.py	Thu Aug 25 19:30:16 2005
@@ -31,6 +31,7 @@
     def yield_thread(self):
         """Notification that the current thread is between two bytecodes:
         release the GIL for a little while."""
-        self.GIL.release()
+        GIL = self.GIL
+        GIL.release()
         # Other threads can run here
-        self.GIL.acquire(True)
+        GIL.acquire(True)

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	Thu Aug 25 19:30:16 2005
@@ -11,26 +11,45 @@
 import pypy.module.thread.rpython.exttable
 
 
+THREAD_STARTUP_LOCK = thread.allocate_lock()
+
+
 class Bootstrapper:
     def bootstrap(self):
-        space      = self.space
-        w_callable = self.w_callable
-        args       = self.args
+        space = self.space
+        THREAD_STARTUP_LOCK.release()
         space.threadlocals.enter_thread(space)
         try:
-            try:
-                space.call_args(w_callable, args)
-            except OperationError, e:
-                if not e.match(space, space.w_SystemExit):
-                    ident = thread.get_ident()
-                    where = 'thread %d started by' % ident
-                    e.write_unraisable(space, where, w_callable)
-                e.clear(space)
+            self.run()
         finally:
+            # release ownership of these objects before we release the GIL
+            self.args       = None
+            self.w_callable = None
+            self.space      = None
+            # at this point the thread should only have a reference to
+            # an empty 'self'.  We hold the last reference to 'self'; indeed,
+            # the parent thread already forgot about it because the above
+            # enter_thread() must have blocked until long after the call to
+            # start_new_thread() below returned.
+            # (be careful of resetting *all* local variables to None here!)
+
             # clean up space.threadlocals to remove the ExecutionContext
             # entry corresponding to the current thread
             space.threadlocals.leave_thread(space)
 
+    def run(self):
+        space      = self.space
+        w_callable = self.w_callable
+        args       = self.args
+        try:
+            space.call_args(w_callable, args)
+        except OperationError, e:
+            if not e.match(space, space.w_SystemExit):
+                ident = thread.get_ident()
+                where = 'thread %d started by' % ident
+                e.write_unraisable(space, where, w_callable)
+            e.clear(space)
+
 
 def start_new_thread(space, w_callable, w_args, w_kwargs=NoneNotWrapped):
     """Start a new thread and return its identifier.  The thread will call the
@@ -47,7 +66,16 @@
     boot.space      = space
     boot.w_callable = w_callable
     boot.args       = args
+
+    THREAD_STARTUP_LOCK.acquire(True)
+
     ident = thread.start_new_thread(Bootstrapper.bootstrap, (boot,))
+
+    # wait until the thread has really started and acquired a reference to
+    # 'boot'.
+    THREAD_STARTUP_LOCK.acquire(True)
+    THREAD_STARTUP_LOCK.release()
+
     return space.wrap(ident)
 
 

Modified: pypy/dist/pypy/module/thread/test/support.py
==============================================================================
--- pypy/dist/pypy/module/thread/test/support.py	(original)
+++ pypy/dist/pypy/module/thread/test/support.py	Thu Aug 25 19:30:16 2005
@@ -12,7 +12,7 @@
             def waitfor(expr, timeout=10.0):
                 limit = time.time() + timeout
                 while time.time() <= limit:
-                    time.sleep(0.005)
+                    time.sleep(0.002)
                     if expr():
                         return
                 print '*** timed out ***'
@@ -23,6 +23,6 @@
             def busywait(t):
                 limit = time.time() + t
                 while time.time() <= limit:
-                    time.sleep(0.005)
+                    time.sleep(0.002)
             return busywait
         """)

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	Thu Aug 25 19:30:16 2005
@@ -123,6 +123,6 @@
             thread.start_new_thread(f, (i, done))
             done_marker.append(done)
         for done in done_marker:
-            self.waitfor(lambda: done, timeout=20.0)
+            self.waitfor(lambda: done, timeout=30.0)
             assert done    # see stderr for failures in threads
         assert sorted(lst) == range(120)



More information about the Pypy-commit mailing list