| author | wenzelm | 
| Fri, 12 Jul 2013 21:13:57 +0200 | |
| changeset 52630 | fe411c1dc180 | 
| parent 52582 | 31467a4b1466 | 
| child 52799 | 6a4498b048b7 | 
| permissions | -rw-r--r-- | 
| 43283 | 1 | /* Title: Pure/System/isabelle_process.scala | 
| 27949 
6eb0327c0b9b
Isabelle process management -- always reactive due to multi-threaded I/O.
 wenzelm parents: diff
changeset | 2 | Author: Makarius | 
| 27963 | 3 | Options: :folding=explicit:collapseFolds=1: | 
| 27949 
6eb0327c0b9b
Isabelle process management -- always reactive due to multi-threaded I/O.
 wenzelm parents: diff
changeset | 4 | |
| 
6eb0327c0b9b
Isabelle process management -- always reactive due to multi-threaded I/O.
 wenzelm parents: diff
changeset | 5 | Isabelle process management -- always reactive due to multi-threaded I/O. | 
| 
6eb0327c0b9b
Isabelle process management -- always reactive due to multi-threaded I/O.
 wenzelm parents: diff
changeset | 6 | */ | 
| 
6eb0327c0b9b
Isabelle process management -- always reactive due to multi-threaded I/O.
 wenzelm parents: diff
changeset | 7 | |
| 
6eb0327c0b9b
Isabelle process management -- always reactive due to multi-threaded I/O.
 wenzelm parents: diff
changeset | 8 | package isabelle | 
| 
6eb0327c0b9b
Isabelle process management -- always reactive due to multi-threaded I/O.
 wenzelm parents: diff
changeset | 9 | |
| 43520 
cec9b95fa35d
explicit import java.lang.System to prevent odd scope problems;
 wenzelm parents: 
43514diff
changeset | 10 | import java.lang.System | 
| 27955 
4c32c5e75eca
use java.util.concurrent.LinkedBlockingQueue, which blocks as required;
 wenzelm parents: 
27949diff
changeset | 11 | import java.util.concurrent.LinkedBlockingQueue | 
| 28045 | 12 | import java.io.{BufferedReader, BufferedWriter, InputStreamReader, OutputStreamWriter,
 | 
| 38270 
71bb3c273dd1
native Isabelle_Process commands, based on efficient byte channel protocol for string lists;
 wenzelm parents: 
38262diff
changeset | 13 | InputStream, OutputStream, BufferedOutputStream, IOException} | 
| 27949 
6eb0327c0b9b
Isabelle process management -- always reactive due to multi-threaded I/O.
 wenzelm parents: diff
changeset | 14 | |
| 32474 
0818e6b1c8a6
Isabelle_Process: receiver as Actor, not EventBus;
 wenzelm parents: 
32448diff
changeset | 15 | import scala.actors.Actor | 
| 
0818e6b1c8a6
Isabelle_Process: receiver as Actor, not EventBus;
 wenzelm parents: 
32448diff
changeset | 16 | import Actor._ | 
| 27949 
6eb0327c0b9b
Isabelle process management -- always reactive due to multi-threaded I/O.
 wenzelm parents: diff
changeset | 17 | |
| 27973 
18d02c0b90b6
moved class Result into static object, removed dynamic tree method;
 wenzelm parents: 
27963diff
changeset | 18 | |
| 32474 
0818e6b1c8a6
Isabelle_Process: receiver as Actor, not EventBus;
 wenzelm parents: 
32448diff
changeset | 19 | object Isabelle_Process | 
| 
0818e6b1c8a6
Isabelle_Process: receiver as Actor, not EventBus;
 wenzelm parents: 
