Skip to content

Commit 61862d2

Browse files
phalleradriaanm
authored andcommitted
SIP-14 backport to 2.9.x
Other than adding the new APIs, a few changes are required: 1. Build. The Java sources in "scala/concurrent/impl" need forkjoin.jar on the classpath. Thus, I replaced the "classpath" attribute in the respective `javac` ant tasks (locker.lib, quick.lib, and strap.lib) with a "classpathref" attribute pointing to a classpath which includes also the forkjoin.jar. In the locker.lib target, exclude the duration package and everything that depends on it. In the docs.lib target, enable dependent method types, since they're used in the `scala.concurrent.duration` package. Also, the library is built with -Ydependent-method-types (for both quick & strap -- use consistent options for stability) 2. Dependent method types and SI-5958. The `duration` package relies on dependent method types, and requires a backport of SI-5958.
1 parent 32782cd commit 61862d2

26 files changed

+4898
-9
lines changed

build.xml

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,8 @@ INITIALISATION
288288
This is to facilitate testing new command line options which do not yet exist in starr. -->
289289
<property name="scalac.args.quickonly" value=""/>
290290
<property name="scalac.args.all" value="${scalac.args} ${scalac.args.optimise}"/>
291-
<property name="scalac.args.quick" value="${scalac.args.all} ${scalac.args.quickonly}"/>
291+
<property name="scalac.args.quick" value="${scalac.args.all} ${scalac.args.quickonly}"/>
292+
<property name="scalac.args.strap.lib" value="${scalac.args.all} -Ydependent-method-types"/>
292293
<!-- Setting-up Ant contrib tasks -->
293294
<taskdef resource="net/sf/antcontrib/antlib.xml" classpath="${lib.dir}/ant/ant-contrib.jar"/>
294295
<!-- This is the start time for the distribution -->
@@ -376,8 +377,9 @@ LOCAL REFERENCE BUILD (LOCKER)
376377
<javac
377378
srcdir="${src.dir}/library"
378379
destdir="${build-locker.dir}/classes/library"
379-
classpath="${build-locker.dir}/classes/library"
380+
classpathref="quick.compilation.path"
380381
includes="**/*.java"
382+
excludes="scala/concurrent/**/*.java"
381383
target="1.5" source="1.5">
382384
<compilerarg line="${javac.args}"/>
383385
</javac>
@@ -392,6 +394,17 @@ LOCAL REFERENCE BUILD (LOCKER)
392394
srcdir="${src.dir}/library"
393395
jvmargs="${scalacfork.jvmargs}">
394396
<include name="**/*.scala"/>
397+
<!-- Exclude duration package and everything that depends on it -->
398+
<exclude name="scala/concurrent/duration/**/*.scala"/>
399+
<exclude name="scala/concurrent/package.scala"/>
400+
<exclude name="scala/concurrent/Awaitable.scala"/>
401+
<exclude name="scala/concurrent/Future.scala"/>
402+
<exclude name="scala/concurrent/Promise.scala"/>
403+
<exclude name="scala/concurrent/ExecutionContext.scala"/>
404+
<exclude name="scala/concurrent/BlockContext.scala"/>
405+
<exclude name="scala/concurrent/impl/Future.scala"/>
406+
<exclude name="scala/concurrent/impl/Promise.scala"/>
407+
<exclude name="scala/concurrent/impl/ExecutionContextImpl.scala"/>
395408
<compilationpath>
396409
<pathelement location="${build-locker.dir}/classes/library"/>
397410
<pathelement location="${lib.dir}/forkjoin.jar"/>
@@ -546,7 +559,7 @@ QUICK BUILD (QUICK)
546559
<javac
547560
srcdir="${src.dir}/library"
548561
destdir="${build-quick.dir}/classes/library"
549-
classpath="${build-quick.dir}/classes/library"
562+
classpathref="quick.compilation.path"
550563
includes="**/*.java"
551564
target="1.5" source="1.5">
552565
<compilerarg line="${javac.args}"/>
@@ -563,7 +576,7 @@ QUICK BUILD (QUICK)
563576
destdir="${build-quick.dir}/classes/library"
564577
compilerpathref="locker.classpath"
565578
srcpath="${src.dir}/library"
566-
params="${scalac.args.quick}"
579+
params="${scalac.args.quick} -Ydependent-method-types"
567580
srcdir="${src.dir}/library"
568581
jvmargs="${scalacfork.jvmargs}">
569582
<include name="**/*.scala"/>
@@ -1083,7 +1096,7 @@ BOOTSTRAPPING BUILD (STRAP)
10831096
<javac
10841097
srcdir="${src.dir}/library"
10851098
destdir="${build-strap.dir}/classes/library"
1086-
classpath="${build-strap.dir}/classes/library"
1099+
classpathref="strap.compilation.path"
10871100
includes="**/*.java"
10881101
target="1.5" source="1.5">
10891102
<compilerarg line="${javac.args}"/>
@@ -1100,7 +1113,7 @@ BOOTSTRAPPING BUILD (STRAP)
11001113
destdir="${build-strap.dir}/classes/library"
11011114
compilerpathref="pack.classpath"
11021115
srcpath="${src.dir}/library"
1103-
params="${scalac.args.all}"
1116+
params="${scalac.args.strap.lib}"
11041117
srcdir="${src.dir}/library"
11051118
jvmargs="${scalacfork.jvmargs}">
11061119
<include name="**/*.scala"/>
@@ -1531,6 +1544,7 @@ DOCUMENTATION
15311544
docUncompilable="${src.dir}/library-aux"
15321545
sourcepath="${src.dir}"
15331546
classpathref="pack.classpath"
1547+
addparams="-Ydependent-method-types"
15341548
docRootContent="${build-docs.dir}/library/lib/rootdoc.txt">
15351549
<src>
15361550
<files includes="${src.dir}/actors"/>
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/* __ *\
2+
** ________ ___ / / ___ Scala API **
3+
** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL **
4+
** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
5+
** /____/\___/_/ |_/____/_/ | | **
6+
** |/ **
7+
\* */
8+
9+
package scala.concurrent
10+
11+
12+
13+
import scala.concurrent.duration.Duration
14+
15+
16+
17+
/**
18+
* An object that may eventually be completed with a result value of type `T` which may be
19+
* awaited using blocking methods.
20+
*
21+
* The [[Await]] object provides methods that allow accessing the result of an `Awaitable`
22+
* by blocking the current thread until the `Awaitable` has been completed or a timeout has
23+
* occurred.
24+
*/
25+
trait Awaitable[+T] {
26+
27+
/**
28+
* Await the "completed" state of this `Awaitable`.
29+
*
30+
* '''''This method should not be called directly; use [[Await.ready]] instead.'''''
31+
*
32+
* @param atMost
33+
* maximum wait time, which may be negative (no waiting is done),
34+
* [[scala.concurrent.duration.Duration.Inf Duration.Inf]] for unbounded waiting, or a finite positive
35+
* duration
36+
* @return this `Awaitable`
37+
* @throws InterruptedException if the current thread is interrupted while waiting
38+
* @throws TimeoutException if after waiting for the specified time this `Awaitable` is still not ready
39+
* @throws IllegalArgumentException if `atMost` is [[scala.concurrent.duration.Duration.Undefined Duration.Undefined]]
40+
*/
41+
@throws(classOf[TimeoutException])
42+
@throws(classOf[InterruptedException])
43+
def ready(atMost: Duration)(implicit permit: CanAwait): this.type
44+
45+
/**
46+
* Await and return the result (of type `T`) of this `Awaitable`.
47+
*
48+
* '''''This method should not be called directly; use [[Await.result]] instead.'''''
49+
*
50+
* @param atMost
51+
* maximum wait time, which may be negative (no waiting is done),
52+
* [[scala.concurrent.duration.Duration.Inf Duration.Inf]] for unbounded waiting, or a finite positive
53+
* duration
54+
* @return the result value if the `Awaitable` is completed within the specific maximum wait time
55+
* @throws InterruptedException if the current thread is interrupted while waiting
56+
* @throws TimeoutException if after waiting for the specified time this `Awaitable` is still not ready
57+
* @throws IllegalArgumentException if `atMost` is [[scala.concurrent.duration.Duration.Undefined Duration.Undefined]]
58+
*/
59+
@throws(classOf[Exception])
60+
def result(atMost: Duration)(implicit permit: CanAwait): T
61+
}
62+
63+
64+
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/* __ *\
2+
** ________ ___ / / ___ Scala API **
3+
** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL **
4+
** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
5+
** /____/\___/_/ |_/____/_/ | | **
6+
** |/ **
7+
\* */
8+
9+
package scala.concurrent
10+
11+
/**
12+
* A context to be notified by `scala.concurrent.blocking` when
13+
* a thread is about to block. In effect this trait provides
14+
* the implementation for `scala.concurrent.Await`.
15+
* `scala.concurrent.Await.result()` and `scala.concurrent.Await.ready()`
16+
* locates an instance of `BlockContext` by first looking for one
17+
* provided through `BlockContext.withBlockContext()` and failing that,
18+
* checking whether `Thread.currentThread` is an instance of `BlockContext`.
19+
* So a thread pool can have its `java.lang.Thread` instances implement
20+
* `BlockContext`. There's a default `BlockContext` used if the thread
21+
* doesn't implement `BlockContext`.
22+
*
23+
* Typically, you'll want to chain to the previous `BlockContext`,
24+
* like this:
25+
* {{{
26+
* val oldContext = BlockContext.current
27+
* val myContext = new BlockContext {
28+
* override def blockOn[T](thunk: =>T)(implicit permission: CanAwait): T = {
29+
* // you'd have code here doing whatever you need to do
30+
* // when the thread is about to block.
31+
* // Then you'd chain to the previous context:
32+
* oldContext.blockOn(thunk)
33+
* }
34+
* }
35+
* BlockContext.withBlockContext(myContext) {
36+
* // then this block runs with myContext as the handler
37+
* // for scala.concurrent.blocking
38+
* }
39+
* }}}
40+
*/
41+
trait BlockContext {
42+
43+
/** Used internally by the framework;
44+
* Designates (and eventually executes) a thunk which potentially blocks the calling `Thread`.
45+
*
46+
* Clients must use `scala.concurrent.blocking` or `scala.concurrent.Await` instead.
47+
*/
48+
def blockOn[T](thunk: =>T)(implicit permission: CanAwait): T
49+
}
50+
51+
object BlockContext {
52+
private object DefaultBlockContext extends BlockContext {
53+
override def blockOn[T](thunk: =>T)(implicit permission: CanAwait): T = thunk
54+
}
55+
56+
private val contextLocal = new ThreadLocal[BlockContext]()
57+
58+
/** Obtain the current thread's current `BlockContext`. */
59+
def current: BlockContext = contextLocal.get match {
60+
case null => Thread.currentThread match {
61+
case ctx: BlockContext => ctx
62+
case _ => DefaultBlockContext
63+
}
64+
case some => some
65+
}
66+
67+
/** Pushes a current `BlockContext` while executing `body`. */
68+
def withBlockContext[T](blockContext: BlockContext)(body: => T): T = {
69+
val old = contextLocal.get // can be null
70+
try {
71+
contextLocal.set(blockContext)
72+
body
73+
} finally {
74+
contextLocal.set(old)
75+
}
76+
}
77+
}

