more robust interrupts;
authorwenzelm
Mon, 06 Apr 2020 22:28:41 +0200
changeset 71718 54ac957c53ec
parent 71717 f871ccd358b3
child 71719 23abd7f9f054
more robust interrupts;
src/Pure/System/isabelle_process.scala
src/Pure/Tools/build.scala
--- a/src/Pure/System/isabelle_process.scala	Mon Apr 06 21:58:24 2020 +0200
+++ b/src/Pure/System/isabelle_process.scala	Mon Apr 06 22:28:41 2020 +0200
@@ -76,4 +76,6 @@
     session.stop()
     result
   }
+
+  def terminate { process.terminate }
 }
--- a/src/Pure/Tools/build.scala	Mon Apr 06 21:58:24 2020 +0200
+++ b/src/Pure/Tools/build.scala	Mon Apr 06 22:28:41 2020 +0200
@@ -174,7 +174,7 @@
       Export.consumer(store.open_database(session_name, output = true), cache = store.xz_cache)
 
     private val future_result: Future[Process_Result] =
-      Future.thread("build") {
+      Future.thread("build", uninterruptible = true) {
         val parent = info.parent.getOrElse("")
         val base = deps(parent)
         val args_yxml =
@@ -321,14 +321,17 @@
               cwd = info.dir.file, env = env)
 
           val errors =
-            Exn.capture { process.await_startup } match {
-              case Exn.Res(_) =>
-                session.protocol_command("build_session", args_yxml)
-                build_session_errors.join
-              case Exn.Exn(exn) => List(Exn.message(exn))
+            Isabelle_Thread.interrupt_handler(_ => process.terminate) {
+              Exn.capture { process.await_startup } match {
+                case Exn.Res(_) =>
+                  session.protocol_command("build_session", args_yxml)
+                  build_session_errors.join_result
+                case Exn.Exn(exn) => Exn.Res(List(Exn.message(exn)))
+              }
             }
 
-          val process_result = process.await_shutdown
+          val process_result =
+            Isabelle_Thread.interrupt_handler(_ => process.terminate) { process.await_shutdown }
           val process_output =
             stdout.toString :: messages.toList :::
             command_timings.toList.map(Protocol.Command_Timing_Marker.apply) :::
@@ -337,11 +340,16 @@
             task_statistics.toList.map(Protocol.Task_Statistics_Marker.apply)
 
           val result = process_result.output(process_output)
-          if (errors.isEmpty) result
-          else {
-            result.error_rc.output(
-              errors.flatMap(s => split_lines(Output.error_message_text(s))) :::
-              errors.map(Protocol.Error_Message_Marker.apply))
+
+          errors match {
+            case Exn.Res(Nil) => result
+            case Exn.Res(errs) =>
+              result.error_rc.output(
+                errs.flatMap(s => split_lines(Output.error_message_text(s))) :::
+                  errs.map(Protocol.Error_Message_Marker.apply))
+            case Exn.Exn(Exn.Interrupt()) =>
+              if (result.ok) result.copy(rc = Exn.Interrupt.return_code) else result
+            case Exn.Exn(exn) => throw exn
           }
         }
         else {
@@ -358,28 +366,30 @@
               use_prelude = use_prelude, eval_main = eval_main,
               cwd = info.dir.file, env = env, cleanup = () => args_file.delete)
 
-          process.result(
-            progress_stdout =
-              {
-                case Protocol.Loading_Theory_Marker(theory) =>
-                  progress.theory(Progress.Theory(theory, session = session_name))
-                case Protocol.Export.Marker((args, path)) =>
-                  val body =
-                    try { Bytes.read(path) }
-                    catch {
-                      case ERROR(msg) =>
-                        error("Failed to read export " + quote(args.compound_name) + "\n" + msg)
-                    }
-                  path.file.delete
-                  export_consumer(session_name, args, body)
-                case _ =>
-              },
-            progress_limit =
-              options.int("process_output_limit") match {
-                case 0 => None
-                case m => Some(m * 1000000L)
-              },
-            strict = false)
+          Isabelle_Thread.interrupt_handler(_ => process.terminate) {
+            process.result(
+              progress_stdout =
+                {
+                  case Protocol.Loading_Theory_Marker(theory) =>
+                    progress.theory(Progress.Theory(theory, session = session_name))
+                  case Protocol.Export.Marker((args, path)) =>
+                    val body =
+                      try { Bytes.read(path) }
+                      catch {
+                        case ERROR(msg) =>
+                          error("Failed to read export " + quote(args.compound_name) + "\n" + msg)
+                      }
+                    path.file.delete
+                    export_consumer(session_name, args, body)
+                  case _ =>
+                },
+              progress_limit =
+                options.int("process_output_limit") match {
+                  case 0 => None
+                  case m => Some(m * 1000000L)
+                },
+              strict = false)
+          }
         }
       }