Skip to content

Commit b6391d9

Browse files
committed
first commit of re-enabling stacklets
1 parent 5766c61 commit b6391d9

6 files changed

Lines changed: 147 additions & 3 deletions

File tree

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@ all: help
22

33
EXTERNALS=../externals
44

5-
PYTHON ?= python
5+
PYTHON ?= pypy
66
PYTHONPATH=$$PYTHONPATH:$(EXTERNALS)/pypy
77

88

9-
COMMON_BUILD_OPTS?=--thread --no-shared --gcrootfinder=shadowstack
9+
COMMON_BUILD_OPTS?=--thread --no-shared --gcrootfinder=shadowstack --continuation
1010
JIT_OPTS?=--opt=jit
1111
TARGET_OPTS?=target.py
1212

pixie/stacklets.pxi

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
(ns pixie.stacklets
2+
(require pixie.uv :as uv))
3+
4+
(def stacklet-loop-h (atom nil))
5+
6+
(defn -spawn-thread [fn]
7+
(let [[h val] (@stacklet-loop-h [:spawn fn])]
8+
(reset! stacklet-loop-h h)
9+
(println h val)
10+
val))
11+
12+
(defn enqueue [q itm]
13+
; TODO: Rewrite this crappy impl
14+
(vec (conj (seq q) itm)))
15+
16+
(defn dequeue [q]
17+
[(ith q -1)
18+
(pop q)])
19+
20+
21+
(defn yield-control []
22+
(let [[h] (@stacklet-loop-h [:yield nil])]
23+
(reset! stacklet-loop-h h)
24+
nil))
25+
26+
27+
(defmacro spawn [& body]
28+
`(let [f (fn [h# _]
29+
(reset! stacklet-loop-h h#)
30+
(try
31+
(println "spawn" h#)
32+
;(reset! stacklet-loop-h h#)
33+
(let [result# (do ~@body)]
34+
(println "returning " result#)
35+
(@stacklet-loop-h [:spawn-end result#]))
36+
(catch e (println e))))
37+
[h# val#] (@stacklet-loop-h [:spawn f])]
38+
(reset! stacklet-loop-h h#)
39+
val#))
40+
41+
(defn -with-stacklets [fn]
42+
(let [[h [op arg]] ((new-stacklet fn) nil)]
43+
(println h op arg)
44+
(loop [op op
45+
arg arg
46+
this_h h
47+
tasks []]
48+
(println "in loop" op arg this_h tasks)
49+
(cond
50+
(= op :spawn) (let [wh (new-stacklet arg)
51+
[h [op arg]] (this_h nil)]
52+
(recur op arg h (enqueue tasks wh)))
53+
(= op :yield) (let [tasks (enqueue tasks this_h)
54+
[task tasks] (dequeue tasks)
55+
[h [op arg]] (task nil)]
56+
(recur op arg h tasks))
57+
(= op :spawn-end) (if (empty? tasks)
58+
arg
59+
(let [[task tasks] (dequeue tasks)
60+
[h [op arg]] (task nil)]
61+
(recur op arg h tasks)))
62+
:else (assert false (str "Unkown command " op " " arg))))))
63+
64+
65+
(defmacro with-stacklets [& body]
66+
`(-with-stacklets
67+
(fn [h# _]
68+
(try
69+
(println h# _)
70+
(reset! stacklet-loop-h h#)
71+
(let [result# (do ~@body)]
72+
(@stacklet-loop-h [:spawn-end result#]))
73+
(catch e
74+
(println e))))))
75+
76+
(with-stacklets (spawn (dotimes [x 10]
77+
(yield-control)
78+
(println x)))
79+
(spawn (dotimes [x 10]
80+
(yield-control)
81+
(println x)))(yield-control))

pixie/stdlib.pxi

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1630,7 +1630,10 @@ All these forms can be combined and nested, in the example below:
16301630

16311631
For more information, see http://clojure.org/special_forms#binding-forms"}
16321632
[bindings & body]
1633-
(let* [destructured-bindings (transduce (map #(apply destructure %1))
1633+
(let* [destructured-bindings (transduce (map (fn [args]
1634+
(assert (= 2 (count args)) (str "Bindings must be in pairs, not " args
1635+
" " (meta (first args))))
1636+
(apply destructure args)))
16341637
concat
16351638
[]
16361639
(partition 2 bindings))]

pixie/vm/rt.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ def wrapper(*args):
6868
import pixie.vm.libs.string
6969
import pixie.vm.threads
7070
import pixie.vm.string_builder
71+
import pixie.vm.stacklet
7172

7273
numbers.init()
7374

pixie/vm/stacklet.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import rpython.rlib.rstacklet as rstacklet
2+
from pixie.vm.object import Object, Type, affirm
3+
from pixie.vm.code import as_var
4+
import pixie.vm.rt as rt
5+
6+
7+
class GlobalState(object):
8+
def __init__(self):
9+
self._is_inited = False
10+
self._val = None
11+
12+
13+
global_state = GlobalState()
14+
15+
16+
def init():
17+
if not global_state._is_inited:
18+
global_state._th = rstacklet.StackletThread(rt.__config__)
19+
global_state._is_inited = True
20+
21+
22+
class StackletHandle(Object):
23+
_type = Type(u"StackletHandle")
24+
def __init__(self, h):
25+
self._stacklet_handle = h
26+
self._used = False
27+
28+
def type(self):
29+
return self._type
30+
31+
def invoke(self, args):
32+
affirm(not self._used, u"Can only call a given stacklet handle once.")
33+
affirm(len(args) == 1, u"Only one arg should be handed to a stacklet handle")
34+
self._used = True
35+
global_state._val = args[0]
36+
new_h = StackletHandle(global_state._th.switch(self._stacklet_handle))
37+
val = global_state._val
38+
global_state._val = None
39+
return rt.vector(new_h, val)
40+
41+
def new_handler(h, _):
42+
fn = global_state._val
43+
global_state._val = None
44+
h = global_state._th.switch(h)
45+
val = global_state._val
46+
fn.invoke([StackletHandle(h), val])
47+
affirm(False, u"TODO: What do we do now?")
48+
return h
49+
50+
51+
52+
@as_var("new-stacklet")
53+
def new_stacklet(fn):
54+
global_state._val = fn
55+
h = global_state._th.new(new_handler)
56+
return StackletHandle(h)

target.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,9 @@ def load_stdlib():
185185

186186
def entry_point(args):
187187
try:
188+
import pixie.vm.stacklet
189+
pixie.vm.stacklet.init()
190+
188191
interactive = True
189192
exit = False
190193
script_args = []

0 commit comments

Comments
 (0)