[pypy-commit] pypy stacklet: Rewrite the logic to simplify it and reduce the allocations.
arigo
noreply at buildbot.pypy.org
Sun Aug 7 15:11:38 CEST 2011
Author: Armin Rigo <arigo at tunes.org>
Branch: stacklet
Changeset: r46346:78fa1d3f1f0b
Date: 2011-08-07 15:03 +0200
http://bitbucket.org/pypy/pypy/changeset/78fa1d3f1f0b/
Log: Rewrite the logic to simplify it and reduce the allocations.
diff --git a/pypy/module/_stacklet/interp_stacklet.py b/pypy/module/_stacklet/interp_stacklet.py
--- a/pypy/module/_stacklet/interp_stacklet.py
+++ b/pypy/module/_stacklet/interp_stacklet.py
@@ -1,6 +1,7 @@
import sys
from pypy.rpython.lltypesystem import lltype, rffi
-from pypy.rlib import rstacklet, jit
+from pypy.rlib import jit
+from pypy.rlib.rstacklet import StackletThread
from pypy.rlib.objectmodel import we_are_translated
from pypy.interpreter.error import OperationError
from pypy.interpreter.executioncontext import ExecutionContext
@@ -8,48 +9,40 @@
from pypy.interpreter.typedef import TypeDef
from pypy.interpreter.gateway import interp2app
-NULLHANDLE = lltype.nullptr(rstacklet.handle.TO)
+class SThread(StackletThread):
-class SThread(object):
def __init__(self, space, ec):
+ StackletThread.__init__(self, space.config)
w_module = space.getbuiltinmodule('_stacklet')
self.space = space
self.ec = ec
self.w_error = space.getattr(w_module, space.wrap('error'))
self.pending_exception = None
self.main_stacklet = None
- self.thrd = rstacklet.newthread()
- if not self.thrd:
- raise MemoryError
def __del__(self):
- thrd = self.thrd
- if thrd:
- if self.main_stacklet is not None:
- self.main_stacklet.__del__()
- self.thrd = lltype.nullptr(rstacklet.thread_handle.TO)
- rstacklet.deletethread(thrd)
+ if self.main_stacklet is not None:
+ self.main_stacklet.__del__()
+ StackletThread.__del__(self)
def new_stacklet_object(self, h):
- if self.pending_exception is not None:
+ if self.pending_exception is None:
+ if self.is_empty_handle(h):
+ return self.space.w_None
+ else:
+ return self.space.wrap(W_Stacklet(self, h))
+ else:
e = self.pending_exception
self.pending_exception = None
+ if not self.is_empty_handle(h):
+ self.destroy(h)
if we_are_translated():
raise e
else:
tb = self.pending_tb
del self.pending_tb
raise e.__class__, e, tb
- if not h:
- start_state.sthread = None
- start_state.w_callable = None
- start_state.args = None
- raise MemoryError
- elif rstacklet.is_empty_handle(h):
- return self.space.w_None
- else:
- return self.space.wrap(W_Stacklet(self, h))
ExecutionContext.stacklet_thread = None
@@ -62,14 +55,13 @@
def __del__(self):
h = self.h
if h:
- self.h = NULLHANDLE
- space = self.sthread.space
- rstacklet.destroy(space.config, self.sthread.thrd, h)
+ self.h = self.get_null_handle()
+ self.sthread.destroy(h)
def consume_handle(self):
h = self.h
if h:
- self.h = NULLHANDLE
+ self.h = self.get_null_handle()
if self is self.sthread.main_stacklet:
self.sthread.main_stacklet = None
return h
@@ -84,7 +76,7 @@
sthread = self.sthread
ec = sthread.ec
saved_frame_top = ec.topframeref
- h = rstacklet.switch(space.config, sthread.thrd, h)
+ h = sthread.switch(h)
ec.topframeref = saved_frame_top
return sthread.new_stacklet_object(h)
@@ -148,7 +140,6 @@
start_state.args = __args__
saved_frame_top = ec.topframeref
ec.topframeref = jit.vref_None
- h = rstacklet.new(space.config, sthread.thrd, new_stacklet_callback,
- lltype.nullptr(rffi.VOIDP.TO))
+ h = sthread.new(new_stacklet_callback)
ec.topframeref = saved_frame_top
return sthread.new_stacklet_object(h)
diff --git a/pypy/rlib/rstacklet.py b/pypy/rlib/_rffi_stacklet.py
copy from pypy/rlib/rstacklet.py
copy to pypy/rlib/_rffi_stacklet.py
--- a/pypy/rlib/rstacklet.py
+++ b/pypy/rlib/_rffi_stacklet.py
@@ -2,15 +2,6 @@
from pypy.tool.autopath import pypydir
from pypy.rpython.lltypesystem import lltype, llmemory, rffi
from pypy.translator.tool.cbuild import ExternalCompilationInfo
-from pypy.rpython.annlowlevel import llhelper
-
-###
-### Note: stacklets do not reliably work on top of CPython, but well,
-### they seem to work fine after being translated... This is due
-### to the fact that on CPython, you get strange effects because the
-### PyThreadState is not explicitly handled when we start a new
-### stacklet or switch to another one, notably the 'frame' field.
-###
cdir = py.path.local(pypydir) / 'translator' / 'c'
@@ -31,10 +22,12 @@
handle = rffi.COpaquePtr(typedef='stacklet_handle', compilation_info=eci)
thread_handle = rffi.COpaquePtr(typedef='stacklet_thread_handle',
compilation_info=eci)
-run_fn = lltype.Ptr(lltype.FuncType([handle, rffi.VOIDP], handle))
+run_fn = lltype.Ptr(lltype.FuncType([handle, llmemory.Address], handle))
# ----- constants -----
+null_handle = lltype.nullptr(handle.TO)
+
def is_empty_handle(h):
return rffi.cast(lltype.Signed, h) == -1
@@ -43,38 +36,11 @@
newthread = llexternal('stacklet_newthread', [], thread_handle)
deletethread = llexternal('stacklet_deletethread',[thread_handle], lltype.Void)
-_new = llexternal('stacklet_new', [thread_handle, run_fn, rffi.VOIDP],
- handle)
-_switch = llexternal('stacklet_switch', [thread_handle, handle], handle)
-_destroy = llexternal('stacklet_destroy', [thread_handle, handle], lltype.Void)
+new = llexternal('stacklet_new', [thread_handle, run_fn, llmemory.Address],
+ handle)
+switch = llexternal('stacklet_switch', [thread_handle, handle], handle)
+destroy = llexternal('stacklet_destroy', [thread_handle, handle], lltype.Void)
_translate_pointer = llexternal("_stacklet_translate_pointer",
[handle, llmemory.Address],
llmemory.Address)
-
-# ____________________________________________________________
-
-def getgcclass(config):
- if (config is None or
- config.translation.gc in ('ref', 'boehm', 'none')): # for tests
- gcrootfinder = 'n/a'
- else:
- gcrootfinder = config.translation.gcrootfinder
- gcrootfinder = gcrootfinder.replace('/', '_')
- module = __import__('pypy.rlib._stacklet_%s' % gcrootfinder,
- None, None, ['__doc__'])
- return module.StackletGcRootFinder
-getgcclass._annspecialcase_ = 'specialize:memo'
-
-def new(config, thrd, runfn, arg):
- c = getgcclass(config)
- return c.new(thrd, llhelper(run_fn, runfn), arg)
-new._annspecialcase_ = 'specialize:arg(2)'
-
-def switch(config, thrd, h):
- c = getgcclass(config)
- return c.switch(thrd, h)
-
-def destroy(config, thrd, h):
- c = getgcclass(config)
- c.destroy(thrd, h)
diff --git a/pypy/rlib/_stacklet_asmgcc.py b/pypy/rlib/_stacklet_asmgcc.py
--- a/pypy/rlib/_stacklet_asmgcc.py
+++ b/pypy/rlib/_stacklet_asmgcc.py
@@ -1,4 +1,4 @@
-from pypy.rlib import rstacklet
+from pypy.rlib import _rffi_stacklet as _c
from pypy.rlib.debug import ll_assert
from pypy.rpython.lltypesystem import lltype, llmemory, rffi
from pypy.rpython.lltypesystem.lloperation import llop
@@ -35,12 +35,7 @@
del p
self.curframe = lltype.malloc(WALKFRAME, flavor='raw')
self.otherframe = lltype.malloc(WALKFRAME, flavor='raw')
- initialframedata = anchor[1]
- ll_assert(initialframedata != llmemory.cast_ptr_to_adr(anchor),
- "no anchored stacklet stack found")
- ll_assert(initialframedata == anchor[0],
- "more than one anchored stacklet stack found")
- self.fill_initial_frame(self.curframe, initialframedata)
+ self.fill_initial_frame(self.curframe, anchor)
return True
def fill_initial_frame(self, curframe, initialframedata):
@@ -57,7 +52,7 @@
def teardown(self):
lltype.free(self.curframe, flavor='raw')
lltype.free(self.otherframe, flavor='raw')
- self.context = lltype.nullptr(rstacklet.handle.TO)
+ self.context = lltype.nullptr(_c.handle.TO)
return llmemory.NULL
def next(self, obj, prev):
@@ -116,7 +111,7 @@
# loop back
def translateptr(self, addr):
- return rstacklet._translate_pointer(self.context, addr)
+ return _c._translate_pointer(self.context, addr)
_stackletrootwalker = StackletRootWalker()
return _stackletrootwalker
@@ -128,110 +123,150 @@
return stackletrootwalker.next(obj, prev)
-ASM_FRAMEDATA_HEAD_PTR = lltype.Ptr(lltype.FixedSizeArray(llmemory.Address, 2))
SUSPSTACK = lltype.GcStruct('SuspStack',
- ('handle', rstacklet.handle),
- ('anchor', ASM_FRAMEDATA_HEAD_PTR),
- ('my_index', lltype.Signed),
- ('next_unused', lltype.Signed),
+ ('handle', _c.handle),
+ ('anchor', llmemory.Address),
rtti=True)
+NULL_SUSPSTACK = lltype.nullptr(SUSPSTACK)
CUSTOMTRACEFUNC = lltype.FuncType([llmemory.Address, llmemory.Address],
llmemory.Address)
customtraceptr = llhelper(lltype.Ptr(CUSTOMTRACEFUNC), customtrace)
lltype.attachRuntimeTypeInfo(SUSPSTACK, customtraceptr=customtraceptr)
-NULL_SUSPSTACK = lltype.Ptr(SUSPSTACK)
+ASM_FRAMEDATA_HEAD_PTR = lltype.Ptr(lltype.ForwardReference())
+ASM_FRAMEDATA_HEAD_PTR.TO.become(lltype.Struct('ASM_FRAMEDATA_HEAD',
+ ('prev', ASM_FRAMEDATA_HEAD_PTR),
+ ('next', ASM_FRAMEDATA_HEAD_PTR)
+ ))
+alternateanchor = lltype.malloc(ASM_FRAMEDATA_HEAD_PTR.TO,
+ immortal=True)
+alternateanchor.prev = alternateanchor
+alternateanchor.next = alternateanchor
-class SuspendedStacks:
-
- def __init__(self):
- self.lst = []
- self.first_unused = -1
- self.current_index = -1
-
- def acquire(self):
- if self.first_unused == -1:
- p = lltype.malloc(SUSPSTACK)
- p.handle = lltype.nullptr(rstacklet.handle.TO)
- p.my_index = len(self.lst)
- p.next_unused = -42000000
- p.anchor = lltype.malloc(ASM_FRAMEDATA_HEAD_PTR.TO, flavor='raw',
- track_allocation=False)
- self.lst.append(p)
- else:
- p = self.lst[self.first_unused]
- self.first_unused = p.next_unused
- p.anchor[0] = p.anchor[1] = llmemory.cast_ptr_to_adr(p.anchor)
- self.current_index = p.my_index
- return p
-
- def release(self, p):
- p.next_unused = self.first_unused
- self.first_unused = p.my_index
-
-suspendedstacks = SuspendedStacks()
-
-FUNCNOARG_P = lltype.Ptr(lltype.FuncType([], rstacklet.handle))
-
+FUNCNOARG_P = lltype.Ptr(lltype.FuncType([], _c.handle))
pypy_asm_stackwalk2 = rffi.llexternal('pypy_asm_stackwalk',
[FUNCNOARG_P,
ASM_FRAMEDATA_HEAD_PTR],
- rstacklet.handle, sandboxsafe=True,
+ _c.handle, sandboxsafe=True,
_nowrapper=True)
-def stack_protected_call(callback):
- p = suspendedstacks.acquire()
- llop.gc_assume_young_pointers(lltype.Void,
- llmemory.cast_ptr_to_adr(p))
- r = pypy_asm_stackwalk2(callback, p.anchor)
- p.handle = lltype.nullptr(rstacklet.handle.TO)
- suspendedstacks.release(p)
- return r
-
-def set_handle_on_most_recent(h):
- index = suspendedstacks.current_index
- if not h or rstacklet.is_empty_handle(h):
- assert index == -1
- else:
- assert index >= 0
- suspendedstacks.lst[index].handle = h
- suspendedstacks.current_index = -1
def _new_callback():
- h = rstacklet._new(suspendedstacks._thrd,
- llhelper(rstacklet.run_fn, _new_runfn),
- lltype.nullptr(rffi.VOIDP.TO))
- set_handle_on_most_recent(h)
+ # Here, we just closed the stack. Get the stack anchor, store
+ # it in the gcrootfinder.suspstack.anchor, and create a new
+ # stacklet with stacklet_new(). If this call fails, then we
+ # are just returning NULL.
+ _stack_just_closed()
+ return _c.new(gcrootfinder.thrd, llhelper(_c.run_fn, _new_runfn),
+ llmemory.NULL)
+
+def _stack_just_closed():
+ # Immediately unlink the new stackanchor from the doubly-linked
+ # chained list. When returning from pypy_asm_stackwalk2, the
+ # assembler code will try to unlink it again, which should be
+ # a no-op given that the doubly-linked list is empty.
+ stackanchor = llmemory.cast_ptr_to_adr(alternateanchor.next)
+ gcrootfinder.suspstack.anchor = stackanchor
+ alternateanchor.prev = alternateanchor
+ alternateanchor.next = alternateanchor
+
+def _new_runfn(h, _):
+ # Here, we are in a fresh new stacklet.
+ llop.gc_stack_bottom(lltype.Void) # marker for trackgcroot.py
+ #
+ # There is a fresh suspstack object waiting on the gcrootfinder,
+ # so populate it with data that represents the parent suspended
+ # stacklet and detach the suspstack object from gcrootfinder.
+ suspstack = gcrootfinder.attach_handle_on_suspstack(h)
+ #
+ # Call the main function provided by the (RPython) user.
+ suspstack = gcrootfinder.runfn(suspstack, gcrootfinder.arg)
+ #
+ # Here, suspstack points to the target stacklet to which we want
+ # to jump to next. Read the 'handle' and forget about the
+ # suspstack object.
+ return _consume_suspstack(suspstack)
+
+def _consume_suspstack(suspstack):
+ h = suspstack.handle
+ ll_assert(bool(h), "_consume_suspstack: null handle")
+ suspstack.handle = _c.null_handle
return h
-def _new_runfn(h, arg):
- set_handle_on_most_recent(h)
- r = suspendedstacks._runfn(h, suspendedstacks._arg)
- llop.gc_stack_bottom(lltype.Void) # marker for trackgcroot.py
- # ^^^ also, xxx, place it here to prevent the call from being
- # considered a tail call
- return r
+def _switch_callback():
+ # Here, we just closed the stack. Get the stack anchor, store
+ # it in the gcrootfinder.suspstack.anchor, and switch to this
+ # suspstack with stacklet_switch(). If this call fails, then we
+ # are just returning NULL.
+ oldanchor = gcrootfinder.suspstack.anchor
+ _stack_just_closed()
+ h = _consume_suspstack(gcrootfinder.suspstack)
+ #
+ # gcrootfinder.suspstack.anchor is left with the anchor of the
+ # previous place (i.e. before the call to switch()).
+ h2 = _c.switch(gcrootfinder.thrd, h)
+ #
+ if not h2: # MemoryError: restore
+ gcrootfinder.suspstack.anchor = oldanchor
+ gcrootfinder.suspstack.handle = h
+ return h2
-def _switch_callback():
- h = rstacklet._switch(suspendedstacks._thrd,
- suspendedstacks._switchto)
- set_handle_on_most_recent(h)
- return h
+class StackletGcRootFinder(object):
+ suspstack = NULL_SUSPSTACK
-class StackletGcRootFinder:
+ def new(self, thrd, callback, arg):
+ self.thrd = thrd
+ self.runfn = callback
+ self.arg = arg
+ # make a fresh new clean SUSPSTACK
+ newsuspstack = lltype.malloc(SUSPSTACK)
+ newsuspstack.handle = _c.null_handle
+ self.suspstack = newsuspstack
+ # Invoke '_new_callback' by closing the stack
+ h = pypy_asm_stackwalk2(llhelper(FUNCNOARG_P, _new_callback),
+ alternateanchor)
+ return self.get_result_suspstack(h)
- @staticmethod
- def new(thrd, runfn, arg):
- suspendedstacks._thrd = thrd
- suspendedstacks._runfn = runfn
- suspendedstacks._arg = arg
- return stack_protected_call(llhelper(FUNCNOARG_P, _new_callback))
+ def switch(self, thrd, suspstack):
+ self.thrd = thrd
+ self.suspstack = suspstack
+ h = pypy_asm_stackwalk2(llhelper(FUNCNOARG_P, _switch_callback),
+ alternateanchor)
+ return self.get_result_suspstack(h)
- @staticmethod
- def switch(thrd, h):
- suspendedstacks._thrd = thrd
- suspendedstacks._switchto = h
- return stack_protected_call(llhelper(FUNCNOARG_P, _switch_callback))
+ def attach_handle_on_suspstack(self, handle):
+ s = self.suspstack
+ self.suspstack = NULL_SUSPSTACK
+ ll_assert(bool(s.anchor), "s.anchor should not be null")
+ s.handle = handle
+ llop.gc_assume_young_pointers(lltype.Void, llmemory.cast_ptr_to_adr(s))
+ return s
- destroy = staticmethod(rstacklet._destroy)
+ def get_result_suspstack(self, h):
+ #
+ # 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:
+ raise MemoryError
+ elif _c.is_empty_handle(h):
+ return NULL_SUSPSTACK
+ else:
+ # This is a return that gave us a real handle. Store it.
+ return self.attach_handle_on_suspstack(h)
+
+ def destroy(self, thrd, suspstack):
+ h = suspstack.handle
+ a = suspstack.anchor
+ suspstack.handle = _c.null_handle
+ _c.destroy(thrd, h)
+ lltype.free(a, flavor='raw')
+
+ def is_empty_handle(self, suspstack):
+ return not suspstack
+
+ def get_null_handle(self):
+ return lltype.nullptr(SUSPSTACK)
+
+
+gcrootfinder = StackletGcRootFinder()
diff --git a/pypy/rlib/_stacklet_n_a.py b/pypy/rlib/_stacklet_n_a.py
--- a/pypy/rlib/_stacklet_n_a.py
+++ b/pypy/rlib/_stacklet_n_a.py
@@ -1,6 +1,30 @@
-from pypy.rlib import rstacklet
+from pypy.rlib import _rffi_stacklet as _c
+from pypy.rpython.annlowlevel import llhelper
+from pypy.tool.staticmethods import StaticMethods
+
class StackletGcRootFinder:
- new = staticmethod(rstacklet._new)
- switch = staticmethod(rstacklet._switch)
- destroy = staticmethod(rstacklet._destroy)
+ __metaclass__ = StaticMethods
+
+ def new(thrd, callback, arg):
+ h = _c.new(thrd, llhelper(_c.run_fn, callback), arg)
+ if not h:
+ raise MemoryError
+ return h
+ new._annspecialcase_ = 'specialize:arg(1)'
+
+ def switch(thrd, h):
+ h = _c.switch(thrd, h)
+ if not h:
+ raise MemoryError
+ return h
+
+ destroy = _c.destroy
+
+ is_empty_handle = _c.is_empty_handle
+
+ def get_null_handle():
+ return _c.null_handle
+
+
+gcrootfinder = StackletGcRootFinder # class object
diff --git a/pypy/rlib/rstacklet.py b/pypy/rlib/rstacklet.py
--- a/pypy/rlib/rstacklet.py
+++ b/pypy/rlib/rstacklet.py
@@ -1,60 +1,40 @@
-import py
-from pypy.tool.autopath import pypydir
-from pypy.rpython.lltypesystem import lltype, llmemory, rffi
-from pypy.translator.tool.cbuild import ExternalCompilationInfo
-from pypy.rpython.annlowlevel import llhelper
+from pypy.rlib import _rffi_stacklet as _c
+from pypy.rpython.lltypesystem import lltype, rffi
-###
-### Note: stacklets do not reliably work on top of CPython, but well,
-### they seem to work fine after being translated... This is due
-### to the fact that on CPython, you get strange effects because the
-### PyThreadState is not explicitly handled when we start a new
-### stacklet or switch to another one, notably the 'frame' field.
-###
+class StackletThread(object):
-cdir = py.path.local(pypydir) / 'translator' / 'c'
+ def __init__(self, config):
+ self._gcrootfinder = _getgcrootfinder(config)
+ self._thrd = _c.newthread()
+ if not self._thrd:
+ raise MemoryError
+ def __del__(self):
+ thrd = self._thrd
+ if thrd:
+ self._thrd = lltype.nullptr(_c.thread_handle.TO)
+ _c.deletethread(thrd)
-eci = ExternalCompilationInfo(
- include_dirs = [cdir],
- includes = ['src/stacklet/stacklet.h'],
- separate_module_sources = ['#include "src/stacklet/stacklet.c"\n'],
-)
+ def new(self, callback, arg=lltype.nullptr(rffi.VOIDP.TO)):
+ return self._gcrootfinder.new(self._thrd, callback, arg)
+ new._annspecialcase_ = 'specialize:arg(1)'
-def llexternal(name, args, result):
- return rffi.llexternal(name, args, result, compilation_info=eci,
- _nowrapper=True)
+ def switch(self, stacklet):
+ return self._gcrootfinder.switch(self._thrd, stacklet)
-# ----- types -----
+ def destroy(self, stacklet):
+ self._gcrootfinder.destroy(self._thrd, stacklet)
-handle = rffi.COpaquePtr(typedef='stacklet_handle', compilation_info=eci)
-thread_handle = rffi.COpaquePtr(typedef='stacklet_thread_handle',
- compilation_info=eci)
-run_fn = lltype.Ptr(lltype.FuncType([handle, rffi.VOIDP], handle))
+ def is_empty_handle(self, stacklet):
+ return self._gcrootfinder.is_empty_handle(stacklet)
-# ----- constants -----
-
-def is_empty_handle(h):
- return rffi.cast(lltype.Signed, h) == -1
-
-# ----- functions -----
-
-newthread = llexternal('stacklet_newthread', [], thread_handle)
-deletethread = llexternal('stacklet_deletethread',[thread_handle], lltype.Void)
-
-_new = llexternal('stacklet_new', [thread_handle, run_fn, rffi.VOIDP],
- handle)
-_switch = llexternal('stacklet_switch', [thread_handle, handle], handle)
-_destroy = llexternal('stacklet_destroy', [thread_handle, handle], lltype.Void)
-
-_translate_pointer = llexternal("_stacklet_translate_pointer",
- [handle, llmemory.Address],
- llmemory.Address)
+ def get_null_handle(self):
+ return self._gcrootfinder.get_null_handle()
# ____________________________________________________________
-def getgcclass(config):
+def _getgcrootfinder(config):
if (config is None or
config.translation.gc in ('ref', 'boehm', 'none')): # for tests
gcrootfinder = 'n/a'
@@ -63,18 +43,5 @@
gcrootfinder = gcrootfinder.replace('/', '_')
module = __import__('pypy.rlib._stacklet_%s' % gcrootfinder,
None, None, ['__doc__'])
- return module.StackletGcRootFinder
-getgcclass._annspecialcase_ = 'specialize:memo'
-
-def new(config, thrd, runfn, arg):
- c = getgcclass(config)
- return c.new(thrd, llhelper(run_fn, runfn), arg)
-new._annspecialcase_ = 'specialize:arg(2)'
-
-def switch(config, thrd, h):
- c = getgcclass(config)
- return c.switch(thrd, h)
-
-def destroy(config, thrd, h):
- c = getgcclass(config)
- c.destroy(thrd, h)
+ return module.gcrootfinder
+_getgcrootfinder._annspecialcase_ = 'specialize:memo'
diff --git a/pypy/rlib/test/test_rstacklet.py b/pypy/rlib/test/test_rstacklet.py
--- a/pypy/rlib/test/test_rstacklet.py
+++ b/pypy/rlib/test/test_rstacklet.py
@@ -1,3 +1,4 @@
+import gc
from pypy.rlib import rstacklet, rrandom
from pypy.rlib.rarithmetic import intmask
from pypy.rpython.lltypesystem import lltype, rffi
@@ -10,11 +11,12 @@
config = None
def init(self, seed):
- self.thrd = rstacklet.newthread()
+ self.sthread = rstacklet.StackletThread(self.config)
self.random = rrandom.Random(seed)
def done(self):
- rstacklet.deletethread(self.thrd)
+ self.sthread = None
+ gc.collect(); gc.collect(); gc.collect()
TESTS = []
def here_is_a_test(fn, TESTS=TESTS):
@@ -24,10 +26,9 @@
@here_is_a_test
def test_new(self):
print 'start'
- h = rstacklet.new(self.config, self.thrd, empty_callback,
- rffi.cast(rffi.VOIDP, 123))
+ h = self.sthread.new(empty_callback, rffi.cast(rffi.VOIDP, 123))
print 'end', h
- assert rstacklet.is_empty_handle(h)
+ assert self.sthread.is_empty_handle(h)
def nextstatus(self, nextvalue):
print 'expected nextvalue to be %d, got %d' % (nextvalue,
@@ -38,14 +39,14 @@
@here_is_a_test
def test_simple_switch(self):
self.status = 0
- h = rstacklet.new(self.config, self.thrd, switchbackonce_callback,
- rffi.cast(rffi.VOIDP, 321))
- assert not rstacklet.is_empty_handle(h)
+ h = self.sthread.new(switchbackonce_callback,
+ rffi.cast(rffi.VOIDP, 321))
+ assert not self.sthread.is_empty_handle(h)
self.nextstatus(2)
- h = rstacklet.switch(self.config, runner.thrd, h)
+ h = self.sthread.switch(h)
self.nextstatus(4)
print 'end', h
- assert rstacklet.is_empty_handle(h)
+ assert self.sthread.is_empty_handle(h)
@here_is_a_test
def test_various_depths(self):
@@ -74,7 +75,7 @@
class Task:
def __init__(self, n):
self.n = n
- self.h = lltype.nullptr(rstacklet.handle.TO)
+ self.h = runner.sthread.get_null_handle()
self.lst = []
def withdepth(self, d):
@@ -108,15 +109,14 @@
if not task.h:
# start a new stacklet
print "NEW", n
- h = rstacklet.new(runner.config, runner.thrd,
- variousstackdepths_callback,
- rffi.cast(rffi.VOIDP, n))
+ h = runner.sthread.new(variousstackdepths_callback,
+ rffi.cast(rffi.VOIDP, n))
else:
# switch to this stacklet
print "switch to", n
h = task.h
- task.h = lltype.nullptr(rstacklet.handle.TO)
- h = rstacklet.switch(runner.config, runner.thrd, h)
+ task.h = runner.sthread.get_null_handle()
+ h = runner.sthread.switch(h)
print "back in self.n = %d, coming from %d" % (self.n,
runner.comefrom)
@@ -131,7 +131,7 @@
assert not task.h
task.h = h
else:
- assert rstacklet.is_empty_handle(h)
+ assert runner.sthread.is_empty_handle(h)
runner.comefrom = -1
runner.gointo = -1
assert (res & (res-1)) == 0 # to prevent a tail-call to withdepth()
@@ -150,10 +150,10 @@
print 'in switchbackonce_callback:', h, arg
assert rffi.cast(lltype.Signed, arg) == 321
runner.nextstatus(1)
- assert not rstacklet.is_empty_handle(h)
- h = rstacklet.switch(runner.config, runner.thrd, h)
+ assert not runner.sthread.is_empty_handle(h)
+ h = runner.sthread.switch(h)
runner.nextstatus(3)
- assert not rstacklet.is_empty_handle(h)
+ assert not runner.sthread.is_empty_handle(h)
return h
def variousstackdepths_callback(h, arg):
@@ -167,7 +167,7 @@
assert 0 <= runner.comefrom < 10
task = runner.tasks[runner.comefrom]
assert not task.h
- assert bool(h) and not rstacklet.is_empty_handle(h)
+ assert bool(h) and not runner.sthread.is_empty_handle(h)
task.h = h
runner.comefrom = -1
runner.gointo = -1
@@ -183,8 +183,8 @@
if h:
break
- assert not rstacklet.is_empty_handle(h)
- runner.tasks[n].h = lltype.nullptr(rstacklet.handle.TO)
+ assert not runner.sthread.is_empty_handle(h)
+ runner.tasks[n].h = runner.sthread.get_null_handle()
runner.comefrom = -42
runner.gointo = n
assert runner.nextstep == -1
More information about the pypy-commit
mailing list