[pypy-svn] r30218 - pypy/dist/pypy/module/_stackless
auc at codespeak.net
auc at codespeak.net
Wed Jul 19 12:43:48 CEST 2006
Author: auc
Date: Wed Jul 19 12:43:46 2006
New Revision: 30218
Modified:
pypy/dist/pypy/module/_stackless/__init__.py
pypy/dist/pypy/module/_stackless/interp_clonable.py
Log:
clonable coroutines with more cholesterol
Modified: pypy/dist/pypy/module/_stackless/__init__.py
==============================================================================
--- pypy/dist/pypy/module/_stackless/__init__.py (original)
+++ pypy/dist/pypy/module/_stackless/__init__.py Wed Jul 19 12:43:46 2006
@@ -14,6 +14,7 @@
interpleveldefs = {
'tasklet' : 'interp_stackless.tasklet',
'coroutine' : 'coroutine.AppCoroutine',
+ 'clonable' : 'interp_clonable.ClonableCoroutine',
'greenlet' : 'interp_greenlet.AppGreenlet',
}
@@ -22,6 +23,8 @@
# are not yet directly supported
from pypy.module._stackless.coroutine import post_install as post_install_coro
post_install_coro(self)
+ from pypy.module._stackless.interp_clonable import post_install as post_install_clonable
+ post_install_clonable(self)
from pypy.module._stackless.interp_greenlet import post_install as post_install_greenlet
post_install_greenlet(self)
Modified: pypy/dist/pypy/module/_stackless/interp_clonable.py
==============================================================================
--- pypy/dist/pypy/module/_stackless/interp_clonable.py (original)
+++ pypy/dist/pypy/module/_stackless/interp_clonable.py Wed Jul 19 12:43:46 2006
@@ -1,26 +1,25 @@
-from pypy.module._stackless.interp_coroutine import AbstractThunk
-from pypy.module._stackless.coroutine import AppCoroutine
+from pypy.module._stackless.interp_coroutine import AbstractThunk, BaseCoState, Coroutine
from pypy.rpython.rgc import gc_swap_pool, gc_clone
from pypy.rpython.objectmodel import we_are_translated
-class InterpClonableCoroutine(AppCoroutine):
+from pypy.module._stackless.stackless_flags import StacklessFlags
+from pypy.interpreter.function import StaticMethod
+from pypy.interpreter.typedef import GetSetProperty, TypeDef
+from pypy.interpreter.gateway import interp2app, ObjSpace, W_Root
+
+from pypy.rpython import rstack # for resume points
+from pypy.tool import stdlib_opcode as pythonopcode
+
+class InterpClonableCoroutine(Coroutine):
local_pool = None
def hello(self):
if we_are_translated():
self.saved_pool = gc_swap_pool(self.local_pool)
- else:
- AppCoroutine.hello(self)
def goodbye(self):
if we_are_translated():
self.local_pool = gc_swap_pool(self.saved_pool)
- else:
- AppCoroutine.goodbye(self)
-
- def w_getcurrent(space):
- return space.wrap(InterpClonableCoroutine._get_state(space).current)
- w_getcurrent = staticmethod(w_getcurrent)
def clone(self):
if not we_are_translated():
@@ -39,6 +38,220 @@
return copy
+class ClonableCoroutine(InterpClonableCoroutine):
+ #XXX yes, cut'n'pasted from AppCoroutine, how nice
+
+ def __init__(self, space, is_main=False):
+ self.space = space
+ state = self._get_state(space)
+ Coroutine.__init__(self, state)
+ self.flags = 0
+ self.framestack = None
+ if not is_main:
+ space.getexecutioncontext().subcontext_new(self)
+ self._exc = None # not space.w_None ?
+
+ def hello(self):
+ if we_are_translated():
+ super(ClonableCoroutine, self).hello()
+ else:
+ ec = self.space.getexecutioncontext()
+ ec.subcontext_enter(self)
+
+ def goodbye(self):
+ if we_are_translated():
+ super(ClonableCoroutine, self).goodbye()
+ else:
+ ec = self.space.getexecutioncontext()
+ ec.subcontext_leave(self)
+
+ def w_getcurrent(space):
+ return space.wrap(ClonableCoroutine._get_state(space).current)
+ w_getcurrent = staticmethod(w_getcurrent)
+
+ def w_finished(self, w_excinfo):
+ """called by AppCoroutine.finish"""
+ self._exc = w_excinfo
+
+ def is_dead(self):
+ return self._exc is not None
+
+ def w_switch(self):
+ space = self.space
+ if self.frame is None:
+ raise OperationError(space.w_ValueError, space.wrap(
+ "cannot switch to an unbound Coroutine"))
+ self.switch()
+ rstack.resume_point("w_switch", self, space)
+ state = self.costate
+ w_ret, state.w_tempval = state.w_tempval, space.w_None
+ return w_ret
+
+ def _get_state(space):
+ return space.fromcache(AppCoState)
+ _get_state = staticmethod(_get_state)
+
+
+ def descr_method__new__(space, w_subtype):
+ co = space.allocate_instance(ClonableCoroutine, w_subtype)
+ ClonableCoroutine.__init__(co, space)
+ return space.wrap(co)
+
+
+ def finish(self, operror=None):
+ space = self.space
+ if isinstance(operror, OperationError):
+ w_exctype = operror.w_type
+ w_excvalue = operror.w_value
+ w_exctraceback = operror.application_traceback
+ w_excinfo = space.newtuple([w_exctype, w_excvalue, w_exctraceback])
+ else:
+ w_N = space.w_None
+ w_excinfo = space.newtuple([w_N, w_N, w_N])
+ return space.call_method(space.wrap(self),'finished', w_excinfo)
+
+
+ # pickling interface
+ def descr__reduce__(self, space):
+ # this is trying to be simplistic at the moment.
+ # we neither allow to pickle main (which can become a mess
+ # since it has some deep anchestor frames)
+ # nor we allowto pickle the current coroutine.
+ # rule: switch before pickling.
+ # you cannot construct the tree that you are climbing.
+ # XXX missing checks!
+ from pypy.interpreter.mixedmodule import MixedModule
+ w_mod = space.getbuiltinmodule('_stackless')
+ mod = space.interp_w(MixedModule, w_mod)
+ w_mod2 = space.getbuiltinmodule('_pickle_support')
+ mod2 = space.interp_w(MixedModule, w_mod2)
+ new_inst = mod.get('coroutine')
+ w = space.wrap
+ nt = space.newtuple
+ ec = self.space.getexecutioncontext()
+
+ if self is self._get_state(space).main:
+ return space.newtuple([mod2.get('return_main'), space.newtuple([])])
+
+ tup_base = [
+ ]
+ tup_state = [
+ w(self.flags),
+ ec.subcontext_getstate(self),
+ ]
+
+ return nt([new_inst, nt(tup_base), nt(tup_state)])
+
+ def descr__setstate__(self, space, w_args):
+ args_w = space.unpackiterable(w_args)
+ w_flags, w_state = args_w
+ self.flags = space.int_w(w_flags)
+ self.parent = ClonableCoroutine._get_state(space).current
+ ec = self.space.getexecutioncontext()
+ ec.subcontext_setstate(self, w_state)
+ self.reconstruct_framechain()
+
+ def reconstruct_framechain(self):
+ from pypy.interpreter.pyframe import PyFrame
+ from pypy.rpython.rstack import resume_state_create
+ if self.framestack.empty():
+ self.frame = None
+ return
+
+ space = self.space
+ ec = space.getexecutioncontext()
+ costate = self.costate
+ # now the big fun of recreating tiny things...
+ bottom = resume_state_create(None, "yield_current_frame_to_caller_1")
+ # resume_point("coroutine__bind", self, state)
+ _bind_frame = resume_state_create(bottom, "coroutine__bind", self, costate)
+ # rstack.resume_point("appthunk", costate, returns=w_result)
+ appthunk_frame = resume_state_create(_bind_frame, "appthunk", costate)
+ chain = appthunk_frame
+ for frame in self.framestack.items:
+ assert isinstance(frame, PyFrame)
+ # rstack.resume_point("evalframe", self, executioncontext, returns=result)
+ evalframe_frame = resume_state_create(chain, "evalframe", frame, ec)
+ # rstack.resume_point("eval", self, executioncontext)
+ eval_frame = resume_state_create(evalframe_frame, "eval", frame, ec)
+ # rstack.resume_point("dispatch_call", self, code, ec)
+ code = frame.getcode().co_code
+ dispatch_call_frame = resume_state_create(eval_frame, "dispatch_call", frame, code, ec)
+ instr = frame.last_instr
+ opcode = ord(code[instr])
+ assert opcode == pythonopcode.opmap['CALL_FUNCTION']
+ instr += 1
+ oparg = ord(code[instr]) | ord(code[instr + 1]) << 8
+ if (oparg >> 8) & 0xff == 0:
+ # Only positional arguments
+ nargs = oparg & 0xff
+ # case1: rstack.resume_point("CALL_FUNCTION", f, nargs, returns=w_result)
+ call_frame = resume_state_create(dispatch_call_frame, 'CALL_FUNCTION', frame, nargs)
+ else:
+ # case2: rstack.resume_point("call_function", f, returns=w_result)
+ call_frame = resume_state_create(dispatch_call_frame, 'call_function', frame)
+ chain = call_frame
+
+ # rstack.resume_point("w_switch", self, space)
+ w_switch_frame = resume_state_create(chain, 'w_switch', self, space)
+ # resume_point("coroutine_switch", self, state, returns=incoming_frame)
+ switch_frame = resume_state_create(w_switch_frame, "coroutine_switch", self, costate)
+ self.frame = switch_frame
+
+
+def makeStaticMethod(module, classname, funcname):
+ space = module.space
+ space.appexec(map(space.wrap, (module, classname, funcname)), """
+ (module, klassname, funcname):
+ klass = getattr(module, klassname)
+ func = getattr(klass, funcname)
+ setattr(klass, funcname, staticmethod(func.im_func))
+ """)
+
+def post_install(module):
+ makeStaticMethod(module, 'clonable', 'getcurrent')
+ space = module.space
+ ClonableCoroutine._get_state(space).post_install()
+
+class AppCoState(BaseCoState):
+ def __init__(self, space):
+ BaseCoState.__init__(self)
+ self.w_tempval = space.w_None
+ self.space = space
+
+ def post_install(self):
+ self.current = self.main = ClonableCoroutine(self.space, is_main=True)
+
+def w_descr__framestack(space, self):
+ assert isinstance(self, ClonableCoroutine)
+ if self.framestack:
+ items = [space.wrap(item) for item in self.framestack.items]
+ return space.newtuple(items)
+ else:
+ return space.newtuple([])
+
+# _mixin_ did not work
+for methname in StacklessFlags.__dict__:
+ meth = getattr(StacklessFlags, methname)
+ if hasattr(meth, 'im_func'):
+ setattr(ClonableCoroutine, meth.__name__, meth.im_func)
+del meth, methname
+
+
+
+ClonableCoroutine.typedef = TypeDef("clonable",
+ __new__ = interp2app(ClonableCoroutine.descr_method__new__.im_func),
+ _framestack = GetSetProperty(w_descr__framestack),
+ getcurrent = interp2app(ClonableCoroutine.w_getcurrent),
+ __reduce__ = interp2app(ClonableCoroutine.descr__reduce__,
+ unwrap_spec=['self', ObjSpace]),
+ __setstate__ = interp2app(ClonableCoroutine.descr__setstate__,
+ unwrap_spec=['self', ObjSpace, W_Root]),
+ __module__ = '_stackless',
+)
+
+
+#--------------------------------------------
class ForkThunk(AbstractThunk):
def __init__(self, coroutine):
self.coroutine = coroutine
@@ -54,11 +267,12 @@
into the parent), or None (if returning into the child). This returns
into the parent first, which can switch to the child later.
"""
+ #XXX ClonableCoroutine might well be InterpClonableCoroutine
current = ClonableCoroutine.getcurrent()
if not isinstance(current, ClonableCoroutine):
raise RuntimeError("fork() in a non-clonable coroutine")
thunk = ForkThunk(current)
- coro_fork = ClonableCoroutine()
+ coro_fork = ClonableCoroutine()
coro_fork.bind(thunk)
coro_fork.switch()
# we resume here twice. The following would need explanations about
More information about the Pypy-commit
mailing list