| author | wenzelm | 
| Sun, 12 May 2013 15:08:11 +0200 | |
| changeset 51942 | 527e39becafc | 
| parent 51664 | 080ef458f21a | 
| child 52581 | 99835e3abca4 | 
| 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 | ||
| 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 | 111 | /* input actors */ | 
| 
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_Text(text: String) | 
| 
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 | 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 | 115 | |
| 
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 | 116 | private case object Close | 
| 39585 
00be8711082f
main Isabelle_Process via Isabelle_System.Managed_Process;
 wenzelm parents: 
39575diff
changeset | 117 | private def close(p: (Thread, Actor)) | 
| 
00be8711082f
main Isabelle_Process via Isabelle_System.Managed_Process;
 wenzelm parents: 
39575diff
changeset | 118 |   {
 | 
| 
00be8711082f
main Isabelle_Process via Isabelle_System.Managed_Process;
 wenzelm parents: 
39575diff
changeset | 119 |     if (p != null && p._1.isAlive) {
 | 
| 
00be8711082f
main Isabelle_Process via Isabelle_System.Managed_Process;
 wenzelm parents: 
39575diff
changeset | 120 | p._2 ! Close | 
| 
00be8711082f
main Isabelle_Process via Isabelle_System.Managed_Process;
 wenzelm parents: 
39575diff
changeset | 121 | p._1.join | 
| 
00be8711082f
main Isabelle_Process via Isabelle_System.Managed_Process;
 wenzelm parents: 
39575diff
changeset | 122 | } | 
| 
00be8711082f
main Isabelle_Process via Isabelle_System.Managed_Process;
 wenzelm parents: 
39575diff
changeset | 123 | } | 
| 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 | 124 | |
| 39585 
00be8711082f
main Isabelle_Process via Isabelle_System.Managed_Process;
 wenzelm parents: 
39575diff
changeset | 125 | @volatile private var standard_input: (Thread, Actor) = null | 
| 
00be8711082f
main Isabelle_Process via Isabelle_System.Managed_Process;
 wenzelm parents: 
39575diff
changeset | 126 | @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 | 127 | |
| 
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 | |
| 39585 
00be8711082f
main Isabelle_Process via Isabelle_System.Managed_Process;
 wenzelm parents: 
