# HG changeset patch # User wenzelm # Date 1315300699 -7200 # Node ID 329320fc88df5de8f4af2c50b026e1472964b9aa # Parent c58b69d888ac303b3adb70fe56d21205824c2dcd buffer prover messages to prevent overloading of session_actor input channel -- which is critical due to synchronous messages wrt. GUI thread; diff -r c58b69d888ac -r 329320fc88df src/Pure/System/isabelle_process.scala --- a/src/Pure/System/isabelle_process.scala Tue Sep 06 10:27:04 2011 +0200 +++ b/src/Pure/System/isabelle_process.scala Tue Sep 06 11:18:19 2011 +0200 @@ -33,7 +33,7 @@ ('H' : Int) -> Markup.RAW) } - abstract class Message + sealed abstract class Message class Input(name: String, args: List[String]) extends Message { diff -r c58b69d888ac -r 329320fc88df src/Pure/System/session.scala --- a/src/Pure/System/session.scala Tue Sep 06 10:27:04 2011 +0200 +++ b/src/Pure/System/session.scala Tue Sep 06 11:18:19 2011 +0200 @@ -7,8 +7,11 @@ package isabelle + import java.lang.System +import java.util.{Timer, TimerTask} +import scala.collection.mutable import scala.actors.TIMEOUT import scala.actors.Actor._ @@ -37,6 +40,7 @@ { /* real time parameters */ // FIXME properties or settings (!?) + val message_delay = Time.seconds(0.01) // prover messages val input_delay = Time.seconds(0.3) // user input (e.g. text edits, cursor movement) val output_delay = Time.seconds(0.1) // prover output (markup, common messages) val update_delay = Time.seconds(0.5) // GUI layout updates @@ -52,7 +56,7 @@ val assignments = new Event_Bus[Session.Assignment.type] val commands_changed = new Event_Bus[Session.Commands_Changed] val phase_changed = new Event_Bus[Session.Phase] - val raw_messages = new Event_Bus[Isabelle_Process.Message] + val raw_messages = new Event_Bus[Isabelle_Process.Message] // potential bottle-neck @@ -141,16 +145,45 @@ doc_edits: List[Document.Edit_Command], previous: Document.Version, version: Document.Version) + private case class Messages(msgs: List[Isabelle_Process.Message]) private val (_, session_actor) = Simple_Thread.actor("session_actor", daemon = true) { val this_actor = self - def receiver(msg: Isabelle_Process.Message) { this_actor ! msg } - var prover: Option[Isabelle_Process with Isar_Document] = None var prune_next = System.currentTimeMillis() + prune_delay.ms + /* buffered prover messages */ + + object receiver + { + private var buffer = new mutable.ListBuffer[Isabelle_Process.Message] + + def flush(): Unit = synchronized { + if (!buffer.isEmpty) { + val msgs = buffer.toList + this_actor ! Messages(msgs) + buffer = new mutable.ListBuffer[Isabelle_Process.Message] + } + } + def invoke(msg: Isabelle_Process.Message): Unit = synchronized { + buffer += msg + msg match { + case result: Isabelle_Process.Result if result.is_raw => flush() + case _ => + } + } + + private val timer = new Timer("session_actor.receiver", true) + timer.schedule(new TimerTask { def run = flush }, message_delay.ms, message_delay.ms) + + def cancel() { timer.cancel() } + } + + var prover: Option[Isabelle_Process with Isar_Document] = None + + /* delayed command changes */ object commands_changed_delay @@ -372,7 +405,8 @@ case Start(timeout, args) if prover.isEmpty => if (phase == Session.Inactive || phase == Session.Failed) { phase = Session.Startup - prover = Some(new Isabelle_Process(timeout, receiver _, args:_*) with Isar_Document) + prover = + Some(new Isabelle_Process(timeout, receiver.invoke _, args:_*) with Isar_Document) } case Stop => @@ -384,6 +418,7 @@ phase = Session.Inactive } finished = true + receiver.cancel() reply(()) case Interrupt if prover.isDefined => @@ -409,12 +444,15 @@ case change: Change_Node if prover.isDefined => handle_change(change) - case input: Isabelle_Process.Input => - raw_messages.event(input) + case Messages(msgs) => + msgs foreach { + case input: Isabelle_Process.Input => + raw_messages.event(input) - case result: Isabelle_Process.Result => - handle_result(result) - raw_messages.event(result) + case result: Isabelle_Process.Result => + handle_result(result) + raw_messages.event(result) + } case bad => System.err.println("session_actor: ignoring bad message " + bad) }