src/HOL/Tools/ATP_Manager/async_manager.ML
author blanchet
Fri, 25 Jun 2010 18:05:36 +0200
changeset 37583 9ce2451647d5
child 37584 2e289dc13615
permissions -rw-r--r--
factored non-ATP specific code from "ATP_Manager" out, so that it can be reused for the LEO-II integration
blanchet@37583
     1
(*  Title:      HOL/Tools/ATP_Manager/async_manager.ML
blanchet@37583
     2
    Author:     Fabian Immler, TU Muenchen
blanchet@37583
     3
    Author:     Makarius
blanchet@37583
     4
    Author:     Jasmin Blanchette, TU Muenchen
blanchet@37583
     5
blanchet@37583
     6
Central manager for asynchronous diagnosis tool threads.
blanchet@37583
     7
*)
blanchet@37583
     8
blanchet@37583
     9
signature ASYNC_MANAGER =
blanchet@37583
    10
sig
blanchet@37583
    11
  val unregister : bool -> string -> Thread.thread -> unit
blanchet@37583
    12
  val register :
blanchet@37583
    13
    string -> bool -> Time.time -> Time.time -> Thread.thread * string -> unit
blanchet@37583
    14
  val kill_threads : string -> unit
blanchet@37583
    15
  val running_threads : string -> unit
blanchet@37583
    16
  val thread_messages : string -> int option -> unit
blanchet@37583
    17
end;
blanchet@37583
    18
blanchet@37583
    19
structure Async_Manager : ASYNC_MANAGER =
blanchet@37583
    20
struct
blanchet@37583
    21
blanchet@37583
    22
(** preferences **)
blanchet@37583
    23
blanchet@37583
    24
val message_store_limit = 20;
blanchet@37583
    25
val message_display_limit = 5;
blanchet@37583
    26
blanchet@37583
    27
blanchet@37583
    28
(** thread management **)
blanchet@37583
    29
blanchet@37583
    30
(* data structures over threads *)
blanchet@37583
    31
blanchet@37583
    32
structure Thread_Heap = Heap
blanchet@37583
    33
(
blanchet@37583
    34
  type elem = Time.time * Thread.thread;
blanchet@37583
    35
  fun ord ((a, _), (b, _)) = Time.compare (a, b);
blanchet@37583
    36
);
blanchet@37583
    37
blanchet@37583
    38
fun lookup_thread xs = AList.lookup Thread.equal xs;
blanchet@37583
    39
fun delete_thread xs = AList.delete Thread.equal xs;
blanchet@37583
    40
fun update_thread xs = AList.update Thread.equal xs;
blanchet@37583
    41
blanchet@37583
    42
blanchet@37583
    43
(* state of thread manager *)
blanchet@37583
    44
blanchet@37583
    45
type state =
blanchet@37583
    46
 {manager: Thread.thread option,
blanchet@37583
    47
  timeout_heap: Thread_Heap.T,
blanchet@37583
    48
  active: (Thread.thread * (Time.time * Time.time * string)) list,
blanchet@37583
    49
  canceling: (Thread.thread * (Time.time * string)) list,
blanchet@37583
    50
  messages: string list,
blanchet@37583
    51
  store: string list};
blanchet@37583
    52
blanchet@37583
    53
fun make_state manager timeout_heap active canceling messages store : state =
blanchet@37583
    54
  {manager = manager, timeout_heap = timeout_heap, active = active,
blanchet@37583
    55
   canceling = canceling, messages = messages, store = store}
blanchet@37583
    56
blanchet@37583
    57
val global_state = Synchronized.var "async_manager"
blanchet@37583
    58
  (make_state NONE Thread_Heap.empty [] [] [] []);
blanchet@37583
    59
blanchet@37583
    60
blanchet@37583
    61
(* unregister thread *)
blanchet@37583
    62
blanchet@37583
    63
fun unregister verbose message thread =
blanchet@37583
    64
  Synchronized.change global_state
