Lgd. Viktor Klang

Systems all the way down

Viktor Klang bio photo


This is the fourth of several posts describing protips for scala.concurrent.Future. For the previous post, click here.

BlockContexts

A rather well-known problem is the use of thread blocking—pausing the execution of a Thread, usually until some sort of condition is met, either a period of time (Ex. Thread.sleep(millis)), or some kind of external trigger (Ex. the completion of an IO operation). The consequence of blocking is that the blocked thread cannot perform any work, not even unrelated work, while being blocked.

In order to ameliorate the impact of blocking SIP-14 introduced the concept of a BlockContext, which can perform actions in response to the signalling of a blocking execution, with the downside that the piece of blocking code needs to be surrounded in a blocking {}-block1 like so:

import scala.concurrent._

def foo() = blocking {
  println("foo")
}

scala>foo()
foo

Let’s say that we want to prohibit blocking within a certain scope, then we could define the following BlockContext:

import scala.concurrent._
import java.security.AccessControlException
object NoBlock extends BlockContext {
  def blockOn[T](thunk: => T)(implicit permission: CanAwait): T =
    throw new AccessControlException("Permission to block DENIED")
}

And then we could install that BlockContext in a specific call chain as so:

scala>foo()
foo

scala> BlockContext.withBlockContext(NoBlock) { foo() }
java.security.AccessControlException: Permission to block DENIED
  at NoBlock$.blockOn(<console>:20)
  at scala.concurrent.package$.blocking(package.scala:142)
  at .foo(<console>:19)
  at .$anonfun$res3$1(<console>:21)
  at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:12)
  at scala.concurrent.BlockContext$.withBlockContext(BlockContext.scala:81)
  ... 29 elided

Mission accomplished!

Cheers,

Click here for the next part in this blog series.

  1. Both Await.result and Await.ready do this under the hood.