Moved the presentation compiler thread in its own top-level class. This allows to collect

the presentation compiler instance when the thread is not GCed, but the compiler should be
discarded (for example, after a shutdown request). Having the thread as an inner class 
keeps a reference to the outer class. review by odersky.

git-svn-id: http://lampsvn.epfl.ch/svn-repos/scala/scala/trunk@23954 5e8d7ff9-d8ef-0310-90f0-a4852d11357a
This commit is contained in:
dragos 2011-01-10 15:43:55 +00:00
parent 0ea81f323b
commit d2e5465a9a
3 changed files with 68 additions and 43 deletions

View File

@ -74,7 +74,7 @@ trait CompilerControl { self: Global =>
/** The scheduler by which client and compiler communicate
* Must be initialized before starting compilerRunner
*/
protected val scheduler = new WorkScheduler
protected[interactive] val scheduler = new WorkScheduler
/** The compilation unit corresponding to a source file
* if it does not yet exist creat a new one atomically
@ -177,9 +177,12 @@ trait CompilerControl { self: Global =>
/** Ask for a computation to be done quickly on the presentation compiler thread */
def ask[A](op: () => A): A = scheduler doQuickly op
}
// ---------------- Interpreted exceptions -------------------
object FreshRunReq extends ControlThrowable
object ShutdownReq extends ControlThrowable
}
/** It has to stay top-level so that the PresentationCompilerThread may access it. */
object FreshRunReq extends ControlThrowable
/** It has to stay top-level so that the PresentationCompilerThread may access it. */
object ShutdownReq extends ControlThrowable

View File

@ -71,7 +71,7 @@ self =>
/** Is a background compiler run needed?
* Note: outOfDate is true as long as there is a background compile scheduled or going on.
*/
private var outOfDate = false
protected[interactive] var outOfDate = false
/** Units compiled by a run with id >= minRunId are considered up-to-date */
private[interactive] var minRunId = 1
@ -269,53 +269,22 @@ self =>
// ----------------- The Background Runner Thread -----------------------
/** The current presentation compiler runner */
@volatile protected var compileRunner = newRunnerThread
compileRunner.start()
@volatile protected[interactive] var compileRunner = newRunnerThread()
private var threadId = 1
private var threadId = 0
/** Create a new presentation compiler runner.
*/
def newRunnerThread: Thread = new Thread("Scala Presentation Compiler V"+threadId) {
override def run() {
debugLog("starting new runner thread")
try {
while (true) {
logreplay("wait for more work", { scheduler.waitForMoreWork(); true })
pollForWork(NoPosition)
debugLog("got more work")
while (outOfDate) {
try {
backgroundCompile()
outOfDate = false
} catch {
case FreshRunReq =>
}
log.flush()
}
}
} catch {
case ex @ ShutdownReq =>
debugLog("exiting presentation compiler")
log.close()
case ex =>
log.flush()
outOfDate = false
compileRunner = newRunnerThread
compileRunner.start()
ex match {
case FreshRunReq => // This shouldn't be reported
case _ : ValidateException => // This will have been reported elsewhere
case _ => ex.printStackTrace(); informIDE("Fatal Error: "+ex)
}
}
}
def newRunnerThread(): Thread = {
threadId += 1
compileRunner = new PresentationCompilerThread(this, threadId)
compileRunner.start()
compileRunner
}
/** Compile all loaded source files in the order given by `allSources`.
*/
private def backgroundCompile() {
protected[interactive] def backgroundCompile() {
informIDE("Starting new presentation compiler type checking pass")
reporter.reset()
// remove any files in first that are no longer maintained by presentation compiler (i.e. closed)

View File

@ -0,0 +1,53 @@
package scala.tools.nsc.interactive
/** A presentation compiler thread. This is a lightweight class, delegating most
* of its functionality to the compiler instance.
*
* @note This thread class may not be GCd, so it's important not to keep around
* large objects. For instance, the JDT weaving framework keeps threads around
* in a map, preventing them from being GCd. This prompted the separation between
* interactive.Global and this class.
*/
class PresentationCompilerThread(var compiler: Global, threadId: Int) extends Thread("Scala Presentation Compiler V"+threadId) {
/** The presentation compiler loop.
*/
override def run() {
compiler.debugLog("starting new runner thread")
try {
while (true) {
compiler.log.logreplay("wait for more work", { compiler.scheduler.waitForMoreWork(); true })
compiler.pollForWork(compiler.NoPosition)
compiler.debugLog("got more work")
while (compiler.outOfDate) {
try {
compiler.backgroundCompile()
compiler.outOfDate = false
} catch {
case FreshRunReq =>
}
compiler.log.flush()
}
}
} catch {
case ex @ ShutdownReq =>
compiler.debugLog("exiting presentation compiler")
compiler.log.close()
// make sure we don't keep around stale instances
compiler = null
case ex =>
compiler.log.flush()
compiler.outOfDate = false
compiler.newRunnerThread()
ex match {
case FreshRunReq => // This shouldn't be reported
case _ : Global#ValidateException => // This will have been reported elsewhere
case _ => ex.printStackTrace(); compiler.informIDE("Fatal Error: "+ex)
}
// make sure we don't keep around stale instances
compiler = null
}
}
}