src/Pure/System/bash.ML
author wenzelm
Tue, 18 Oct 2016 16:03:30 +0200
changeset 64304 96bc94c87a81
parent 62923 3a122e1e352a
child 71692 f8e52c0152fe
permissions -rw-r--r--
clarified modules;
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
62584
6cd36a0d2a28 clarified files;
wenzelm
parents: 62569
diff changeset
     1
(*  Title:      Pure/System/bash.ML
40748
591b6778d076 removed bash from ML system bootstrap, and past the Secure ML barrier;
wenzelm
parents:
diff changeset
     2
    Author:     Makarius
591b6778d076 removed bash from ML system bootstrap, and past the Secure ML barrier;
wenzelm
parents:
diff changeset
     3
62879
4764473c9b8d back to static conditional compilation -- simplified bootstrap;
wenzelm
parents: 62850
diff changeset
     4
GNU bash processes, with propagation of interrupts -- POSIX version.
40748
591b6778d076 removed bash from ML system bootstrap, and past the Secure ML barrier;
wenzelm
parents:
diff changeset
     5
*)
591b6778d076 removed bash from ML system bootstrap, and past the Secure ML barrier;
wenzelm
parents:
diff changeset
     6
44054
da5fcc0f6c52 proper signature;
wenzelm
parents: 43850
diff changeset
     7
signature BASH =
da5fcc0f6c52 proper signature;
wenzelm
parents: 43850
diff changeset
     8
sig
64304
96bc94c87a81 clarified modules;
wenzelm
parents: 62923
diff changeset
     9
  val string: string -> string
96bc94c87a81 clarified modules;
wenzelm
parents: 62923
diff changeset
    10
  val strings: string list -> string
47499
4b0daca2bf88 redirect bash stderr to Isabelle warning as appropriate -- avoid raw process error output which may either get ignored or overload PIDE syslog in extreme cases;
wenzelm
parents: 44112
diff changeset
    11
  val process: string -> {out: string, err: string, rc: int, terminate: unit -> unit}
44054
da5fcc0f6c52 proper signature;
wenzelm
parents: 43850
diff changeset
    12
end;
da5fcc0f6c52 proper signature;
wenzelm
parents: 43850
diff changeset
    13
62911
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    14
if ML_System.platform_is_windows then ML
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    15
\<open>
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    16
structure Bash: BASH =
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    17
struct
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    18
64304
96bc94c87a81 clarified modules;
wenzelm
parents: 62923
diff changeset
    19
val string = Bash_Syntax.string;
96bc94c87a81 clarified modules;
wenzelm
parents: 62923
diff changeset
    20
val strings = Bash_Syntax.strings;
96bc94c87a81 clarified modules;
wenzelm
parents: 62923
diff changeset
    21
62923
3a122e1e352a clarified bootstrap;
wenzelm
parents: 62911
diff changeset
    22