39575diff
changeset | 129 | /** 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 | 130 | |
| 45158 | 131 | 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 | 132 | |
| 39585 
00be8711082f
main Isabelle_Process via Isabelle_System.Managed_Process;
 wenzelm parents: 
39575diff
changeset | 133 | 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 | 134 |     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 | 135 | val cmdline = | 
| 45027 
f459e93a038e
more abstract wrapping of fifos as System_Channel;
 wenzelm parents: 
44775diff
changeset | 136 |         Isabelle_System.getenv_strict("ISABELLE_PROCESS") ::
 | 
| 45055 
55274f7e306b
explicit option for socket vs. fifo communication;
 wenzelm parents: 
45027diff
changeset | 137 | (system_channel.isabelle_args ::: args) | 
| 48353 
bcce872202b3
support external processes with explicit environment;
 wenzelm parents: 
48020diff
changeset | 138 | 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 | 139 | } | 
| 45027 
f459e93a038e
more abstract wrapping of fifos as System_Channel;
 wenzelm parents: 
44775diff
changeset | 140 |     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 | 141 | |
| 48355 
6b36da29a0bf
support for detached Bash_Job with some control operations;
 wenzelm parents: 
48353diff
changeset | 142 | val (_, process_result) = | 
| 39587 
f84b70e3bb9c
more reactive handling of Isabelle_Process startup errors;
 wenzelm parents: 
39585diff
changeset | 143 |     Simple_Thread.future("process_result") { process.join }
 | 
| 
f84b70e3bb9c
more reactive handling of Isabelle_Process startup errors;
 wenzelm parents: 
39585diff
changeset | 144 | |
| 39585 
00be8711082f
main Isabelle_Process via Isabelle_System.Managed_Process;
 wenzelm parents: 
39575diff
changeset | 145 | private def terminate_process() | 
| 
00be8711082f
main Isabelle_Process via Isabelle_System.Managed_Process;
 wenzelm parents: 
39575diff
changeset | 146 |   {
 | 
| 
00be8711082f
main Isabelle_Process via Isabelle_System.Managed_Process;
 wenzelm parents: 
39575diff
changeset | 147 |     try { process.terminate }
 | 
| 46772 
be21f050eda4
tuned signature -- emphasize Isabelle_Process Input vs. Output;
 wenzelm parents: 
46769diff
changeset | 148 |     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 | 149 | } | 
| 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 | 150 | |
| 39585 
00be8711082f
main Isabelle_Process via Isabelle_System.Managed_Process;
 wenzelm parents: 
39575diff
changeset | 151 |   private val process_manager = Simple_Thread.fork("process_manager")
 | 
| 39572 | 152 |   {
 | 
| 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 | 153 | 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 | 154 |     {
 | 
| 48020 
a4f9957878ab
clarified prover startup: no timeout, read stderr more carefully;
 wenzelm parents: 
48019diff
changeset | 155 | 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 | 156 | val result = new StringBuilder(100) | 
| 48020 
a4f9957878ab
clarified prover startup: no timeout, read stderr more carefully;
 wenzelm parents: 
48019diff
changeset | 157 |       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 | 158 |         while (finished.isEmpty && process.stderr.ready) {
 | 
| 48020 
a4f9957878ab
clarified prover startup: no timeout, read stderr more carefully;
 wenzelm parents: 
48019diff
changeset | 159 |           try {
 | 
| 
a4f9957878ab
clarified prover startup: no timeout, read stderr more carefully;
 wenzelm parents: 
48019diff
changeset | 160 | val c = process.stderr.read | 
| 
a4f9957878ab
clarified prover startup: no timeout, read stderr more carefully;
 wenzelm parents: 
48019diff
changeset | 161 | if (c == 2) finished = Some(true) | 
| 
a4f9957878ab
clarified prover startup: no timeout, read stderr more carefully;
 wenzelm parents: 
48019diff
changeset | 162 | else result += c.toChar | 
| 
a4f9957878ab
clarified prover startup: no timeout, read stderr more carefully;
 wenzelm parents: 
48019diff
changeset | 163 | } | 
| 
a4f9957878ab
clarified prover startup: no timeout, read stderr more carefully;
 wenzelm parents: 
48019diff
changeset | 164 |           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 | 165 | } | 
| 48020 
a4f9957878ab
clarified prover startup: no timeout, read stderr more carefully;
 wenzelm parents: 
48019diff
changeset | 166 | 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 | 167 | } | 
| 39623 | 168 | (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 | 169 | } | 
| 46772 
be21f050eda4
tuned signature -- emphasize Isabelle_Process Input vs. Output;
 wenzelm parents: 
46769diff
changeset | 170 | if (startup_errors != "") system_output(startup_errors) | 
| 39572 | 171 | |
| 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 | 172 |     if (startup_failed) {
 | 
| 48016 
edbc8e8accd9
more explicit treatment of return code vs. session phase;
 wenzelm parents: 
46774diff
changeset | 173 | exit_message(127) | 
| 39585 
00be8711082f
main Isabelle_Process via Isabelle_System.Managed_Process;
 wenzelm parents: 
39575diff
changeset | 174 | process.stdin.close | 
| 
00be8711082f
main Isabelle_Process via Isabelle_System.Managed_Process;
 wenzelm parents: 
39575diff
changeset | 175 | Thread.sleep(300) | 
| 
00be8711082f
main Isabelle_Process via Isabelle_System.Managed_Process;
 wenzelm parents: 
39575diff
changeset | 176 | terminate_process() | 
| 39587 
f84b70e3bb9c
more reactive handling of Isabelle_Process startup errors;
 wenzelm parents: 
39585diff
changeset | 177 | 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 | 178 | } | 
| 
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 | 179 |     else {
 | 
| 45027 
f459e93a038e
more abstract wrapping of fifos as System_Channel;
 wenzelm parents: 
44775diff
changeset | 180 | 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 | 181 | |
| 39585 
00be8711082f
main Isabelle_Process via Isabelle_System.Managed_Process;
 wenzelm parents: 
39575diff
changeset | 182 | standard_input = stdin_actor() | 
| 46773 | 183 | val stdout = physical_output_actor(false) | 
| 184 | val stderr = physical_output_actor(true) | |
| 39585 
00be8711082f
main Isabelle_Process via Isabelle_System.Managed_Process;
 wenzelm parents: 
39575diff
changeset | 185 | command_input = input_actor(command_stream) | 
| 39572 | 186 | 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 | 187 | |
| 39587 
f84b70e3bb9c
more reactive handling of Isabelle_Process startup errors;
 wenzelm parents: 
39585diff
changeset | 188 | val rc = process_result.join | 
| 46772 
be21f050eda4
tuned signature -- emphasize Isabelle_Process Input vs. Output;
 wenzelm parents: 
46769diff
changeset | 189 |       system_output("process terminated")
 | 
| 48019 
226dee06ab6e
need to close_input before expecting threads to terminate/join;
 wenzelm parents: 
48016diff
changeset | 190 | close_input() | 
| 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 | 191 | for ((thread, _) <- List(standard_input, stdout, stderr, command_input, message)) | 
| 
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 | 192 | thread.join | 
| 46772 
be21f050eda4
tuned signature -- emphasize Isabelle_Process Input vs. Output;
 wenzelm parents: 
46769diff
changeset | 193 |       system_output("process_manager terminated")
 | 
| 48016 
edbc8e8accd9
more explicit treatment of return code vs. session phase;
 wenzelm parents: 
46774diff
changeset | 194 | 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 | 195 | } | 
| 45027 
f459e93a038e
more abstract wrapping of fifos as System_Channel;
 wenzelm parents: 
44775diff
changeset | 196 | 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 | 197 | } | 
| 27973 
18d02c0b90b6
moved class Result into static object, removed dynamic tree method;
 wenzelm parents: 
27963diff
changeset | 198 | |
| 39572 | 199 | |
| 39585 
00be8711082f
main Isabelle_Process via Isabelle_System.Managed_Process;
 wenzelm parents: 
39575diff
changeset | 200 | /* management methods */ | 
| 27973 
18d02c0b90b6
moved class Result into static object, removed dynamic tree method;
 wenzelm parents: 
