[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