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:
parent
0ea81f323b
commit
d2e5465a9a
|
@ -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 -------------------
|
||||
|
||||
/** 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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue