| author | wenzelm | 
| Sat, 11 Jan 2014 17:05:03 +0100 | |
| changeset 54992 | e5f4075d4c5e | 
| parent 54678 | 87910da843d5 | 
| child 56291 | e79f76a48449 | 
| permissions | -rw-r--r-- | 
| 52605 | 1 | (* Title: Pure/PIDE/execution.ML | 
| 52596 | 2 | Author: Makarius | 
| 3 | ||
| 52606 | 4 | Global management of execution. Unique running execution serves as | 
| 53192 | 5 | barrier for further exploration of forked command execs. | 
| 52596 | 6 | *) | 
| 7 | ||
| 52605 | 8 | signature EXECUTION = | 
| 52596 | 9 | sig | 
| 52606 | 10 | val start: unit -> Document_ID.execution | 
| 11 | val discontinue: unit -> unit | |
| 12 | val is_running: Document_ID.execution -> bool | |
| 52784 
4ba2e8b9972f
de-assign execs that were not registered as running yet -- observe change of perspective more thoroughly;
 wenzelm parents: 
52775diff
changeset | 13 | val is_running_exec: Document_ID.exec -> bool | 
| 53375 
78693e46a237
Execution.fork formally requires registered Execution.running;
 wenzelm parents: 
53193diff
changeset | 14 | val running: Document_ID.execution -> Document_ID.exec -> Future.group list -> bool | 
| 53192 | 15 | val peek: Document_ID.exec -> Future.group list | 
| 52655 
3b2b1ef13979
more careful termination of removed execs, leaving running execs undisturbed;
 wenzelm parents: 
52608diff
changeset | 16 | val cancel: Document_ID.exec -> unit | 
| 
3b2b1ef13979
more careful termination of removed execs, leaving running execs undisturbed;
 wenzelm parents: 
52608diff
changeset | 17 | val terminate: Document_ID.exec -> unit | 
| 53192 | 18 |   val fork: {name: string, pos: Position.T, pri: int} -> (unit -> 'a) -> 'a future
 | 
| 19 | val purge: Document_ID.exec list -> unit | |
| 20 | val reset: unit -> Future.group list | |
| 21 | val shutdown: unit -> unit | |
| 52596 | 22 | end; | 
| 23 | ||
| 52605 | 24 | structure Execution: EXECUTION = | 
| 52596 | 25 | struct | 
| 26 | ||
| 52787 
c143ad7811fc
pro-forma Execution.reset, despite lack of final join/commit;
 wenzelm parents: 
52784diff
changeset | 27 | (* global state *) | 
| 
c143ad7811fc
pro-forma Execution.reset, despite lack of final join/commit;
 wenzelm parents: 
52784diff
changeset | 28 | |
| 53192 | 29 | datatype state = State of | 
| 30 |   {execution: Document_ID.execution,  (*overall document execution*)
 | |
| 31 | execs: Future.group list Inttab.table}; (*command execs with registered forks*) | |
| 52787 
c143ad7811fc
pro-forma Execution.reset, despite lack of final join/commit;
 wenzelm parents: 
52784diff
changeset | 32 | |
| 53192 | 33 | fun make_state (execution, execs) = State {execution = execution, execs = execs};
 | 
| 34 | fun map_state f (State {execution, execs}) = make_state (f (execution, execs));
 | |
| 35 | ||
| 53375 
78693e46a237
Execution.fork formally requires registered Execution.running;
 wenzelm parents: 
53193diff
changeset | 36 | val init_state = make_state (Document_ID.none, Inttab.make [(Document_ID.none, [])]); | 
| 52787 
c143ad7811fc
pro-forma Execution.reset, despite lack of final join/commit;
 wenzelm parents: 
52784diff
changeset | 37 | val state = Synchronized.var "Execution.state" init_state; | 
| 52602 
00170ef1dc39
strictly monotonic Document.update: avoid disruptive cancel_execution, merely discontinue_execution and cancel/terminate old execs individually;
 wenzelm parents: 
52596diff
changeset | 38 | |
| 53192 | 39 | fun get_state () = let val State args = Synchronized.value state in args end; | 
| 40 | fun change_state f = Synchronized.change state (map_state f); | |
| 41 | ||
| 52604 | 42 | |
| 52606 | 43 | (* unique running execution *) | 
| 52604 | 44 | |
| 52606 | 45 | fun start () = | 
| 52602 
00170ef1dc39
strictly monotonic Document.update: avoid disruptive cancel_execution, merely discontinue_execution and cancel/terminate old execs individually;
 wenzelm parents: 
52596diff
changeset | 46 | let | 
| 52606 | 47 | val execution_id = Document_ID.make (); | 
| 53192 | 48 | val _ = change_state (apfst (K execution_id)); | 
| 52606 | 49 | in execution_id end; | 
| 52604 | 50 | |
| 53192 | 51 | fun discontinue () = change_state (apfst (K Document_ID.none)); | 
| 52606 | 52 | |
| 53192 | 53 | fun is_running execution_id = execution_id = #execution (get_state ()); | 
| 52604 | 54 | |
| 55 | ||
| 53192 | 56 | (* execs *) | 
| 52604 | 57 | |
| 52784 
4ba2e8b9972f
de-assign execs that were not registered as running yet -- observe change of perspective more thoroughly;
 wenzelm parents: 
52775diff
changeset | 58 | fun is_running_exec exec_id = | 
| 53192 | 59 | Inttab.defined (#execs (get_state ())) exec_id; | 
| 52784 
4ba2e8b9972f
de-assign execs that were not registered as running yet -- observe change of perspective more thoroughly;
 wenzelm parents: 
52775diff
changeset | 60 | |
| 53375 
78693e46a237
Execution.fork formally requires registered Execution.running;
 wenzelm parents: 
53193diff
changeset | 61 | fun running execution_id exec_id groups = | 
| 
78693e46a237
Execution.fork formally requires registered Execution.running;
 wenzelm parents: 
53193diff
changeset | 62 | Synchronized.change_result state | 
| 53192 | 63 |     (fn State {execution = execution_id', execs} =>
 | 
| 52604 | 64 | let | 
| 52606 | 65 | val continue = execution_id = execution_id'; | 
| 52604 | 66 | val execs' = | 
| 52606 | 67 | if continue then | 
| 53375 
78693e46a237
Execution.fork formally requires registered Execution.running;
 wenzelm parents: 
53193diff
changeset | 68 | Inttab.update_new (exec_id, groups) execs | 
| 53192 | 69 | handle Inttab.DUP dup => | 
| 53375 
78693e46a237
Execution.fork formally requires registered Execution.running;
 wenzelm parents: 
53193diff
changeset | 70 |                 raise Fail ("Execution already registered: " ^ Document_ID.print dup)
 | 
| 52604 | 71 | else execs; | 
| 53375 
78693e46a237
Execution.fork formally requires registered Execution.running;
 wenzelm parents: 
53193diff
changeset | 72 | in (continue, make_state (execution_id', execs')) end); | 
| 53192 | 73 | |
| 74 | fun peek exec_id = | |
| 75 | Inttab.lookup_list (#execs (get_state ())) exec_id; | |
| 76 | ||
| 77 | fun cancel exec_id = List.app Future.cancel_group (peek exec_id); | |
| 78 | fun terminate exec_id = List.app Future.terminate (peek exec_id); | |
| 79 | ||
| 80 | ||
| 81 | (* fork *) | |
| 82 | ||
| 83 | fun status task markups = | |
| 84 | let val props = Markup.properties [(Markup.taskN, Task_Queue.str_of_task task)] | |
| 85 | in Output.status (implode (map (Markup.markup_only o props) markups)) end; | |
| 86 | ||
| 87 | fun fork {name, pos, pri} e =
 | |
| 88 | uninterruptible (fn _ => Position.setmp_thread_data pos (fn () => | |
| 89 | let | |
| 90 | val exec_id = the_default 0 (Position.parse_id pos); | |
| 91 | val group = Future.worker_subgroup (); | |
| 53375 
78693e46a237
Execution.fork formally requires registered Execution.running;
 wenzelm parents: 
53193diff
changeset | 92 | val _ = change_state (apsnd (fn execs => | 
| 
78693e46a237
Execution.fork formally requires registered Execution.running;
 wenzelm parents: 
53193diff
changeset | 93 | if Inttab.defined execs exec_id | 
| 
78693e46a237
Execution.fork formally requires registered Execution.running;
 wenzelm parents: 
53193diff
changeset | 94 | then Inttab.cons_list (exec_id, group) execs | 
| 
78693e46a237
Execution.fork formally requires registered Execution.running;
 wenzelm parents: 
53193diff
changeset | 95 |         else raise Fail ("Cannot fork from unregistered execution: " ^ Document_ID.print exec_id)));
 | 
| 52655 
3b2b1ef13979
more careful termination of removed execs, leaving running execs undisturbed;
 wenzelm parents: 
52608diff
changeset | 96 | |
| 53192 | 97 | val future = | 
| 98 | (singleton o Future.forks) | |
| 99 |           {name = name, group = SOME group, deps = [], pri = pri, interrupts = false}
 | |
| 100 | (fn () => | |
| 101 | let | |
| 102 | val task = the (Future.worker_task ()); | |
| 103 | val _ = status task [Markup.running]; | |
| 104 | val result = | |
| 105 | Exn.capture (Future.interruptible_task e) () | |
| 106 | |> Future.identify_result pos; | |
| 54646 
2b38549374ba
more robust status reports: avoid loosing information about physical events (see also 28d207ba9340, 2bc5924b117f, 9edfd36a0355) -- NB: TTY and Proof General ignore Output.status and Output.report;
 wenzelm parents: 
53375diff
changeset | 107 | val _ = status task [Markup.joined]; | 
| 53192 | 108 | val _ = | 
| 109 | (case result of | |
| 54678 
87910da843d5
more uniform status -- accommodate spurious Exn.Interrupt from user code, allow ML_Compiler.exn_messages_id to crash;
 wenzelm parents: 
54646diff
changeset | 110 | Exn.Exn exn => | 
| 54646 
2b38549374ba
more robust status reports: avoid loosing information about physical events (see also 28d207ba9340, 2bc5924b117f, 9edfd36a0355) -- NB: TTY and Proof General ignore Output.status and Output.report;
 wenzelm parents: 
53375diff
changeset | 111 | (status task [Markup.failed]; | 
| 54678 
87910da843d5
more uniform status -- accommodate spurious Exn.Interrupt from user code, allow ML_Compiler.exn_messages_id to crash;
 wenzelm parents: 
54646diff
changeset | 112 | status task [Markup.finished]; | 
| 54646 
2b38549374ba
more robust status reports: avoid loosing information about physical events (see also 28d207ba9340, 2bc5924b117f, 9edfd36a0355) -- NB: TTY and Proof General ignore Output.status and Output.report;
 wenzelm parents: 
53375diff
changeset | 113 | Output.report (Markup.markup_only Markup.bad); | 
| 
2b38549374ba
more robust status reports: avoid loosing information about physical events (see also 28d207ba9340, 2bc5924b117f, 9edfd36a0355) -- NB: TTY and Proof General ignore Output.status and Output.report;
 wenzelm parents: 
53375diff
changeset | 114 | if exec_id = 0 then () | 
| 54678 
87910da843d5
more uniform status -- accommodate spurious Exn.Interrupt from user code, allow ML_Compiler.exn_messages_id to crash;
 wenzelm parents: 
54646diff
changeset | 115 | else List.app (Future.error_msg pos) (ML_Compiler.exn_messages_ids exn)) | 
| 
87910da843d5
more uniform status -- accommodate spurious Exn.Interrupt from user code, allow ML_Compiler.exn_messages_id to crash;
 wenzelm parents: 
54646diff
changeset | 116 | | Exn.Res _ => | 
| 
87910da843d5
more uniform status -- accommodate spurious Exn.Interrupt from user code, allow ML_Compiler.exn_messages_id to crash;
 wenzelm parents: 
54646diff
changeset | 117 | status task [Markup.finished]) | 
| 53192 | 118 | in Exn.release result end); | 
| 54646 
2b38549374ba
more robust status reports: avoid loosing information about physical events (see also 28d207ba9340, 2bc5924b117f, 9edfd36a0355) -- NB: TTY and Proof General ignore Output.status and Output.report;
 wenzelm parents: 
53375diff
changeset | 119 | |
| 53192 | 120 | val _ = status (Future.task_of future) [Markup.forked]; | 
| 121 | in future end)) (); | |
| 52604 | 122 | |
| 53192 | 123 | |
| 124 | (* cleanup *) | |
| 125 | ||
| 126 | fun purge exec_ids = | |
| 127 | (change_state o apsnd) (fn execs => | |
| 128 | let | |
| 129 | val execs' = fold Inttab.delete_safe exec_ids execs; | |
| 130 | val () = | |
| 131 | (execs', ()) |-> Inttab.fold (fn (exec_id, groups) => fn () => | |
| 132 | if Inttab.defined execs' exec_id then () | |
| 133 | else groups |> List.app (fn group => | |
| 134 | if Task_Queue.is_canceled group then () | |
| 53375 
78693e46a237
Execution.fork formally requires registered Execution.running;
 wenzelm parents: 
53193diff
changeset | 135 |             else raise Fail ("Attempt to purge valid execution: " ^ Document_ID.print exec_id)));
 | 
| 53192 | 136 | in execs' end); | 
| 137 | ||
| 138 | fun reset () = | |
| 139 |   Synchronized.change_result state (fn State {execs, ...} =>
 | |
| 140 | let val groups = Inttab.fold (append o #2) execs [] | |
| 141 | in (groups, init_state) end); | |
| 142 | ||
| 143 | fun shutdown () = | |
| 144 | (Future.shutdown (); | |
| 145 | (case maps Task_Queue.group_status (reset ()) of | |
| 146 | [] => () | |
| 147 | | exns => raise Par_Exn.make exns)); | |
| 148 | ||
| 149 | end; | |
| 150 |