27963diff
changeset | 201 | |
| 39585 
00be8711082f
main Isabelle_Process via Isabelle_System.Managed_Process;
 wenzelm parents: 
39575diff
changeset | 202 |   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 | 203 | |
| 39585 
00be8711082f
main Isabelle_Process via Isabelle_System.Managed_Process;
 wenzelm parents: 
39575diff
changeset | 204 | def terminate() | 
| 38270 
71bb3c273dd1
native Isabelle_Process commands, based on efficient byte channel protocol for string lists;
 wenzelm parents: 
38262diff
changeset | 205 |   {
 | 
| 48019 
226dee06ab6e
need to close_input before expecting threads to terminate/join;
 wenzelm parents: 
48016diff
changeset | 206 | close_input() | 
| 46772 
be21f050eda4
tuned signature -- emphasize Isabelle_Process Input vs. Output;
 wenzelm parents: 
46769diff
changeset | 207 |     system_output("Terminating Isabelle process")
 | 
| 39585 
00be8711082f
main Isabelle_Process via Isabelle_System.Managed_Process;
 wenzelm parents: 
39575diff
changeset | 208 | terminate_process() | 
| 27973 
18d02c0b90b6
moved class Result into static object, removed dynamic tree method;
 wenzelm parents: 
27963diff
changeset | 209 | } | 
| 
18d02c0b90b6
moved class Result into static object, removed dynamic tree method;
 wenzelm parents: 
27963diff
changeset | 210 | |
| 27949 
6eb0327c0b9b
Isabelle process management -- always reactive due to multi-threaded I/O.
 wenzelm parents: diff