32448diff
changeset | 20 | {
 | 
| 46772 
be21f050eda4
tuned signature -- emphasize Isabelle_Process Input vs. Output;
 wenzelm parents: 
46769diff
changeset | 21 | /* messages */ | 
| 27949 
6eb0327c0b9b
Isabelle process management -- always reactive due to multi-threaded I/O.
 wenzelm parents: diff
changeset | 22 | |
| 44733 
329320fc88df
buffer prover messages to prevent overloading of session_actor input channel -- which is critical due to synchronous messages wrt. GUI thread;
 wenzelm parents: 
44732diff
changeset | 23 | sealed abstract class Message | 
| 43721 
fad8634cee62
echo prover input via raw_messages, for improved protocol tracing;
 wenzelm parents: 
43695diff
changeset | 24 | |
| 
fad8634cee62
echo prover input via raw_messages, for improved protocol tracing;
 wenzelm parents: 
43695diff
changeset | 25 | class Input(name: String, args: List[String]) extends Message | 
| 
fad8634cee62
echo prover input via raw_messages, for improved protocol tracing;
 wenzelm parents: 
43695diff
changeset | 26 |   {
 | 
| 
fad8634cee62
echo prover input via raw_messages, for improved protocol tracing;
 wenzelm parents: 
43695diff
changeset | 27 | override def toString: String = | 
| 50201 
c26369c9eda6
Isabelle-specific implementation of quasi-abstract markup elements -- back to module arrangement before d83797ef0d2d;
 wenzelm parents: 
50117diff
changeset | 28 | XML.Elem(Markup(Markup.PROVER_COMMAND, List((Markup.NAME, name))), | 
| 43721 
fad8634cee62
echo prover input via raw_messages, for improved protocol tracing;
 wenzelm parents: 
43695diff
changeset | 29 | args.map(s => | 
| 50201 
c26369c9eda6
Isabelle-specific implementation of quasi-abstract markup elements -- back to module arrangement before d83797ef0d2d;
 wenzelm parents: 
50117diff
changeset | 30 |           List(XML.Text("\n"), XML.elem(Markup.PROVER_ARG, YXML.parse_body(s)))).flatten).toString
 | 
| 43721 
fad8634cee62
echo prover input via raw_messages, for improved protocol tracing;
 wenzelm parents: 
43695diff
changeset | 31 | } | 
| 
fad8634cee62
echo prover input via raw_messages, for improved protocol tracing;
 wenzelm parents: 
43695diff
changeset | 32 | |
| 46772 
be21f050eda4
tuned signature -- emphasize Isabelle_Process Input vs. Output;
 wenzelm parents: 
46769diff
changeset | 33 | class Output(val message: XML.Elem) extends Message | 
| 34100 | 34 |   {
 | 
| 43747 | 35 | def kind: String = message.markup.name | 
| 43780 | 36 | def properties: Properties.T = message.markup.properties | 
| 43747 | 37 | def body: XML.Body = message.body | 
| 37689 
628eabe2213a
simplified Isabelle_Process.Result: use markup directly;
 wenzelm parents: 
37132diff
changeset | 38 | |
| 50201 
c26369c9eda6
Isabelle-specific implementation of quasi-abstract markup elements -- back to module arrangement before d83797ef0d2d;
 wenzelm parents: 
50117diff
changeset | 39 | def is_init = kind == Markup.INIT | 
| 
c26369c9eda6
Isabelle-specific implementation of quasi-abstract markup elements -- back to module arrangement before d83797ef0d2d;
 wenzelm parents: 
50117diff
changeset | 40 | def is_exit = kind == Markup.EXIT | 
| 
c26369c9eda6
Isabelle-specific implementation of quasi-abstract markup elements -- back to module arrangement before d83797ef0d2d;
 wenzelm parents: 
50117diff
changeset | 41 | def is_stdout = kind == Markup.STDOUT | 
| 
c26369c9eda6
Isabelle-specific implementation of quasi-abstract markup elements -- back to module arrangement before d83797ef0d2d;
 wenzelm parents: 
50117diff
changeset | 42 | def is_stderr = kind == Markup.STDERR | 
| 
c26369c9eda6
Isabelle-specific implementation of quasi-abstract markup elements -- back to module arrangement before d83797ef0d2d;
 wenzelm parents: 
50117diff
changeset | 43 | def is_system = kind == Markup.SYSTEM | 
| 
c26369c9eda6
Isabelle-specific implementation of quasi-abstract markup elements -- back to module arrangement before d83797ef0d2d;
 wenzelm parents: 
50117diff
changeset | 44 | def is_status = kind == Markup.STATUS | 
| 
c26369c9eda6
Isabelle-specific implementation of quasi-abstract markup elements -- back to module arrangement before d83797ef0d2d;
 wenzelm parents: 
50117diff
changeset | 45 | def is_report = kind == Markup.REPORT | 
| 
c26369c9eda6
Isabelle-specific implementation of quasi-abstract markup elements -- back to module arrangement before d83797ef0d2d;
 wenzelm parents: 
50117diff
changeset | 46 | def is_protocol = kind == Markup.PROTOCOL | 
| 46121 | 47 | def is_syslog = is_init || is_exit || is_system || is_stderr | 
| 34100 | 48 | |
| 49 | override def toString: String = | |
| 50 |     {
 | |
| 29522 
793766d4c1b5
moved message markup into Scala layer -- reduced redundancy;
 wenzelm parents: 
29506diff
changeset | 51 | val res = | 
| 38236 
d8c7be27e01d
explicitly distinguish Output.status (essential feedback) vs. Output.report (useful markup);
 wenzelm parents: 
38231diff
changeset | 52 | if (is_status || is_report) message.body.map(_.toString).mkString | 
| 46774 | 53 | else if (is_protocol) "..." | 
| 37689 
628eabe2213a
simplified Isabelle_Process.Result: use markup directly;
 wenzelm parents: 
37132diff
changeset | 54 | else Pretty.string_of(message.body) | 
| 38230 
ed147003de4b
simplified type XML.Tree: embed Markup directly, avoid slightly odd triple;
 wenzelm parents: 
37712diff
changeset | 55 | if (properties.isEmpty) | 
| 29572 
e3a99d957392
replaced java.util.Properties by plain association list;
 wenzelm parents: 
29522diff
changeset | 56 | kind.toString + " [[" + res + "]]" | 
| 
e3a99d957392
replaced java.util.Properties by plain association list;
 wenzelm parents: 
29522diff
changeset | 57 | else | 
| 
e3a99d957392
replaced java.util.Properties by plain association list;
 wenzelm parents: 
29522diff
changeset | 58 | kind.toString + " " + | 
| 38230 
ed147003de4b
simplified type XML.Tree: embed Markup directly, avoid slightly odd triple;
 wenzelm parents: 
37712diff
changeset | 59 |           (for ((x, y) <- properties) yield x + "=" + y).mkString("{", ",", "}") + " [[" + res + "]]"
 | 
| 27949 
6eb0327c0b9b
Isabelle process management -- always reactive due to multi-threaded I/O.
 wenzelm parents: diff
changeset | 60 | } | 
| 27973 
18d02c0b90b6
moved class Result into static object, removed dynamic tree method;
 wenzelm parents: 
27963diff
changeset | 61 | } | 
| 
18d02c0b90b6
moved class Result into static object, removed dynamic tree method;
 wenzelm parents: 
27963diff
changeset | 62 | } | 
| 
18d02c0b90b6
moved class Result into static object, removed dynamic tree method;
 wenzelm parents: 
27963diff
changeset | 63 | |
| 
18d02c0b90b6
moved class Result into static object, removed dynamic tree method;
 wenzelm parents: 
27963diff
changeset | 64 | |
| 45055 
55274f7e306b
explicit option for socket vs. fifo communication;
 wenzelm parents: 