val process = Thread_Attributes.uninterruptible (fn restore_attributes => fn script =>
62911
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    23
  let
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    24
    datatype result = Wait | Signal | Result of int;
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    25
    val result = Synchronized.var "bash_result" Wait;
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    26
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    27
    val id = serial_string ();
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    28
    val script_path = File.tmp_path (Path.basic ("bash_script" ^ id));
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    29
    val out_path = File.tmp_path (Path.basic ("bash_out" ^ id));
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    30
    val err_path = File.tmp_path (Path.basic ("bash_err" ^ id));
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    31
    val pid_path = File.tmp_path (Path.basic ("bash_pid" ^ id));
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    32
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    33
    fun cleanup_files () =
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    34
     (try File.rm script_path;
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    35
      try File.rm out_path;
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    36
      try File.rm err_path;
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    37
      try File.rm pid_path);
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    38
    val _ = cleanup_files ();
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    39
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    40
    val system_thread =
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    41
      Standard_Thread.fork {name = "bash", stack_limit = NONE, interrupts = false} (fn () =>
62923
3a122e1e352a clarified bootstrap;
wenzelm
parents: 62911
diff changeset
    42
        Thread_Attributes.with_attributes Thread_Attributes.private_interrupts (fn _ =>
62911
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    43
          let
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    44
            val _ = File.write script_path script;
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    45
            val bash_script =
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    46
              "bash " ^ File.bash_path script_path ^
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    47
                " > " ^ File.bash_path out_path ^
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    48
                " 2> " ^ File.bash_path err_path;
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    49
            val bash_process = getenv_strict "ISABELLE_BASH_PROCESS";
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    50
            val rc =
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    51
              Windows.simpleExecute ("",
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    52
                quote (ML_System.platform_path bash_process) ^ " " ^
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    53
                quote (File.platform_path pid_path) ^  " \"\" bash -c " ^ quote bash_script)
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    54
              |> Windows.fromStatus |> SysWord.toInt;
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    55
            val res = if rc = 130 orelse rc = 512 then Signal else Result rc;
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    56
          in Synchronized.change result (K res) end
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    57
          handle exn =>
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    58
            (Synchronized.change result (fn Wait => Signal | res => res); Exn.reraise exn)));
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    59
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    60
    fun read_pid 0 = NONE
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    61
      | read_pid count =
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    62
          (case (Int.fromString (File.read pid_path) handle IO.Io _ => NONE) of
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    63
            NONE => (OS.Process.sleep (seconds 0.1); read_pid (count - 1))
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    64
          | some => some);
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    65
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    66
    fun terminate NONE = ()
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    67
      | terminate (SOME pid) =
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    68
          let
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    69
            fun kill s =
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    70
              let
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    71
                val cmd = getenv_strict "CYGWIN_ROOT" ^ "\\bin\\bash.exe";
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    72
                val arg = "kill -" ^ s ^ " -" ^ string_of_int pid;
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    73
              in
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    74
                OS.Process.isSuccess (Windows.simpleExecute ("", quote cmd ^ " -c " ^ quote arg))
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    75
                  handle OS.SysErr _ => false
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    76
              end;
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    77
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    78
            fun multi_kill count s =
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    79
              count = 0 orelse
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    80
                (kill s; kill "0") andalso
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    81
                (OS.Process.sleep (seconds 0.1); multi_kill (count - 1) s);
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    82
            val _ =
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    83
              multi_kill 10 "INT" andalso
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    84
              multi_kill 10 "TERM" andalso
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    85
              multi_kill 10 "KILL";
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    86
          in () end;
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    87
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    88
    fun cleanup () =
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    89
     (Standard_Thread.interrupt_unsynchronized system_thread;
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    90
      cleanup_files ());
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    91
  in
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    92
    let
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    93
      val _ =
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    94
        restore_attributes (fn () =>
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    95
          Synchronized.guarded_access result (fn Wait => NONE | x => SOME ((), x))) ();
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    96
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    97
      val out = the_default "" (try File.read out_path);
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    98
      val err = the_default "" (try File.read err_path);
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
    99
      val rc = (case Synchronized.value result of Signal => Exn.interrupt () | Result rc => rc);
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
   100
      val pid = read_pid 1;
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
   101
      val _ = cleanup ();
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
   102
    in {out = out, err = err, rc = rc, terminate = fn () => terminate pid} end
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
   103
    handle exn => (terminate (read_pid 10); cleanup (); Exn.reraise exn)
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
   104
  end);
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
   105
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
   106
end;
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
   107
\<close>
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
   108
else ML
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
   109
\<open>
44054
da5fcc0f6c52 proper signature;
wenzelm
parents: 43850
diff changeset
   110
structure Bash: BASH =
43850
7f2cbc713344 moved bash operations to Isabelle_System (cf. Scala version);
wenzelm
parents: 43847
diff changeset
   111
struct
7f2cbc713344 moved bash operations to Isabelle_System (cf. Scala version);
wenzelm
parents: 43847
diff changeset
   112
64304
96bc94c87a81 clarified modules;
wenzelm
parents: 62923
diff changeset
   113
