[pypy-commit] pypy stacklet: Various fixes until the test passes.
arigo
noreply at buildbot.pypy.org
Tue Aug 9 07:50:14 CEST 2011
Author: Armin Rigo <arigo at tunes.org>
Branch: stacklet
Changeset: r46385:38cb12a0100c
Date: 2011-08-09 07:49 +0200
http://bitbucket.org/pypy/pypy/changeset/38cb12a0100c/
Log: Various fixes until the test passes.
diff --git a/pypy/rlib/_stacklet_shadowstack.py b/pypy/rlib/_stacklet_shadowstack.py
--- a/pypy/rlib/_stacklet_shadowstack.py
+++ b/pypy/rlib/_stacklet_shadowstack.py
@@ -1,11 +1,13 @@
from pypy.rlib import _rffi_stacklet as _c
from pypy.rpython.lltypesystem import lltype, llmemory, rffi
from pypy.rpython.lltypesystem.lloperation import llop
-from pypy.rlib import rstacklet
-from pypy.rlib.debug import ll_assert
+from pypy.rlib import rstacklet, rgc
+from pypy.rlib.debug import ll_assert, debug_print
from pypy.rpython.annlowlevel import llhelper
+DEBUG = False
+
PTR_SUSPSTACK = lltype.Ptr(lltype.GcForwardReference())
SUSPSTACK = lltype.GcStruct('SuspStack',
('handle', _c.handle),
@@ -24,12 +26,15 @@
sizeofaddr = llmemory.sizeof(llmemory.Address)
def repr_suspstack(suspstack):
- return '<SuspStack %d: stop=%d, start=%d, saved=%d>' % (
- rffi.cast(lltype.Signed, suspstack.handle),
- rffi.cast(lltype.Signed, suspstack.shadowstack_stop),
- rffi.cast(lltype.Signed, suspstack.shadowstack_start),
- suspstack.shadowstack_saved)
-
+ debug_print('<SuspStack',
+ rffi.cast(lltype.Signed, suspstack.handle),
+ ': stop',
+ rffi.cast(lltype.Signed, suspstack.shadowstack_stop),
+ 'start',
+ rffi.cast(lltype.Signed, suspstack.shadowstack_start),
+ 'saved',
+ suspstack.shadowstack_saved,
+ '>')
# every thread has a 'current stack stop', which is like
# g_current_stack_stop in stacklet.c but about the shadowstack
@@ -47,94 +52,129 @@
def _new_runfn(h, arg):
- gcrootfinder.thrd._current_shadowstack_stop = root_stack_top()
+ thrd = gcrootfinder.thrd
+ thrd._current_shadowstack_stop = root_stack_top()
suspstack = gcrootfinder.attach_handle_on_suspstack(h)
+ #
suspstack = gcrootfinder.runfn(suspstack, arg)
- return gcrootfinder.consume_suspstack(suspstack)
+ #
+ gcrootfinder.thrd = thrd
+ gcrootfinder.g_source = NULL_SUSPSTACK
+ gcrootfinder.g_target = suspstack
+ return gcrootfinder.consume_suspstack()
class StackletGcRootFinder(object):
- suspstack = NULL_SUSPSTACK
+ g_source = NULL_SUSPSTACK
+ g_target = NULL_SUSPSTACK
def new(self, thrd, callback, arg):
- if thrd._current_shadowstack_stop == llmemory.NULL:
- thrd._current_shadowstack_stop = root_stack_top()
- self.allocate_source_suspstack(thrd)
+ rst = root_stack_top()
+ if (thrd._current_shadowstack_stop == llmemory.NULL or
+ thrd._current_shadowstack_stop > rst):
+ thrd._current_shadowstack_stop = rst
+ self.allocate_source_suspstack(rst, thrd)
self.runfn = callback
h = _c.new(thrd._thrd, llhelper(_c.run_fn, _new_runfn), arg)
- return self.get_result_suspstack(h)
+ return self.get_result_suspstack(h, False)
def switch(self, thrd, suspstack):
- self.allocate_source_suspstack(thrd)
- h = self.consume_suspstack(suspstack)
- h2 = _c.switch(thrd._thrd, h)
- return self.get_result_suspstack(h2)
-
- def allocate_source_suspstack(self, thrd):
- # Attach to 'self.suspstack' a SUSPSTACK that represents the
- # old, but still current, stacklet. All that is left to
- # fill is 'self.suspstack.handle', done later by a call
- # to attach_handle_on_suspstack().
rst = root_stack_top()
if thrd._current_shadowstack_stop > rst:
thrd._current_shadowstack_stop = rst
+ self.allocate_source_suspstack(rst, thrd)
+ self.g_target = suspstack
+ h = self.consume_suspstack()
+ h2 = _c.switch(thrd._thrd, h)
+ return self.get_result_suspstack(h2, True)
+
+ def allocate_source_suspstack(self, rst, thrd):
+ # Attach to 'self' a SUSPSTACK that represents the
+ # old, but still current, stacklet. All that is left to
+ # fill is 'self.g_source.handle', done later by a call
+ # to attach_handle_on_suspstack().
count = (rst - thrd._current_shadowstack_stop) // sizeofaddr
newsuspstack = lltype.malloc(SUSPSTACK, count)
newsuspstack.shadowstack_stop = thrd._current_shadowstack_stop
newsuspstack.shadowstack_start = rst
newsuspstack.shadowstack_saved = 0
newsuspstack.shadowstack_prev = thrd._shadowstack_chain_head
+ #
+ newsuspstack.handle = _c.null_handle
+ if DEBUG:
+ debug_print("NEW")
+ repr_suspstack(newsuspstack)
+ #
thrd._shadowstack_chain_head = newsuspstack
- self.suspstack = newsuspstack
+ self.g_source = newsuspstack
self.thrd = thrd
+ allocate_source_suspstack._dont_inline_ = True
+ # ^^^ dont_inline because it has a malloc, so we want its effects on
+ # the root_stack_top to be isolated
+ @rgc.no_collect
def attach_handle_on_suspstack(self, handle):
- s = self.suspstack
- self.suspstack = NULL_SUSPSTACK
+ s = self.g_source
+ self.g_source = NULL_SUSPSTACK
s.handle = handle
- print 'ATTACH HANDLE', repr_suspstack(s)
+ if DEBUG:
+ debug_print('ATTACH HANDLE')
+ repr_suspstack(s)
return s
- def get_result_suspstack(self, h):
+ @rgc.no_collect
+ def get_result_suspstack(self, h, restore_if_out_of_memory):
#
# Return from a new() or a switch(): 'h' is a handle, possibly
# an empty one, that says from where we switched to.
if not h:
# oups, we didn't actually switch anywhere, but just got
# an out-of-memory condition. Restore the current suspstack.
- self.consume_suspstack(self.suspstack)
- self.suspstack = NULL_SUSPSTACK
+ if restore_if_out_of_memory:
+ self.g_target = self.g_source
+ self.consume_suspstack()
+ self.g_source = NULL_SUSPSTACK
+ self.g_target = NULL_SUSPSTACK
self.thrd = None
raise MemoryError
#
+ ll_assert(self.g_target == NULL_SUSPSTACK, "g_target must be cleared")
+ #
if _c.is_empty_handle(h):
+ ll_assert(self.g_source == NULL_SUSPSTACK,
+ "g_source must be cleared")
self.thrd = None
return NULL_SUSPSTACK
else:
# This is a return that gave us a real handle. Store it.
return self.attach_handle_on_suspstack(h)
- def consume_suspstack(self, suspstack):
- print 'CONSUME', repr_suspstack(suspstack)
+ @rgc.no_collect
+ def consume_suspstack(self):
+ if DEBUG:
+ debug_print('CONSUME')
+ repr_suspstack(self.g_target)
#
# We want to switch to or return to 'suspstack'. First get
# how far we have to clean up the shadowstack.
- target = suspstack.shadowstack_stop
+ target = self.possibly_move_back()
#
# Clean the shadowstack up to that position.
- self.clear_shadowstack(target, suspstack)
+ self.clear_shadowstack(target)
#
# Now restore data from suspstack.shadowstack_copy.
- self.restore_suspstack(suspstack)
+ self.restore_suspstack()
#
# Set the new root stack bounds.
+ suspstack = self.g_target
self.thrd._current_shadowstack_stop = target
set_root_stack_top(suspstack.shadowstack_start)
#
# Now the real shadowstack is ready for 'suspstack'.
+ self.g_target = NULL_SUSPSTACK
return suspstack.handle
- def clear_shadowstack(self, target_stop, targetsuspstack):
+ def clear_shadowstack(self, target_stop):
# NB. see also g_clear_stack() in stacklet.c.
#
current = self.thrd._shadowstack_chain_head
@@ -144,7 +184,7 @@
while bool(current) and current.shadowstack_stop >= target_stop:
prev = current.shadowstack_prev
current.shadowstack_prev = NULL_SUSPSTACK
- if current != targetsuspstack:
+ if current != self.g_target:
# don't bother saving away targetsuspstack, because
# it would be immediately restored
self._save(current, current.shadowstack_stop)
@@ -170,7 +210,8 @@
num1 += 1
suspstack.shadowstack_saved = num1
- def restore_suspstack(self, suspstack):
+ def restore_suspstack(self):
+ suspstack = self.g_target
target = suspstack.shadowstack_start
saved = suspstack.shadowstack_saved
suspstack.shadowstack_saved = 0
@@ -181,6 +222,25 @@
target.address[0] = addr
i += 1
+ def possibly_move_back(self):
+ # if suspstack.shadowstack_stop is after root_stack_top, then
+ # restoring it there would leave an uninitialized gap containing
+ # garbage in the real shadowstack. Avoid this by shifting
+ # susp.shadowstack_{stop,start}.
+ suspstack = self.g_target
+ rst = root_stack_top()
+ delta = suspstack.shadowstack_stop - rst
+ if delta > 0:
+ # completely saved in this case
+ ll_assert(suspstack.shadowstack_start - suspstack.shadowstack_stop
+ == suspstack.shadowstack_saved * sizeofaddr,
+ "not completely saved shadowstack?")
+ if DEBUG:
+ debug_print('moving to the left by', delta)
+ suspstack.shadowstack_stop -= delta
+ suspstack.shadowstack_start -= delta
+ return suspstack.shadowstack_stop
+
def destroy(self, thrd, suspstack):
h = suspstack.handle
suspstack.handle = _c.null_handle
More information about the pypy-commit
mailing list