
Guido van Rossum wrote:
...
[cooperative multitasking]
Right. That PEP better explain how one writes C code that calls into Python without involving the C stack as well!
Quick reply to give you an idea:
A tail recursive call is rather trivial, so here the non-trivial side of the coin:
Conventional style:
PyObject * some_c_code(some_args) { PyObject *ret, ret2;
/* do preparation things */ /* call into Python */
ret = PyEval_CallObject(some_args);
/* do post-processing */ ret2 = some_other_processing(ret); return ret2; }
Stackless style (simplified and sketched, only):
PyObject * some_c_code(some_args) { PyObject *ret, ret2;
/* do preparation things */ create_miniframe(some_c_code_post); /* put parameters in miniframe */
/* deferred call into Python */
ret = PyEval_CallObject_defer(some_args); return <special value> }
PyObject * some_c_code_post(miniframe) { /* reload variables from miniframe */ /* drop miniframe */ /* do post-processing */ ret2 = some_other_processing(ret); return ret2; }
So the idea is to avoid recursions by creating frame-like tiny structures, which are then executed by a toplevel loop which does nothing than call the next frame. The <special value> (not specified here) passes through the currently involved C code as a dummy which unwinds the stack until the toplevel loop is reached. There this value is captured and unpacked, and execution continues.
Well, this was rough and incomplete. A PEP would be nice and also quite much work. The protocol sketched above is a lot of work to do if you want to do it throughout all of Python, and I didn't do it in most cases, but did the simple tail-recursive things (which don't need that extra tinyframe) everywhere where possible. If adopting a similar technique for parts of Python is not feasible, then the PEP would be a waste of time. There is no other principal way to do it in plain C, IMHO.
cheers - chris