changeset | 211 | |
| 
6eb0327c0b9b
Isabelle process management -- always reactive due to multi-threaded I/O.
 wenzelm parents: diff
changeset | 212 | |
| 38259 
2b61c5e27399
distinguish proper Isabelle_Process INPUT vs. raw STDIN, tuned corresponding method names;
 wenzelm parents: 
38253diff
changeset | 213 | /** stream actors **/ | 
| 27949 
6eb0327c0b9b
Isabelle process management -- always reactive due to multi-threaded I/O.
 wenzelm parents: diff
changeset | 214 | |
| 46773 | 215 | /* physical stdin */ | 
| 38270 
71bb3c273dd1
native Isabelle_Process commands, based on efficient byte channel protocol for string lists;
 wenzelm parents: 
38262diff
changeset | 216 | |
| 39572 | 217 | private def stdin_actor(): (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 | 218 |   {
 | 
| 
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 | 219 | val name = "standard_input" | 
| 38636 
b7647ca7de5a
module for simplified thread operations (Scala version);
 wenzelm parents: 
38573diff
changeset | 220 |     Simple_Thread.actor(name) {
 | 
| 46769 | 221 |       try {
 | 
| 222 | var finished = false | |
| 223 |         while (!finished) {
 | |
| 27949 
6eb0327c0b9b
Isabelle process management -- always reactive due to multi-threaded I/O.
 wenzelm parents: diff
changeset | 224 |           //{{{
 | 
| 38259 
2b61c5e27399
distinguish proper Isabelle_Process INPUT vs. raw STDIN, tuned corresponding method names;
 wenzelm parents: 
38253diff
changeset | 225 |           receive {
 | 
| 38270 
71bb3c273dd1
native Isabelle_Process commands, based on efficient byte channel protocol for string lists;
 wenzelm parents: 
38262diff
changeset | 226 | case Input_Text(text) => | 
| 39585 
00be8711082f
main Isabelle_Process via Isabelle_System.Managed_Process;
 wenzelm parents: 
39575diff
changeset | 227 | process.stdin.write(text) | 
| 
00be8711082f
main Isabelle_Process via Isabelle_System.Managed_Process;
 wenzelm parents: 
39575diff
changeset | 228 | process.stdin.flush | 
| 38259 
2b61c5e27399
distinguish proper Isabelle_Process INPUT vs. raw STDIN, tuned corresponding method names;
 wenzelm parents: 
38253diff
changeset | 229 | case Close => | 
| 39585 
00be8711082f
main Isabelle_Process via Isabelle_System.Managed_Process;
 wenzelm parents: 
39575diff
changeset | 230 | process.stdin.close | 
| 38259 
2b61c5e27399
distinguish proper Isabelle_Process INPUT vs. raw STDIN, tuned corresponding method names;
 wenzelm parents: 
38253diff
changeset | 231 | finished = true | 
| 
2b61c5e27399
distinguish proper Isabelle_Process INPUT vs. raw STDIN, tuned corresponding method names;
 wenzelm parents: 
38253diff
changeset | 232 | 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 | 233 | } | 
| 
6eb0327c0b9b
Isabelle process management -- always reactive due to multi-threaded I/O.
 wenzelm parents: diff
changeset | 234 | //}}} | 
| 
6eb0327c0b9b
Isabelle process management -- always reactive due to multi-threaded I/O.
 wenzelm parents: diff
changeset | 235 | } | 
| 
6eb0327c0b9b
Isabelle process management -- always reactive due to multi-threaded I/O.
 wenzelm parents: diff
changeset | 236 | } | 
| 46772 
be21f050eda4
tuned signature -- emphasize Isabelle_Process Input vs. Output;
 wenzelm parents: 
46769diff
changeset | 237 |       catch { case e: IOException => system_output(name + ": " + e.getMessage) }
 | 
| 
be21f050eda4
tuned signature -- emphasize Isabelle_Process Input vs. Output;
 wenzelm parents: 
46769diff
changeset | 238 | system_output(name + " terminated") | 
| 27949 
6eb0327c0b9b
Isabelle process management -- always reactive due to multi-threaded I/O.
 wenzelm parents: diff
changeset | 239 | } | 
| 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 | 240 | } | 
| 27949 
6eb0327c0b9b
Isabelle process management -- always reactive due to multi-threaded I/O.
 wenzelm parents: diff
changeset | 241 | |
| 
6eb0327c0b9b
Isabelle process management -- always reactive due to multi-threaded I/O.
 wenzelm parents: diff
changeset | 242 | |
| 46773 | 243 | /* physical output */ | 
| 27949 
6eb0327c0b9b
Isabelle process management -- always reactive due to multi-threaded I/O.
 wenzelm parents: diff
changeset | 244 | |
| 46773 | 245 | 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 | 246 |   {
 | 
| 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 | 247 | val (name, reader, markup) = | 
| 50201 
c26369c9eda6
Isabelle-specific implementation of quasi-abstract markup elements -- back to module arrangement before d83797ef0d2d;
 wenzelm parents: 
50117diff
changeset | 248 |       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 | 249 |       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 | 250 | |
| 38636 
b7647ca7de5a
module for simplified thread operations (Scala version);
 wenzelm parents: 
38573diff
changeset | 251 |     Simple_Thread.actor(name) {
 | 
| 46769 | 252 |       try {
 | 
| 253 | var result = new StringBuilder(100) | |
| 254 | var finished = false | |
| 255 |         while (!finished) {
 | |
| 28045 | 256 |           //{{{
 | 
| 257 | var c = -1 | |
| 258 | 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 | 259 |           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 | 260 | c = reader.read | 
| 28045 | 261 | if (c >= 0) result.append(c.asInstanceOf[Char]) | 
| 262 | else done = true | |
| 263 | } | |
| 264 |           if (result.length > 0) {
 | |
| 48705 
dd32321d6eef
tuned signature -- slightly more abstract text representation of prover process;
 wenzelm parents: 
48355diff
changeset | 265 | output_message(markup, Nil, List(XML.Text(decode(result.toString)))) | 
| 28045 | 266 | result.length = 0 | 
| 27949 
6eb0327c0b9b
Isabelle process management -- always reactive due to multi-threaded I/O.
 wenzelm parents: diff
changeset | 267 | } | 
| 
6eb0327c0b9b
Isabelle process management -- always reactive due to multi-threaded I/O.
 wenzelm parents: diff
changeset | 268 |           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 | 269 | reader.close | 
| 28045 | 270 | finished = true | 
| 38270 
71bb3c273dd1
native Isabelle_Process commands, based on efficient byte channel protocol for string lists;
 wenzelm parents: 
38262diff
changeset | 271 | } | 
| 
71bb3c273dd1
native Isabelle_Process commands, based on efficient byte channel protocol for string lists;
 wenzelm parents: 
38262diff
changeset | 272 | //}}} | 
| 
71bb3c273dd1
native Isabelle_Process commands, based on efficient byte channel protocol for string lists;
 wenzelm parents: 
38262diff
changeset | 273 | } | 
| 
71bb3c273dd1
native Isabelle_Process commands, based on efficient byte channel protocol for string lists;
 wenzelm parents: 
38262diff
changeset | 274 | } | 
| 46772 
be21f050eda4
tuned signature -- emphasize Isabelle_Process Input vs. Output;
 wenzelm parents: 
46769diff
changeset | 275 |       catch { case e: IOException => system_output(name + ": " + e.getMessage) }
 | 
| 
be21f050eda4
tuned signature -- emphasize Isabelle_Process Input vs. Output;
 wenzelm parents: 
46769diff
changeset | 276 | system_output(name + " terminated") | 
| 38270 
71bb3c273dd1
native Isabelle_Process commands, based on efficient byte channel protocol for string lists;
 wenzelm parents: 
38262diff
changeset | 277 | } | 
| 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 | 278 | } | 
| 38270 
71bb3c273dd1
native Isabelle_Process commands, based on efficient byte channel protocol for string lists;
 wenzelm parents: 
