[pypy-commit] pypy nogil-unsafe-2: (arigo, remi) make shadowstack really threadlocal

Raemi pypy.commits at gmail.com
Thu Mar 2 06:31:07 EST 2017


Author: Remi Meier <remi.meier at gmail.com>
Branch: nogil-unsafe-2
Changeset: r90474:b7c2b62351e0
Date: 2017-03-02 12:30 +0100
http://bitbucket.org/pypy/pypy/changeset/b7c2b62351e0/

Log:	(arigo, remi) make shadowstack really threadlocal

	shadowstack push/pop was still non-tl, and we didn't visit all
	stacks of all threads during minor collection

diff --git a/rpython/memory/gc/incminimark.py b/rpython/memory/gc/incminimark.py
--- a/rpython/memory/gc/incminimark.py
+++ b/rpython/memory/gc/incminimark.py
@@ -897,6 +897,7 @@
                 self.set_nursery_top(self.nursery_barriers.popleft())
             else:
                 rgil.master_request_safepoint()
+                # we are the only thread here; all others are in gc-safepoints
 
                 minor_collection_count += 1
                 if minor_collection_count == 1:
diff --git a/rpython/memory/gctransform/shadowstack.py b/rpython/memory/gctransform/shadowstack.py
--- a/rpython/memory/gctransform/shadowstack.py
+++ b/rpython/memory/gctransform/shadowstack.py
@@ -11,6 +11,8 @@
      BaseFrameworkGCTransformer, BaseRootWalker, sizeofaddr)
 from rpython.rtyper.rbuiltin import gen_cast
 
+from rpython.rlib import rthread
+
 
 class ShadowStackFrameworkGCTransformer(BaseFrameworkGCTransformer):
     def annotate_walker_functions(self, getfn):
@@ -24,7 +26,8 @@
                                    inline = True)
 
     def build_root_walker(self):
-        return ShadowStackRootWalker(self)
+        # XXX: select between GIL and NoGil variant
+        return NoGilShadowStackRootWalker(self)
 
     def push_roots(self, hop, keep_current_args=False):
         livevars = self.get_livevars_for_roots(hop, keep_current_args)
@@ -55,6 +58,108 @@
                 hop.genop("gc_reload_possibly_moved", [v_newaddr, var])
 
 
+class NoGilShadowStackRootWalker(BaseRootWalker):
+    tl_shadowstack = rthread.ThreadLocalField(llmemory.Address, 'shadowstack')
+    tl_shadowstack_top = rthread.ThreadLocalField(llmemory.Address, 'shadowstack_top')
+    tl_synclock = rthread.ThreadLocalField(lltype.Signed, 'synclock')
+
+    def __init__(self, gctransformer):
+        BaseRootWalker.__init__(self, gctransformer)
+
+        tl_shadowstack_top = self.tl_shadowstack_top
+        tl_shadowstack = self.tl_shadowstack
+
+        def incr_stack(n):
+            top = tl_shadowstack_top.getraw()
+            tl_shadowstack_top.setraw(top + n * sizeofaddr)
+            return top
+        self.incr_stack = incr_stack
+
+        def decr_stack(n):
+            top = tl_shadowstack_top.getraw() - n * sizeofaddr
+            tl_shadowstack_top.setraw(top)
+            return top
+        self.decr_stack = decr_stack
+
+        def walk_stack_root(callback, start, end):
+            gc = self.gc
+            addr = end
+            while addr != start:
+                addr -= sizeofaddr
+                if gc.points_to_valid_gc_object(addr):
+                    callback(gc, addr)
+        self.rootstackhook = walk_stack_root
+
+        def walk_thread_stack(collect_stack_root, tl):
+            # XXX: only visit if nursery_free was not NULL
+            base = (tl + tl_shadowstack._offset).address[0]
+            top = (tl + tl_shadowstack_top._offset).address[0]
+            self.rootstackhook(collect_stack_root, base, top)
+        self._walk_thread_stack = walk_thread_stack
+
+    def push_stack(self, addr):
+        top = self.incr_stack(1)
+        top.address[0] = addr
+
+    def pop_stack(self):
+        top = self.decr_stack(1)
+        return top.address[0]
+
+
+    def walk_stack_roots(self, collect_stack_root, is_minor=False):
+        rthread.enum_all_threadlocals(self._walk_thread_stack,
+                                      collect_stack_root)
+
+    def need_thread_support(self, gctransformer, getfn):  # NO GIL VERSION
+        # the interfacing between the threads and the GC is done via
+        # two completely ad-hoc operations at the moment:
+        # gc_thread_run and gc_thread_die.  See docstrings below.
+
+        tl_shadowstack = self.tl_shadowstack
+        tl_shadowstack_top = self.tl_shadowstack_top
+        tl_synclock = self.tl_synclock
+
+        def thread_setup():
+            allocate_shadow_stack()
+            tl_synclock.get_or_make_raw()  # reference the field at least once
+
+        def thread_run():
+            # If it's the first time we see this thread, allocate
+            # a shadowstack.
+            if tl_shadowstack.get_or_make_raw() == llmemory.NULL:
+                allocate_shadow_stack()
+
+        def allocate_shadow_stack():
+            root_stack_depth = 163840
+            root_stack_size = sizeofaddr * root_stack_depth
+            ss = llmemory.raw_malloc(root_stack_size)
+            if not ss:
+                raise MemoryError
+            tl_shadowstack.setraw(ss)
+            tl_shadowstack_top.setraw(ss)
+        allocate_shadow_stack._dont_inline_ = True
+
+        def thread_die():
+            """Called just before the final GIL release done by a dying
+            thread.  After a thread_die(), no more gc operation should
+            occur in this thread.
+            """
+            p = tl_shadowstack.get_or_make_raw()
+            tl_shadowstack.setraw(llmemory.NULL)
+            tl_shadowstack_top.setraw(llmemory.NULL)
+            llmemory.raw_free(p)
+
+        self.thread_setup = thread_setup
+        self.thread_run_ptr = getfn(thread_run, [], annmodel.s_None,
+                                    inline=True, minimal_transform=False)
+        self.thread_die_ptr = getfn(thread_die, [], annmodel.s_None,
+                                    minimal_transform=False)
+
+    def need_stacklet_support(self, gctransformer, getfn):
+        from rpython.rlib import _stacklet_shadowstack
+        _stacklet_shadowstack.complete_destrptr(gctransformer)
+
+
 class ShadowStackRootWalker(BaseRootWalker):
     def __init__(self, gctransformer):
         BaseRootWalker.__init__(self, gctransformer)