45027diff
changeset | 65 | class Isabelle_Process( | 
| 
55274f7e306b
explicit option for socket vs. fifo communication;
 wenzelm parents: 
45027diff
changeset | 66 | receiver: Isabelle_Process.Message => Unit = Console.println(_), | 
| 
55274f7e306b
explicit option for socket vs. fifo communication;
 wenzelm parents: 
45027diff
changeset | 67 | args: List[String] = Nil) | 
| 29192 | 68 | {
 | 
| 31797 | 69 | import Isabelle_Process._ | 
| 29194 | 70 | |
| 27973 
18d02c0b90b6
moved class Result into static object, removed dynamic tree method;
 wenzelm parents: 
27963diff
changeset | 71 | |
| 48705 
dd32321d6eef
tuned signature -- slightly more abstract text representation of prover process;
 wenzelm parents: 
48355diff
changeset | 72 | /* text representation */ | 
| 
dd32321d6eef
tuned signature -- slightly more abstract text representation of prover process;
 wenzelm parents: 
48355diff
changeset | 73 | |
| 
dd32321d6eef
tuned signature -- slightly more abstract text representation of prover process;
 wenzelm parents: 
48355diff
changeset | 74 | def encode(s: String): String = Symbol.encode(s) | 
| 
dd32321d6eef
tuned signature -- slightly more abstract text representation of prover process;
 wenzelm parents: 
48355diff
changeset | 75 | def decode(s: String): String = Symbol.decode(s) | 
| 
dd32321d6eef
tuned signature -- slightly more abstract text representation of prover process;
 wenzelm parents: 
48355diff
changeset | 76 | |
| 
dd32321d6eef
tuned signature -- slightly more abstract text representation of prover process;
 wenzelm parents: 
48355diff
changeset | 77 | object Encode | 
| 
dd32321d6eef
tuned signature -- slightly more abstract text representation of prover process;
 wenzelm parents: 
48355diff
changeset | 78 |   {
 | 
| 
dd32321d6eef
tuned signature -- slightly more abstract text representation of prover process;
 wenzelm parents: 
48355diff
changeset | 79 | val string: XML.Encode.T[String] = (s => XML.Encode.string(encode(s))) | 
| 
dd32321d6eef
tuned signature -- slightly more abstract text representation of prover process;
 wenzelm parents: 
48355diff
changeset | 80 | } | 
| 
dd32321d6eef
tuned signature -- slightly more abstract text representation of prover process;
 wenzelm parents: 
48355diff
changeset | 81 | |
| 
dd32321d6eef
tuned signature -- slightly more abstract text representation of prover process;
 wenzelm parents: 
48355diff
changeset | 82 | |
| 46772 
be21f050eda4
tuned signature -- emphasize Isabelle_Process Input vs. Output;
 wenzelm parents: 
46769diff
changeset | 83 | /* output */ | 
| 39573 | 84 | |
| 51664 | 85 | val xml_cache = new XML.Cache() | 
| 86 | ||
| 46772 
be21f050eda4
tuned signature -- emphasize Isabelle_Process Input vs. Output;
 wenzelm parents: 
46769diff
changeset | 87 | private def system_output(text: String) | 
| 39573 | 88 |   {
 | 
| 50201 
c26369c9eda6
Isabelle-specific implementation of quasi-abstract markup elements -- back to module arrangement before d83797ef0d2d;
 wenzelm parents: 
50117diff
changeset | 89 | receiver(new Output(XML.Elem(Markup(Markup.SYSTEM, Nil), List(XML.Text(text))))) | 
| 39573 | 90 | } | 
| 91 | ||
| 46772 
be21f050eda4
tuned signature -- emphasize Isabelle_Process Input vs. Output;
 wenzelm parents: 
46769diff
changeset | 92 | private def output_message(kind: String, props: Properties.T, body: XML.Body) | 
| 39573 | 93 |   {
 | 
| 50201 
c26369c9eda6
Isabelle-specific implementation of quasi-abstract markup elements -- back to module arrangement before d83797ef0d2d;
 wenzelm parents: 
50117diff
changeset | 94 | if (kind == Markup.INIT) system_channel.accepted() | 
| 
c26369c9eda6
Isabelle-specific implementation of quasi-abstract markup elements -- back to module arrangement before d83797ef0d2d;
 wenzelm parents: 
50117diff
changeset | 95 | if (kind == Markup.PROTOCOL) | 
| 46772 
be21f050eda4
tuned signature -- emphasize Isabelle_Process Input vs. Output;
 wenzelm parents: 
46769diff
changeset | 96 | receiver(new Output(XML.Elem(Markup(kind, props), body))) | 
| 43746 
a41f618c641d
some support for raw messages, which bypass standard Symbol/YXML decoding;
 wenzelm parents: 
43745diff
changeset | 97 |     else {
 | 
| 49445 
638cefe3ee99
earlier treatment of embedded report/no_report messages (see also 4110cc1b8f9f);
 wenzelm parents: 
48705diff
changeset | 98 | val main = XML.Elem(Markup(kind, props), Protocol.clean_message(body)) | 
| 
638cefe3ee99
earlier treatment of embedded report/no_report messages (see also 4110cc1b8f9f);
 wenzelm parents: 
48705diff
changeset | 99 | val reports = Protocol.message_reports(props, body) | 
| 51663 | 100 | for (msg <- main :: reports) receiver(new Output(xml_cache.elem(msg))) | 
| 43746 
a41f618c641d
some support for raw messages, which bypass standard Symbol/YXML decoding;
 wenzelm parents: 
43745diff
changeset | 101 | } | 
| 39573 | 102 | } | 
| 103 | ||
| 48016 
edbc8e8accd9
more explicit treatment of return code vs. session phase;
 wenzelm parents: 
46774diff
changeset | 104 | private def exit_message(rc: Int) | 
| 39573 | 105 |   {
 | 
| 50201 
c26369c9eda6
Isabelle-specific implementation of quasi-abstract markup elements -- back to module arrangement before d83797ef0d2d;
 wenzelm parents: 
50117diff
changeset | 106 | output_message(Markup.EXIT, Markup.Return_Code(rc), | 
| 48016 
edbc8e8accd9
more explicit treatment of return code vs. session phase;
 wenzelm parents: 
46774diff
changeset | 107 |       List(XML.Text("Return code: " + rc.toString)))
 | 
| 39573 | 108 | } | 
| 109 | ||
| 110 | ||
| 52581 | 111 | /* command input actor */ | 
| 39528 
c01d89d18ff0
refined Isabelle_Process startup: emit \002 before rendezvous on fifos, more robust treatment of startup failure with timeout, do not quit() after main loop;
 wenzelm parents: 
39526diff
changeset | 112 | |
| 
c01d89d18ff0
refined Isabelle_Process startup: emit \002 before rendezvous on fifos, more robust treatment of startup failure with timeout, do not quit() after main loop;
 wenzelm parents: 
39526diff
changeset | 113 | private case class Input_Chunks(chunks: List[Array[Byte]]) | 
| 
c01d89d18ff0
refined Isabelle_Process startup: emit \002 before rendezvous on fifos, more robust treatment of startup failure with timeout, do not quit() after main loop;
 wenzelm parents: 
39526diff
changeset | 114 | |
| 
c01d89d18ff0
refined Isabelle_Process startup: emit \002 before rendezvous on fifos, more robust treatment of startup failure with timeout, do not quit() after main loop;
 wenzelm parents: 
39526diff
changeset | 115 | private case object Close | 
| 39585 
00be8711082f
main Isabelle_Process via Isabelle_System.Managed_Process;
 wenzelm parents: 
39575diff
changeset | 116 | private def close(p: (Thread, Actor)) | 
| 
00be8711082f
main Isabelle_Process via Isabelle_System.Managed_Process;
 wenzelm parents: 
39575diff
changeset | 117 |   {
 | 
| 
00be8711082f
main Isabelle_Process via Isabelle_System.Managed_Process;
 wenzelm parents: 
39575diff
changeset | 118 |     if (p != null && p._1.isAlive) {
 | 
| 
00be8711082f
main Isabelle_Process via Isabelle_System.Managed_Process;
 wenzelm parents: 
39575diff
changeset | 119 | p._2 ! Close | 
| 
00be8711082f
main Isabelle_Process via Isabelle_System.Managed_Process;
 wenzelm parents: 
39575diff
changeset | 120 | p._1.join | 
| 
00be8711082f
main Isabelle_Process via Isabelle_System.Managed_Process;
 wenzelm parents: 
39575diff
changeset | 121 | } | 
| 
00be8711082f
main Isabelle_Process via Isabelle_System.Managed_Process;
 wenzelm parents: 
39575diff
changeset | 122 | } | 
| 39528 
c01d89d18ff0
refined Isabelle_Process startup: emit \002 before rendezvous on fifos, more robust treatment of startup failure with timeout, do not quit() after main loop;
 wenzelm parents: 
39526diff
changeset | 123 | |
| 39585 
00be8711082f
main Isabelle_Process via Isabelle_System.Managed_Process;
 wenzelm parents: 
39575diff
changeset | 124 | @volatile private var command_input: (Thread, Actor) = null | 
| 39528 
c01d89d18ff0
refined Isabelle_Process startup: emit \002 before rendezvous on fifos, more robust treatment of startup failure with timeout, do not quit() after main loop;
 wenzelm parents: 
39526diff
changeset | 125 | |
| 
c01d89d18ff0
refined Isabelle_Process startup: emit \002 before rendezvous on fifos, more robust treatment of startup failure with timeout, do not quit() after main loop;
 wenzelm parents: 
39526diff
changeset | 126 | |
| 39585 
00be8711082f
main Isabelle_Process via Isabelle_System.Managed_Process;
 wenzelm parents: 
39575diff
changeset | 127 | /** process manager **/ | 
| 39528 
c01d89d18ff0
refined Isabelle_Process startup: emit \002 before rendezvous on fifos, more robust treatment of startup failure with timeout, do not quit() after main loop;
 wenzelm parents: 
39526diff
changeset | 128 | |
| 45158 | 129 | private val system_channel = System_Channel() | 
| 39528 
c01d89d18ff0
refined Isabelle_Process startup: emit \002 before rendezvous on fifos, more robust treatment of startup failure with timeout, do not quit() after main loop;
 wenzelm parents: 
39526diff
changeset | 130 | |
| 39585 
00be8711082f
main Isabelle_Process via Isabelle_System.Managed_Process;
 wenzelm parents: 
39575diff
changeset | 131 | private val process = | 
| 39528 
c01d89d18ff0
refined Isabelle_Process startup: emit \002 before rendezvous on fifos, more robust treatment of startup failure with timeout, do not quit() after main loop;
 wenzelm parents: 
39526diff
changeset | 132 |     try {
 | 
| 
c01d89d18ff0
refined Isabelle_Process startup: emit \002 before rendezvous on fifos, more robust treatment of startup failure with timeout, do not quit() after main loop;
 wenzelm parents: 
39526diff
changeset | 133 | val cmdline = | 
| 45027 
f459e93a038e
more abstract wrapping of fifos as System_Channel;
 wenzelm parents: 
44775diff
changeset | 134 |         Isabelle_System.getenv_strict("ISABELLE_PROCESS") ::
 | 
| 45055 
55274f7e306b
explicit option for socket vs. fifo communication;
 wenzelm parents: 
45027diff
changeset | 135 | (system_channel.isabelle_args ::: args) | 
| 48353 
bcce872202b3
support external processes with explicit environment;
 wenzelm parents: 
48020diff
changeset | 136 | new Isabelle_System.Managed_Process(null, null, false, cmdline: _*) | 
| 39528 
c01d89d18ff0
refined Isabelle_Process startup: emit \002 before rendezvous on fifos, more robust treatment of startup failure with timeout, do not quit() after main loop;
 wenzelm parents: 
39526diff
changeset | 137 | } | 
| 45027 
f459e93a038e
more abstract wrapping of fifos as System_Channel;
 wenzelm parents: 
44775diff
changeset | 138 |     catch { case e: IOException => system_channel.accepted(); throw(e) }
 | 
| 39528 
c01d89d18ff0
refined Isabelle_Process startup: emit \002 before rendezvous on fifos, more robust treatment of startup failure with timeout, do not quit() after main loop;
 wenzelm parents: 
39526diff
changeset | 139 | |
| 48355 
6b36da29a0bf
support for detached Bash_Job with some control operations;
 wenzelm parents: 
48353diff
changeset | 140 | val (_, process_result) = | 
| 39587 
f84b70e3bb9c
more reactive handling of Isabelle_Process startup errors;
 wenzelm parents: 
39585diff
changeset | 141 |     Simple_Thread.future("process_result") { process.join }
 | 
| 
f84b70e3bb9c
more reactive handling of Isabelle_Process startup errors;
 wenzelm parents: 
39585diff
changeset | 142 | |
| 39585 
00be8711082f
main Isabelle_Process via Isabelle_System.Managed_Process;
 wenzelm parents: 
39575diff
changeset | 143 | private def terminate_process() | 
| 
00be8711082f
main Isabelle_Process via Isabelle_System.Managed_Process;
 wenzelm parents: 
39575diff
changeset | 144 |   {
 | 
| 
00be8711082f
main Isabelle_Process via Isabelle_System.Managed_Process;
 wenzelm parents: 
39575diff
changeset | 145 |     try { process.terminate }
 | 
| 46772 
be21f050eda4
tuned signature -- emphasize Isabelle_Process Input vs. Output;
 wenzelm parents: 
46769diff
changeset | 146 |     catch { case e: IOException => system_output("Failed to terminate Isabelle: " + e.getMessage) }
 | 
| 39585 
00be8711082f
main Isabelle_Process via Isabelle_System.Managed_Process;
 wenzelm parents: 
39575diff
changeset | 147 | } | 
| 39528 
c01d89d18ff0
refined Isabelle_Process startup: emit \002 before rendezvous on fifos, more robust treatment of startup failure with timeout, do not quit() after main loop;
 wenzelm parents: 
39526diff
changeset | 148 | |
| 39585 
00be8711082f
main Isabelle_Process via Isabelle_System.Managed_Process;
 wenzelm parents: 
39575diff
changeset | 149 |   private val process_manager = Simple_Thread.fork("process_manager")
 | 
| 39572 | 150 |   {
 | 
| 46548 
c54a4a22501c
clarified initial process startup errors: recover image load failure message (cf. 2cb7e34f6096) and suppress accidental output from raw ML toplevel;
 wenzelm parents: 
46121diff
changeset | 151 | val (startup_failed, startup_errors) = | 
| 39528 
c01d89d18ff0
refined Isabelle_Process startup: emit \002 before rendezvous on fifos, more robust treatment of startup failure with timeout, do not quit() after main loop;
 wenzelm parents: 
39526diff
changeset | 152 |     {
 | 
| 48020 
a4f9957878ab
clarified prover startup: no timeout, read stderr more carefully;
 wenzelm parents: 
48019diff
changeset | 153 | var finished: Option[Boolean] = None | 
| 39528 
c01d89d18ff0
refined Isabelle_Process startup: emit \002 before rendezvous on fifos, more robust treatment of startup failure with timeout, do not quit() after main loop;
 wenzelm parents: 
39526diff
changeset | 154 | val result = new StringBuilder(100) | 
| 48020 
a4f9957878ab
clarified prover startup: no timeout, read stderr more carefully;
 wenzelm parents: 
48019diff
changeset | 155 |       while (finished.isEmpty && (process.stderr.ready || !process_result.is_finished)) {
 | 
| 46548 
c54a4a22501c
clarified initial process startup errors: recover image load failure message (cf. 2cb7e34f6096) and suppress accidental output from raw ML toplevel;
 wenzelm parents: 
46121diff
changeset | 156 |         while (finished.isEmpty && process.stderr.ready) {
 | 
| 48020 
a4f9957878ab
clarified prover startup: no timeout, read stderr more carefully;
 wenzelm parents: 
48019diff
changeset | 157 |           try {
 | 
| 
a4f9957878ab
clarified prover startup: no timeout, read stderr more carefully;
 wenzelm parents: 
48019diff
changeset | 158 | val c = process.stderr.read | 
| 
a4f9957878ab
clarified prover startup: no timeout, read stderr more carefully;
 wenzelm parents: 
48019diff
changeset | 159 | if (c == 2) finished = Some(true) | 
| 
a4f9957878ab
clarified prover startup: no timeout, read stderr more carefully;
 wenzelm parents: 
48019diff
changeset | 160 | else result += c.toChar | 
| 
a4f9957878ab
clarified prover startup: no timeout, read stderr more carefully;
 wenzelm parents: 
48019diff
changeset | 161 | } | 
| 
a4f9957878ab
clarified prover startup: no timeout, read stderr more carefully;
 wenzelm parents: 
48019diff
changeset | 162 |           catch { case _: IOException => finished = Some(false) }
 | 
| 39528 
c01d89d18ff0
refined Isabelle_Process startup: emit \002 before rendezvous on fifos, more robust treatment of startup failure with timeout, do not quit() after main loop;
 wenzelm parents: 
39526diff
changeset | 163 | } | 
| 48020 
a4f9957878ab
clarified prover startup: no timeout, read stderr more carefully;
 wenzelm parents: 
48019diff
changeset | 164 | Thread.sleep(10) | 
| 39528 
c01d89d18ff0
refined Isabelle_Process startup: emit \002 before rendezvous on fifos, more robust treatment of startup failure with timeout, do not quit() after main loop;
 wenzelm parents: 
39526diff
changeset | 165 | } | 
| 39623 | 166 | (finished.isEmpty || !finished.get, result.toString.trim) | 
| 39528 
c01d89d18ff0
refined Isabelle_Process startup: emit \002 before rendezvous on fifos, more robust treatment of startup failure with timeout, do not quit() after main loop;
 wenzelm parents: 
39526diff
changeset | 167 | } | 
| 46772 
be21f050eda4
tuned signature -- emphasize Isabelle_Process Input vs. Output;
 wenzelm parents: 
46769diff
changeset | 168 | if (startup_errors != "") system_output(startup_errors) | 
| 39572 | 169 | |
| 52581 | 170 | process.stdin.close | 
| 39528 
c01d89d18ff0
refined Isabelle_Process startup: emit \002 before rendezvous on fifos, more robust treatment of startup failure with timeout, do not quit() after main loop;
 wenzelm parents: 
39526diff
changeset | 171 |     if (startup_failed) {
 | 
| 48016 
edbc8e8accd9
more explicit treatment of return code vs. session phase;
 wenzelm parents: 
46774diff
changeset | 172 | exit_message(127) | 
| 39585 
00be8711082f
main Isabelle_Process via Isabelle_System.Managed_Process;
 wenzelm parents: 
39575diff
changeset | 173 | Thread.sleep(300) | 
| 
00be8711082f
main Isabelle_Process via Isabelle_System.Managed_Process;
 wenzelm parents: 
39575diff
changeset | 174 | terminate_process() | 
| 39587 
f84b70e3bb9c
more reactive handling of Isabelle_Process startup errors;
 wenzelm parents: 
39585diff
changeset | 175 | process_result.join | 
| 39528 
c01d89d18ff0
refined Isabelle_Process startup: emit \002 before rendezvous on fifos, more robust treatment of startup failure with timeout, do not quit() after main loop;
 wenzelm parents: 
39526diff
changeset | 176 | } | 
| 
c01d89d18ff0
refined Isabelle_Process startup: emit \002 before rendezvous on fifos, more robust treatment of startup failure with timeout, do not quit() after main loop;
 wenzelm parents: 
39526diff
changeset | 177 |     else {
 | 
| 45027 
f459e93a038e
more abstract wrapping of fifos as System_Channel;
 wenzelm parents: 
44775diff
changeset | 178 | val (command_stream, message_stream) = system_channel.rendezvous() | 
| 39530 
16adc476348f
Isabelle_Process: more robust rendezvous, even without proper blocking on open (Cygwin);
 wenzelm parents: 
39528diff
changeset | 179 | |
| 46773 | 180 | val stdout = physical_output_actor(false) | 
| 181 | val stderr = physical_output_actor(true) | |
| 39585 
00be8711082f
main Isabelle_Process via Isabelle_System.Managed_Process;
 wenzelm parents: 
39575diff
changeset | 182 | command_input = input_actor(command_stream) | 
| 39572 | 183 | val message = message_actor(message_stream) | 
| 39528 
c01d89d18ff0
refined Isabelle_Process startup: emit \002 before rendezvous on fifos, more robust treatment of startup failure with timeout, do not quit() after main loop;
 wenzelm parents: 
39526diff
changeset | 184 | |
| 39587 
f84b70e3bb9c
more reactive handling of Isabelle_Process startup errors;
 wenzelm parents: 
39585diff
changeset | 185 | val rc = process_result.join | 
| 46772 
be21f050eda4
tuned signature -- emphasize Isabelle_Process Input vs. Output;
 wenzelm parents: 
46769diff
changeset | 186 |       system_output("process terminated")
 | 
| 52581 | 187 | close(command_input) | 
| 188 | for ((thread, _) <- List(stdout, stderr, command_input, message)) | |
| 45633 
2cb7e34f6096
retain stderr and include it in syslog, which is buffered and thus increases the chance that users see remains from crashes etc.;
 wenzelm parents: 
45158diff
changeset | 189 | thread.join | 
| 46772 
be21f050eda4
tuned signature -- emphasize Isabelle_Process Input vs. Output;
 wenzelm parents: 
46769diff
changeset | 190 |       system_output("process_manager terminated")
 | 
| 48016 
edbc8e8accd9
more explicit treatment of return code vs. session phase;
 wenzelm parents: 
46774diff
changeset | 191 | exit_message(rc) | 
| 39528 
c01d89d18ff0
refined Isabelle_Process startup: emit \002 before rendezvous on fifos, more robust treatment of startup failure with timeout, do not quit() after main loop;
 wenzelm parents: 
39526diff
changeset | 192 | } | 
| 45027 
f459e93a038e
more abstract wrapping of fifos as System_Channel;
 wenzelm parents: 
44775diff
changeset | 193 | system_channel.accepted() | 
| 39528 
c01d89d18ff0
refined Isabelle_Process startup: emit \002 before rendezvous on fifos, more robust treatment of startup failure with timeout, do not quit() after main loop;
 wenzelm parents: 
39526diff
changeset | 194 | } | 
| 27973 
18d02c0b90b6
moved class Result into static object, removed dynamic tree method;
 wenzelm parents: 
27963diff
changeset | 195 | |
| 39572 | 196 | |
| 39585 
00be8711082f
main Isabelle_Process via Isabelle_System.Managed_Process;
 wenzelm parents: 
39575diff
changeset | 197 | /* management methods */ | 
| 27973 
18d02c0b90b6
moved class Result into static object, removed dynamic tree method;
 wenzelm parents: 
27963diff
changeset | 198 | |
| 39585 
00be8711082f
main Isabelle_Process via Isabelle_System.Managed_Process;
 wenzelm parents: 
39575diff
changeset | 199 |   def join() { process_manager.join() }
 | 
| 39528 
c01d89d18ff0
refined Isabelle_Process startup: emit \002 before rendezvous on fifos, more robust treatment of startup failure with timeout, do not quit() after main loop;
 wenzelm parents: 
39526diff
changeset | 200 | |
| 39585 
00be8711082f
main Isabelle_Process via Isabelle_System.Managed_Process;
 wenzelm parents: 
39575diff
changeset | 201 | def terminate() | 
| 38270 
71bb3c273dd1
native Isabelle_Process commands, based on efficient byte channel protocol for string lists;
 wenzelm parents: 
38262diff
changeset | 202 |   {
 | 
| 52581 | 203 | close(command_input) | 
| 46772 
be21f050eda4
tuned signature -- emphasize Isabelle_Process Input vs. Output;
 wenzelm parents: 
46769diff
changeset | 204 |     system_output("Terminating Isabelle process")
 | 
| 39585 
00be8711082f
main Isabelle_Process via Isabelle_System.Managed_Process;
 wenzelm parents: 
39575diff
changeset | 205 | terminate_process() | 
| 27973 
18d02c0b90b6
moved class Result into static object, removed dynamic tree method;
 wenzelm parents: 
27963diff
changeset | 206 | } | 
| 
18d02c0b90b6
moved class Result into static object, removed dynamic tree method;
 wenzelm parents: 
27963diff
changeset | 207 | |
| 27949 
6eb0327c0b9b
Isabelle process management -- always reactive due to multi-threaded I/O.
 wenzelm parents: diff
changeset | 208 | |
| 
6eb0327c0b9b
Isabelle process management -- always reactive due to multi-threaded I/O.
 wenzelm parents: diff
changeset | 209 | |
| 38259 
2b61c5e27399
distinguish proper Isabelle_Process INPUT vs. raw STDIN, tuned corresponding method names;
 wenzelm parents: 
38253diff
changeset | 210 | /** stream actors **/ | 
| 27949 
6eb0327c0b9b
Isabelle process management -- always reactive due to multi-threaded I/O.
 wenzelm parents: diff
changeset | 211 | |
| 46773 | 212 | /* physical output */ | 
| 27949 
6eb0327c0b9b
Isabelle process management -- always reactive due to multi-threaded I/O.
 wenzelm parents: diff
changeset | 213 | |
| 46773 | 214 | private def physical_output_actor(err: Boolean): (Thread, Actor) = | 
| 39528 
c01d89d18ff0
refined Isabelle_Process startup: emit \002 before rendezvous on fifos, more robust treatment of startup failure with timeout, do not quit() after main loop;
 wenzelm parents: 
39526diff
changeset | 215 |   {
 | 
| 45633 
2cb7e34f6096
retain stderr and include it in syslog, which is buffered and thus increases the chance that users see remains from crashes etc.;
 wenzelm parents: 
45158diff
changeset | 216 | val (name, reader, markup) = | 
| 50201 
c26369c9eda6
Isabelle-specific implementation of quasi-abstract markup elements -- back to module arrangement before d83797ef0d2d;
 wenzelm parents: 
50117diff
changeset | 217 |       if (err) ("standard_error", process.stderr, Markup.STDERR)
 | 
| 
c26369c9eda6
Isabelle-specific implementation of quasi-abstract markup elements -- back to module arrangement before d83797ef0d2d;
 wenzelm parents: 
50117diff
changeset | 218 |       else ("standard_output", process.stdout, Markup.STDOUT)
 | 
| 45633 
2cb7e34f6096
retain stderr and include it in syslog, which is buffered and thus increases the chance that users see remains from crashes etc.;
 wenzelm parents: 
45158diff
changeset | 219 | |
| 38636 
b7647ca7de5a
module for simplified thread operations (Scala version);
 wenzelm parents: 
38573diff
changeset | 220 |     Simple_Thread.actor(name) {
 | 
| 46769 | 221 |       try {
 | 
| 222 | var result = new StringBuilder(100) | |
| 223 | var finished = false | |
| 224 |         while (!finished) {
 | |
| 28045 | 225 |           //{{{
 | 
| 226 | var c = -1 | |
| 227 | var done = false | |
| 45633 
2cb7e34f6096
retain stderr and include it in syslog, which is buffered and thus increases the chance that users see remains from crashes etc.;
 wenzelm parents: 
45158diff
changeset | 228 |           while (!done && (result.length == 0 || reader.ready)) {
 | 
| 
2cb7e34f6096
retain stderr and include it in syslog, which is buffered and thus increases the chance that users see remains from crashes etc.;
 wenzelm parents: 
45158diff
changeset | 229 | c = reader.read | 
| 28045 | 230 | if (c >= 0) result.append(c.asInstanceOf[Char]) | 
| 231 | else done = true | |
| 232 | } | |
| 233 |           if (result.length > 0) {
 | |
| 48705 
dd32321d6eef
tuned signature -- slightly more abstract text representation of prover process;
 wenzelm parents: 
48355diff
changeset | 234 | output_message(markup, Nil, List(XML.Text(decode(result.toString)))) | 
| 28045 | 235 | result.length = 0 | 
| 27949 
6eb0327c0b9b
Isabelle process management -- always reactive due to multi-threaded I/O.
 wenzelm parents: diff
changeset | 236 | } | 
| 
6eb0327c0b9b
Isabelle process management -- always reactive due to multi-threaded I/O.
 wenzelm parents: diff
changeset | 237 |           else {
 | 
| 45633 
2cb7e34f6096
retain stderr and include it in syslog, which is buffered and thus increases the chance that users see remains from crashes etc.;
 wenzelm parents: 
45158diff
changeset | 238 | reader.close | 
| 28045 | 239 | finished = true | 
| 38270 
71bb3c273dd1
native Isabelle_Process commands, based on efficient byte channel protocol for string lists;
 wenzelm parents: 
38262diff
changeset | 240 | } | 
| 
71bb3c273dd1
native Isabelle_Process commands, based on efficient byte channel protocol for string lists;
 wenzelm parents: 
38262diff
changeset | 241 | //}}} | 
| 
71bb3c273dd1
native Isabelle_Process commands, based on efficient byte channel protocol for string lists;
 wenzelm parents: 
38262diff
changeset | 242 | } | 
| 
71bb3c273dd1
native Isabelle_Process commands, based on efficient byte channel protocol for string lists;
 wenzelm parents: 
38262diff
changeset | 243 | } | 
| 46772 
be21f050eda4
tuned signature -- emphasize Isabelle_Process Input vs. Output;
 wenzelm parents: 
46769diff
changeset | 244 |       catch { case e: IOException => system_output(name + ": " + e.getMessage) }
 | 
| 
be21f050eda4
tuned signature -- emphasize Isabelle_Process Input vs. Output;
 wenzelm parents: 
46769diff
changeset | 245 | system_output(name + " terminated") | 
| 38270 
71bb3c273dd1
native Isabelle_Process commands, based on efficient byte channel protocol for string lists;
 wenzelm parents: 
38262diff
changeset | 246 | } | 
| 39528 
c01d89d18ff0
refined Isabelle_Process startup: emit \002 before rendezvous on fifos, more robust treatment of startup failure with timeout, do not quit() after main loop;
 wenzelm parents: 
39526diff
changeset | 247 | } | 
| 38270 
71bb3c273dd1
native Isabelle_Process commands, based on efficient byte channel protocol for string lists;
 wenzelm parents: 
38262diff
changeset | 248 | |
| 
71bb3c273dd1
native Isabelle_Process commands, based on efficient byte channel protocol for string lists;
 wenzelm parents: 
38262diff
changeset | 249 | |
| 
71bb3c273dd1
native Isabelle_Process commands, based on efficient byte channel protocol for string lists;
 wenzelm parents: 
38262diff
changeset | 250 | /* command input */ | 
| 
71bb3c273dd1
native Isabelle_Process commands, based on efficient byte channel protocol for string lists;
 wenzelm parents: 
38262diff
changeset | 251 | |
| 39572 | 252 | private def input_actor(raw_stream: OutputStream): (Thread, Actor) = | 
| 39528 
c01d89d18ff0
refined Isabelle_Process startup: emit \002 before rendezvous on fifos, more robust treatment of startup failure with timeout, do not quit() after main loop;
 wenzelm parents: 
39526diff
changeset | 253 |   {
 | 
| 
c01d89d18ff0
refined Isabelle_Process startup: emit \002 before rendezvous on fifos, more robust treatment of startup failure with timeout, do not quit() after main loop;
 wenzelm parents: 
39526diff
changeset | 254 | val name = "command_input" | 
| 38636 
b7647ca7de5a
module for simplified thread operations (Scala version);
 wenzelm parents: 
38573diff
changeset | 255 |     Simple_Thread.actor(name) {
 | 
| 46769 | 256 |       try {
 | 
| 257 | val stream = new BufferedOutputStream(raw_stream) | |
| 258 | var finished = false | |
| 259 |         while (!finished) {
 | |
| 38270 
71bb3c273dd1
native Isabelle_Process commands, based on efficient byte channel protocol for string lists;
 wenzelm parents: 
38262diff
changeset | 260 |           //{{{
 | 
| 
71bb3c273dd1
native Isabelle_Process commands, based on efficient byte channel protocol for string lists;
 wenzelm parents: 
38262diff
changeset | 261 |           receive {
 | 
| 
71bb3c273dd1
native Isabelle_Process commands, based on efficient byte channel protocol for string lists;
 wenzelm parents: 
38262diff
changeset | 262 | case Input_Chunks(chunks) => | 
| 50203 | 263 |               stream.write(UTF8.string_bytes(chunks.map(_.length).mkString("", ",", "\n")))
 | 
| 264 | chunks.foreach(stream.write(_)) | |
| 38270 
71bb3c273dd1
native Isabelle_Process commands, based on efficient byte channel protocol for string lists;
 wenzelm parents: 
38262diff
changeset | 265 | stream.flush | 
| 
71bb3c273dd1
native Isabelle_Process commands, based on efficient byte channel protocol for string lists;
 wenzelm parents: 
38262diff
changeset | 266 | case Close => | 
| 
71bb3c273dd1
native Isabelle_Process commands, based on efficient byte channel protocol for string lists;
 wenzelm parents: 
38262diff
changeset | 267 | stream.close | 
| 
71bb3c273dd1
native Isabelle_Process commands, based on efficient byte channel protocol for string lists;
 wenzelm parents: 
38262diff
changeset | 268 | finished = true | 
| 
71bb3c273dd1
native Isabelle_Process commands, based on efficient byte channel protocol for string lists;
 wenzelm parents: 
38262diff
changeset | 269 | case bad => System.err.println(name + ": ignoring bad message " + bad) | 
| 27949 
6eb0327c0b9b
Isabelle process management -- always reactive due to multi-threaded I/O.
 wenzelm parents: diff
changeset | 270 | } | 
| 28045 | 271 | //}}} | 
| 27963 | 272 | } | 
| 27949 
6eb0327c0b9b
Isabelle process management -- always reactive due to multi-threaded I/O.
 wenzelm parents: diff
changeset | 273 | } | 
| 46772 
be21f050eda4
tuned signature -- emphasize Isabelle_Process Input vs. Output;
 wenzelm parents: 
46769diff
changeset | 274 |       catch { case e: IOException => system_output(name + ": " + e.getMessage) }
 | 
| 
be21f050eda4
tuned signature -- emphasize Isabelle_Process Input vs. Output;
 wenzelm parents: 
46769diff
changeset | 275 | system_output(name + " terminated") | 
| 27949 
6eb0327c0b9b
Isabelle process management -- always reactive due to multi-threaded I/O.
 wenzelm parents: diff
changeset | 276 | } | 
| 39528 
c01d89d18ff0
refined Isabelle_Process startup: emit \002 before rendezvous on fifos, more robust treatment of startup failure with timeout, do not quit() after main loop;
 wenzelm parents: 
39526diff
changeset | 277 | } | 
| 27949 
6eb0327c0b9b
Isabelle process management -- always reactive due to multi-threaded I/O.
 wenzelm parents: diff
changeset | 278 | |
| 
6eb0327c0b9b
Isabelle process management -- always reactive due to multi-threaded I/O.
 wenzelm parents: diff
changeset | 279 | |
| 38259 
2b61c5e27399
distinguish proper Isabelle_Process INPUT vs. raw STDIN, tuned corresponding method names;
 wenzelm parents: 
38253diff
changeset | 280 | /* message output */ | 
| 27949 
6eb0327c0b9b
Isabelle process management -- always reactive due to multi-threaded I/O.
 wenzelm parents: diff
changeset | 281 | |
| 39572 | 282 | private def message_actor(stream: InputStream): (Thread, Actor) = | 
| 39526 | 283 |   {
 | 
| 284 | class EOF extends Exception | |
| 285 | class Protocol_Error(msg: String) extends Exception(msg) | |
| 38259 
2b61c5e27399
distinguish proper Isabelle_Process INPUT vs. raw STDIN, tuned corresponding method names;
 wenzelm parents: 
38253diff
changeset | 286 | |
| 39528 
c01d89d18ff0
refined Isabelle_Process startup: emit \002 before rendezvous on fifos, more robust treatment of startup failure with timeout, do not quit() after main loop;
 wenzelm parents: 
39526diff
changeset | 287 | val name = "message_output" | 
| 38636 
b7647ca7de5a
module for simplified thread operations (Scala version);
 wenzelm parents: 
38573diff
changeset | 288 |     Simple_Thread.actor(name) {
 | 
| 34100 | 289 | val default_buffer = new Array[Byte](65536) | 
| 290 | var c = -1 | |
| 27949 
6eb0327c0b9b
Isabelle process management -- always reactive due to multi-threaded I/O.
 wenzelm parents: diff
changeset | 291 | |
| 48705 
dd32321d6eef
tuned signature -- slightly more abstract text representation of prover process;
 wenzelm parents: 
48355diff
changeset | 292 | def read_chunk(do_decode: Boolean): XML.Body = | 
| 34100 | 293 |       {
 | 
| 294 |         //{{{
 | |
| 295 | // chunk size | |
| 296 | var n = 0 | |
| 297 | c = stream.read | |
| 39526 | 298 | if (c == -1) throw new EOF | 
| 34100 | 299 |         while (48 <= c && c <= 57) {
 | 
| 300 | n = 10 * n + (c - 48) | |
| 301 | c = stream.read | |
| 302 | } | |
| 303 |         if (c != 10) throw new Protocol_Error("bad message chunk header")
 | |
| 304 | ||
| 305 | // chunk content | |
| 306 | val buf = | |
| 307 | if (n <= default_buffer.size) default_buffer | |
| 308 | else new Array[Byte](n) | |
| 309 | ||
| 310 | var i = 0 | |
| 311 | var m = 0 | |
| 312 |         do {
 | |
| 313 | m = stream.read(buf, i, n - i) | |
| 39731 
5cb0d7b0d601
bulk read: observe EOF protocol more carefully -- 0 counts as successful read;
 wenzelm parents: 
39632diff
changeset | 314 | if (m != -1) i += m | 
| 
5cb0d7b0d601
bulk read: observe EOF protocol more carefully -- 0 counts as successful read;
 wenzelm parents: 
39632diff
changeset | 315 | } while (m != -1 && n > i) | 
| 34100 | 316 | |
| 317 |         if (i != n) throw new Protocol_Error("bad message chunk content")
 | |
| 318 | ||
| 48705 
dd32321d6eef
tuned signature -- slightly more abstract text representation of prover process;
 wenzelm parents: 
48355diff
changeset | 319 | if (do_decode) | 
| 50203 | 320 | YXML.parse_body_failsafe(UTF8.decode_chars(decode, buf, 0, n)) | 
| 321 | else List(XML.Text(UTF8.decode_chars(s => s, buf, 0, n).toString)) | |
| 34100 | 322 | //}}} | 
| 323 | } | |
| 324 | ||
| 46769 | 325 |       try {
 | 
| 326 |         do {
 | |
| 327 |           try {
 | |
| 328 |             //{{{
 | |
| 329 | val header = read_chunk(true) | |
| 330 |             header match {
 | |
| 49677 
c4e2762a265c
more direct message header: eliminated historic encoding via single letter;
 wenzelm parents: 
49445diff
changeset | 331 | case List(XML.Elem(Markup(name, props), Nil)) => | 
| 
c4e2762a265c
more direct message header: eliminated historic encoding via single letter;
 wenzelm parents: 
49445diff
changeset | 332 | val kind = name.intern | 
| 50201 
c26369c9eda6
Isabelle-specific implementation of quasi-abstract markup elements -- back to module arrangement before d83797ef0d2d;
 wenzelm parents: 
50117diff
changeset | 333 | val body = read_chunk(kind != Markup.PROTOCOL) | 
| 46772 
be21f050eda4
tuned signature -- emphasize Isabelle_Process Input vs. Output;
 wenzelm parents: 
46769diff
changeset | 334 | output_message(kind, props, body) | 
| 46769 | 335 | case _ => | 
| 336 | read_chunk(false) | |
| 337 |                 throw new Protocol_Error("bad header: " + header.toString)
 | |
| 338 | } | |
| 339 | //}}} | |
| 28063 | 340 | } | 
| 46769 | 341 |           catch { case _: EOF => }
 | 
| 342 | } while (c != -1) | |
| 343 | } | |
| 344 |       catch {
 | |
| 46772 
be21f050eda4
tuned signature -- emphasize Isabelle_Process Input vs. Output;
 wenzelm parents: 
46769diff
changeset | 345 |         case e: IOException => system_output("Cannot read message:\n" + e.getMessage)
 | 
| 
be21f050eda4
tuned signature -- emphasize Isabelle_Process Input vs. Output;
 wenzelm parents: 
46769diff
changeset | 346 |         case e: Protocol_Error => system_output("Malformed message:\n" + e.getMessage)
 | 
| 46769 | 347 | } | 
| 34100 | 348 | stream.close | 
| 349 | ||
| 46772 
be21f050eda4
tuned signature -- emphasize Isabelle_Process Input vs. Output;
 wenzelm parents: 
46769diff
changeset | 350 | system_output(name + " terminated") | 
| 27949 
6eb0327c0b9b
Isabelle process management -- always reactive due to multi-threaded I/O.
 wenzelm parents: diff
changeset | 351 | } | 
| 39526 | 352 | } | 
| 27949 
6eb0327c0b9b
Isabelle process management -- always reactive due to multi-threaded I/O.
 wenzelm parents: diff
changeset | 353 | |
| 
6eb0327c0b9b
Isabelle process management -- always reactive due to multi-threaded I/O.
 wenzelm parents: diff
changeset | 354 | |
| 38259 
2b61c5e27399
distinguish proper Isabelle_Process INPUT vs. raw STDIN, tuned corresponding method names;
 wenzelm parents: 
38253diff
changeset | 355 | /** main methods **/ | 
| 
2b61c5e27399
distinguish proper Isabelle_Process INPUT vs. raw STDIN, tuned corresponding method names;
 wenzelm parents: 
38253diff
changeset | 356 | |
| 52582 | 357 | def protocol_command_raw(name: String, args: Array[Byte]*): Unit = | 
| 50203 | 358 | command_input._2 ! Input_Chunks(UTF8.string_bytes(name) :: args.toList) | 
| 38372 
e753f71b6b34
added Isabelle_Process.input_bytes, which avoids the somewhat slow Standard_System.string_bytes (just in case someone wants to stream raw data at 250MB/s);
 wenzelm parents: 
38270diff
changeset | 359 | |
| 52582 | 360 | def protocol_command(name: String, args: String*) | 
| 43721 
fad8634cee62
echo prover input via raw_messages, for improved protocol tracing;
 wenzelm parents: 
43695diff
changeset | 361 |   {
 | 
| 44732 | 362 | receiver(new Input(name, args.toList)) | 
| 52582 | 363 | protocol_command_raw(name, args.map(UTF8.string_bytes): _*) | 
| 43721 
fad8634cee62
echo prover input via raw_messages, for improved protocol tracing;
 wenzelm parents: 
43695diff
changeset | 364 | } | 
| 38259 
2b61c5e27399
distinguish proper Isabelle_Process INPUT vs. raw STDIN, tuned corresponding method names;
 wenzelm parents: 
38253diff
changeset | 365 | |
| 50117 | 366 | def options(opts: Options): Unit = | 
| 52582 | 367 |     protocol_command("Isabelle_Process.options", YXML.string_of_body(opts.encode))
 | 
| 27949 
6eb0327c0b9b
Isabelle process management -- always reactive due to multi-threaded I/O.
 wenzelm parents: diff
changeset | 368 | } |