src/Pure/Tools/build_process.scala
changeset 78529 0e79fa88cab6
parent 78510 8f45302a9ff0
child 78530 d637e60427db
--- a/src/Pure/Tools/build_process.scala	Sun Aug 13 19:27:58 2023 +0200
+++ b/src/Pure/Tools/build_process.scala	Wed Aug 16 14:42:43 2023 +0200
@@ -55,6 +55,7 @@
     build: Option[Build_Job]
   ) extends Library.Named {
     def no_build: Job = copy(build = None)
+    def join_build: Option[(Process_Result, SHA1.Shasum)] = build.flatMap(_.join)
   }
 
   sealed case class Result(
@@ -217,8 +218,6 @@
       copy(serial = i)
     }
 
-    def finished: Boolean = pending.isEmpty
-
     def remove_pending(name: String): State =
       copy(pending = pending.flatMap(
         entry => if (entry.name == name) None else Some(entry.resolve(name))))
@@ -228,10 +227,13 @@
     def stop_running(): Unit =
       for (job <- running.valuesIterator; build <- job.build) build.cancel()
 
+    def build_running: List[Build_Job] =
+      List.from(for (job <- running.valuesIterator; build <- job.build) yield build)
+
     def finished_running(): List[Job] =
       List.from(
         for (job <- running.valuesIterator; build <- job.build if build.is_finished)
-        yield job)
+          yield job)
 
     def add_running(job: Job): State =
       copy(running = running + (job.name -> job))
@@ -880,6 +882,7 @@
           val progress_db = store.open_build_database(Progress.private_data.database, server = server)
           val progress =
             new Database_Progress(progress_db, build_progress,
+              output_stopped = build_context.master,
               hostname = hostname,
               context_uuid = build_uuid,
               kind = "build_process")
@@ -957,8 +960,10 @@
   }
 
   protected def next_jobs(state: Build_Process.State): List[String] = {
-    val running = List.from(state.running.valuesIterator.filter(_.worker_uuid == worker_uuid))
-    val limit = if (progress.stopped) Int.MaxValue else build_context.max_jobs - running.length
+    val limit = {
+      if (progress.stopped) { if (build_context.master) Int.MaxValue else 0 }
+      else build_context.max_jobs - state.build_running.length
+    }
     if (limit > 0) {
       state.pending.filter(entry => entry.is_ready && !state.is_running(entry.name))
         .sortBy(_.name)(state.sessions.ordering)
@@ -1013,10 +1018,13 @@
         make_result(result_name, Process_Result.error, output_shasum)
     }
     else if (cancelled) {
-      progress.echo(session_name + " CANCELLED")
-      state
-        .remove_pending(session_name)
-        .make_result(result_name, Process_Result.undefined, output_shasum)
+      if (build_context.master) {
+        progress.echo(session_name + " CANCELLED")
+        state
+          .remove_pending(session_name)
+          .make_result(result_name, Process_Result.undefined, output_shasum)
+      }
+      else state
     }
     else {
       def used_nodes: Set[Int] =
@@ -1085,7 +1093,10 @@
       synchronized_database("Build_Process.init") { _state = init_state(_state) }
     }
 
-    def finished(): Boolean = synchronized_database("Build_Process.test") { _state.finished }
+    def finished(): Boolean = synchronized_database("Build_Process.test") {
+      if (!build_context.master && progress.stopped) _state.build_running.isEmpty
+      else _state.pending.isEmpty
+    }
 
     def sleep(): Unit =
       Isabelle_Thread.interrupt_handler(_ => progress.stop()) { build_delay.sleep() }
@@ -1128,12 +1139,17 @@
             if (progress.stopped) _state.stop_running()
 
             for (job <- _state.finished_running()) {
-              val result_name = (job.name, worker_uuid, build_uuid)
-              val (process_result, output_shasum) = job.build.get.join
-              _state = _state.
-                remove_pending(job.name).
-                remove_running(job.name).
-                make_result(result_name, process_result, output_shasum, node_info = job.node_info)
+              job.join_build match {
+                case None =>
+                  _state = _state.remove_running(job.name)
+                case Some((process_result, output_shasum)) =>
+                  val result_name = (job.name, worker_uuid, build_uuid)
+                  _state = _state.
+                    remove_pending(job.name).
+                    remove_running(job.name).
+                    make_result(result_name, process_result, output_shasum,
+                      node_info = job.node_info)
+              }
             }
           }