src/Pure/Concurrent/bash.ML
author wenzelm
Sat, 16 Jul 2011 20:52:41 +0200
changeset 43850 7f2cbc713344
parent 43847 529159f81d06
child 44054 da5fcc0f6c52
permissions -rw-r--r--
moved bash operations to Isabelle_System (cf. Scala version);
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
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
591b6778d076 removed bash from ML system bootstrap, and past the Secure ML barrier;
wenzelm
parents:
diff changeset
     4
GNU bash processes, with propagation of interrupts.
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
43850
7f2cbc713344 moved bash operations to Isabelle_System (cf. Scala version);
wenzelm
parents: 43847
diff changeset
     7
structure Bash =
7f2cbc713344 moved bash operations to Isabelle_System (cf. Scala version);
wenzelm
parents: 43847
diff changeset
     8
struct
7f2cbc713344 moved bash operations to Isabelle_System (cf. Scala version);
wenzelm
parents: 43847
diff changeset
     9
7f2cbc713344 moved bash operations to Isabelle_System (cf. Scala version);
wenzelm
parents: 43847
diff changeset
    10
val process = uninterruptible (fn restore_attributes => fn script =>
40749
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
    11
  let
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
    12
    datatype result = Wait | Signal | Result of int;
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
    13
    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
    14
40749
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
    15
    val id = serial_string ();
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
    16
    val script_path = File.tmp_path (Path.basic ("bash_script" ^ id));
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
    17
    val output_path = File.tmp_path (Path.basic ("bash_output" ^ id));
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
    18
    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
    19
40749
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
    20
    val system_thread =
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
    21
      Simple_Thread.fork false (fn () =>
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
    22
        Multithreading.with_attributes Multithreading.private_interrupts (fn _ =>
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
    23
          let
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
    24
            val _ = File.write script_path script;
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
    25
            val status =
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
    26
              OS.Process.system
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
    27
                ("exec \"$ISABELLE_HOME/lib/scripts/process\" group " ^
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
    28
                  File.shell_path pid_path ^ " script \"exec bash " ^
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
    29
                  File.shell_path script_path ^ " > " ^
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
    30
                  File.shell_path output_path ^ "\"");
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
    31
            val res =
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
    32
              (case Posix.Process.fromStatus status of
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
    33
                Posix.Process.W_EXITED => Result 0
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
    34
              | Posix.Process.W_EXITSTATUS 0wx82 => Signal
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
    35
              | Posix.Process.W_EXITSTATUS w => Result (Word8.toInt w)
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
    36
              | Posix.Process.W_SIGNALED s =>
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
    37
                  if s = Posix.Signal.int then Signal
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
    38
                  else Result (256 + LargeWord.toInt (Posix.Signal.toWord s))
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
    39
              | Posix.Process.W_STOPPED s =>
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
    40
                  Result (512 + LargeWord.toInt (Posix.Signal.toWord s)));
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
    41
          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
    42
          handle exn =>
21f7e8d66a39 more conventional exception propagation -- taking into account Simple_Thread.fork wrapping;
wenzelm
parents: 40750
diff changeset
    43
            (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
    44
43847
529159f81d06 more general bash_process, which allows to terminate background processes as well;
wenzelm
parents: 40896
diff changeset
    45
    fun get_pid () = Int.fromString (File.read pid_path) handle IO.Io _ => NONE;
529159f81d06 more general bash_process, which allows to terminate background processes as well;
wenzelm
parents: 40896
diff changeset
    46
529159f81d06 more general bash_process, which allows to terminate background processes as well;
wenzelm
parents: 40896
diff changeset
    47
    fun terminate opt_pid =
40750
2064991db2ac more thorough process termination (cf. Scala version);
wenzelm
parents: 40749
diff changeset
    48
      let
2064991db2ac more thorough process termination (cf. Scala version);
wenzelm
parents: 40749
diff changeset
    49
        val sig_test = Posix.Signal.fromWord 0w0;
2064991db2ac more thorough process termination (cf. Scala version);
wenzelm
parents: 40749
diff changeset
    50
2064991db2ac more thorough process termination (cf. Scala version);
wenzelm
parents: 40749
diff changeset
    51
        fun kill_group pid s =
2064991db2ac more thorough process termination (cf. Scala version);
wenzelm
parents: 40749
diff changeset
    52
          (Posix.Process.kill
2064991db2ac more thorough process termination (cf. Scala version);
wenzelm
parents: 40749
diff changeset
    53
            (Posix.Process.K_GROUP (Posix.Process.wordToPid (LargeWord.fromInt pid)), s); true)
2064991db2ac more thorough process termination (cf. Scala version);
wenzelm
parents: 40749
diff changeset
    54
          handle OS.SysErr _ => false;
2064991db2ac more thorough process termination (cf. Scala version);
wenzelm
parents: 40749
diff changeset
    55
2064991db2ac more thorough process termination (cf. Scala version);
wenzelm
parents: 40749
diff changeset
    56
        fun kill s =
43847
529159f81d06 more general bash_process, which allows to terminate background processes as well;
wenzelm
parents: 40896
diff changeset
    57
          (case opt_pid of
40750
2064991db2ac more thorough process termination (cf. Scala version);
wenzelm
parents: 40749
diff changeset
    58
            NONE => true
43847
529159f81d06 more general bash_process, which allows to terminate background processes as well;
wenzelm
parents: 40896
diff changeset
    59
          | SOME pid => (kill_group pid s; kill_group pid sig_test));
40750
2064991db2ac more thorough process termination (cf. Scala version);
wenzelm
parents: 40749
diff changeset
    60
2064991db2ac more thorough process termination (cf. Scala version);
wenzelm
parents: 40749
diff changeset
    61
        fun multi_kill count s =
2064991db2ac more thorough process termination (cf. Scala version);
wenzelm
parents: 40749
diff changeset
    62
          count = 0 orelse
2064991db2ac more thorough process termination (cf. Scala version);
wenzelm
parents: 40749
diff changeset
    63
            kill s andalso (OS.Process.sleep (seconds 0.1); multi_kill (count - 1) s);
2064991db2ac more thorough process termination (cf. Scala version);
wenzelm
parents: 40749
diff changeset
    64
        val _ =
2064991db2ac more thorough process termination (cf. Scala version);
wenzelm
parents: 40749
diff changeset
    65
          multi_kill 10 Posix.Signal.int andalso
2064991db2ac more thorough process termination (cf. Scala version);
wenzelm
parents: 40749
diff changeset
    66
          multi_kill 10 Posix.Signal.term andalso
2064991db2ac more thorough process termination (cf. Scala version);
wenzelm
parents: 40749
diff changeset
    67
          multi_kill 10 Posix.Signal.kill;
2064991db2ac more thorough process termination (cf. Scala version);
wenzelm
parents: 40749
diff changeset
    68
      in () end;
2064991db2ac more thorough process termination (cf. Scala version);
wenzelm
parents: 40749
diff changeset
    69
40749
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
    70
    fun cleanup () =
40896
d9c112c587f9 bash wrapper: terminate only in exceptional case, keep background processes running (e.g. 'thy_deps' or 'display_drafts');
wenzelm
parents: 40783
diff changeset
    71
     (Simple_Thread.interrupt system_thread;
40749
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
    72
      try File.rm script_path;
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
    73
      try File.rm output_path;
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
    74
      try File.rm pid_path);
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
    75
  in
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
    76
    let
40748
591b6778d076 removed bash from ML system bootstrap, and past the Secure ML barrier;
wenzelm
parents:
diff changeset
    77
      val _ =
40749
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
    78
        restore_attributes (fn () =>
40750
2064991db2ac more thorough process termination (cf. Scala version);
wenzelm
parents: 40749
diff changeset
    79
          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
    80
40749
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
    81
      val output = the_default "" (try File.read output_path);
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
    82
      val rc = (case Synchronized.value result of Signal => Exn.interrupt () | Result rc => rc);
43847
529159f81d06 more general bash_process, which allows to terminate background processes as well;
wenzelm
parents: 40896
diff changeset
    83
      val pid = get_pid ();
40749
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
    84
      val _ = cleanup ();
43847
529159f81d06 more general bash_process, which allows to terminate background processes as well;
wenzelm
parents: 40896
diff changeset
    85
    in {output = output, rc = rc, terminate = fn () => terminate pid} end
529159f81d06 more general bash_process, which allows to terminate background processes as well;
wenzelm
parents: 40896
diff changeset
    86
    handle exn => (terminate (get_pid ()); cleanup (); reraise exn)
40749
cb6698d2dbaf prefer Isabelle/ML concurrency elements;
wenzelm
parents: 40748
diff changeset
    87
  end);
40748
591b6778d076 removed bash from ML system bootstrap, and past the Secure ML barrier;
wenzelm
parents:
diff changeset
    88
43850
7f2cbc713344 moved bash operations to Isabelle_System (cf. Scala version);
wenzelm
parents: 43847
diff changeset
    89
end;
7f2cbc713344 moved bash operations to Isabelle_System (cf. Scala version);
wenzelm
parents: 43847
diff changeset
    90