@@ -104,7 +209,7 @@
         self.rootstackhook(collect_stack_root,
                            gcdata.root_stack_base, gcdata.root_stack_top)
 
-    def need_thread_support_WITH_GIL(self, gctransformer, getfn):
+    def need_thread_support(self, gctransformer, getfn):
         from rpython.rlib import rthread    # xxx fish
         gcdata = self.gcdata
         # the interfacing between the threads and the GC is done via
@@ -218,51 +323,6 @@
                                            annmodel.s_None,
                                            minimal_transform=False)
 
-    def need_thread_support(self, gctransformer, getfn):  # NO GIL VERSION
-        from rpython.rlib import rthread
-        gcdata = self.gcdata
-        # the interfacing between the threads and the GC is done via
-        # two completely ad-hoc operations at the moment:
-        # gc_thread_run and gc_thread_die.  See docstrings below.
-
-        tl_shadowstack = rthread.ThreadLocalField(llmemory.Address,
-                                                  'shadowstack')
-        tl_synclock = rthread.ThreadLocalField(lltype.Signed, 'synclock')
-
-        def thread_setup():
-            allocate_shadow_stack()
-            tl_synclock.get_or_make_raw()  # reference the field at least once
-
-        def thread_run():
-            # If it's the first time we see this thread, allocate
-            # a shadowstack.
-            if tl_shadowstack.get_or_make_raw() == llmemory.NULL:
-                allocate_shadow_stack()
-
-        def allocate_shadow_stack():
-            root_stack_depth = 163840
-            root_stack_size = sizeofaddr * root_stack_depth
-            ss = llmemory.raw_malloc(root_stack_size)
-            if not ss:
-                raise MemoryError
-            tl_shadowstack.setraw(ss)
-        allocate_shadow_stack._dont_inline_ = True
-
-        def thread_die():
-            """Called just before the final GIL release done by a dying
-            thread.  After a thread_die(), no more gc operation should
-            occur in this thread.
-            """
-            p = tl_shadowstack.get_or_make_raw()
-            tl_shadowstack.setraw(llmemory.NULL)
-            llmemory.raw_free(p)
-
-        self.thread_setup = thread_setup
-        self.thread_run_ptr = getfn(thread_run, [], annmodel.s_None,
-                                    inline=True, minimal_transform=False)
-        self.thread_die_ptr = getfn(thread_die, [], annmodel.s_None,
-                                    minimal_transform=False)
-
     def need_stacklet_support(self, gctransformer, getfn):
         from rpython.rlib import _stacklet_shadowstack
         _stacklet_shadowstack.complete_destrptr(gctransformer)


More information about the pypy-commit mailing list