Author: Remi Meier <[email protected]>
Branch: stmgc-c4
Changeset: r66392:ff994d51e7d4
Date: 2013-08-28 15:09 +0200
http://bitbucket.org/pypy/pypy/changeset/ff994d51e7d4/
Log: implement rgc.no_release_gil
diff --git a/rpython/memory/gctransform/framework.py
b/rpython/memory/gctransform/framework.py
--- a/rpython/memory/gctransform/framework.py
+++ b/rpython/memory/gctransform/framework.py
@@ -46,6 +46,32 @@
return (op.opname in LL_OPERATIONS and
LL_OPERATIONS[op.opname].canmallocgc)
+class GilAnalyzer(graphanalyze.BoolGraphAnalyzer):
+
+ def analyze_direct_call(self, graph, seen=None):
+ try:
+ func = graph.func
+ except AttributeError:
+ pass
+ else:
+ if getattr(func, '_gctransformer_hint_close_stack_', False):
+ return True
+ if getattr(func, '_transaction_break_', False):
+ return True
+
+ return graphanalyze.BoolGraphAnalyzer.analyze_direct_call(self, graph,
+ seen)
+ def analyze_external_call(self, op, seen=None):
+ funcobj = op.args[0].value._obj
+ if getattr(funcobj, 'transactionsafe', False):
+ return False
+ else:
+ return False
+
+ def analyze_simple_operation(self, op, graphinfo):
+ return False
+
+
def find_initializing_stores(collect_analyzer, graph):
from rpython.flowspace.model import mkentrymap
entrymap = mkentrymap(graph)
@@ -251,6 +277,9 @@
self.collect_analyzer = CollectAnalyzer(self.translator)
self.collect_analyzer.analyze_all()
+ self.gil_analyzer = GilAnalyzer(self.translator)
+ self.gil_analyzer.analyze_all()
+
s_gc = self.translator.annotator.bookkeeper.valueoftype(GCClass)
r_gc = self.translator.rtyper.getrepr(s_gc)
self.c_const_gc = rmodel.inputconst(r_gc, self.gcdata.gc)
@@ -639,6 +668,27 @@
# causes it to return True
raise Exception("'no_collect' function can trigger collection:"
" %s\n%s" % (func, err.getvalue()))
+
+ if func and getattr(func, '_no_release_gil_', False):
+ if self.gil_analyzer.analyze_direct_call(graph):
+ # 'no_release_gil' function can release the gil
+ import cStringIO
+ err = cStringIO.StringIO()
+ import sys
+ prev = sys.stdout
+ try:
+ sys.stdout = err
+ ca = GilAnalyzer(self.translator)
+ ca.verbose = True
+ ca.analyze_direct_call(graph) # print the "traceback" here
+ sys.stdout = prev
+ except:
+ sys.stdout = prev
+ # ^^^ for the dump of which operation in which graph actually
+ # causes it to return True
+ raise Exception("'no_release_gil' function can release the
GIL:"
+ " %s\n%s" % (func, err.getvalue()))
+
if self.write_barrier_ptr:
self.clean_sets = (
diff --git a/rpython/memory/gctransform/test/test_framework.py
b/rpython/memory/gctransform/test/test_framework.py
--- a/rpython/memory/gctransform/test/test_framework.py
+++ b/rpython/memory/gctransform/test/test_framework.py
@@ -5,7 +5,7 @@
from rpython.rtyper.lltypesystem.lloperation import llop
from rpython.memory.gc.semispace import SemiSpaceGC
from rpython.memory.gctransform.framework import (CollectAnalyzer,
- find_initializing_stores, find_clean_setarrayitems)
+ find_initializing_stores, find_clean_setarrayitems, GilAnalyzer)
from rpython.memory.gctransform.shadowstack import (
ShadowStackFrameworkGCTransformer)
from rpython.memory.gctransform.test.test_transform import rtype
@@ -100,6 +100,21 @@
gg = graphof(t, g)
assert CollectAnalyzer(t).analyze_direct_call(gg)
+def test_canrelease_external():
+ for ths in ['auto', True, False]:
+ for sbxs in [True, False]:
+ fext = rffi.llexternal('fext2', [], lltype.Void,
+ threadsafe=ths, sandboxsafe=sbxs)
+ def g():
+ fext()
+ t = rtype(g, [])
+ gg = graphof(t, g)
+
+ releases = (ths == 'auto' and not sbxs) or ths is True
+ assert releases == GilAnalyzer(t).analyze_direct_call(gg)
+ return
+
+
def test_no_collect(gc="minimark"):
from rpython.rlib import rgc
from rpython.translator.c.genc import CStandaloneBuilder
@@ -125,6 +140,60 @@
def test_no_collect_stm():
test_no_collect("stmgc")
+def test_no_release_gil(gc="minimark"):
+ from rpython.rlib import rgc
+ from rpython.translator.c.genc import CStandaloneBuilder
+
+ @rgc.no_release_gil
+ def g():
+ return 1
+
+ assert g._dont_inline_
+ assert g._no_release_gil_
+
+ def entrypoint(argv):
+ return g() + 2
+
+ t = rtype(entrypoint, [s_list_of_strings])
+ if gc == "stmgc":
+ t.config.translation.stm = True
+ t.config.translation.gc = gc
+ cbuild = CStandaloneBuilder(t, entrypoint, t.config,
+ gcpolicy=FrameworkGcPolicy2)
+ db = cbuild.generate_graphs_for_llinterp()
+
+def test_no_release_gil_stm():
+ test_no_release_gil("stmgc")
+
+def test_no_release_gil_detect(gc="minimark"):
+ from rpython.rlib import rgc
+ from rpython.translator.c.genc import CStandaloneBuilder
+
+ fext1 = rffi.llexternal('fext1', [], lltype.Void, threadsafe=True)
+ @rgc.no_release_gil
+ def g():
+ fext1()
+ return 1
+
+ assert g._dont_inline_
+ assert g._no_release_gil_
+
+ def entrypoint(argv):
+ return g() + 2
+
+ t = rtype(entrypoint, [s_list_of_strings])
+ if gc == "stmgc":
+ t.config.translation.stm = True
+ t.config.translation.gc = gc
+ cbuild = CStandaloneBuilder(t, entrypoint, t.config,
+ gcpolicy=FrameworkGcPolicy2)
+ f = py.test.raises(Exception, cbuild.generate_graphs_for_llinterp)
+ expected = "'no_release_gil' function can release the GIL: <function g at "
+ assert str(f.value).startswith(expected)
+
+def test_no_release_gil_detect_stm():
+ test_no_release_gil_detect("stmgc")
+
def test_no_collect_detection(gc="minimark"):
from rpython.rlib import rgc
from rpython.translator.c.genc import CStandaloneBuilder
diff --git a/rpython/rlib/rgc.py b/rpython/rlib/rgc.py
--- a/rpython/rlib/rgc.py
+++ b/rpython/rlib/rgc.py
@@ -312,7 +312,11 @@
keepalive_until_here(newp)
return newp
-
+def no_release_gil(func):
+ func._dont_inline_ = True
+ func._no_release_gil_ = True
+ return func
+
def no_collect(func):
func._dont_inline_ = True
func._gc_no_collect_ = True
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit