Import Upstream version 20180207
[hcoop/debian/mlton.git] / lib / mlton / basic / engine.sml
CommitLineData
7f918cf1
CE
1(* Copyright (C) 1999-2006 Henry Cejtin, Matthew Fluet, Suresh
2 * Jagannathan, and Stephen Weeks.
3 *
4 * MLton is released under a BSD-style license.
5 * See the file MLton-LICENSE for details.
6 *)
7
8structure Engine: ENGINE =
9struct
10
11datatype 'a t = T of {return: 'a res Thread.t option ref,
12 thread: Thread.Runnable.t}
13and 'a res =
14 Done of 'a
15 | Raise of exn
16 | TimeOut of 'a t
17
18val which = Itimer.Real
19val signal = Itimer.signal which
20
21fun done (return): unit =
22 (return := NONE
23 ; Itimer.set (which, {value = Time.zero,
24 interval = Time.zero})
25 ; Signal.setHandler (signal, Signal.Handler.default))
26
27fun new (f: unit -> 'a): 'a t =
28 let
29 val return = ref NONE
30 val thread =
31 Thread.new
32 (fn () =>
33 let
34 val res = Done (f ()) handle e => Raise e
35 val ret = valOf (!return)
36 val _ = done return
37 in
38 Thread.switch (fn _ => Thread.prepare (ret, res))
39 end)
40 val thread = Thread.prepare (thread, ())
41 in
42 T {return = return, thread = thread}
43 end
44
45fun run (T {return, thread}, time: Time.t): 'a res =
46 Thread.switch
47 (fn cur: 'a res Thread.t =>
48 let
49 val _ = return := SOME cur
50 fun handler (me: Thread.Runnable.t): Thread.Runnable.t =
51 Thread.prepare
52 (Thread.prepend (cur, fn () => (done return
53 ; TimeOut (T {return = return,
54 thread = me}))),
55 ())
56 val _ = Signal.setHandler (signal, Signal.Handler.handler handler)
57 val _ = Itimer.set (which, {value = time,
58 interval = Time.zero})
59 in
60 thread
61 end)
62
63fun timeLimit (t: Time.t, f: unit -> 'a): 'a option =
64 case run (new f, t) of
65 Done a => SOME a
66 | Raise e => raise e
67 | TimeOut _ => NONE
68
69fun repeat {thunk, limit, tries} =
70 let
71 fun loop (n: int) =
72 if n <= 0
73 then NONE
74 else (case timeLimit (limit, thunk) of
75 NONE => loop (n - 1)
76 | SOME a => SOME a)
77 in loop tries
78 end
79
80end