Skip to content

Commit 4bfc43f

Browse files
committed
adjust cancellation
1 parent a25d252 commit 4bfc43f

File tree

3 files changed

+26
-35
lines changed

3 files changed

+26
-35
lines changed

compiler/src/dotty/tools/dotc/sbt/package.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ inline val TermNameHash = 1987 // 300th prime
1717
inline val TypeNameHash = 1993 // 301st prime
1818
inline val InlineParamHash = 1997 // 302nd prime
1919

20-
def asyncZincPhasesCompleted(cb: IncrementalCallback, pending: Option[BufferingReporter]): Option[BufferingReporter] =
20+
def asyncZincPhasesCompleted(cb: IncrementalCallback, pending: Option[BufferingReporter]): BufferingReporter =
2121
val zincReporter = pending match
2222
case Some(buffered) => buffered
2323
case None => BufferingReporter()
@@ -27,7 +27,7 @@ def asyncZincPhasesCompleted(cb: IncrementalCallback, pending: Option[BufferingR
2727
catch
2828
case NonFatal(t) =>
2929
zincReporter.exception(em"signaling API and Dependencies phases completion", t)
30-
if zincReporter.hasErrors then Some(zincReporter) else None
30+
zincReporter
3131

3232
extension (sym: Symbol)
3333

compiler/src/dotty/tools/dotc/transform/Pickler.scala

+11-16
Original file line numberDiff line numberDiff line change
@@ -53,22 +53,21 @@ object Pickler {
5353
import scala.concurrent.duration.Duration
5454
import AsyncTastyHolder.Signal
5555

56-
private val _cancel = AtomicBoolean(false)
56+
private val _cancelled = AtomicBoolean(false)
5757

5858
/**Cancel any outstanding work.
59-
* This should be done at the end of a run, e.g. if there were errors that prevented reaching the backend. */
59+
* This should be done at the end of a run, e.g. background work may be running even though
60+
* errors in main thread will prevent reaching the backend. */
6061
def cancel(): Unit =
61-
while
62-
val cancelled = _cancel.get()
63-
!cancelled && !_cancel.compareAndSet(false, true)
64-
do ()
65-
if incCallback != null then
62+
if _cancelled.compareAndSet(false, true) then
6663
asyncTastyWritten.trySuccess(None) // cancel the wait for TASTy writing
67-
if incCallback != null then
68-
asyncAPIComplete.trySuccess(Signal.Cancelled) // cancel the wait for API completion
64+
if incCallback != null then
65+
asyncAPIComplete.trySuccess(Signal.Cancelled) // cancel the wait for API completion
66+
else
67+
() // nothing else to do
6968

7069
/** check if the work has been cancelled. */
71-
def cancelled: Boolean = _cancel.get()
70+
def cancelled: Boolean = _cancelled.get()
7271

7372
private val asyncTastyWritten = Promise[Option[AsyncTastyHolder.State]]()
7473
private val asyncAPIComplete =
@@ -81,7 +80,7 @@ object Pickler {
8180
asyncState.map: optState =>
8281
optState.flatMap: state =>
8382
if incCallback != null && state.done && !state.hasErrors then
84-
asyncZincPhasesCompleted(incCallback, state.pending)
83+
asyncZincPhasesCompleted(incCallback, state.pending).toBuffered
8584
else state.pending
8685

8786
/** awaits the state of async TASTy operations indefinitely, returns optionally any buffered reports. */
@@ -112,11 +111,7 @@ object Pickler {
112111
AsyncTastyHolder.State(
113112
hasErrors = ctx.reporter.hasErrors,
114113
done = done,
115-
pending = (
116-
ctx.reporter match
117-
case buffered: BufferingReporter => Some(buffered)
118-
case _: EagerReporter => None // already reported
119-
)
114+
pending = ctx.reporter.toBuffered
120115
)
121116
)
122117
end signalAsyncTastyWritten

compiler/src/dotty/tools/io/FileWriters.scala

+13-17
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import dotty.tools.backend.jvm.PostProcessorFrontendAccess.BackendReporting
3838
import scala.annotation.constructorOnly
3939
import java.util.concurrent.atomic.AtomicReference
4040
import java.util.concurrent.atomic.AtomicBoolean
41+
import java.util.ConcurrentModificationException
4142

4243
/** !!!Copied from `dotty.tools.backend.jvm.ClassfileWriters` but no `PostProcessorFrontendAccess` needed.
4344
* this should probably be changed to wrap that class instead.
@@ -56,6 +57,11 @@ object FileWriters {
5657
def warning(message: Context ?=> Message, position: SourcePosition): Unit
5758
def log(message: String): Unit
5859

60+
final def toBuffered: Option[BufferingReporter] = this match
61+
case buffered: BufferingReporter =>
62+
if buffered.hasReports then Some(buffered) else None
63+
case _: EagerReporter => None
64+
5965
def error(message: Context ?=> Message): Unit = error(message, NoSourcePosition)
6066
def warning(message: Context ?=> Message): Unit = warning(message, NoSourcePosition)
6167
final def exception(reason: Context ?=> Message, throwable: Throwable): Unit =
@@ -94,28 +100,18 @@ object FileWriters {
94100

95101
/** Atomically record that an error occurred */
96102
private def recordError(): Unit =
97-
while
98-
val old = _hasErrors.get
99-
!old && !_hasErrors.compareAndSet(old, true)
100-
do ()
103+
_hasErrors.set(true)
101104

102105
/** Atomically add a report to the log */
103106
private def recordReport(report: Report): Unit =
104-
while
105-
val old = _bufferedReports.get
106-
!_bufferedReports.compareAndSet(old, report :: old)
107-
do ()
107+
_bufferedReports.getAndUpdate(report :: _)
108108

109-
/** atomically extract and clear the buffered reports */
109+
/** atomically extract and clear the buffered reports, must only be called at a synchonization point. */
110110
private def resetReports(): List[Report] =
111-
while
112-
val old = _bufferedReports.get
113-
if _bufferedReports.compareAndSet(old, Nil) then
114-
return old
115-
else
116-
true
117-
do ()
118-
throw new AssertionError("Unreachable")
111+
val curr = _bufferedReports.get()
112+
if curr.nonEmpty && !_bufferedReports.compareAndSet(curr, Nil) then
113+
throw ConcurrentModificationException("concurrent modification of buffered reports")
114+
else curr
119115

120116
def hasErrors: Boolean = _hasErrors.get()
121117
def hasReports: Boolean = _bufferedReports.get().nonEmpty

0 commit comments

Comments
 (0)