5 */ |
5 */ |
6 |
6 |
7 package isabelle |
7 package isabelle |
8 |
8 |
9 |
9 |
|
10 import java.util.{Timer, TimerTask} |
10 import java.io.{BufferedInputStream, FileInputStream, |
11 import java.io.{BufferedInputStream, FileInputStream, |
11 BufferedReader, InputStreamReader, IOException} |
12 BufferedReader, InputStreamReader, IOException} |
12 import java.util.zip.GZIPInputStream |
13 import java.util.zip.GZIPInputStream |
13 |
14 |
14 import scala.collection.mutable |
15 import scala.collection.mutable |
329 |
330 |
330 |
331 |
331 /* jobs */ |
332 /* jobs */ |
332 |
333 |
333 private class Job(dir: Path, env: Map[String, String], script: String, args: String, |
334 private class Job(dir: Path, env: Map[String, String], script: String, args: String, |
334 val parent_heap: String, output: Path, do_output: Boolean) |
335 val parent_heap: String, output: Path, do_output: Boolean, time: Time) |
335 { |
336 { |
336 private val args_file = File.tmp_file("args") |
337 private val args_file = File.tmp_file("args") |
337 private val env1 = env + ("ARGS_FILE" -> Isabelle_System.posix_path(args_file.getPath)) |
338 private val env1 = env + ("ARGS_FILE" -> Isabelle_System.posix_path(args_file.getPath)) |
338 File.write(args_file, args) |
339 File.write(args_file, args) |
339 |
340 |
340 private val (thread, result) = |
341 private val (thread, result) = |
341 Simple_Thread.future("build") { Isabelle_System.bash_env(dir.file, env1, script) } |
342 Simple_Thread.future("build") { Isabelle_System.bash_env(dir.file, env1, script) } |
342 |
343 |
343 def terminate: Unit = thread.interrupt |
344 def terminate: Unit = thread.interrupt |
344 def is_finished: Boolean = result.is_finished |
345 def is_finished: Boolean = result.is_finished |
345 def join: (String, String, Int) = { val res = result.join; args_file.delete; res } |
346 |
|
347 @volatile private var timeout = false |
|
348 private val timer: Option[Timer] = |
|
349 if (time.seconds > 0.0) { |
|
350 val t = new Timer("build", true) |
|
351 t.schedule(new TimerTask { def run = { terminate; timeout = true } }, time.ms) |
|
352 Some(t) |
|
353 } |
|
354 else None |
|
355 |
|
356 def join: (String, String, Int) = { |
|
357 val (out, err, rc) = result.join |
|
358 args_file.delete |
|
359 timer.map(_.cancel()) |
|
360 |
|
361 val err1 = |
|
362 if (rc == 130) |
|
363 (if (err.isEmpty || err.endsWith("\n")) err else err + "\n") + |
|
364 (if (timeout) "*** Timeout\n" else "*** Interrupt\n") |
|
365 else err |
|
366 (out, err1, rc) |
|
367 } |
|
368 |
346 def output_path: Option[Path] = if (do_output) Some(output) else None |
369 def output_path: Option[Path] = if (do_output) Some(output) else None |
347 } |
370 } |
348 |
371 |
349 private def start_job(name: String, info: Session.Info, parent_heap: String, |
372 private def start_job(name: String, info: Session.Info, parent_heap: String, |
350 output: Path, do_output: Boolean, options: Options, verbose: Boolean, browser_info: Path): Job = |
373 output: Path, do_output: Boolean, options: Options, verbose: Boolean, browser_info: Path): Job = |
400 pair(bool, pair(Options.encode, pair(bool, pair(Path.encode, pair(string, |
423 pair(bool, pair(Options.encode, pair(bool, pair(Path.encode, pair(string, |
401 pair(string, list(pair(Options.encode, list(Path.encode)))))))))( |
424 pair(string, list(pair(Options.encode, list(Path.encode)))))))))( |
402 (do_output, (options, (verbose, (browser_info, (parent, |
425 (do_output, (options, (verbose, (browser_info, (parent, |
403 (name, info.theories))))))) |
426 (name, info.theories))))))) |
404 } |
427 } |
405 new Job(info.dir, env, script, YXML.string_of_body(args_xml), parent_heap, output, do_output) |
428 new Job(info.dir, env, script, YXML.string_of_body(args_xml), parent_heap, |
|
429 output, do_output, Time.seconds(options.real("timeout"))) |
406 } |
430 } |
407 |
431 |
408 |
432 |
409 /* log files and corresponding heaps */ |
433 /* log files and corresponding heaps */ |
410 |
434 |
523 (output_dir + Path.basic(name)).file.delete |
547 (output_dir + Path.basic(name)).file.delete |
524 (output_dir + log_gz(name)).file.delete |
548 (output_dir + log_gz(name)).file.delete |
525 |
549 |
526 File.write(output_dir + log(name), out) |
550 File.write(output_dir + log(name), out) |
527 echo(name + " FAILED") |
551 echo(name + " FAILED") |
528 echo("(see also " + (output_dir + log(name)).file.toString + ")") |
552 if (rc != 130) { |
529 val lines = split_lines(out) |
553 echo("(see also " + (output_dir + log(name)).file.toString + ")") |
530 val tail = lines.drop(lines.length - 20 max 0) |
554 val lines = split_lines(out) |
531 echo("\n" + cat_lines(tail)) |
555 val tail = lines.drop(lines.length - 20 max 0) |
|
556 echo("\n" + cat_lines(tail)) |
|
557 } |
532 |
558 |
533 no_heap |
559 no_heap |
534 } |
560 } |
535 loop(pending - name, running - name, results + (name -> Result(false, heap, rc))) |
561 loop(pending - name, running - name, results + (name -> Result(false, heap, rc))) |
536 |
562 |