From b8c1799d4183cf4b0ef50c21140b2acd2f6d2cfa Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Fri, 24 Jul 2020 18:57:38 +0200 Subject: [PATCH] Better handling of ctrl-c while the compiler is running Previously, the compiler tried its best to continue working after ctrl-c, which usually resulted in a flood of error messages. This commit takes inspiration from https://github.com/scala/scala/pull/6479 to handle ClosedByInterruptException and InterruptedException gracefully and avoid this. Note that the Scala 2 PR goes further: it checks `Thread.interrupted()` to set a global `cancelled` flag (Should we do the same with our `Run#isCancelled` ?) and it also catches InterruptedException at the top-level so that ctrl-c does not end up printing a stacktrace, but this is beyond what I have the time to look at currently. --- .../src/dotty/tools/backend/jvm/BytecodeWriters.scala | 7 +++++++ compiler/src/dotty/tools/backend/jvm/GenBCode.scala | 10 ++++++++++ compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala | 5 +++++ 3 files changed, 22 insertions(+) diff --git a/compiler/src/dotty/tools/backend/jvm/BytecodeWriters.scala b/compiler/src/dotty/tools/backend/jvm/BytecodeWriters.scala index 77e3b6440713..4b6b1bf9c858 100644 --- a/compiler/src/dotty/tools/backend/jvm/BytecodeWriters.scala +++ b/compiler/src/dotty/tools/backend/jvm/BytecodeWriters.scala @@ -3,6 +3,8 @@ package backend package jvm import java.io.{ DataOutputStream, FileOutputStream, IOException, OutputStream, File => JFile } +import java.nio.channels.ClosedByInterruptException +import java.nio.file.Files import dotty.tools.io._ import dotty.tools.dotc.report @@ -112,6 +114,11 @@ trait BytecodeWriters { val outstream = new DataOutputStream(outfile.bufferedOutput) try outstream.write(jclassBytes, 0, jclassBytes.length) + catch case ex: ClosedByInterruptException => + try + outfile.delete() // don't leave an empty or half-written classfile around after an interrupt + catch case _: Throwable => + throw ex finally outstream.close() report.informProgress("wrote '" + label + "' to " + outfile) } diff --git a/compiler/src/dotty/tools/backend/jvm/GenBCode.scala b/compiler/src/dotty/tools/backend/jvm/GenBCode.scala index 8b5694ecff7a..5a845d4c39bf 100644 --- a/compiler/src/dotty/tools/backend/jvm/GenBCode.scala +++ b/compiler/src/dotty/tools/backend/jvm/GenBCode.scala @@ -22,6 +22,7 @@ import Symbols._ import Decorators._ import java.io.DataOutputStream +import java.nio.channels.ClosedByInterruptException import dotty.tools.tasty.{ TastyBuffer, TastyHeaderUnpickler } @@ -190,6 +191,8 @@ class GenBCodePipeline(val int: DottyBackendInterface)(using Context) extends BC else { try { /*withCurrentUnit(item.cunit)*/(visit(item)) } catch { + case ex: InterruptedException => + throw ex case ex: Throwable => println(s"Error while emitting ${item.cunit.source.file.name}") throw ex @@ -233,6 +236,11 @@ class GenBCodePipeline(val int: DottyBackendInterface)(using Context) extends BC val outTastyFile = getFileForClassfile(outF, store.name, ".tasty") val outstream = new DataOutputStream(outTastyFile.bufferedOutput) try outstream.write(binary) + catch case ex: ClosedByInterruptException => + try + outTastyFile.delete() // don't leave an empty or half-written tastyfile around after an interrupt + catch case _: Throwable => + throw ex finally outstream.close() val uuid = new TastyHeaderUnpickler(binary).readHeader() @@ -424,6 +432,8 @@ class GenBCodePipeline(val int: DottyBackendInterface)(using Context) extends BC addLambdaDeserialize(plainNode, serializableLambdas) addToQ3(item) } catch { + case ex: InterruptedException => + throw ex case ex: Throwable => println(s"Error while emitting ${item.plain.classNode.name}") throw ex diff --git a/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala b/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala index 0755b3ae5fc0..4f6785fcfa9e 100644 --- a/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala +++ b/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala @@ -3,6 +3,7 @@ package dotc package core import java.io.{IOException, File} +import java.nio.channels.ClosedByInterruptException import scala.compat.Platform.currentTime import dotty.tools.io.{ ClassPath, ClassRepresentation, AbstractFile } import config.Config @@ -343,6 +344,10 @@ abstract class SymbolLoader extends LazyType { self => report.informTime("loaded " + description, start) } catch { + case ex: InterruptedException => + throw ex + case ex: ClosedByInterruptException => + throw new InterruptedException case ex: IOException => signalError(ex) case NonFatal(ex: TypeError) =>