added Execution.print: accumulate print operations for some command execution, which are applied later and print time;
authorwenzelm
Wed, 26 Mar 2014 12:15:42 +0100
changeset 56291 e79f76a48449
parent 56288 bf1bdf335ea0
child 56292 1a91a0da65ab
added Execution.print: accumulate print operations for some command execution, which are applied later and print time; misc tuning;
src/Pure/PIDE/command.ML
src/Pure/PIDE/execution.ML
--- a/src/Pure/PIDE/command.ML	Wed Mar 26 09:19:04 2014 +0100
+++ b/src/Pure/PIDE/command.ML	Wed Mar 26 12:15:42 2014 +0100
@@ -20,7 +20,7 @@
     eval -> print list -> print list option
   type print_fn = Toplevel.transition -> Toplevel.state -> unit
   type print_function =
-    {command_name: string, args: string list} ->
+    {command_name: string, args: string list, exec_id: Document_ID.exec} ->
       {delay: Time.time option, pri: int, persistent: bool, strict: bool, print_fn: print_fn} option
   val print_function: string -> print_function -> unit
   val no_print_function: string -> unit
@@ -172,9 +172,10 @@
 
 datatype eval = Eval of {exec_id: Document_ID.exec, eval_process: eval_state memo};
 
-fun eval_eq (Eval {exec_id, ...}, Eval {exec_id = exec_id', ...}) = exec_id = exec_id';
+fun eval_exec_id (Eval {exec_id, ...}) = exec_id;
+val eval_eq = op = o pairself eval_exec_id;
 
-fun eval_running (Eval {exec_id, ...}) = Execution.is_running_exec exec_id;
+val eval_running = Execution.is_running_exec o eval_exec_id;
 fun eval_finished (Eval {eval_process, ...}) = memo_finished eval_process;
 
 fun eval_result (Eval {eval_process, ...}) = memo_result eval_process;
@@ -260,10 +261,13 @@
  {name: string, args: string list, delay: Time.time option, pri: int, persistent: bool,
   exec_id: Document_ID.exec, print_process: unit memo};
 
+fun print_exec_id (Print {exec_id, ...}) = exec_id;
+val print_eq = op = o pairself print_exec_id;
+
 type print_fn = Toplevel.transition -> Toplevel.state -> unit;
 
 type print_function =
-  {command_name: string, args: string list} ->
+  {command_name: string, args: string list, exec_id: Document_ID.exec} ->
     {delay: Time.time option, pri: int, persistent: bool, strict: bool, print_fn: print_fn} option;
 
 local
@@ -277,8 +281,6 @@
       if Exn.is_interrupt exn then reraise exn
       else List.app (Future.error_msg (Toplevel.pos_of tr)) (ML_Compiler.exn_messages_ids exn);
 
-fun print_eq (Print {exec_id, ...}, Print {exec_id = exec_id', ...}) = exec_id = exec_id';
-
 fun print_finished (Print {print_process, ...}) = memo_finished print_process;
 
 fun print_persistent (Print {persistent, ...}) = persistent;
@@ -315,7 +317,7 @@
 
     fun new_print name args get_pr =
       let
-        val params = {command_name = command_name, args = args};
+        val params = {command_name = command_name, args = args, exec_id = eval_exec_id eval};
       in
         (case Exn.capture (Toplevel.controlled_execution NONE get_pr) params of
           Exn.Res NONE => NONE
@@ -353,6 +355,14 @@
 end;
 
 val _ =
+  print_function "Execution.print"
+    (fn {args, exec_id, ...} =>
+      if null args then
+        SOME {delay = NONE, pri = 1, persistent = false, strict = true,
+          print_fn = fn _ => fn _ => Execution.apply_prints exec_id}
+      else NONE);
+
+val _ =
   print_function "print_state"
     (fn {command_name, ...} =>
       SOME {delay = NONE, pri = 1, persistent = false, strict = true,
@@ -373,8 +383,7 @@
   (Eval {exec_id = Document_ID.none, eval_process = memo_value init_eval_state}, []);
 
 fun exec_ids NONE = []
-  | exec_ids (SOME (Eval {exec_id, ...}, prints)) =
-      exec_id :: map (fn Print {exec_id, ...} => exec_id) prints;
+  | exec_ids (SOME (eval, prints)) = eval_exec_id eval :: map print_exec_id prints;
 
 local
 
--- a/src/Pure/PIDE/execution.ML	Wed Mar 26 09:19:04 2014 +0100
+++ b/src/Pure/PIDE/execution.ML	Wed Mar 26 12:15:42 2014 +0100
@@ -16,6 +16,8 @@
   val cancel: Document_ID.exec -> unit
   val terminate: Document_ID.exec -> unit
   val fork: {name: string, pos: Position.T, pri: int} -> (unit -> 'a) -> 'a future
+  val print: (serial -> unit) -> unit
+  val apply_prints: Document_ID.exec -> unit
   val purge: Document_ID.exec list -> unit
   val reset: unit -> Future.group list
   val shutdown: unit -> unit
@@ -26,18 +28,19 @@
 
 (* global state *)
 
-datatype state = State of
-  {execution: Document_ID.execution,  (*overall document execution*)
-   execs: Future.group list Inttab.table};  (*command execs with registered forks*)
+type exec_state = Future.group list * (unit -> unit) list;  (*active forks, prints*)
+type state =
+  Document_ID.execution * (*overall document execution*)
+  exec_state Inttab.table;  (*running command execs*)
 
-fun make_state (execution, execs) = State {execution = execution, execs = execs};
-fun map_state f (State {execution, execs}) = make_state (f (execution, execs));
-
-val init_state = make_state (Document_ID.none, Inttab.make [(Document_ID.none, [])]);
+val init_state: state = (Document_ID.none, Inttab.make [(Document_ID.none, ([], []))]);
 val state = Synchronized.var "Execution.state" init_state;
 
-fun get_state () = let val State args = Synchronized.value state in args end;
-fun change_state f = Synchronized.change state (map_state f);
+fun get_state () = Synchronized.value state;
+fun change_state_result f = Synchronized.change_result state f;
+fun change_state f = Synchronized.change state f;
+
+fun unregistered exec_id = "Unregistered execution: " ^ Document_ID.print exec_id;
 
 
 (* unique running execution *)
@@ -50,29 +53,30 @@
 
 fun discontinue () = change_state (apfst (K Document_ID.none));
 
-fun is_running execution_id = execution_id = #execution (get_state ());
+fun is_running execution_id = execution_id = #1 (get_state ());
 
 
 (* execs *)
 
 fun is_running_exec exec_id =
-  Inttab.defined (#execs (get_state ())) exec_id;
+  Inttab.defined (#2 (get_state ())) exec_id;
 
 fun running execution_id exec_id groups =
-  Synchronized.change_result state
-    (fn State {execution = execution_id', execs} =>
-      let
-        val continue = execution_id = execution_id';
-        val execs' =
-          if continue then
-            Inttab.update_new (exec_id, groups) execs
-              handle Inttab.DUP dup =>
-                raise Fail ("Execution already registered: " ^ Document_ID.print dup)
-          else execs;
-      in (continue, make_state (execution_id', execs')) end);
+  change_state_result (fn (execution_id', execs) =>
+    let
+      val continue = execution_id = execution_id';
+      val execs' =
+        if continue then
+          Inttab.update_new (exec_id, (groups, [])) execs
+            handle Inttab.DUP dup =>
+              raise Fail ("Execution already registered: " ^ Document_ID.print dup)
+        else execs;
+    in (continue, (execution_id', execs')) end);
 
 fun peek exec_id =
-  Inttab.lookup_list (#execs (get_state ())) exec_id;
+  (case Inttab.lookup (#2 (get_state ())) exec_id of
+    SOME (groups, _) => groups
+  | NONE => []);
 
 fun cancel exec_id = List.app Future.cancel_group (peek exec_id);
 fun terminate exec_id = List.app Future.terminate (peek exec_id);
@@ -90,9 +94,10 @@
       val exec_id = the_default 0 (Position.parse_id pos);
       val group = Future.worker_subgroup ();
       val _ = change_state (apsnd (fn execs =>
-        if Inttab.defined execs exec_id
-        then Inttab.cons_list (exec_id, group) execs
-        else raise Fail ("Cannot fork from unregistered execution: " ^ Document_ID.print exec_id)));
+        (case Inttab.lookup execs exec_id of
+          SOME (groups, prints) =>
+            Inttab.update (exec_id, (group :: groups, prints)) execs
+        | NONE => raise Fail (unregistered exec_id))));
 
       val future =
         (singleton o Future.forks)
@@ -121,6 +126,37 @@
     in future end)) ();
 
 
+(* print *)
+
+fun print pr =
+  change_state (apsnd (fn execs =>
+    let
+      val exec_id = the_default 0 (Position.parse_id (Position.thread_data ()));
+      val i = serial ();
+    in
+      (case Inttab.lookup execs exec_id of
+        SOME (groups, prints) =>
+          Inttab.update (exec_id, (groups, (fn () => pr i) :: prints)) execs
+      | NONE => raise Fail (unregistered exec_id))
+    end));
+
+fun apply_prints exec_id =
+  (case Inttab.lookup (#2 (get_state ())) exec_id of
+    SOME (_, prints) =>
+      if null prints orelse null (tl prints) orelse not (Multithreading.enabled ())
+      then List.app (fn e => e ()) (rev prints)
+      else
+        let
+          val pos = Position.thread_data ();
+          val pri =
+            (case Future.worker_task () of
+              SOME task => Task_Queue.pri_of_task task
+            | NONE => 0);
+          val futures = map (fork {name = "Execution.print", pos = pos, pri = pri}) (rev prints);
+        in ignore (Future.joins futures) end
+  | NONE => raise Fail (unregistered exec_id));
+
+
 (* cleanup *)
 
 fun purge exec_ids =
@@ -128,7 +164,7 @@
     let
       val execs' = fold Inttab.delete_safe exec_ids execs;
       val () =
-        (execs', ()) |-> Inttab.fold (fn (exec_id, groups) => fn () =>
+        (execs', ()) |-> Inttab.fold (fn (exec_id, (groups, _)) => fn () =>
           if Inttab.defined execs' exec_id then ()
           else groups |> List.app (fn group =>
             if Task_Queue.is_canceled group then ()
@@ -136,8 +172,8 @@
     in execs' end);
 
 fun reset () =
-  Synchronized.change_result state (fn State {execs, ...} =>
-    let val groups = Inttab.fold (append o #2) execs []
+  change_state_result (fn (_, execs) =>
+    let val groups = Inttab.fold (append o #1 o #2) execs []
     in (groups, init_state) end);
 
 fun shutdown () =