Import Upstream version 20180207
[hcoop/debian/mlton.git] / lib / cml / core-cml / thread.sml
CommitLineData
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
12structure 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