[pypy-commit] pypy concurrent-marksweep: Hack hack hack until the translator is sure that the collector thread

arigo noreply at buildbot.pypy.org
Sat Oct 8 14:40:19 CEST 2011


Author: Armin Rigo <arigo at tunes.org>
Branch: concurrent-marksweep
Changeset: r47876:49ab73172117
Date: 2011-10-08 14:39 +0200
http://bitbucket.org/pypy/pypy/changeset/49ab73172117/

Log:	Hack hack hack until the translator is sure that the collector
	thread doesn't do anything with exceptions. This lets us keep the
	global exception state non-thread-local.

diff --git a/pypy/module/thread/ll_thread.py b/pypy/module/thread/ll_thread.py
--- a/pypy/module/thread/ll_thread.py
+++ b/pypy/module/thread/ll_thread.py
@@ -39,6 +39,9 @@
     return rffi.cast(rffi.LONG, ident)
 
 CALLBACK = lltype.Ptr(lltype.FuncType([], lltype.Void))
+c_thread_start_nowrapper = llexternal('RPyThreadStart', [CALLBACK], rffi.LONG,
+                                      _callable=_emulated_start_new_thread,
+                                      _nowrapper=True)
 c_thread_start = llexternal('RPyThreadStart', [CALLBACK], rffi.LONG,
                             _callable=_emulated_start_new_thread,
                             threadsafe=True)  # release the GIL, but most
diff --git a/pypy/rlib/debug.py b/pypy/rlib/debug.py
--- a/pypy/rlib/debug.py
+++ b/pypy/rlib/debug.py
@@ -210,7 +210,7 @@
         c_pythonfunction = hop.inputconst(lltype.Void, pythonfunction)
         args_v = [hop.inputarg(hop.args_r[i], arg=i)
                   for i in range(2, hop.nb_args)]
-        hop.exception_is_here()
+        hop.exception_cannot_occur()
         return hop.genop('debug_llinterpcall', [c_pythonfunction] + args_v,
                          resulttype=RESTYPE)
 
diff --git a/pypy/rpython/lltypesystem/lloperation.py b/pypy/rpython/lltypesystem/lloperation.py
--- a/pypy/rpython/lltypesystem/lloperation.py
+++ b/pypy/rpython/lltypesystem/lloperation.py
@@ -530,8 +530,7 @@
     'debug_flush':          LLOp(canrun=True),
     'debug_assert':         LLOp(tryfold=True),
     'debug_fatalerror':     LLOp(),
-    'debug_llinterpcall':   LLOp(canraise=(Exception,)),
-                                    # Python func call 'res=arg[0](*arg[1:])'
+    'debug_llinterpcall':   LLOp(), # Python func call 'res=arg[0](*arg[1:])'
                                     # in backends, abort() or whatever is fine
     'debug_start_traceback':   LLOp(),
     'debug_record_traceback':  LLOp(),
diff --git a/pypy/rpython/memory/gc/base.py b/pypy/rpython/memory/gc/base.py
--- a/pypy/rpython/memory/gc/base.py
+++ b/pypy/rpython/memory/gc/base.py
@@ -231,7 +231,7 @@
                     j += 1
                 item += itemlength
                 length -= 1
-        if self.has_custom_trace(typeid):
+        if self.has_custom_trace(typeid) and 0: # XXX XXX temporarily disabled
             generator = self.get_custom_trace(typeid)
             item = llmemory.NULL
             while True:
diff --git a/pypy/rpython/memory/gc/concurrentms.py b/pypy/rpython/memory/gc/concurrentms.py
--- a/pypy/rpython/memory/gc/concurrentms.py
+++ b/pypy/rpython/memory/gc/concurrentms.py
@@ -1,6 +1,7 @@
 import time, sys
 from pypy.rpython.lltypesystem import lltype, llmemory, llarena, llgroup, rffi
 from pypy.rpython.lltypesystem.llmemory import raw_malloc_usage
+from pypy.rpython.annlowlevel import llhelper
 from pypy.translator.tool.cbuild import ExternalCompilationInfo
 from pypy.rlib.objectmodel import we_are_translated, running_on_llinterp
 from pypy.rlib.debug import ll_assert
@@ -127,6 +128,7 @@
                     print 'Crash!', e.__class__.__name__, e
                     self._exc_info = sys.exc_info()
         #
+        collector_start._should_never_raise_ = True
         self.collector_start = collector_start
         #
         #self.mutex_lock = ...built in setup()
@@ -150,8 +152,9 @@
         self.acquire(self.finished_lock)
         self.acquire(self.ready_to_start_lock)
         #
-        self.collector_ident = ll_thread.start_new_thread(
-            self.collector_start, ())
+        self.collector_ident = ll_thread.c_thread_start_nowrapper(
+            llhelper(ll_thread.CALLBACK, self.collector_start))
+        assert self.collector_ident != -1
 
     def _teardown(self):
         "Stop the collector thread after tests have run."
@@ -542,7 +545,12 @@
 
     def collector_run(self):
         """Main function of the collector's thread."""
