Stack switching for fun and profit
-
Upload
saul-ibarra-corretge -
Category
Technology
-
view
534 -
download
0
description
Transcript of Stack switching for fun and profit
Stack switchingfor fun & profitSaúl Ibarra Corretgé - @saghul
FOSDEM 2014
Hi!
@saghul
FOSDEM
Open Source
import open_source
github.com/saghul
Some background
Who knows what greenlet is?
Who has used it (standalone)?
Who understands how it works?
Greenlet
Micro-threads with no implicit scheduling
Lightweight
Only one can run at a time
Spin-off Stackless
Greenlet APIgreenlet(func, parent=None): creates a greenlet to run ‘func’
greenlet.switch(*args, **kw): switches execution to the target greenlet, the first timefunc(*args, **kw) will be executed
greenlet.throw([typ, [val, [tb]]]): switches execution to the target greenlet and raises the specified exception (GreenletExit by default)
Exampleimport greenlet
main = greenlet.getcurrent()
def foo(n): main.switch(n)
def bar(n): foo(n) return 'hello'
g1 = greenlet.greenlet(bar)print g1.switch(42) # 42print g1.switch() # 'hello'print g1.dead # True
How does it work?‘Stack switching’
Non portable asm code
Copy stack slices on the heap
State is saved and restored when switching
CPU registers
Current Python frame, recursion depth and exception state
How does it work? (II)
Organized in a tree structure
Each greenlet has a ‘parent’, except main
Execution order isn’t always obvious
Example (II)import greenlet
main = greenlet.getcurrent()
def foo_async(cb): # Will call cb(result, error) eventually pass
def foo_sync(): current = greenlet.getcurrent() def cb(result, error): if error is not None: current.throw(Exception(error)) else: current.switch(result) foo_async(cb) main.switch()
Stackless Python
Fork of CPython, first release in 1999
Provides tasklets and channels
Builtin scheduler
Different approaches to switching
Stackless Python (II)Different ways of switching: soft and hard
Soft switching
“Move some pointers around”
Hard switching
Platform dependent assembly code
When soft-switching is not possible
Enter PyPy
New shiny and fast implementation of Python
Vast amount of fairy-dust covered unicorns included
Includes implementations of both greenlet and Stackless
Implemented on top of “continulet” objects
import _continuation
Continulets are one-shot continuations
Switching code is a standalone C library: stacklet
rpython/translator/c/src/stacklet/
Continulet APIcontinulet(func, *args, **kw): create a continulet object which will call fun(cont, *args, **kw)
continulet.switch(value=None, to=None): start the continulet or activate the previously suspended one. If to is specified a ‘double switch’ is performed
continulet.throw(type, value=None, tb=None, to=None): similar to switch, but raise the given exception after the switch is done
Stacklet
Tiny library implementing one-shot continuations for C
Single C file (~400 lines) + per-platform asm
Supports x86, x86_64 and ARM
Nice and simple API
Stacklet API
stacklet_newthread(): creates a new thread handle
stacklet_new(thread_handle, run_func, run_arg): calls run(arg) in a new stacklet, starts immediately
stacklet_switch(target): switches execution to target stacklet
Example#include <assert.h>#include "stacklet.h"
static stacklet_thread_handle thrd;
stacklet_handle empty_callback(stacklet_handle h, void *arg){ assert(arg == (void *)123); return h;}
void test_new(void){ stacklet_handle h = stacklet_new(thrd, empty_callback, (void *)123); assert(h == EMPTY_STACKLET_HANDLE);}
int main(int argc, char **argv){ thrd = stacklet_newthread(); test_new(); stacklet_deletethread(thrd); return 0;}
import fibersMicro-threadling library API inspired by Python threads and greenlet
Uses stacklet underneath
Works on CPython and PyPy
On PyPy it uses continulets
github.com/saghul/python-fibers
Or pip install fibers
fibers APIFiber(target=None, args=(), kwargs={}, parent=None): creates a new fiber which will run “target(*args, **kwargs)”
Fiber.switch(value=None): switch execution to the target fiber, value can only be passed after the fiber is running
Fiber.throw(typ, [value, [tb]]): switch execution to the target fiber and raise the specified exception
Motivation
Couldn’t build the API I wanted on top of greenlet
Early binding
More exceptions in expected places
No magic exceptions (GreenletExit)
No switching on GC
Exampleimport fibers
main = fibers.current()
def foo(n): main.switch(n)
def bar(n): foo(n) return 'hello'
g1 = fibers.Fiber(target=bar, args=(42,))print g1.switch() # 42print g1.switch() # 'hello'print g1.is_alive() # False
Projects using fibers
github.com/saghul/evergreen
github.com/geertj/gruvi
github.com/benoitc/offset
Should I add yours here?
The Stacklet Sandwich (TM)
stacklet
continulet
greenlet / stackless / fibers
Questions?
bettercallsaghul.com@saghul