38262diff
changeset | 279 | |
| 
71bb3c273dd1
native Isabelle_Process commands, based on efficient byte channel protocol for string lists;
 wenzelm parents: 
38262diff
changeset | 280 | |
| 
71bb3c273dd1
native Isabelle_Process commands, based on efficient byte channel protocol for string lists;
 wenzelm parents: 
38262diff
changeset | 281 | /* command input */ | 
| 
71bb3c273dd1
native Isabelle_Process commands, based on efficient byte channel protocol for string lists;
 wenzelm parents: 
38262diff
changeset | 282 | |
| 39572 | 283 | 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 | 284 |   {
 | 
| 
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 | 285 | val name = "command_input" | 
| 38636 
b7647ca7de5a
module for simplified thread operations (Scala version);
 wenzelm parents: 
38573diff
changeset | 286 |     Simple_Thread.actor(name) {
 | 
| 46769 | 287 |       try {
 | 
| 288 | val stream = new BufferedOutputStream(raw_stream) | |
| 289 | var finished = false | |
| 290 |         while (!finished) {
 | |
| 38270 
71bb3c273dd1
native Isabelle_Process commands, based on efficient byte channel protocol for string lists;
 wenzelm parents: 
38262diff
changeset | 291 |           //{{{
 | 
| 
71bb3c273dd1
native Isabelle_Process commands, based on efficient byte channel protocol for string lists;
 wenzelm parents: 
38262diff
changeset | 292 |           receive {
 | 
| 
71bb3c273dd1
native Isabelle_Process commands, based on efficient byte channel protocol for string lists;
 wenzelm parents: 
38262diff
changeset | 293 | case Input_Chunks(chunks) => | 
| 50203 | 294 |               stream.write(UTF8.string_bytes(chunks.map(_.length).mkString("", ",", "\n")))
 | 
| 295 | chunks.foreach(stream.write(_)) | |
| 38270 
71bb3c273dd1
native Isabelle_Process commands, based on efficient byte channel protocol for string lists;
 wenzelm parents: 
38262diff
changeset | 296 | stream.flush | 
| 
71bb3c273dd1
native Isabelle_Process commands, based on efficient byte channel protocol for string lists;
 wenzelm parents: 
38262diff
changeset | 297 | case Close => | 
| 
71bb3c273dd1
native Isabelle_Process commands, based on efficient byte channel protocol for string lists;
 wenzelm parents: 
38262diff
changeset | 298 | stream.close | 
| 
71bb3c273dd1
native Isabelle_Process commands, based on efficient byte channel protocol for string lists;
 wenzelm parents: 
38262diff
changeset | 299 | finished = true | 
| 
71bb3c273dd1
native Isabelle_Process commands, based on efficient byte channel protocol for string lists;
 wenzelm parents: 
38262diff
changeset | 300 | 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 | 301 | } | 
| 28045 | 302 | //}}} | 
| 27963 | 303 | } | 
| 27949 
6eb0327c0b9b
Isabelle process management -- always reactive due to multi-threaded I/O.
 wenzelm parents: diff
changeset | 304 | } | 
| 46772 
be21f050eda4
tuned signature -- emphasize Isabelle_Process Input vs. Output;
 wenzelm parents: 
46769diff
changeset | 305 |       catch { case e: IOException => system_output(name + ": " + e.getMessage) }
 | 
| 
be21f050eda4
tuned signature -- emphasize Isabelle_Process Input vs. Output;
 wenzelm parents: 
46769diff
changeset | 306 | system_output(name + " terminated") | 
| 27949 
6eb0327c0b9b
Isabelle process management -- always reactive due to multi-threaded I/O.
 wenzelm parents: diff
changeset | 307 | } | 
| 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 | 308 | } | 
| 27949 
6eb0327c0b9b
Isabelle process management -- always reactive due to multi-threaded I/O.
 wenzelm parents: diff