src/library/scala/concurrent/DelayedLazyVal.scala

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@
99

1010
package scala.concurrent
1111

12-
import ops.future
13-
1412
/** A <code>DelayedLazyVal</code> is a wrapper for lengthy
1513
* computations which have a valid partially computed result.
1614
* The first argument is a function for obtaining the result
@@ -41,7 +39,7 @@ class DelayedLazyVal[T](f: () => T, body: => Unit) {
4139
*/
4240
def apply(): T = if (isDone) complete else f()
4341

44-
future {
42+
ops.future {
4543
body
4644
_isDone = true
4745
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/* __ *\
2+
** ________ ___ / / ___ Scala API **
3+
** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL **
4+
** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
5+
** /____/\___/_/ |_/____/_/ | | **
6+
** |/ **
7+
\* */
8+
9+
package scala.concurrent
10+
11+
12+
import java.util.concurrent.{ Executor, ExecutorService }
13+
import scala.annotation.implicitNotFound
14+
15+
/**
16+
* An `ExecutionContext` is an abstraction over an entity that can execute program logic.
17+
*/
18+
@implicitNotFound("Cannot find an implicit ExecutionContext, either require one yourself or import ExecutionContext.Implicits.global")
19+
trait ExecutionContext {
20+
21+
/** Runs a block of code on this execution context.
22+
*/
23+
def execute(runnable: Runnable): Unit
24+
25+
/** Reports that an asynchronous computation failed.
26+
*/
27+
def reportFailure(t: Throwable): Unit
28+
29+
/** Prepares for the execution of a task. Returns the prepared
30+
* execution context. A valid implementation of `prepare` is one
31+
* that simply returns `this`.
32+
*/
33+
def prepare(): ExecutionContext = this
34+
35+
}
36+
37+
/**
38+
* Union interface since Java does not support union types
39+
*/
40+
trait ExecutionContextExecutor extends ExecutionContext with Executor
41+
42+
/**
43+
* Union interface since Java does not support union types
44+
*/
45+
trait ExecutionContextExecutorService extends ExecutionContextExecutor with ExecutorService
46+
47+
48+
/** Contains factory methods for creating execution contexts.
49+
*/
50+
object ExecutionContext {
51+
/**
52+
* This is the explicit global ExecutionContext,
53+
* call this when you want to provide the global ExecutionContext explicitly
54+
*/
55+
def global: ExecutionContextExecutor = Implicits.global
56+
57+
object Implicits {
58+
/**
59+
* This is the implicit global ExecutionContext,
60+
* import this when you want to provide the global ExecutionContext implicitly
61+
*/
62+
implicit lazy val global: ExecutionContextExecutor = impl.ExecutionContextImpl.fromExecutor(null: Executor)
63+
}
64+
65+
/** Creates an `ExecutionContext` from the given `ExecutorService`.
66+
*/
67+
def fromExecutorService(e: ExecutorService, reporter: Throwable => Unit): ExecutionContextExecutorService =
68+
impl.ExecutionContextImpl.fromExecutorService(e, reporter)
69+
70+
/** Creates an `ExecutionContext` from the given `ExecutorService` with the default Reporter.
71+
*/
72+
def fromExecutorService(e: ExecutorService): ExecutionContextExecutorService = fromExecutorService(e, defaultReporter)
73+
74+
/** Creates an `ExecutionContext` from the given `Executor`.
75+
*/
76+
def fromExecutor(e: Executor, reporter: Throwable => Unit): ExecutionContextExecutor =
77+
impl.ExecutionContextImpl.fromExecutor(e, reporter)
78+
79+
/** Creates an `ExecutionContext` from the given `Executor` with the default Reporter.
80+
*/
81+
def fromExecutor(e: Executor): ExecutionContextExecutor = fromExecutor(e, defaultReporter)
82+
83+
/** The default reporter simply prints the stack trace of the `Throwable` to System.err.
84+
*/
85+
def defaultReporter: Throwable => Unit = (t: Throwable) => t.printStackTrace()
86+
}
87+
88+

0 commit comments

Comments
 (0)