src/Pure/PIDE/prover.scala
changeset 75393 87ebf5a50283
parent 74253 45dc9de1bd33
child 77243 629dce95bb5c
equal deleted inserted replaced
75388:b3ca4a6ed74b 75393:87ebf5a50283
     9 
     9 
    10 
    10 
    11 import java.io.{InputStream, OutputStream, BufferedOutputStream, IOException}
    11 import java.io.{InputStream, OutputStream, BufferedOutputStream, IOException}
    12 
    12 
    13 
    13 
    14 object Prover
    14 object Prover {
    15 {
       
    16   /* messages */
    15   /* messages */
    17 
    16 
    18   sealed abstract class Message
    17   sealed abstract class Message
    19   type Receiver = Message => Unit
    18   type Receiver = Message => Unit
    20 
    19 
    21   class Input(val name: String, val args: List[String]) extends Message
    20   class Input(val name: String, val args: List[String]) extends Message {
    22   {
       
    23     override def toString: String =
    21     override def toString: String =
    24       XML.Elem(Markup(Markup.PROVER_COMMAND, List((Markup.NAME, name))),
    22       XML.Elem(Markup(Markup.PROVER_COMMAND, List((Markup.NAME, name))),
    25         args.flatMap(s =>
    23         args.flatMap(s =>
    26           List(XML.newline, XML.elem(Markup.PROVER_ARG, YXML.parse_body(s))))).toString
    24           List(XML.newline, XML.elem(Markup.PROVER_ARG, YXML.parse_body(s))))).toString
    27   }
    25   }
    28 
    26 
    29   class Output(val message: XML.Elem) extends Message
    27   class Output(val message: XML.Elem) extends Message {
    30   {
       
    31     def kind: String = message.markup.name
    28     def kind: String = message.markup.name
    32     def properties: Properties.T = message.markup.properties
    29     def properties: Properties.T = message.markup.properties
    33     def body: XML.Body = message.body
    30     def body: XML.Body = message.body
    34 
    31 
    35     def is_init: Boolean = kind == Markup.INIT
    32     def is_init: Boolean = kind == Markup.INIT
    39     def is_system: Boolean = kind == Markup.SYSTEM
    36     def is_system: Boolean = kind == Markup.SYSTEM
    40     def is_status: Boolean = kind == Markup.STATUS
    37     def is_status: Boolean = kind == Markup.STATUS
    41     def is_report: Boolean = kind == Markup.REPORT
    38     def is_report: Boolean = kind == Markup.REPORT
    42     def is_syslog: Boolean = is_init || is_exit || is_system || is_stderr
    39     def is_syslog: Boolean = is_init || is_exit || is_system || is_stderr
    43 
    40 
    44     override def toString: String =
    41     override def toString: String = {
    45     {
       
    46       val res =
    42       val res =
    47         if (is_status || is_report) message.body.map(_.toString).mkString
    43         if (is_status || is_report) message.body.map(_.toString).mkString
    48         else Pretty.string_of(message.body, metric = Symbol.Metric)
    44         else Pretty.string_of(message.body, metric = Symbol.Metric)
    49       if (properties.isEmpty)
    45       if (properties.isEmpty)
    50         kind + " [[" + res + "]]"
    46         kind + " [[" + res + "]]"
    63       case List(chunk) => chunk
    59       case List(chunk) => chunk
    64       case _ => throw new Malformed("single chunk expected: " + print)
    60       case _ => throw new Malformed("single chunk expected: " + print)
    65     }
    61     }
    66 
    62 
    67   class Protocol_Output(props: Properties.T, val chunks: List[Bytes])
    63   class Protocol_Output(props: Properties.T, val chunks: List[Bytes])
    68     extends Output(XML.Elem(Markup(Markup.PROTOCOL, props), Nil))
    64   extends Output(XML.Elem(Markup(Markup.PROTOCOL, props), Nil)) {
    69   {
       
    70     def chunk: Bytes = the_chunk(chunks, toString)
    65     def chunk: Bytes = the_chunk(chunks, toString)
    71     lazy val text: String = chunk.text
    66     lazy val text: String = chunk.text
    72   }
    67   }
    73 }
    68 }
    74 
    69 
    75 
    70 
    76 class Prover(
    71 class Prover(
    77   receiver: Prover.Receiver,
    72   receiver: Prover.Receiver,
    78   cache: XML.Cache,
    73   cache: XML.Cache,
    79   channel: System_Channel,
    74   channel: System_Channel,
    80   process: Bash.Process) extends Protocol
    75   process: Bash.Process
    81 {
    76 ) extends Protocol {
    82   /** receiver output **/
    77   /** receiver output **/
    83 
    78 
    84   private def system_output(text: String): Unit =
    79   private def system_output(text: String): Unit = {
    85   {
       
    86     receiver(new Prover.Output(XML.Elem(Markup(Markup.SYSTEM, Nil), List(XML.Text(text)))))
    80     receiver(new Prover.Output(XML.Elem(Markup(Markup.SYSTEM, Nil), List(XML.Text(text)))))
    87   }
    81   }
    88 
    82 
    89   private def protocol_output(props: Properties.T, chunks: List[Bytes]): Unit =
    83   private def protocol_output(props: Properties.T, chunks: List[Bytes]): Unit = {
    90   {
       
    91     receiver(new Prover.Protocol_Output(props, chunks))
    84     receiver(new Prover.Protocol_Output(props, chunks))
    92   }
    85   }
    93 
    86 
    94   private def output(kind: String, props: Properties.T, body: XML.Body): Unit =
    87   private def output(kind: String, props: Properties.T, body: XML.Body): Unit = {
    95   {
       
    96     val main = XML.Elem(Markup(kind, props), Protocol_Message.clean_reports(body))
    88     val main = XML.Elem(Markup(kind, props), Protocol_Message.clean_reports(body))
    97     val reports = Protocol_Message.reports(props, body)
    89     val reports = Protocol_Message.reports(props, body)
    98     for (msg <- main :: reports) receiver(new Prover.Output(cache.elem(msg)))
    90     for (msg <- main :: reports) receiver(new Prover.Output(cache.elem(msg)))
    99   }
    91   }
   100 
    92 
   101   private def exit_message(result: Process_Result): Unit =
    93   private def exit_message(result: Process_Result): Unit = {
   102   {
       
   103     output(Markup.EXIT, Markup.Process_Result(result),
    94     output(Markup.EXIT, Markup.Process_Result(result),
   104       List(XML.Text(result.print_return_code)))
    95       List(XML.Text(result.print_return_code)))
   105   }
    96   }
   106 
    97 
   107 
    98 
   113       val rc = process.join()
   104       val rc = process.join()
   114       val timing = process.get_timing
   105       val timing = process.get_timing
   115       Process_Result(rc, timing = timing)
   106       Process_Result(rc, timing = timing)
   116     }
   107     }
   117 
   108 
   118   private def terminate_process(): Unit =
   109   private def terminate_process(): Unit = {
   119   {
       
   120     try { process.terminate() }
   110     try { process.terminate() }
   121     catch {
   111     catch {
   122       case exn @ ERROR(_) => system_output("Failed to terminate prover process: " + exn.getMessage)
   112       case exn @ ERROR(_) => system_output("Failed to terminate prover process: " + exn.getMessage)
   123     }
   113     }
   124   }
   114   }
   125 
   115 
   126   private val process_manager = Isabelle_Thread.fork(name = "process_manager")
   116   private val process_manager = Isabelle_Thread.fork(name = "process_manager") {
   127   {
       
   128     val stdout = physical_output(false)
   117     val stdout = physical_output(false)
   129 
   118 
   130     val (startup_failed, startup_errors) =
   119     val (startup_failed, startup_errors) = {
   131     {
       
   132       var finished: Option[Boolean] = None
   120       var finished: Option[Boolean] = None
   133       val result = new StringBuilder(100)
   121       val result = new StringBuilder(100)
   134       while (finished.isEmpty && (process.stderr.ready || !process_result.is_finished)) {
   122       while (finished.isEmpty && (process.stderr.ready || !process_result.is_finished)) {
   135         while (finished.isEmpty && process.stderr.ready) {
   123         while (finished.isEmpty && process.stderr.ready) {
   136           try {
   124           try {
   172 
   160 
   173   /* management methods */
   161   /* management methods */
   174 
   162 
   175   def join(): Unit = process_manager.join()
   163   def join(): Unit = process_manager.join()
   176 
   164 
   177   def terminate(): Unit =
   165   def terminate(): Unit = {
   178   {
       
   179     system_output("Terminating prover process")
   166     system_output("Terminating prover process")
   180     command_input_close()
   167     command_input_close()
   181 
   168 
   182     var count = 10
   169     var count = 10
   183     while (!process_result.is_finished && count > 0) {
   170     while (!process_result.is_finished && count > 0) {
   195 
   182 
   196   private var command_input: Option[Consumer_Thread[List[Bytes]]] = None
   183   private var command_input: Option[Consumer_Thread[List[Bytes]]] = None
   197 
   184 
   198   private def command_input_close(): Unit = command_input.foreach(_.shutdown())
   185   private def command_input_close(): Unit = command_input.foreach(_.shutdown())
   199 
   186 
   200   private def command_input_init(raw_stream: OutputStream): Unit =
   187   private def command_input_init(raw_stream: OutputStream): Unit = {
   201   {
       
   202     val name = "command_input"
   188     val name = "command_input"
   203     val stream = new BufferedOutputStream(raw_stream)
   189     val stream = new BufferedOutputStream(raw_stream)
   204     command_input =
   190     command_input =
   205       Some(
   191       Some(
   206         Consumer_Thread.fork(name)(
   192         Consumer_Thread.fork(name)(
   221   }
   207   }
   222 
   208 
   223 
   209 
   224   /* physical output */
   210   /* physical output */
   225 
   211 
   226   private def physical_output(err: Boolean): Thread =
   212   private def physical_output(err: Boolean): Thread = {
   227   {
       
   228     val (name, reader, markup) =
   213     val (name, reader, markup) =
   229       if (err) ("standard_error", process.stderr, Markup.STDERR)
   214       if (err) ("standard_error", process.stderr, Markup.STDERR)
   230       else ("standard_output", process.stdout, Markup.STDOUT)
   215       else ("standard_output", process.stdout, Markup.STDOUT)
   231 
   216 
   232     Isabelle_Thread.fork(name = name) {
   217     Isabelle_Thread.fork(name = name) {
   259   }
   244   }
   260 
   245 
   261 
   246 
   262   /* message output */
   247   /* message output */
   263 
   248 
   264   private def message_output(stream: InputStream): Thread =
   249   private def message_output(stream: InputStream): Thread = {
   265   {
       
   266     def decode_chunk(chunk: Bytes): XML.Body =
   250     def decode_chunk(chunk: Bytes): XML.Body =
   267       Symbol.decode_yxml_failsafe(chunk.text, cache = cache)
   251       Symbol.decode_yxml_failsafe(chunk.text, cache = cache)
   268 
   252 
   269     val thread_name = "message_output"
   253     val thread_name = "message_output"
   270     Isabelle_Thread.fork(name = thread_name) {
   254     Isabelle_Thread.fork(name = thread_name) {
   310         }
   294         }
   311         thread.send(Bytes(name) :: args)
   295         thread.send(Bytes(name) :: args)
   312       case _ => error("Inactive prover input thread for command " + quote(name))
   296       case _ => error("Inactive prover input thread for command " + quote(name))
   313     }
   297     }
   314 
   298 
   315   def protocol_command_args(name: String, args: List[String]): Unit =
   299   def protocol_command_args(name: String, args: List[String]): Unit = {
   316   {
       
   317     receiver(new Prover.Input(name, args))
   300     receiver(new Prover.Input(name, args))
   318     protocol_command_raw(name, args.map(Bytes(_)))
   301     protocol_command_raw(name, args.map(Bytes(_)))
   319   }
   302   }
   320 
   303 
   321   def protocol_command(name: String, args: String*): Unit =
   304   def protocol_command(name: String, args: String*): Unit =