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