blanchet@37583
    65
  (fn state as {manager, timeout_heap, active, canceling, messages, store} =>
blanchet@37583
    66
    (case lookup_thread active thread of
blanchet@37583
    67
      SOME (birth_time, _, desc) =>
blanchet@37583
    68
        let
blanchet@37583
    69
          val active' = delete_thread thread active;
blanchet@37583
    70
          val now = Time.now ()
blanchet@37583
    71
          val canceling' = (thread, (now, desc)) :: canceling
blanchet@37583
    72
          val message' =
blanchet@37583
    73
            desc ^ "\n" ^ message ^
blanchet@37583
    74
            (if verbose then
blanchet@37583
    75
               "Total time: " ^ Int.toString (Time.toMilliseconds
blanchet@37583
    76
                                          (Time.- (now, birth_time))) ^ " ms.\n"
blanchet@37583
    77
             else
blanchet@37583
    78
               "")
blanchet@37583
    79
          val messages' = message' :: messages;
blanchet@37583
    80
          val store' = message' ::
blanchet@37583
    81
            (if length store <= message_store_limit then store
blanchet@37583
    82
             else #1 (chop message_store_limit store));
blanchet@37583
    83
        in make_state manager timeout_heap active' canceling' messages' store' end
blanchet@37583
    84
    | NONE => state));
blanchet@37583
    85
blanchet@37583
    86
blanchet@37583
    87
(* main manager thread -- only one may exist *)
blanchet@37583
    88
blanchet@37583
    89
val min_wait_time = Time.fromMilliseconds 300;
blanchet@37583
    90
val max_wait_time = Time.fromSeconds 10;
blanchet@37583
    91
blanchet@37583
    92
fun replace_all bef aft =
blanchet@37583
    93
  let
blanchet@37583
    94
    fun aux seen "" = String.implode (rev seen)
blanchet@37583
    95
      | aux seen s =
blanchet@37583
    96
        if String.isPrefix bef s then
blanchet@37583
    97
          aux seen "" ^ aft ^ aux [] (unprefix bef s)
blanchet@37583
    98
        else
blanchet@37583
    99
          aux (String.sub (s, 0) :: seen) (String.extract (s, 1, NONE))
blanchet@37583
   100
  in aux [] end
blanchet@37583
   101
blanchet@37583
   102
(* This is a workaround for Proof General's off-by-a-few sendback display bug,
blanchet@37583
   103
   whereby "pr" in "proof" is not highlighted. *)
blanchet@37583
   104
val break_into_chunks =
blanchet@37583
   105
  map (replace_all "\n\n" "\000") #> maps (space_explode "\000")
blanchet@37583
   106
blanchet@37583
   107
fun print_new_messages tool =
blanchet@37583
   108
  case Synchronized.change_result global_state
blanchet@37583
   109
         (fn {manager, timeout_heap, active, canceling, messages, store} =>
blanchet@37583
   110
             (messages, make_state manager timeout_heap active canceling []
blanchet@37583
   111
                                   store)) of
blanchet@37583
   112
    [] => ()
blanchet@37583
   113
  | msgs =>
blanchet@37583
   114
    msgs |> break_into_chunks
blanchet@37583
   115
         |> (fn msg :: msgs => tool ^ ": " ^ msg :: msgs)
blanchet@37583
   116
         |> List.app priority
blanchet@37583
   117
blanchet@37583
   118
fun check_thread_manager tool verbose = Synchronized.change global_state
blanchet@37583
   119
  (fn state as {manager, timeout_heap, active, canceling, messages, store} =>
blanchet@37583
   120
    if (case manager of SOME thread => Thread.isActive thread | NONE => false) then state
blanchet@37583
   121
    else let val manager = SOME (Toplevel.thread false (fn () =>
blanchet@37583
   122
      let
blanchet@37583
   123
        fun time_limit timeout_heap =
blanchet@37583
   124
          (case try Thread_Heap.min timeout_heap of
blanchet@37583
   125
            NONE => Time.+ (Time.now (), max_wait_time)
blanchet@37583
   126
          | SOME (time, _) => time);
blanchet@37583
   127
blanchet@37583
   128
        (*action: find threads whose timeout is reached, and interrupt canceling threads*)
blanchet@37583
   129
        fun action {manager, timeout_heap, active, canceling, messages, store} =
blanchet@37583
   130
          let val (timeout_threads, timeout_heap') =
blanchet@37583
   131
            Thread_Heap.upto (Time.now (), Thread.self ()) timeout_heap;
blanchet@37583
   132
          in
blanchet@37583
   133
            if null timeout_threads andalso null canceling
blanchet@37583
   134
            then NONE
blanchet@37583
   135
            else
blanchet@37583
   136
              let
blanchet@37583
   137
                val _ = List.app (Simple_Thread.interrupt o #1) canceling
blanchet@37583
   138
                val canceling' = filter (Thread.isActive o #1) canceling
blanchet@37583
   139
                val state' = make_state manager timeout_heap' active canceling' messages store;
blanchet@37583
   140
              in SOME (map #2 timeout_threads, state') end
blanchet@37583
   141
          end;
blanchet@37583
   142
      in
blanchet@37583
   143
        while Synchronized.change_result global_state
blanchet@37583
   144
          (fn state as {timeout_heap, active, canceling, messages, store, ...} =>
blanchet@37583
   145
            if null active andalso null canceling andalso null messages
blanchet@37583
   146
            then (false, make_state NONE timeout_heap active canceling messages store)
blanchet@37583
   147
            else (true, state))
blanchet@37583
   148
        do
blanchet@37583
   149
          (Synchronized.timed_access global_state (SOME o time_limit o #timeout_heap) action
blanchet@37583
   150
            |> these
blanchet@37583
   151
            |> List.app (unregister verbose "Timed out.\n");
blanchet@37583
   152
            print_new_messages tool;
blanchet@37583
   153
            (*give threads some time to respond to interrupt*)
blanchet@37583
   154
            OS.Process.sleep min_wait_time)
blanchet@37583
   155
      end))
blanchet@37583
   156
    in make_state manager timeout_heap active canceling messages store end)
blanchet@37583
   157
blanchet@37583
   158
blanchet@37583
   159
(* register thread *)
blanchet@37583
   160
blanchet@37583
   161
fun register tool verbose birth_time death_time (thread, desc) =
blanchet@37583
   162
 (Synchronized.change global_state
blanchet@37583
   163
    (fn {manager, timeout_heap, active, canceling, messages, store} =>
blanchet@37583
   164
      let
blanchet@37583
   165
        val timeout_heap' = Thread_Heap.insert (death_time, thread) timeout_heap;
blanchet@37583
   166
        val active' = update_thread (thread, (birth_time, death_time, desc)) active;
blanchet@37583
   167
        val state' = make_state manager timeout_heap' active' canceling messages store;
blanchet@37583
   168
      in state' end);
blanchet@37583
   169
  check_thread_manager tool verbose);
blanchet@37583
   170
blanchet@37583
   171
blanchet@37583
   172
blanchet@37583
   173
(** user commands **)
blanchet@37583
   174
blanchet@37583
   175
(* kill threads *)
blanchet@37583
   176
blanchet@37583
   177
fun kill_threads tools = Synchronized.change global_state
blanchet@37583
   178
  (fn {manager, timeout_heap, active, canceling, messages, store} =>
blanchet@37583
   179
    let
blanchet@37583
   180
      val killing = map (fn (th, (_, _, desc)) => (th, (Time.now (), desc))) active;
blanchet@37583
   181
      val state' = make_state manager timeout_heap [] (killing @ canceling) messages store;
blanchet@37583
   182
      val _ = if null active then () else priority ("Killed active " ^ tools ^ ".")
blanchet@37583
   183
    in state' end);
blanchet@37583
   184
blanchet@37583
   185
blanchet@37583
   186
(* running threads *)
blanchet@37583
   187
blanchet@37583
   188
fun seconds time = string_of_int (Time.toSeconds time) ^ "s";
blanchet@37583
   189
blanchet@37583
   190
fun running_threads tools =
blanchet@37583
   191
  let
blanchet@37583
   192
    val {active, canceling, ...} = Synchronized.value global_state;
blanchet@37583
   193
blanchet@37583
   194
    val now = Time.now ();
blanchet@37583
   195
    fun running_info (_, (birth_time, death_time, desc)) =
blanchet@37583
   196
      "Running: " ^ seconds (Time.- (now, birth_time)) ^ " -- " ^
blanchet@37583
   197
        seconds (Time.- (death_time, now)) ^ " to live:\n" ^ desc;
blanchet@37583
   198
    fun canceling_info (_, (deadth_time, desc)) =
blanchet@37583
   199
      "Trying to interrupt thread since " ^ seconds (Time.- (now, deadth_time)) ^ ":\n" ^ desc;
blanchet@37583
   200
blanchet@37583
   201
    val running =
blanchet@37583
   202
      case map running_info active of
blanchet@37583
   203
        [] => ["No " ^ tools ^ " running."]
blanchet@37583
   204
      | ss => "Running " ^ tools ^ ":" :: ss
blanchet@37583
   205
    val interrupting =
blanchet@37583
   206
      case map canceling_info canceling of
blanchet@37583
   207
        [] => []
blanchet@37583
   208
      | ss => "Trying to interrupt the following " ^ tools ^ ":" :: ss
blanchet@37583
   209
  in priority (space_implode "\n\n" (running @ interrupting)) end
blanchet@37583
   210
blanchet@37583
   211
fun thread_messages tool opt_limit =
blanchet@37583
   212
  let
blanchet@37583
   213
    val limit = the_default message_display_limit opt_limit;
blanchet@37583
   214
    val {store, ...} = Synchronized.value global_state;
blanchet@37583
   215
    val header =
blanchet@37583
   216
      "Recent " ^ tool ^ " messages" ^
blanchet@37583
   217
        (if length store <= limit then ":" else " (" ^ string_of_int limit ^ " displayed):");
blanchet@37583
   218
  in List.app priority (header :: break_into_chunks (#1 (chop limit store))) end
blanchet@37583
   219
blanchet@37583
   220
end;