Commit | Line | Data |
---|---|---|
7f918cf1 CE |
1 | (* thread.sml |
2 | * 2004 Matthew Fluet (mfluet@acm.org) | |
3 | * Ported to MLton threads. | |
4 | *) | |
5 | ||
6 | (* thread.sml | |
7 | * | |
8 | * COPYRIGHT (c) 1995 AT&T Bell Laboratories. | |
9 | * COPYRIGHT (c) 1989-1991 John H. Reppy | |
10 | *) | |
11 | ||
12 | structure Thread : THREAD = | |
13 | struct | |
14 | structure Assert = LocalAssert(val assert = false) | |
15 | structure Debug = LocalDebug(val debug = false) | |
16 | ||
17 | structure S = Scheduler | |
18 | fun debug msg = Debug.sayDebug ([S.atomicMsg, S.tidMsg], msg) | |
19 | fun debug' msg = debug (fn () => msg) | |
20 | ||
21 | open ThreadID | |
22 | ||
23 | fun generalExit (tid', clr') = | |
24 | let | |
25 | val () = Assert.assertNonAtomic' "Thread.generalExit" | |
26 | val () = debug' "generalExit" (* NonAtomic *) | |
27 | val () = Assert.assertNonAtomic' "Thread.generalExit" | |
28 | in | |
29 | S.switchToNext | |
30 | (fn t => | |
31 | let | |
32 | val tid as TID {dead, props, ...} = S.getThreadId t | |
33 | val () = Assert.assert ([], fn () => | |
34 | concat ["Thread.generalExit ", | |
35 | Option.getOpt (Option.map tidToString tid', "NONE"), | |
36 | " <> ", | |
37 | tidToString tid], fn () => | |
38 | case tid' of NONE => true | |
39 | | SOME tid' => sameTid (tid', tid)) | |
40 | val () = if clr' then props := [] else () | |
41 | val () = Event.atomicCVarSet dead | |
42 | in | |
43 | () | |
44 | end) | |
45 | end | |
46 | ||
47 | fun doHandler (TID {exnHandler, ...}, exn) = | |
48 | (debug (fn () => concat ["Exception: ", exnName exn, " : ", exnMessage exn]) | |
49 | ; ((!exnHandler) exn) handle _ => ()) | |
50 | ||
51 | fun spawnc f x = | |
52 | let | |
53 | val () = S.atomicBegin () | |
54 | fun thread tid () = | |
55 | ((f x) handle ex => doHandler (tid, ex) | |
56 | ; generalExit (SOME tid, false)) | |
57 | val t = S.new thread | |
58 | val tid = S.getThreadId t | |
59 | val () = S.ready (S.prep t) | |
60 | val () = S.atomicEnd () | |
61 | val () = debug (fn () => concat ["spawnc ", tidToString tid]) (* NonAtomic *) | |
62 | in | |
63 | tid | |
64 | end | |
65 | fun spawn f = spawnc f () | |
66 | ||
67 | fun joinEvt (TID{dead, ...}) = Event.cvarGetEvt dead | |
68 | ||
69 | val getTid = S.getCurThreadId | |
70 | ||
71 | fun exit () = | |
72 | let | |
73 | val () = Assert.assertNonAtomic' "Thread.exit" | |
74 | val () = debug' "exit" (* NonAtomic *) | |
75 | val () = Assert.assertNonAtomic' "Thread.exit" | |
76 | in | |
77 | generalExit (NONE, true) | |
78 | end | |
79 | ||
80 | fun yield () = | |
81 | let | |
82 | val () = Assert.assertNonAtomic' "Thread.yield" | |
83 | val () = debug' "yield" (* NonAtomic *) | |
84 | val () = Assert.assertNonAtomic' "Thread.yield" | |
85 | in | |
86 | S.readyAndSwitchToNext (fn () => ()) | |
87 | end | |
88 | ||
89 | (* thread-local data *) | |
90 | local | |
91 | fun mkProp () = | |
92 | let | |
93 | exception E of 'a | |
94 | fun cons (a, l) = E a :: l | |
95 | fun peek [] = NONE | |
96 | | peek (E a :: _) = SOME a | |
97 | | peek (_ :: l) = peek l | |
98 | fun delete [] = [] | |
99 | | delete (E _ :: r) = r | |
100 | | delete (x :: r) = x :: delete r | |
101 | in | |
102 | {cons = cons, | |
103 | peek = peek, | |
104 | delete = delete} | |
105 | end | |
106 | fun mkFlag () = | |
107 | let | |
108 | exception E | |
109 | fun peek [] = false | |
110 | | peek (E :: _) = true | |
111 | | peek (_ :: l) = peek l | |
112 | fun set (l, flg) = | |
113 | let | |
114 | fun set ([], _) = if flg then E::l else l | |
115 | | set (E::r, xs) = if flg then l else List.revAppend(xs, r) | |
116 | | set (x::r, xs) = set (r, x::xs) | |
117 | in | |
118 | set (l, []) | |
119 | end | |
120 | in | |
121 | {set = set, | |
122 | peek = peek} | |
123 | end | |
124 | fun getProps () = | |
125 | let val TID {props, ...} = getTid () | |
126 | in props | |
127 | end | |
128 | in | |
129 | fun newThreadProp (init : unit -> 'b) = | |
130 | let | |
131 | val {peek, cons, delete} = mkProp() | |
132 | fun peekFn () = peek(!(getProps())) | |
133 | fun getF () = | |
134 | let val h = getProps() | |
135 | in | |
136 | case peek(!h) of | |
137 | NONE => let val b = init() | |
138 | in h := cons(b, !h); b | |
139 | end | |
140 | | (SOME b) => b | |
141 | end | |
142 | fun clrF () = | |
143 | let val h = getProps() | |
144 | in h := delete(!h) | |
145 | end | |
146 | fun setFn x = | |
147 | let val h = getProps() | |
148 | in h := cons(x, delete(!h)) | |
149 | end | |
150 | in | |
151 | {peekFn = peekFn, | |
152 | getFn = getF, | |
153 | clrFn = clrF, | |
154 | setFn = setFn} | |
155 | end | |
156 | ||
157 | fun newThreadFlag () = | |
158 | let | |
159 | val {peek, set} = mkFlag() | |
160 | fun getF ()= peek(!(getProps())) | |
161 | fun setF flg = | |
162 | let val h = getProps() | |
163 | in h := set(!h, flg) | |
164 | end | |
165 | in | |
166 | {getFn = getF, | |
167 | setFn = setF} | |
168 | end | |
169 | end | |
170 | end |