src/Pure/Tools/isabelle_process.scala
changeset 27973 18d02c0b90b6
parent 27963 c9ea82444189
child 27990 f9dd4c9ed812
equal deleted inserted replaced
27972:a87be8fcb25c 27973:18d02c0b90b6
    14 
    14 
    15 import scala.collection.mutable.ArrayBuffer
    15 import scala.collection.mutable.ArrayBuffer
    16 import isabelle.{Symbol, XML}
    16 import isabelle.{Symbol, XML}
    17 
    17 
    18 
    18 
    19 class IsabelleProcess(args: String*) {
    19 object IsabelleProcess {
       
    20 
       
    21   /* exception */
    20 
    22 
    21   class IsabelleProcessException(msg: String) extends Exception {
    23   class IsabelleProcessException(msg: String) extends Exception {
    22     override def toString = "IsabelleProcess: " + msg
    24     override def toString = "IsabelleProcess: " + msg
    23   }
    25   }
    24 
       
    25 
       
    26   /* process information */
       
    27 
       
    28   private var proc: Process = null
       
    29   private var closing = false
       
    30   private var pid: String = null
       
    31   private var session: String = null
       
    32 
       
    33 
       
    34   /* encoding */
       
    35 
       
    36   private val charset = "UTF-8"
       
    37   private val symbols = new Symbol.Interpretation
       
    38 
    26 
    39 
    27 
    40   /* results */
    28   /* results */
    41 
    29 
    42   object Kind extends Enumeration {
    30   object Kind extends Enumeration {
    70       kind == PROMPT ||
    58       kind == PROMPT ||
    71       kind == STATUS ||
    59       kind == STATUS ||
    72       kind == SYSTEM
    60       kind == SYSTEM
    73   }
    61   }
    74 
    62 
    75   class Result(kind: Kind.Value, props: Properties, result: String) {
    63   class Result(val kind: Kind.Value, val props: Properties, val result: String) {
    76     //{{{
       
    77     override def toString = {
    64     override def toString = {
    78       val res = XML.content(YXML.parse_failsafe(result)).mkString("")
    65       val res = XML.content(YXML.parse_failsafe(result)).mkString("")
    79       if (props == null) kind.toString + " [[" + res + "]]"
    66       if (props == null) kind.toString + " [[" + res + "]]"
    80       else kind.toString + " " + props.toString + " [[" + res + "]]"
    67       else kind.toString + " " + props.toString + " [[" + res + "]]"
    81     }
    68     }
    82 
    69     def is_raw() = Kind.is_raw(kind)
    83     private var the_tree: XML.Tree = null
    70     def is_system() = Kind.is_system(kind)
    84     def tree() = synchronized {
    71   }
    85       if (the_tree == null) {
    72 
    86         val t = YXML.parse_failsafe(symbols.decode(result))
    73 }
    87         the_tree = if (Kind.is_raw(kind)) XML.Elem(Markup.RAW, Nil, List(t)) else t
    74 
    88       }
    75 
    89       the_tree
    76 class IsabelleProcess(args: String*) {
    90     }
    77 
    91     //}}}
    78   import IsabelleProcess._
    92   }
    79 
       
    80 
       
    81   /* process information */
       
    82 
       
    83   private var proc: Process = null
       
    84   private var closing = false
       
    85   private var pid: String = null
       
    86   private var the_session: String = null
       
    87   def session() = the_session
       
    88 
       
    89 
       
    90   /* results */
    93 
    91 
    94   val results = new LinkedBlockingQueue[Result]
    92   val results = new LinkedBlockingQueue[Result]
    95 
    93 
    96   private def put_result(kind: Kind.Value, props: Properties, result: String) {
    94   private def put_result(kind: Kind.Value, props: Properties, result: String) {
    97     if (kind == Kind.INIT && props != null) {
    95     if (kind == Kind.INIT && props != null) {
    98       pid = props.getProperty("pid")
    96       pid = props.getProperty(Markup.PID)
    99       session = props.getProperty("session")
    97       the_session = props.getProperty(Markup.SESSION)
   100     }
    98     }
   101     Console.println(new Result(kind, props, result))
       
   102     results.put(new Result(kind, props, result))
    99     results.put(new Result(kind, props, result))
       
   100   }
       
   101 
       
   102   val symbols = new Symbol.Interpretation
       
   103   def result_tree(result: Result) = YXML.parse_failsafe(symbols.decode(result.result))
       
   104 
       
   105 
       
   106   /* signals */
       
   107 
       
   108   def interrupt() = synchronized {
       
   109     if (proc == null) throw new IsabelleProcessException("Cannot interrupt: no process")
       
   110     if (pid == null) put_result(Kind.SYSTEM, null, "Cannot interrupt: unknown pid")
       
   111     else {
       
   112       put_result(Kind.SIGNAL, null, "INT")
       
   113       try {
       
   114         if (IsabelleSystem.exec(List("kill", "-INT", pid)).waitFor != 0)
       
   115           put_result(Kind.SYSTEM, null, "Cannot interrupt: kill command failed")
       
   116       }
       
   117       catch { case e: IOException => throw new IsabelleProcessException(e.getMessage) }
       
   118     }
       
   119   }
       
   120 
       
   121   def kill() = synchronized {
       
   122     if (proc == 0) throw new IsabelleProcessException("Cannot kill: no process")
       
   123     else {
       
   124       try_close()
       
   125       Thread.sleep(300)
       
   126       put_result(Kind.SIGNAL, null, "KILL")
       
   127       proc.destroy
       
   128       proc = null
       
   129     }
   103   }
   130   }
   104 
   131 
   105 
   132 
   106   /* output being piped into the process */
   133   /* output being piped into the process */
   107 
   134 
   311 
   338 
   312 
   339 
   313   /** main **/
   340   /** main **/
   314 
   341 
   315   {
   342   {
   316     /* command line */
   343     /* exec process */
   317 
   344 
   318     val cmdline = {
   345     try {
   319       val cmdline = new ArrayBuffer[String]
   346       proc = IsabelleSystem.exec(List(
   320 
   347         IsabelleSystem.getenv_strict("ISABELLE_HOME") + "/bin/isabelle-process", "-W") ++ args)
   321       IsabelleSystem.shell_prefix match {
   348     }
   322         case None => ()
   349     catch { case e: IOException => throw new IsabelleProcessException(e.getMessage) }
   323         case Some(prefix) => cmdline + prefix
   350 
   324       }
   351 
   325       cmdline + (IsabelleSystem.getenv_strict("ISABELLE_HOME") + "/bin/isabelle-process")
   352     /* control process via threads */
   326       cmdline + "-W"
   353 
   327       for (arg <- args) cmdline + arg
   354     val charset = "UTF-8"
   328       cmdline.toArray
       
   329     }
       
   330 
       
   331     try { proc = Runtime.getRuntime.exec(cmdline) }
       
   332     catch {
       
   333       case e: IOException => throw new IsabelleProcessException(e.getMessage)
       
   334     }
       
   335 
       
   336 
       
   337     /* process control via threads */
       
   338 
       
   339     new StdinThread(new BufferedWriter(new OutputStreamWriter(proc.getOutputStream, charset))).start
   355     new StdinThread(new BufferedWriter(new OutputStreamWriter(proc.getOutputStream, charset))).start
   340     new StdoutThread(new BufferedReader(new InputStreamReader(proc.getInputStream, charset))).start
   356     new StdoutThread(new BufferedReader(new InputStreamReader(proc.getInputStream, charset))).start
   341     new StderrThread(new BufferedReader(new InputStreamReader(proc.getErrorStream, charset))).start
   357     new StderrThread(new BufferedReader(new InputStreamReader(proc.getErrorStream, charset))).start
   342     new ExitThread().start
   358     new ExitThread().start
   343   }
   359   }
   344 
   360 
   345 }
   361 }
   346