@@ -7,6 +7,7 @@ import caseapp.core.help.HelpFormat
77import java .io .File
88import java .util .Locale
99import java .util .concurrent .CompletableFuture
10+ import java .util .concurrent .atomic .AtomicReference
1011
1112import scala .build .EitherCps .{either , value }
1213import scala .build .*
@@ -229,18 +230,18 @@ object Run extends ScalaCommand[RunOptions] with BuildCommandHelpers {
229230 /** A handle to the Runner process, used to kill the process if it's still alive when a change
230231 * occured and restarts are allowed or to wait for it if restarts are not allowed
231232 */
232- var processOpt = Option .empty[(Process , CompletableFuture [_])]
233+ val processOpt = AtomicReference ( Option .empty[(Process , CompletableFuture [_])])
233234
234235 /** shouldReadInput controls whether [[WatchUtil.waitForCtrlC ]](that's keeping the main thread
235236 * alive) should try to read StdIn or just call wait()
236237 */
237- var shouldReadInput = false
238+ val shouldReadInput = AtomicReference ( false )
238239
239- /** a handle to the main thread to interrupt its operations when:
240+ /** A handle to the main thread to interrupt its operations when:
240241 * - it's blocked on reading StdIn, and it's no longer required
241242 * - it's waiting and should start reading StdIn
242243 */
243- var mainThreadOpt = Option .empty[Thread ]
244+ val mainThreadOpt = AtomicReference ( Option .empty[Thread ])
244245
245246 val watcher = Build .watch(
246247 inputs,
@@ -253,22 +254,22 @@ object Run extends ScalaCommand[RunOptions] with BuildCommandHelpers {
253254 partial = None ,
254255 actionableDiagnostics = actionableDiagnostics,
255256 postAction = () =>
256- if (processOpt.exists(_._1.isAlive()))
257+ if (processOpt.get(). exists(_._1.isAlive()))
257258 WatchUtil .printWatchWhileRunningMessage()
258259 else
259260 WatchUtil .printWatchMessage()
260261 ) { res =>
261- for ((process, onExitProcess) <- processOpt) {
262+ for ((process, onExitProcess) <- processOpt.get() ) {
262263 onExitProcess.cancel(true )
263264 ProcUtil .interruptProcess(process, logger)
264265 }
265266 res.orReport(logger).map(_.main).foreach {
266267 case s : Build .Successful =>
267- for ((proc, _) <- processOpt if proc.isAlive)
268+ for ((proc, _) <- processOpt.get() if proc.isAlive)
268269 // If the process doesn't exit, send SIGKILL
269270 ProcUtil .forceKillProcess(proc, logger)
270- shouldReadInput = false
271- mainThreadOpt.foreach(_.interrupt())
271+ shouldReadInput.set( false )
272+ mainThreadOpt.get(). foreach(_.interrupt())
272273 val maybeProcess = maybeRun(
273274 s,
274275 allowTerminate = false ,
@@ -282,29 +283,36 @@ object Run extends ScalaCommand[RunOptions] with BuildCommandHelpers {
282283 case (proc, onExit) =>
283284 if (options.sharedRun.watch.restart)
284285 onExit.thenApply { _ =>
285- shouldReadInput = true
286- mainThreadOpt.foreach(_.interrupt())
286+ shouldReadInput.set( true )
287+ mainThreadOpt.get(). foreach(_.interrupt())
287288 }
288289 (proc, onExit)
289290 }
290291 s.copyOutput(options.shared)
291292 if (options.sharedRun.watch.restart)
292- processOpt = maybeProcess
293+ processOpt.set( maybeProcess)
293294 else {
294295 for ((proc, onExit) <- maybeProcess)
295296 ProcUtil .waitForProcess(proc, onExit)
296- shouldReadInput = true
297- mainThreadOpt.foreach(_.interrupt())
297+ shouldReadInput.set( true )
298+ mainThreadOpt.get(). foreach(_.interrupt())
298299 }
299300 case _ : Build .Failed =>
300301 System .err.println(" Compilation failed" )
301302 }
302303 }
303- mainThreadOpt = Some (Thread .currentThread())
304-
305- try WatchUtil .waitForCtrlC(() => watcher.schedule(), () => shouldReadInput)
304+ mainThreadOpt.set(Some (Thread .currentThread()))
305+
306+ try
307+ WatchUtil .waitForCtrlC(
308+ { () =>
309+ watcher.schedule()
310+ shouldReadInput.set(false )
311+ },
312+ () => shouldReadInput.get()
313+ )
306314 finally {
307- mainThreadOpt = None
315+ mainThreadOpt.set( None )
308316 watcher.dispose()
309317 }
310318 }
0 commit comments