src/Pure/Concurrent/bash_windows.ML
author wenzelm
Tue, 01 Mar 2016 14:23:24 +0100
changeset 62484 4759dbb35148
parent 61556 0d4ee4168e41
child 62505 9e2a65912111
permissions -rw-r--r--
prefer bash_process;
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
60977
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
     1
(*  Title:      Pure/Concurrent/bash_windows.ML
60962
faa452d8e265 basic setup for native Windows (RAW session without image);
wenzelm
parents:
diff changeset
     2
    Author:     Makarius
faa452d8e265 basic setup for native Windows (RAW session without image);
wenzelm
parents:
diff changeset
     3
60977
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
     4
GNU bash processes, with propagation of interrupts -- Windows version.
60962
faa452d8e265 basic setup for native Windows (RAW session without image);
wenzelm
parents:
diff changeset
     5
*)
faa452d8e265 basic setup for native Windows (RAW session without image);
wenzelm
parents:
diff changeset
     6
faa452d8e265 basic setup for native Windows (RAW session without image);
wenzelm
parents:
diff changeset
     7
signature BASH =
faa452d8e265 basic setup for native Windows (RAW session without image);
wenzelm
parents:
diff changeset
     8
sig
faa452d8e265 basic setup for native Windows (RAW session without image);
wenzelm
parents:
diff changeset
     9
  val process: string -> {out: string, err: string, rc: int, terminate: unit -> unit}
faa452d8e265 basic setup for native Windows (RAW session without image);
wenzelm
parents:
diff changeset
    10
end;
faa452d8e265 basic setup for native Windows (RAW session without image);
wenzelm
parents:
diff changeset
    11
faa452d8e265 basic setup for native Windows (RAW session without image);
wenzelm
parents:
diff changeset
    12
structure Bash: BASH =
faa452d8e265 basic setup for native Windows (RAW session without image);
wenzelm
parents:
diff changeset
    13
struct
faa452d8e265 basic setup for native Windows (RAW session without image);
wenzelm
parents:
diff changeset
    14