changeset | 309 | |
| 
6eb0327c0b9b
Isabelle process management -- always reactive due to multi-threaded I/O.
 wenzelm parents: diff
changeset | 310 | |
| 38259 
2b61c5e27399
distinguish proper Isabelle_Process INPUT vs. raw STDIN, tuned corresponding method names;
 wenzelm parents: 
38253diff
changeset | 311 | /* message output */ | 
| 27949 
6eb0327c0b9b
Isabelle process management -- always reactive due to multi-threaded I/O.
 wenzelm parents: diff
changeset | 312 | |
| 39572 | 313 | private def message_actor(stream: InputStream): (Thread, Actor) = | 
| 39526 | 314 |   {
 | 
| 315 | class EOF extends Exception | |
| 316 | 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 | 317 | |
| 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 | 318 | val name = "message_output" | 
| 38636 
b7647ca7de5a
module for simplified thread operations (Scala version);
 wenzelm parents: 
38573diff
changeset | 319 |     Simple_Thread.actor(name) {
 | 
| 34100 | 320 | val default_buffer = new Array[Byte](65536) | 
| 321 | var c = -1 | |
| 27949 
6eb0327c0b9b
Isabelle process management -- always reactive due to multi-threaded I/O.
 wenzelm parents: diff
changeset | 322 | |
| 48705 
dd32321d6eef
tuned signature -- slightly more abstract text representation of prover process;
 wenzelm parents: 
48355diff
changeset | 323 | def read_chunk(do_decode: Boolean): XML.Body = | 
| 34100 | 324 |       {
 | 
| 325 |         //{{{
 | |
| 326 | // chunk size | |
| 327 | var n = 0 | |
| 328 | c = stream.read | |
| 39526 | 329 | if (c == -1) throw new EOF | 
| 34100 | 330 |         while (48 <= c && c <= 57) {
 | 
| 331 | n = 10 * n + (c - 48) | |
| 332 | c = stream.read | |
| 333 | } | |
| 334 |         if (c != 10) throw new Protocol_Error("bad message chunk header")
 | |
| 335 | ||
| 336 | // chunk content | |
| 337 | val buf = | |
| 338 | if (n <= default_buffer.size) default_buffer | |
| 339 | else new Array[Byte](n) | |
| 340 | ||
| 341 | var i = 0 | |
| 342 | var m = 0 | |
| 343 |         do {
 | |
| 344 | 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 | 345 | if (m != -1) i += m | 
| 
5cb0d7b0d601
bulk read: observe EOF protocol more carefully -- 0 counts as successful read;
 wenzelm parents: 
39632diff
changeset | 346 | } while (m != -1 && n > i) | 
| 34100 | 347 | |
| 348 |         if (i != n) throw new Protocol_Error("bad message chunk content")
 | |
| 349 | ||
| 48705 
dd32321d6eef
tuned signature -- slightly more abstract text representation of prover process;
 wenzelm parents: 
48355diff
changeset | 350 | if (do_decode) | 
| 50203 | 351 | YXML.parse_body_failsafe(UTF8.decode_chars(decode, buf, 0, n)) | 
| 352 | else List(XML.Text(UTF8.decode_chars(s => s, buf, 0, n).toString)) | |
| 34100 | 353 | //}}} | 
| 354 | } | |
| 355 | ||
| 46769 | 356 |       try {
 | 
| 357 |         do {
 | |
| 358 |           try {
 | |
| 359 |             //{{{
 | |
| 360 | val header = read_chunk(true) | |
| 361 |             header match {
 | |
| 49677 
c4e2762a265c
more direct message header: eliminated historic encoding via single letter;
 wenzelm parents: 
49445diff
changeset | 362 | case List(XML.Elem(Markup(name, props), Nil)) => | 
| 
c4e2762a265c
more direct message header: eliminated historic encoding via single letter;
 wenzelm parents: 
49445diff
changeset | 363 | val kind = name.intern | 
| 50201 
c26369c9eda6
Isabelle-specific implementation of quasi-abstract markup elements -- back to module arrangement before d83797ef0d2d;
 wenzelm parents: 
50117diff
changeset | 364 | val body = read_chunk(kind != Markup.PROTOCOL) | 
| 46772 
be21f050eda4
tuned signature -- emphasize Isabelle_Process Input vs. Output;
 wenzelm parents: 
46769diff
changeset | 365 | output_message(kind, props, body) | 
| 46769 | 366 | case _ => | 
| 367 | read_chunk(false) | |
| 368 |                 throw new Protocol_Error("bad header: " + header.toString)
 | |
| 369 | } | |
| 370 | //}}} | |
| 28063 | 371 | } | 
| 46769 | 372 |           catch { case _: EOF => }
 | 
| 373 | } while (c != -1) | |
| 374 | } | |
| 375 |       catch {
 | |
| 46772 
be21f050eda4
tuned signature -- emphasize Isabelle_Process Input vs. Output;
 wenzelm parents: 
46769diff
changeset | 376 |         case e: IOException => system_output("Cannot read message:\n" + e.getMessage)
 | 
| 
be21f050eda4
tuned signature -- emphasize Isabelle_Process Input vs. Output;
 wenzelm parents: 
46769diff
changeset | 377 |         case e: Protocol_Error => system_output("Malformed message:\n" + e.getMessage)
 | 
| 46769 | 378 | } | 
| 34100 | 379 | stream.close | 
| 380 | ||
| 46772 
be21f050eda4
tuned signature -- emphasize Isabelle_Process Input vs. Output;
 wenzelm parents: 
46769diff
changeset | 381 | system_output(name + " terminated") | 
| 27949 
6eb0327c0b9b
Isabelle process management -- always reactive due to multi-threaded I/O.
 wenzelm parents: diff
changeset | 382 | } | 
| 39526 | 383 | } | 
| 27949 
6eb0327c0b9b
Isabelle process management -- always reactive due to multi-threaded I/O.
 wenzelm parents: diff
