src/Pure/System/bash.scala
changeset 80235 06036a16779f
parent 80229 5e32da8238e1
child 80237 305d2f4a395f
equal deleted inserted replaced
80234:cce5670be9f9 80235:06036a16779f
    72     val component = Components.provide(Component_Bash_Process.home, ssh = ssh)
    72     val component = Components.provide(Component_Bash_Process.home, ssh = ssh)
    73     val exe = Component_Bash_Process.remote_program(component)
    73     val exe = Component_Bash_Process.remote_program(component)
    74     ssh.make_command(args_host = true, args = ssh.bash_path(exe))
    74     ssh.make_command(args_host = true, args = ssh.bash_path(exe))
    75   }
    75   }
    76 
    76 
    77   type Watchdog = (Time, Process => Boolean)
    77   object Watchdog {
       
    78     val none: Watchdog = new Watchdog(Time.zero, _ => false) {
       
    79       override def toString: String = "Bash.Watchdog.none"
       
    80     }
       
    81     def apply(time: Time, check: Process => Boolean = _ => true): Watchdog =
       
    82       if (time.is_zero) none else new Watchdog(time, check)
       
    83   }
       
    84   class Watchdog private(val time: Time, val check: Process => Boolean) {
       
    85     override def toString: String = "Bash.Watchdog(" + time + ")"
       
    86     def defined: Boolean = !time.is_zero
       
    87   }
    78 
    88 
    79   def process(script: String,
    89   def process(script: String,
    80       description: String = "",
    90       description: String = "",
    81       ssh: SSH.System = SSH.Local,
    91       ssh: SSH.System = SSH.Local,
    82       cwd: Path = Path.current,
    92       cwd: Path = Path.current,
   246 
   256 
   247     def result(
   257     def result(
   248       input: String = "",
   258       input: String = "",
   249       progress_stdout: String => Unit = (_: String) => (),
   259       progress_stdout: String => Unit = (_: String) => (),
   250       progress_stderr: String => Unit = (_: String) => (),
   260       progress_stderr: String => Unit = (_: String) => (),
   251       watchdog: Option[Watchdog] = None,
   261       watchdog: Watchdog = Watchdog.none,
   252       strict: Boolean = true
   262       strict: Boolean = true
   253     ): Process_Result = {
   263     ): Process_Result = {
   254       val in =
   264       val in =
   255         if (input.isEmpty) Future.value(stdin.close())
   265         if (input.isEmpty) Future.value(stdin.close())
   256         else Future.thread("bash_stdin") { stdin.write(input); stdin.flush(); stdin.close(); }
   266         else Future.thread("bash_stdin") { stdin.write(input); stdin.flush(); stdin.close(); }
   258         Future.thread("bash_stdout") { File.read_lines(stdout, progress_stdout) }
   268         Future.thread("bash_stdout") { File.read_lines(stdout, progress_stdout) }
   259       val err_lines =
   269       val err_lines =
   260         Future.thread("bash_stderr") { File.read_lines(stderr, progress_stderr) }
   270         Future.thread("bash_stderr") { File.read_lines(stderr, progress_stderr) }
   261 
   271 
   262       val watchdog_thread =
   272       val watchdog_thread =
   263         for ((time, check) <- watchdog)
   273         if (watchdog.defined) {
   264         yield {
   274           Some(
   265           Future.thread("bash_watchdog") {
   275             Future.thread("bash_watchdog") {
   266             while (proc.isAlive) {
   276               while (proc.isAlive) {
   267               time.sleep()
   277                 watchdog.time.sleep()
   268               if (check(this)) interrupt()
   278                 if (watchdog.check(this)) interrupt()
   269             }
   279               }
   270           }
   280             })
   271         }
   281         }
       
   282         else None
   272 
   283 
   273       val rc =
   284       val rc =
   274         try { join() }
   285         try { join() }
   275         catch { case Exn.Interrupt() => terminate(); Process_Result.RC.interrupt }
   286         catch { case Exn.Interrupt() => terminate(); Process_Result.RC.interrupt }
   276 
   287 
   375               _processes.change(processes => processes + (uuid -> process))
   386               _processes.change(processes => processes + (uuid -> process))
   376               reply(List(Server.UUID, uuid.toString))
   387               reply(List(Server.UUID, uuid.toString))
   377 
   388 
   378               Isabelle_Thread.fork(name = "bash_process") {
   389               Isabelle_Thread.fork(name = "bash_process") {
   379                 @volatile var is_timeout = false
   390                 @volatile var is_timeout = false
   380                 val watchdog: Option[Watchdog] =
   391                 val watchdog =
   381                   if (timeout.is_zero) None else Some((timeout, _ => { is_timeout = true; true }))
   392                   if (timeout.is_zero) Watchdog.none
       
   393                   else Watchdog(timeout, _ => { is_timeout = true; true })
   382 
   394 
   383                 Exn.capture { process.result(input = input, watchdog = watchdog, strict = false) }
   395                 Exn.capture { process.result(input = input, watchdog = watchdog, strict = false) }
   384                 match {
   396                 match {
   385                   case Exn.Exn(exn) => reply_failure(exn)
   397                   case Exn.Exn(exn) => reply_failure(exn)
   386                   case Exn.Res(res0) =>
   398                   case Exn.Res(res0) =>