val string = Bash_Syntax.string;
96bc94c87a81 clarified modules;
wenzelm
parents: 62923
diff changeset
   114
val strings = Bash_Syntax.strings;
96bc94c87a81 clarified modules;
wenzelm
parents: 62923
diff changeset
   115
62923
3a122e1e352a clarified bootstrap;
wenzelm
parents: 62911
diff changeset
   116
val process = Thread_Attributes.uninterruptible (fn restore_attributes => fn script =>
40749
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
   117
  let
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
   118
    datatype result = Wait | Signal | Result of int;
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
   119
    val result = Synchronized.var "bash_result" Wait;
40748
591b6778d076 removed bash from ML system bootstrap, and past the Secure ML barrier;
wenzelm
parents:
diff changeset
   120
40749
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
   121
    val id = serial_string ();
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
   122
    val script_path = File.tmp_path (Path.basic ("bash_script" ^ id));
47499
4b0daca2bf88 redirect bash stderr to Isabelle warning as appropriate -- avoid raw process error output which may either get ignored or overload PIDE syslog in extreme cases;
wenzelm
parents: 44112
diff changeset
   123
    val out_path = File.tmp_path (Path.basic ("bash_out" ^ id));
4b0daca2bf88 redirect bash stderr to Isabelle warning as appropriate -- avoid raw process error output which may either get ignored or overload PIDE syslog in extreme cases;
wenzelm
parents: 44112
diff changeset
   124
    val err_path = File.tmp_path (Path.basic ("bash_err" ^ id));
40749
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
   125
    val pid_path = File.tmp_path (Path.basic ("bash_pid" ^ id));
40748
591b6778d076 removed bash from ML system bootstrap, and past the Secure ML barrier;
wenzelm
parents:
diff changeset
   126
54651
d71e7908eec3 more thorough read_pid with extra delay, to give external process a chance to write pid file before attempting to terminate it -- especially relevant for PIDE document processing, where interrupts can happen in the range of milliseconds;
wenzelm
parents: 47764
diff changeset
   127
    fun cleanup_files () =
d71e7908eec3 more thorough read_pid with extra delay, to give external process a chance to write pid file before attempting to terminate it -- especially relevant for PIDE document processing, where interrupts can happen in the range of milliseconds;
wenzelm
parents: 47764
diff changeset
   128
     (try File.rm script_path;
d71e7908eec3 more thorough read_pid with extra delay, to give external process a chance to write pid file before attempting to terminate it -- especially relevant for PIDE document processing, where interrupts can happen in the range of milliseconds;
wenzelm
parents: 47764
diff changeset
   129
      try File.rm out_path;
d71e7908eec3 more thorough read_pid with extra delay, to give external process a chance to write pid file before attempting to terminate it -- especially relevant for PIDE document processing, where interrupts can happen in the range of milliseconds;
wenzelm
parents: 47764
diff changeset
   130
      try File.rm err_path;
d71e7908eec3 more thorough read_pid with extra delay, to give external process a chance to write pid file before attempting to terminate it -- especially relevant for PIDE document processing, where interrupts can happen in the range of milliseconds;
wenzelm
parents: 47764
diff changeset
   131
      try File.rm pid_path);
d71e7908eec3 more thorough read_pid with extra delay, to give external process a chance to write pid file before attempting to terminate it -- especially relevant for PIDE document processing, where interrupts can happen in the range of milliseconds;
wenzelm
parents: 47764
diff changeset
   132
    val _ = cleanup_files ();
d71e7908eec3 more thorough read_pid with extra delay, to give external process a chance to write pid file before attempting to terminate it -- especially relevant for PIDE document processing, where interrupts can happen in the range of milliseconds;
wenzelm
parents: 47764
diff changeset
   133
40749
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
   134
    val system_thread =
61556
0d4ee4168e41 clarified modules;
wenzelm
parents: 60976
diff changeset
   135
      Standard_Thread.fork {name = "bash", stack_limit = NONE, interrupts = false} (fn () =>
62923
3a122e1e352a clarified bootstrap;
wenzelm
parents: 62911
diff changeset
   136
        Thread_Attributes.with_attributes Thread_Attributes.private_interrupts (fn _ =>
40749
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
   137
          let
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
   138
            val _ = File.write script_path script;
62295
4f2fb9adfae5 clarified bash process;
wenzelm
parents: 61556
diff changeset
   139
            val _ = getenv_strict "ISABELLE_BASH_PROCESS";
40749
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
   140
            val status =
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
   141
              OS.Process.system
62569
5db10482f4cf bash process with builtin timing;
wenzelm
parents: 62549
diff changeset
   142
                ("exec \"$ISABELLE_BASH_PROCESS\" " ^ File.bash_path pid_path ^ " \"\"" ^
62549
9498623b27f0 File.bash_string operations in ML as in Scala -- exclusively for GNU bash, not perl and not user output;
wenzelm
parents: 62505
diff changeset
   143
                  " bash " ^ File.bash_path script_path ^
9498623b27f0 File.bash_string operations in ML as in Scala -- exclusively for GNU bash, not perl and not user output;
wenzelm
parents: 62505
diff changeset
   144
                  " > " ^ File.bash_path out_path ^
9498623b27f0 File.bash_string operations in ML as in Scala -- exclusively for GNU bash, not perl and not user output;
wenzelm
parents: 62505
diff changeset
   145
                  " 2> " ^ File.bash_path err_path);
40749
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
   146
            val res =
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
   147
              (case Posix.Process.fromStatus status of
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
   148
                Posix.Process.W_EXITED => Result 0
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
   149
              | Posix.Process.W_EXITSTATUS 0wx82 => Signal
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
   150
              | Posix.Process.W_EXITSTATUS w => Result (Word8.toInt w)
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
   151
              | Posix.Process.W_SIGNALED s =>
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
   152
                  if s = Posix.Signal.int then Signal
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
   153
                  else Result (256 + LargeWord.toInt (Posix.Signal.toWord s))
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
   154
              | Posix.Process.W_STOPPED s =>
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
   155
                  Result (512 + LargeWord.toInt (Posix.Signal.toWord s)));
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
   156
          in Synchronized.change result (K res) end
40783
21f7e8d66a39 more conventional exception propagation -- taking into account Simple_Thread.fork wrapping;
wenzelm
parents: 40750
diff changeset
   157
          handle exn =>
62505
9e2a65912111 clarified modules;
wenzelm
parents: 62483
diff changeset
   158
            (Synchronized.change result (fn Wait => Signal | res => res); Exn.reraise exn)));
40748
591b6778d076 removed bash from ML system bootstrap, and past the Secure ML barrier;
wenzelm
parents:
diff changeset
   159
54651
d71e7908eec3 more thorough read_pid with extra delay, to give external process a chance to write pid file before attempting to terminate it -- especially relevant for PIDE document processing, where interrupts can happen in the range of milliseconds;
wenzelm
parents: 47764
diff changeset
   160
    fun read_pid 0 = NONE
d71e7908eec3 more thorough read_pid with extra delay, to give external process a chance to write pid file before attempting to terminate it -- especially relevant for PIDE document processing, where interrupts can happen in the range of milliseconds;
wenzelm
parents: 47764
diff changeset
   161
      | read_pid count =
d71e7908eec3 more thorough read_pid with extra delay, to give external process a chance to write pid file before attempting to terminate it -- especially relevant for PIDE document processing, where interrupts can happen in the range of milliseconds;
wenzelm
parents: 47764
diff changeset
   162
          (case (Int.fromString (File.read pid_path) handle IO.Io _ => NONE) of
d71e7908eec3 more thorough read_pid with extra delay, to give external process a chance to write pid file before attempting to terminate it -- especially relevant for PIDE document processing, where interrupts can happen in the range of milliseconds;
wenzelm
parents: 47764
diff changeset
   163
            NONE => (OS.Process.sleep (seconds 0.1); read_pid (count - 1))
d71e7908eec3 more thorough read_pid with extra delay, to give external process a chance to write pid file before attempting to terminate it -- especially relevant for PIDE document processing, where interrupts can happen in the range of milliseconds;
wenzelm
parents: 47764
diff changeset
   164
          | some => some);
43847
529159f81d06 more general bash_process, which allows to terminate background processes as well;
wenzelm
parents: 40896
diff changeset
   165
54651
d71e7908eec3 more thorough read_pid with extra delay, to give external process a chance to write pid file before attempting to terminate it -- especially relevant for PIDE document processing, where interrupts can happen in the range of milliseconds;
wenzelm
parents: 47764
diff changeset
   166
    fun terminate NONE = ()
d71e7908eec3 more thorough read_pid with extra delay, to give external process a chance to write pid file before attempting to terminate it -- especially relevant for PIDE document processing, where interrupts can happen in the range of milliseconds;
wenzelm
parents: 47764
diff changeset
   167
      | terminate (SOME pid) =
d71e7908eec3 more thorough read_pid with extra delay, to give external process a chance to write pid file before attempting to terminate it -- especially relevant for PIDE document processing, where interrupts can happen in the range of milliseconds;
wenzelm
parents: 47764
diff changeset
   168
          let
60976
wenzelm
parents: 60764
diff changeset
   169
            fun kill s =
54651
d71e7908eec3 more thorough read_pid with extra delay, to give external process a chance to write pid file before attempting to terminate it -- especially relevant for PIDE document processing, where interrupts can happen in the range of milliseconds;
wenzelm
parents: 47764
diff changeset
   170
              (Posix.Process.kill
d71e7908eec3 more thorough read_pid with extra delay, to give external process a chance to write pid file before attempting to terminate it -- especially relevant for PIDE document processing, where interrupts can happen in the range of milliseconds;
wenzelm
parents: 47764
diff changeset
   171
                (Posix.Process.K_GROUP (Posix.Process.wordToPid (LargeWord.fromInt pid)), s); true)
d71e7908eec3 more thorough read_pid with extra delay, to give external process a chance to write pid file before attempting to terminate it -- especially relevant for PIDE document processing, where interrupts can happen in the range of milliseconds;
wenzelm
parents: 47764
diff changeset
   172
              handle OS.SysErr _ => false;
d71e7908eec3 more thorough read_pid with extra delay, to give external process a chance to write pid file before attempting to terminate it -- especially relevant for PIDE document processing, where interrupts can happen in the range of milliseconds;
wenzelm
parents: 47764
diff changeset
   173
d71e7908eec3 more thorough read_pid with extra delay, to give external process a chance to write pid file before attempting to terminate it -- especially relevant for PIDE document processing, where interrupts can happen in the range of milliseconds;
wenzelm
parents: 47764
diff changeset
   174
            fun multi_kill count s =
d71e7908eec3 more thorough read_pid with extra delay, to give external process a chance to write pid file before attempting to terminate it -- especially relevant for PIDE document processing, where interrupts can happen in the range of milliseconds;
wenzelm
parents: 47764
diff changeset
   175
              count = 0 orelse
60976
wenzelm
parents: 60764
diff changeset
   176
                (kill s; kill (Posix.Signal.fromWord 0w0)) andalso
wenzelm
parents: 60764
diff changeset
   177
                (OS.Process.sleep (seconds 0.1); multi_kill (count - 1) s);
54651
d71e7908eec3 more thorough read_pid with extra delay, to give external process a chance to write pid file before attempting to terminate it -- especially relevant for PIDE document processing, where interrupts can happen in the range of milliseconds;
wenzelm
parents: 47764
diff changeset
   178
            val _ =
d71e7908eec3 more thorough read_pid with extra delay, to give external process a chance to write pid file before attempting to terminate it -- especially relevant for PIDE document processing, where interrupts can happen in the range of milliseconds;
wenzelm
parents: 47764
diff changeset
   179
              multi_kill 10 Posix.Signal.int andalso
d71e7908eec3 more thorough read_pid with extra delay, to give external process a chance to write pid file before attempting to terminate it -- especially relevant for PIDE document processing, where interrupts can happen in the range of milliseconds;
wenzelm
parents: 47764
diff changeset
   180
              multi_kill 10 Posix.Signal.term andalso
d71e7908eec3 more thorough read_pid with extra delay, to give external process a chance to write pid file before attempting to terminate it -- especially relevant for PIDE document processing, where interrupts can happen in the range of milliseconds;
wenzelm
parents: 47764
diff changeset
   181
              multi_kill 10 Posix.Signal.kill;
d71e7908eec3 more thorough read_pid with extra delay, to give external process a chance to write pid file before attempting to terminate it -- especially relevant for PIDE document processing, where interrupts can happen in the range of milliseconds;
wenzelm
parents: 47764
diff changeset
   182
          in () end;
40750
2064991db2ac more thorough process termination (cf. Scala version);
wenzelm
parents: 40749
diff changeset
   183
40749
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
   184
    fun cleanup () =
61556
0d4ee4168e41 clarified modules;
wenzelm
parents: 60976
diff changeset
   185
     (Standard_Thread.interrupt_unsynchronized system_thread;
54651
d71e7908eec3 more thorough read_pid with extra delay, to give external process a chance to write pid file before attempting to terminate it -- especially relevant for PIDE document processing, where interrupts can happen in the range of milliseconds;
wenzelm
parents: 47764
diff changeset
   186
      cleanup_files ());
40749
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
   187
  in
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
   188
    let
40748
591b6778d076 removed bash from ML system bootstrap, and past the Secure ML barrier;
wenzelm
parents:
diff changeset
   189
      val _ =
40749
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
   190
        restore_attributes (fn () =>
40750
2064991db2ac more thorough process termination (cf. Scala version);
wenzelm
parents: 40749
diff changeset
   191
          Synchronized.guarded_access result (fn Wait => NONE | x => SOME ((), x))) ();
40748
591b6778d076 removed bash from ML system bootstrap, and past the Secure ML barrier;
wenzelm
parents:
diff changeset
   192
47499
4b0daca2bf88 redirect bash stderr to Isabelle warning as appropriate -- avoid raw process error output which may either get ignored or overload PIDE syslog in extreme cases;
wenzelm
parents: 44112
diff changeset
   193
      val out = the_default "" (try File.read out_path);
4b0daca2bf88 redirect bash stderr to Isabelle warning as appropriate -- avoid raw process error output which may either get ignored or overload PIDE syslog in extreme cases;
wenzelm
parents: 44112
diff changeset
   194
      val err = the_default "" (try File.read err_path);
40749
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
   195
      val rc = (case Synchronized.value result of Signal => Exn.interrupt () | Result rc => rc);
54651
d71e7908eec3 more thorough read_pid with extra delay, to give external process a chance to write pid file before attempting to terminate it -- especially relevant for PIDE document processing, where interrupts can happen in the range of milliseconds;
wenzelm
parents: 47764
diff changeset
   196
      val pid = read_pid 1;
40749
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
   197
      val _ = cleanup ();
47499
4b0daca2bf88 redirect bash stderr to Isabelle warning as appropriate -- avoid raw process error output which may either get ignored or overload PIDE syslog in extreme cases;
wenzelm
parents: 44112
diff changeset
   198
    in {out = out, err = err, rc = rc, terminate = fn () => terminate pid} end
62505
9e2a65912111 clarified modules;
wenzelm
parents: 62483
diff changeset
   199
    handle exn => (terminate (read_pid 10); cleanup (); Exn.reraise exn)
40749
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
   200
  end);
40748
591b6778d076 removed bash from ML system bootstrap, and past the Secure ML barrier;
wenzelm
parents:
diff changeset
   201
43850
7f2cbc713344 moved bash operations to Isabelle_System (cf. Scala version);
wenzelm
parents: 43847
diff changeset
   202
end;
62911
78e03d8bf1c4 back to dynamic conditional compilation (reverting 4764473c9b8d) via recursive ML name space;
wenzelm
parents: 62891
diff changeset
   203
\<close>