changeset | 384 | |
| 
6eb0327c0b9b
Isabelle process management -- always reactive due to multi-threaded I/O.
 wenzelm parents: diff
changeset | 385 | |
| 38259 
2b61c5e27399
distinguish proper Isabelle_Process INPUT vs. raw STDIN, tuned corresponding method names;
 wenzelm parents: 
38253diff
changeset | 386 | /** main methods **/ | 
| 
2b61c5e27399
distinguish proper Isabelle_Process INPUT vs. raw STDIN, tuned corresponding method names;
 wenzelm parents: 
38253diff
changeset | 387 | |
| 39585 
00be8711082f
main Isabelle_Process via Isabelle_System.Managed_Process;
 wenzelm parents: 
39575diff
changeset | 388 | def input_raw(text: String): Unit = standard_input._2 ! Input_Text(text) | 
| 38259 
2b61c5e27399
distinguish proper Isabelle_Process INPUT vs. raw STDIN, tuned corresponding method names;
 wenzelm parents: 
38253diff
changeset | 389 | |
| 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 | 390 | def input_bytes(name: String, args: Array[Byte]*): Unit = | 
| 50203 | 391 | 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 | 392 | |
| 50117 | 393 | def input(name: String, args: String*) | 
| 43721 
fad8634cee62
echo prover input via raw_messages, for improved protocol tracing;
 wenzelm parents: 
43695diff
changeset | 394 |   {
 | 
| 44732 | 395 | receiver(new Input(name, args.toList)) | 
| 50203 | 396 | input_bytes(name, args.map(UTF8.string_bytes): _*) | 
| 43721 
fad8634cee62
echo prover input via raw_messages, for improved protocol tracing;
 wenzelm parents: 
43695diff
changeset | 397 | } | 
| 38259 
2b61c5e27399
distinguish proper Isabelle_Process INPUT vs. raw STDIN, tuned corresponding method names;
 wenzelm parents: 
38253diff
changeset | 398 | |
| 50117 | 399 | def options(opts: Options): Unit = | 
| 400 |     input("Isabelle_Process.options", YXML.string_of_body(opts.encode))
 | |
| 401 | ||
| 402 | def close_input() | |
| 403 |   {
 | |
| 404 | close(command_input) | |
| 405 | close(standard_input) | |
| 406 | } | |
| 27949 
6eb0327c0b9b
Isabelle process management -- always reactive due to multi-threaded I/O.
 wenzelm parents: diff
changeset | 407 | } |