| author | wenzelm | 
| Wed, 06 Jan 2016 00:04:15 +0100 | |
| changeset 62075 | ea3360245939 | 
| parent 61556 | 0d4ee4168e41 | 
| child 62295 | 4f2fb9adfae5 | 
| permissions | -rw-r--r-- | 
| 40748 
591b6778d076
removed bash from ML system bootstrap, and past the Secure ML barrier;
 wenzelm parents: diff
changeset | 1 | (* Title: Pure/Concurrent/bash.ML | 
| 
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 | |
| 60976 | 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 | 7 | signature BASH = | 
| 8 | sig | |
| 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: 
44112diff
changeset | 9 |   val process: string -> {out: string, err: string, rc: int, terminate: unit -> unit}
 | 
| 44054 | 10 | end; | 
| 11 | ||
| 12 | structure Bash: BASH = | |
| 43850 
7f2cbc713344
moved bash operations to Isabelle_System (cf. Scala version);
 wenzelm parents: 
43847diff
changeset | 13 | struct | 
| 
7f2cbc713344
moved bash operations to Isabelle_System (cf. Scala version);
 wenzelm parents: 
43847diff
changeset | 14 | |
| 
7f2cbc713344
moved bash operations to Isabelle_System (cf. Scala version);
 wenzelm parents: 
43847diff
changeset | 15 | val process = uninterruptible (fn restore_attributes => fn script => | 
| 40749 | 16 | let | 
| 17 | datatype result = Wait | Signal | Result of int; | |
| 18 | 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 | 19 | |
| 40749 | 20 | val id = serial_string (); | 
| 21 |     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: 
44112diff
changeset | 22 |     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: 
44112diff
changeset | 23 |     val err_path = File.tmp_path (Path.basic ("bash_err" ^ id));
 | 
| 40749 | 24 |     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 | 25 | |
| 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: 
47764diff
changeset | 26 | 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: 
47764diff
changeset | 27 | (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: 
47764diff
changeset | 28 | 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: 
47764diff
changeset | 29 | 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: 
47764diff
changeset | 30 | 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: 
47764diff
changeset | 31 | 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: 
47764diff
changeset | 32 | |
| 40749 | 33 | val system_thread = | 
| 61556 | 34 |       Standard_Thread.fork {name = "bash", stack_limit = NONE, interrupts = false} (fn () =>
 | 
| 40749 | 35 | Multithreading.with_attributes Multithreading.private_interrupts (fn _ => | 
| 36 | let | |
| 37 | val _ = File.write script_path script; | |
| 47764 
d141f1193789
more direct bash process group invocation on Cygwin, bypassing extra sh.exe and perl.exe which tend to crash;
 wenzelm parents: 
47499diff
changeset | 38 | val bash_script = | 
| 
d141f1193789
more direct bash process group invocation on Cygwin, bypassing extra sh.exe and perl.exe which tend to crash;
 wenzelm parents: 
47499diff
changeset | 39 | "exec bash " ^ | 
| 
d141f1193789
more direct bash process group invocation on Cygwin, bypassing extra sh.exe and perl.exe which tend to crash;
 wenzelm parents: 
47499diff
changeset | 40 | File.shell_path script_path ^ | 
| 
d141f1193789
more direct bash process group invocation on Cygwin, bypassing extra sh.exe and perl.exe which tend to crash;
 wenzelm parents: 
47499diff
changeset | 41 | " > " ^ File.shell_path out_path ^ | 
| 
d141f1193789
more direct bash process group invocation on Cygwin, bypassing extra sh.exe and perl.exe which tend to crash;
 wenzelm parents: 
47499diff
changeset | 42 | " 2> " ^ File.shell_path err_path; | 
| 54677 
ae5426994961
strict EXEC_PROCESS: component can be expected to be present;
 wenzelm parents: 
54651diff
changeset | 43 | val _ = getenv_strict "EXEC_PROCESS"; | 
| 40749 | 44 | val status = | 
| 45 | OS.Process.system | |
| 54677 
ae5426994961
strict EXEC_PROCESS: component can be expected to be present;
 wenzelm parents: 
54651diff
changeset | 46 |                 ("exec \"$EXEC_PROCESS\" " ^ File.shell_path pid_path ^ " " ^ quote bash_script);
 | 
| 40749 | 47 | val res = | 
| 48 | (case Posix.Process.fromStatus status of | |
| 49 | Posix.Process.W_EXITED => Result 0 | |
| 50 | | Posix.Process.W_EXITSTATUS 0wx82 => Signal | |
| 51 | | Posix.Process.W_EXITSTATUS w => Result (Word8.toInt w) | |
| 52 | | Posix.Process.W_SIGNALED s => | |
| 53 | if s = Posix.Signal.int then Signal | |
| 54 | else Result (256 + LargeWord.toInt (Posix.Signal.toWord s)) | |
| 55 | | Posix.Process.W_STOPPED s => | |
| 56 | Result (512 + LargeWord.toInt (Posix.Signal.toWord s))); | |
| 57 | in Synchronized.change result (K res) end | |
| 40783 
21f7e8d66a39
more conventional exception propagation -- taking into account Simple_Thread.fork wrapping;
 wenzelm parents: 
40750diff
changeset | 58 | handle exn => | 
| 
21f7e8d66a39
more conventional exception propagation -- taking into account Simple_Thread.fork wrapping;
 wenzelm parents: 
40750diff
changeset | 59 | (Synchronized.change result (fn Wait => Signal | res => res); reraise exn))); | 
| 40748 
591b6778d076
removed bash from ML system bootstrap, and past the Secure ML barrier;
 wenzelm parents: diff
changeset | 60 | |
| 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: 
47764diff
changeset | 61 | 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: 
47764diff
changeset | 62 | | 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: 
47764diff
changeset | 63 | (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: 
47764diff
changeset | 64 | 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: 
47764diff
changeset | 65 | | some => some); | 
| 43847 
529159f81d06
more general bash_process, which allows to terminate background processes as well;
 wenzelm parents: 
40896diff
changeset | 66 | |
| 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: 
47764diff
changeset | 67 | 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: 
47764diff
changeset | 68 | | 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: 
47764diff
changeset | 69 | let | 
| 60976 | 70 | 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: 
47764diff
changeset | 71 | (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: 
47764diff
changeset | 72 | (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: 
47764diff
changeset | 73 | 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: 
47764diff
changeset | 74 | |
| 
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: 
47764diff
changeset | 75 | 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: 
47764diff
changeset | 76 | count = 0 orelse | 
| 60976 | 77 | (kill s; kill (Posix.Signal.fromWord 0w0)) andalso | 
| 78 | (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: 
47764diff
changeset | 79 | 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: 
47764diff
changeset | 80 | 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: 
47764diff
changeset | 81 | 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: 
47764diff
changeset | 82 | 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: 
47764diff
changeset | 83 | in () end; | 
| 40750 
2064991db2ac
more thorough process termination (cf. Scala version);
 wenzelm parents: 
40749diff
changeset | 84 | |
| 40749 | 85 | fun cleanup () = | 
| 61556 | 86 | (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: 
47764diff
changeset | 87 | cleanup_files ()); | 
| 40749 | 88 | in | 
| 89 | let | |
| 40748 
591b6778d076
removed bash from ML system bootstrap, and past the Secure ML barrier;
 wenzelm parents: diff
changeset | 90 | val _ = | 
| 40749 | 91 | restore_attributes (fn () => | 
| 40750 
2064991db2ac
more thorough process termination (cf. Scala version);
 wenzelm parents: 
40749diff
changeset | 92 | 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 | 93 | |
| 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: 
44112diff
changeset | 94 | 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: 
44112diff
changeset | 95 | val err = the_default "" (try File.read err_path); | 
| 40749 | 96 | 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: 
47764diff
changeset | 97 | val pid = read_pid 1; | 
| 40749 | 98 | 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: 
44112diff
changeset | 99 |     in {out = out, err = err, rc = rc, terminate = fn () => terminate pid} end
 | 
| 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: 
47764diff
changeset | 100 | handle exn => (terminate (read_pid 10); cleanup (); reraise exn) | 
| 40749 | 101 | end); | 
| 40748 
591b6778d076
removed bash from ML system bootstrap, and past the Secure ML barrier;
 wenzelm parents: diff
changeset | 102 | |
| 43850 
7f2cbc713344
moved bash operations to Isabelle_System (cf. Scala version);
 wenzelm parents: 
43847diff
changeset | 103 | end; | 
| 
7f2cbc713344
moved bash operations to Isabelle_System (cf. Scala version);
 wenzelm parents: 
43847diff
changeset | 104 |