Scala Programming Language
  1. Scala Programming Language
  2. SI-7029

Fork join execution context loses fatal exceptions

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Critical Critical
    • Resolution: Fixed
    • Affects Version/s: Scala 2.10.0
    • Fix Version/s: Scala 2.10.1
    • Component/s: Concurrent Library
    • Labels:
      None

      Description

      The fork join execution context loses fatal exceptions. It should allow them to be handled by the threads uncaught exception handler, so that they can be logged. But it doesn't, they get lost, not reported anywhere. Here is an example in the repl:

      scala> import scala.concurrent._
      import scala.concurrent._
      
      scala> val ec = scala.concurrent.ExecutionContext.global
      ec: scala.concurrent.ExecutionContextExecutor = scala.concurrent.impl.ExecutionContextImpl@4a640180
      
      scala> val f = Future[Unit](throw new NotImplementedError())(ec)
      f: scala.concurrent.Future[Unit] = scala.concurrent.impl.Promise$DefaultPromise@3ec9e1f9
      

      Nothing happens. What I expected is for my NotImplementedError to be at least handled by the uncaught exception handler, and logged. Now, I know the uncaught exception handler is there and working:

      scala> val f = Future[Unit](Thread.currentThread.getUncaughtExceptionHandler.uncaughtException(Thread.currentThread, new NotImplementedError()))(ec)
      f: scala.concurrent.Future[Unit] = scala.concurrent.impl.Promise$DefaultPromise@4aac53a8
      Exception in thread "ForkJoinPool-1-worker-1" scala.NotImplementedError: an implementation is missing
      	at $line53.$read$$iw$$iw$$iw$$iw$$anonfun$1.apply$mcV$sp(<console>:11)
      	at $line53.$read$$iw$$iw$$iw$$iw$$anonfun$1.apply(<console>:11)
      	at $line53.$read$$iw$$iw$$iw$$iw$$anonfun$1.apply(<console>:11)
      	at scala.concurrent.impl.Future$PromiseCompletingRunnable.liftedTree1$1(Future.scala:24)
      	at scala.concurrent.impl.Future$PromiseCompletingRunnable.run(Future.scala:24)
      	at scala.concurrent.forkjoin.ForkJoinTask$AdaptedRunnableAction.exec(ForkJoinTask.java:1417)
      	at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:262)
      	at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:975)
      	at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1478)
      	at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:104)
      

      And if I use a different execution context, such as a Java executor, it works as expected:

      scala> val es = java.util.concurrent.Executors.newSingleThreadExecutor
      es: java.util.concurrent.ExecutorService = java.util.concurrent.Executors$FinalizableDelegatedExecutorService@10cd508f
      
      scala> val ec = ExecutionContext.fromExecutorService(es)
      ec: scala.concurrent.ExecutionContextExecutorService = scala.concurrent.impl.ExecutionContextImpl$$anon$1@11e9c5a7
      
      scala> val f = Future[Unit](throw new NotImplementedError())(ec)
      f: scala.concurrent.Future[Unit] = scala.concurrent.impl.Promise$DefaultPromise@7309eabd
      Exception in thread "pool-1-thread-1" scala.NotImplementedError: an implementation is missing
      
       	at $line69.$read$$iw$$iw$$iw$$iw$$anonfun$1.apply(<console>:12)
      	at $line69.$read$$iw$$iw$$iw$$iw$$anonfun$1.apply(<console>:12)
      	at scala.concurrent.impl.Future$PromiseCompletingRunnable.liftedTree1$1(Future.scala:24)
      	at scala.concurrent.impl.Future$PromiseCompletingRunnable.run(Future.scala:24)
      	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
      	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
      	at java.lang.Thread.run(Thread.java:722)
      

        Activity

        Hide
        Jason Zaugg added a comment -

        Philipp: could you take a look of this ahead of 2.10.1?

        Show
        Jason Zaugg added a comment - Philipp: could you take a look of this ahead of 2.10.1?
        Hide
        James Roper added a comment -

        Apparently Viktor has been talking to Doug Lea about getting a fix for this, since the problem is in the Java forkjoin library.

        Show
        James Roper added a comment - Apparently Viktor has been talking to Doug Lea about getting a fix for this, since the problem is in the Java forkjoin library.
        Hide
        Viktor Klang added a comment -

        I've managed to work around it for Akka, but to fix the global EC in scala.concurrent, we need to do something similar to this: https://github.com/akka/akka/pull/1085/files
        However, there's a bigger topic at hand here, the one whether NotImplementedError, InterruptedException and ControlThrowable are to be considered fatal or not.

        Show
        Viktor Klang added a comment - I've managed to work around it for Akka, but to fix the global EC in scala.concurrent, we need to do something similar to this: https://github.com/akka/akka/pull/1085/files However, there's a bigger topic at hand here, the one whether NotImplementedError, InterruptedException and ControlThrowable are to be considered fatal or not.
        Show
        Viktor Klang added a comment - - edited Fixed here: https://github.com/viktorklang/scala/commit/b673248542af4f2558f1a41e41b63e162a09581d
        Hide
        Philipp Haller added a comment -

        I've just reviewed Viktor's fix. I think we should open a new self-contained pull request, though.

        Show
        Philipp Haller added a comment - I've just reviewed Viktor's fix. I think we should open a new self-contained pull request, though.
        Hide
        Viktor Klang added a comment -

        Yeah, that's fine, just cherry-pick my commit above. This should go in for both 2.10.x and 2.11 IMO

        Show
        Viktor Klang added a comment - Yeah, that's fine, just cherry-pick my commit above. This should go in for both 2.10.x and 2.11 IMO
        Hide
        Philipp Haller added a comment -
        Show
        Philipp Haller added a comment - New PR: https://github.com/scala/scala/pull/2044

          People

          • Assignee:
            Philipp Haller
            Reporter:
            James Roper
          • Votes:
            0 Vote for this issue
            Watchers:
            6 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development