-        while True:
+        #
+        # hack: make it an infinite loop, but in a way that the annotator
+        # doesn't notice.  It prevents the caller from ending automatically
+        # in a "raise AssertionError", annoyingly, because we don't want
+        # any exception in this thread
+        while self.collection_running < 99:
             #
             # Wait for the lock to be released
             self.acquire(self.ready_to_start_lock)
@@ -601,7 +609,7 @@
             # acquired the 'mutex_lock', so all reachable objects have
             # been marked.
             if not self.gray_objects.non_empty():
-                return
+                break
 
     def _collect_mark(self):
         current_mark = self.current_mark
diff --git a/pypy/rpython/memory/support.py b/pypy/rpython/memory/support.py
--- a/pypy/rpython/memory/support.py
+++ b/pypy/rpython/memory/support.py
@@ -1,7 +1,7 @@
-from pypy.rpython.lltypesystem import lltype, llmemory
+from pypy.rpython.lltypesystem import lltype, llmemory, llarena
 from pypy.rlib.objectmodel import free_non_gc_object, we_are_translated
 from pypy.rlib.rarithmetic import r_uint, LONG_BIT
-from pypy.rlib.debug import ll_assert
+from pypy.rlib.debug import ll_assert, fatalerror
 from pypy.tool.identity_dict import identity_dict
 
 
@@ -39,10 +39,17 @@
             if not self.free_list:
                 # we zero-initialize the chunks to make the translation
                 # backends happy, but we don't need to do it at run-time.
-                zero = not we_are_translated()
-                return lltype.malloc(CHUNK, flavor="raw", zero=zero,
-                                     track_allocation=False)
-                
+                if we_are_translated():
+                    zero = 0
+                else:
+                    zero = 2
+                size = llmemory.raw_malloc_usage(llmemory.sizeof(CHUNK))
+                addr = llarena.arena_malloc(size, zero)
+                if not addr:
+                    fatalerror("out of memory in GC support code")
+                llarena.arena_reserve(addr, llmemory.sizeof(CHUNK))
+                return llmemory.cast_adr_to_ptr(addr, lltype.Ptr(CHUNK))
+
             result = self.free_list
             self.free_list = result.next
             return result
diff --git a/pypy/translator/backendopt/canraise.py b/pypy/translator/backendopt/canraise.py
--- a/pypy/translator/backendopt/canraise.py
+++ b/pypy/translator/backendopt/canraise.py
@@ -12,20 +12,31 @@
 class RaiseAnalyzer(graphanalyze.BoolGraphAnalyzer):
     def analyze_simple_operation(self, op, graphinfo):
         try:
-            return bool(LL_OPERATIONS[op.opname].canraise)
+            if LL_OPERATIONS[op.opname].canraise:
+                self.reason = op
+                return True
+            return False
         except KeyError:
             log.WARNING("Unknown operation: %s" % op.opname)
+            self.reason = op
             return True
 
     def analyze_external_call(self, op, seen=None):
         fnobj = get_funcobj(op.args[0].value)
-        return getattr(fnobj, 'canraise', True)
+        if getattr(fnobj, 'canraise', True):
+            self.reason = 'external call:', fnobj
+            return True
+        return False
 
     def analyze_external_method(self, op, TYPE, meth):
         assert op.opname == 'oosend'
-        return getattr(meth, '_can_raise', True)
+        if getattr(meth, '_can_raise', True):
+            self.reason = 'external method:', meth
+            return True
+        return False
 
     def analyze_exceptblock(self, block, seen=None):
+        self.reason = "except block:", block
         return True
 
     # backward compatible interface
diff --git a/pypy/translator/backendopt/graphanalyze.py b/pypy/translator/backendopt/graphanalyze.py
--- a/pypy/translator/backendopt/graphanalyze.py
+++ b/pypy/translator/backendopt/graphanalyze.py
@@ -4,6 +4,7 @@
 
 class GraphAnalyzer(object):
     verbose = False
+    reason = None
 
     def __init__(self, translator):
         self.translator = translator
@@ -86,6 +87,7 @@
             if graphs is None:
                 if self.verbose:
                     print '\t%s to unknown' % (op,)
+                self.reason = op
                 return self.top_result()
             x = self.analyze_indirect_call(graphs, seen)
             if self.verbose and x:
diff --git a/pypy/translator/exceptiontransform.py b/pypy/translator/exceptiontransform.py
--- a/pypy/translator/exceptiontransform.py
+++ b/pypy/translator/exceptiontransform.py
@@ -198,8 +198,19 @@
             assert self.same_obj(self.exc_data_ptr, graph.exceptiontransformed)
             return
         else:
-            self.raise_analyzer.analyze_direct_call(graph)
+            # side-effect: perform the analysis of all graphs reachable from
+            # 'graph'
+            can_raise = self.raise_analyzer.analyze_direct_call(graph)
             graph.exceptiontransformed = self.exc_data_ptr
+            func = getattr(graph, 'func', None)
+            if getattr(func, '_should_never_raise_', False):
+                if not can_raise:
+                    return
+                ra = canraise.RaiseAnalyzer(self.translator)
+                ra.analyze_direct_call(graph)
+                raise Exception("%r is marked as _should_never_raise_, "
+                                "but is found to raise.  Reason: %r" % (
+                    graph, ra.reason))
 
         join_blocks(graph)
         # collect the blocks before changing them


More information about the pypy-commit mailing list