[pypy-commit] pypy stacklet: Starting on the new _stacklet module...
arigo
noreply at buildbot.pypy.org
Sat Aug 6 12:31:14 CEST 2011
Author: Armin Rigo <arigo at tunes.org>
Branch: stacklet
Changeset: r46309:8d3f74f9011b
Date: 2011-08-06 11:15 +0200
http://bitbucket.org/pypy/pypy/changeset/8d3f74f9011b/
Log: Starting on the new _stacklet module...
diff --git a/pypy/module/_stacklet/__init__.py b/pypy/module/_stacklet/__init__.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_stacklet/__init__.py
@@ -0,0 +1,15 @@
+from pypy.interpreter.mixedmodule import MixedModule
+
+
+class Module(MixedModule):
+ """
+ This module exposes stacklets directly.
+ """
+
+ appleveldefs = {
+ 'error': 'app_stacklet.error',
+ }
+
+ interpleveldefs = {
+ 'newstacklet': 'interp_stacklet.stacklet_new',
+ }
diff --git a/pypy/module/_stacklet/app_stacklet.py b/pypy/module/_stacklet/app_stacklet.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_stacklet/app_stacklet.py
@@ -0,0 +1,4 @@
+
+
+class error(Exception):
+ "Usage error of the _stacklet module."
diff --git a/pypy/module/_stacklet/interp_stacklet.py b/pypy/module/_stacklet/interp_stacklet.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_stacklet/interp_stacklet.py
@@ -0,0 +1,96 @@
+from pypy.rpython.lltypesystem import lltype, rffi
+from pypy.rlib import rstacklet
+from pypy.interpreter.error import OperationError
+from pypy.interpreter.executioncontext import ExecutionContext
+from pypy.interpreter.baseobjspace import Wrappable
+from pypy.interpreter.typedef import TypeDef
+from pypy.interpreter.gateway import interp2app
+
+
+class SThread(object):
+ def __init__(self, space):
+ w_module = space.getbuiltinmodule('_stacklet')
+ self.space = space
+ self.w_error = space.getattr(w_module, space.wrap('error'))
+ self.thrd = rstacklet.newthread()
+ if not self.thrd:
+ raise MemoryError
+
+ def __del__(self):
+ thrd = self.thrd
+ if thrd:
+ self.thrd = lltype.nullptr(rstacklet.thread_handle.TO)
+ rstacklet.deletethread(thrd)
+
+ def new_stacklet_object(self, space, h):
+ 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 space.w_None
+ else:
+ return W_Stacklet(self, h)
+
+ExecutionContext.stacklet_thread = None
+
+
+class W_Stacklet(Wrappable):
+ def __init__(self, sthread, h):
+ self.sthread = sthread
+ self.h = h
+
+ def consume_handle(self):
+ h = self.h
+ if h:
+ self.h = lltype.nullptr(rstacklet.handle.TO)
+ return h
+ else:
+ space = self.sthread.space
+ raise OperationError(
+ self.sthread.w_error,
+ space.wrap("stacklet has already been resumed"))
+
+ def is_pending(self, space):
+ return space.newbool(bool(self.h))
+
+W_Stacklet.typedef = TypeDef(
+ 'Stacklet',
+ __module__ = '_stacklet',
+ is_pending = interp2app(W_Stacklet.is_pending),
+ )
+
+
+class StartState:
+ sthread = None # xxx a single global to pass around the function to start
+ w_callable = None
+ args = None
+start_state = StartState()
+
+def new_stacklet_callback(h, arg):
+ sthread = start_state.sthread
+ w_callable = start_state.w_callable
+ args = start_state.args
+ start_state.sthread = None
+ start_state.w_callable = None
+ start_state.args = None
+ #
+ space = sthread.space
+ args = args.prepend(space.wrap(W_Stacklet(sthread, h)))
+ w_result = space.call_args(w_callable, args)
+ #
+ assert isinstance(w_result, W_Stacklet)
+ return w_result.consume_handle()
+
+def stacklet_new(space, w_callable, __args__):
+ ec = space.getexecutioncontext()
+ sthread = ec.stacklet_thread
+ if not sthread:
+ sthread = ec.stacklet_thread = SThread(space)
+ start_state.sthread = sthread
+ start_state.w_callable = w_callable
+ start_state.args = __args__
+ h = rstacklet.new(sthread.thrd, new_stacklet_callback,
+ lltype.nullptr(rffi.VOIDP.TO))
+ return sthread.new_stacklet_object(space, h)
diff --git a/pypy/module/_stacklet/test/test_stacklet.py b/pypy/module/_stacklet/test/test_stacklet.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_stacklet/test/test_stacklet.py
@@ -0,0 +1,19 @@
+from pypy.conftest import gettestobjspace
+
+
+class AppTestStacklet:
+ def setup_class(cls):
+ cls.space = gettestobjspace(usemodules=['_stacklet'])
+
+ def test_new_empty(self):
+ from _stacklet import newstacklet
+ #
+ def empty_callback(h):
+ assert h.is_pending()
+ seen.append(1)
+ return h
+ #
+ seen = []
+ h = newstacklet(empty_callback)
+ assert h is None
+ assert seen == [1]
diff --git a/pypy/rlib/rcoroutine.py b/pypy/rlib/rcoroutine.py
--- a/pypy/rlib/rcoroutine.py
+++ b/pypy/rlib/rcoroutine.py
@@ -29,6 +29,11 @@
The type of a switch is determined by the target's costate.
"""
+import py; py.test.skip("fixme: rewrite using rlib.rstacklet")
+# XXX ^^^ the reason it is not done is that pypy.rlib.rcoroutine
+# plus pypy/module/_stackless look like faaaaaar too much code
+# to me :-(
+
from pypy.rlib.rstack import yield_current_frame_to_caller
from pypy.rlib.objectmodel import we_are_translated
diff --git a/pypy/rlib/rstacklet.py b/pypy/rlib/rstacklet.py
--- a/pypy/rlib/rstacklet.py
+++ b/pypy/rlib/rstacklet.py
@@ -3,12 +3,15 @@
###
### Note: stacklets do not reliably work on top of CPython, but well,
-### they seem to work fine after being translated...
+### 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'
-cdir = '/home/arigo/hg/arigo/hack/pypy-hack/stacklet'
+cdir = '/home/arigo/hg/arigo/hack/pypy-hack/stacklet' # XXX FIXME
eci = ExternalCompilationInfo(
@@ -18,8 +21,8 @@
)
def llexternal(name, args, result):
- return rffi.llexternal(name, args, result, compilation_info=eci)
-
+ return rffi.llexternal(name, args, result, compilation_info=eci,
+ sandboxsafe=True)
# ----- types -----
More information about the pypy-commit
mailing list