src/Pure/Concurrent/bash.scala
author wenzelm
Sun, 14 Feb 2016 11:52:27 +0100
changeset 62302 236e1ea5a197
parent 62296 b04a5ddd6121
child 62303 f868f12f9419
permissions -rw-r--r--
tuned signature;
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
60991
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
     1
/*  Title:      Pure/Concurrent/bash.scala
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
     2
    Author:     Makarius
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
     3
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
     4
GNU bash processes, with propagation of interrupts.
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
     5
*/
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
     6
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
     7
package isabelle
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
     8
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
     9
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    10
import java.io.{File => JFile, BufferedReader, InputStreamReader,
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    11
  BufferedWriter, OutputStreamWriter}
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    12
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    13
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    14
object Bash
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    15
{
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    16
  /** result **/
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    17
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    18
  final case class Result(out_lines: List[String], err_lines: List[String], rc: Int)
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    19
  {
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    20
    def out: String = cat_lines(out_lines)
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    21
    def err: String = cat_lines(err_lines)
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    22
    def add_err(s: String): Result = copy(err_lines = err_lines ::: List(s))
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    23
    def set_rc(i: Int): Result = copy(rc = i)
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    24
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    25
    def check_error: Result =
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    26
      if (rc == Exn.Interrupt.return_code) throw Exn.Interrupt()
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    27
      else if (rc != 0) error(err)
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    28
      else this
62302
236e1ea5a197 tuned signature;
wenzelm
parents: 62296
diff changeset
    29
236e1ea5a197 tuned signature;
wenzelm
parents: 62296
diff changeset
    30
    def print: Result =
236e1ea5a197 tuned signature;
wenzelm
parents: 62296
diff changeset
    31
    {
236e1ea5a197 tuned signature;
wenzelm
parents: 62296
diff changeset
    32
      Output.warning(Library.trim_line(err))
236e1ea5a197 tuned signature;
wenzelm
parents: 62296
diff changeset
    33
      Output.writeln(Library.trim_line(out))
236e1ea5a197 tuned signature;
wenzelm
parents: 62296
diff changeset
    34
      Result(Nil, Nil, rc)
236e1ea5a197 tuned signature;
wenzelm
parents: 62296
diff changeset
    35
    }
60991
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    36
  }
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    37
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    38
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    39
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    40
  /** process **/
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    41
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    42
  def process(cwd: JFile, env: Map[String, String], redirect: Boolean, args: String*): Process =
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    43
    new Process(cwd, env, redirect, args:_*)
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    44
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    45
  class Process private [Bash](
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    46
      cwd: JFile, env: Map[String, String], redirect: Boolean, args: String*)
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    47
    extends Prover.System_Process
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    48
  {
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    49
    private val params =
62296
b04a5ddd6121 clarified bash process -- similar to ML version;
wenzelm
parents: 61025
diff changeset
    50
      List(Isabelle_System.getenv_strict("ISABELLE_BASH_PROCESS"), "-", "bash")
b04a5ddd6121 clarified bash process -- similar to ML version;
wenzelm
parents: 61025
diff changeset
    51
    private val proc =
b04a5ddd6121 clarified bash process -- similar to ML version;
wenzelm
parents: 61025
diff changeset
    52
      Isabelle_System.execute_env(cwd, env, redirect, (params ::: args.toList):_*)
60991
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    53
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    54
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    55
    // channels
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    56
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    57
    val stdin: BufferedWriter =
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    58
      new BufferedWriter(new OutputStreamWriter(proc.getOutputStream, UTF8.charset))
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    59
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    60
    val stdout: BufferedReader =
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    61
      new BufferedReader(new InputStreamReader(proc.getInputStream, UTF8.charset))
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    62
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    63
    val stderr: BufferedReader =
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    64
      new BufferedReader(new InputStreamReader(proc.getErrorStream, UTF8.charset))
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    65
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    66
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    67
    // signals
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    68
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    69
    private val pid = stdout.readLine
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    70
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    71
    private def kill(signal: String): Boolean =
61025
636b578bfadd clarified kill on Windows: just one executable;
wenzelm
parents: 60991
diff changeset
    72
      Exn.Interrupt.postpone {
636b578bfadd clarified kill on Windows: just one executable;
wenzelm
parents: 60991
diff changeset
    73
        Isabelle_System.kill(signal, pid)
636b578bfadd clarified kill on Windows: just one executable;
wenzelm
parents: 60991
diff changeset
    74
        Isabelle_System.kill("0", pid)._2 == 0 } getOrElse true
60991
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    75
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    76
    private def multi_kill(signal: String): Boolean =
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    77
    {
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    78
      var running = true
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    79
      var count = 10
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    80
      while (running && count > 0) {
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    81
        if (kill(signal)) {
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    82
          Exn.Interrupt.postpone {
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    83
            Thread.sleep(100)
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    84
            count -= 1
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    85
          }
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    86
        }
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    87
        else running = false
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    88
      }
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    89
      running
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    90
    }
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    91
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    92
    def interrupt() { multi_kill("INT") }
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    93
    def terminate() { multi_kill("INT") && multi_kill("TERM") && kill("KILL"); proc.destroy }
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    94
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    95
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    96
    // JVM shutdown hook
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    97
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    98
    private val shutdown_hook = new Thread { override def run = terminate() }
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
    99
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
   100
    try { Runtime.getRuntime.addShutdownHook(shutdown_hook) }
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
   101
    catch { case _: IllegalStateException => }
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
   102
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
   103
    private def cleanup() =
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
   104
      try { Runtime.getRuntime.removeShutdownHook(shutdown_hook) }
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
   105
      catch { case _: IllegalStateException => }
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
   106
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
   107
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
   108
    /* result */
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
   109
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
   110
    def join: Int = { val rc = proc.waitFor; cleanup(); rc }
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
   111
  }
2fc5a44346b5 clarified modules, like ML version;
wenzelm
parents:
diff changeset
   112
}