60977
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    15
val process = uninterruptible (fn restore_attributes => fn script =>
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    16
  let
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    17
    datatype result = Wait | Signal | Result of int;
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    18
    val result = Synchronized.var "bash_result" Wait;
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    19
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    20
    val id = serial_string ();
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    21
    val script_path = File.tmp_path (Path.basic ("bash_script" ^ id));
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    22
    val out_path = File.tmp_path (Path.basic ("bash_out" ^ id));
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    23
    val err_path = File.tmp_path (Path.basic ("bash_err" ^ id));
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    24
    val pid_path = File.tmp_path (Path.basic ("bash_pid" ^ id));
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    25
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    26
    fun cleanup_files () =
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    27
     (try File.rm script_path;
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    28
      try File.rm out_path;
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    29
      try File.rm err_path;
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    30
      try File.rm pid_path);
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    31
    val _ = cleanup_files ();
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    32
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    33
    val system_thread =
61556
0d4ee4168e41 clarified modules;
wenzelm
parents: 60977
diff changeset
    34
      Standard_Thread.fork {name = "bash", stack_limit = NONE, interrupts = false} (fn () =>
60977
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    35
        Multithreading.with_attributes Multithreading.private_interrupts (fn _ =>
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    36
          let
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    37
            val _ = File.write script_path script;
62484
4759dbb35148 prefer bash_process;
wenzelm
parents: 61556
diff changeset
    38
            val bash_script =
4759dbb35148 prefer bash_process;
wenzelm
parents: 61556
diff changeset
    39
              "bash " ^ File.shell_path script_path ^
4759dbb35148 prefer bash_process;
wenzelm
parents: 61556
diff changeset
    40
                " > " ^ File.shell_path out_path ^
4759dbb35148 prefer bash_process;
wenzelm
parents: 61556
diff changeset
    41
                " 2> " ^ File.shell_path err_path;
4759dbb35148 prefer bash_process;
wenzelm
parents: 61556
diff changeset
    42
            val bash_process = getenv_strict "ISABELLE_BASH_PROCESS";
60977
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    43
            val rc =
62484
4759dbb35148 prefer bash_process;
wenzelm
parents: 61556
diff changeset
    44
              Windows.simpleExecute ("",
4759dbb35148 prefer bash_process;
wenzelm
parents: 61556
diff changeset
    45
                quote (ML_System.platform_path bash_process) ^ " " ^
4759dbb35148 prefer bash_process;
wenzelm
parents: 61556
diff changeset
    46
                quote (File.platform_path pid_path) ^ " bash -c " ^ quote bash_script)
60977
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    47
              |> Windows.fromStatus |> SysWord.toInt;
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    48
            val res = if rc = 130 orelse rc = 512 then Signal else Result rc;
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    49
          in Synchronized.change result (K res) end
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    50
          handle exn =>
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    51
            (Synchronized.change result (fn Wait => Signal | res => res); reraise exn)));
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    52
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    53
    fun read_pid 0 = NONE
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    54
      | read_pid count =
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    55
          (case (Int.fromString (File.read pid_path) handle IO.Io _ => NONE) of
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    56
            NONE => (OS.Process.sleep (seconds 0.1); read_pid (count - 1))
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    57
          | some => some);
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    58
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    59
    fun terminate NONE = ()
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    60
      | terminate (SOME pid) =
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    61
          let
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    62
            fun kill s =
62484
4759dbb35148 prefer bash_process;
wenzelm
parents: 61556
diff changeset
    63
              let
4759dbb35148 prefer bash_process;
wenzelm
parents: 61556
diff changeset
    64
                val cmd = getenv_strict "CYGWIN_ROOT" ^ "\\bin\\bash.exe";
4759dbb35148 prefer bash_process;
wenzelm
parents: 61556
diff changeset
    65
                val arg = "kill -" ^ s ^ " -" ^ string_of_int pid;
4759dbb35148 prefer bash_process;
wenzelm
parents: 61556
diff changeset
    66
              in
4759dbb35148 prefer bash_process;
wenzelm
parents: 61556
diff changeset
    67
                OS.Process.isSuccess (Windows.simpleExecute ("", quote cmd ^ " -c " ^ quote arg))
4759dbb35148 prefer bash_process;
wenzelm
parents: 61556
diff changeset
    68
                  handle OS.SysErr _ => false
4759dbb35148 prefer bash_process;
wenzelm
parents: 61556
diff changeset
    69
              end;
4759dbb35148 prefer bash_process;
wenzelm
parents: 61556
diff changeset
    70
60977
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    71
            fun multi_kill count s =
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    72
              count = 0 orelse
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    73
                (kill s; kill "0") andalso
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    74
                (OS.Process.sleep (seconds 0.1); multi_kill (count - 1) s);
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    75
            val _ =
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    76
              multi_kill 10 "INT" andalso
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    77
              multi_kill 10 "TERM" andalso
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    78
              multi_kill 10 "KILL";
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    79
          in () end;
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    80
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    81
    fun cleanup () =
61556
0d4ee4168e41 clarified modules;
wenzelm
parents: 60977
diff changeset
    82
     (Standard_Thread.interrupt_unsynchronized system_thread;
60977
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    83
      cleanup_files ());
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    84
  in
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    85
    let
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    86
      val _ =
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    87
        restore_attributes (fn () =>
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    88
          Synchronized.guarded_access result (fn Wait => NONE | x => SOME ((), x))) ();
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    89
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    90
      val out = the_default "" (try File.read out_path);
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    91
      val err = the_default "" (try File.read err_path);
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    92
      val rc = (case Synchronized.value result of Signal => Exn.interrupt () | Result rc => rc);
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    93
      val pid = read_pid 1;
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    94
      val _ = cleanup ();
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    95
    in {out = out, err = err, rc = rc, terminate = fn () => terminate pid} end
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    96
    handle exn => (terminate (read_pid 10); cleanup (); reraise exn)
c362c2d0f725 Cygwin bash on Windows;
wenzelm
parents: 60962
diff changeset
    97
  end);
60962
faa452d8e265 basic setup for native Windows (RAW session without image);
wenzelm
parents:
diff changeset
    98
faa452d8e265 basic setup for native Windows (RAW session without image);
wenzelm
parents:
diff changeset
    99
end;