summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoland <rk@rkuhn.info>2012-09-11 17:58:35 +0200
committerRoland <rk@rkuhn.info>2012-09-11 17:58:35 +0200
commitad6c261eafbe72e014d005d0452c8a628a07f123 (patch)
tree9d96d5c18f44ea1bb6305d8b689019864f90a3b4
parent3767a6a83efc74d34e9025f798eeb2a043e6df8d (diff)
downloadscala-ad6c261eafbe72e014d005d0452c8a628a07f123.tar.gz
scala-ad6c261eafbe72e014d005d0452c8a628a07f123.tar.bz2
scala-ad6c261eafbe72e014d005d0452c8a628a07f123.zip
improve docs and Promise impl
- scaladoc the exceptions thrown by Await.* and Awaitable.* - move intercept[Exception] into partest’s TestUtil object - improve Promise.tryAwait implementation following Viktor’s comments and make use of Deadline to avoid calling System.nanoTime too often
-rw-r--r--src/library/scala/concurrent/Awaitable.scala22
-rw-r--r--src/library/scala/concurrent/impl/Promise.scala30
-rw-r--r--src/library/scala/concurrent/package.scala34
-rw-r--r--src/partest/scala/tools/partest/TestUtil.scala12
-rw-r--r--test/files/jvm/scala-concurrent-tck.scala9
5 files changed, 65 insertions, 42 deletions
diff --git a/src/library/scala/concurrent/Awaitable.scala b/src/library/scala/concurrent/Awaitable.scala
index 2205dd9869..655115349a 100644
--- a/src/library/scala/concurrent/Awaitable.scala
+++ b/src/library/scala/concurrent/Awaitable.scala
@@ -16,20 +16,34 @@ import scala.concurrent.util.Duration
trait Awaitable[+T] {
/**
- * Should throw [[scala.concurrent.TimeoutException]] if it times out
+ * Await the "resolved" state of this Awaitable.
* This method should not be called directly.
*
- * @throws InterruptedException if the wait call was interrupted
+ * @param atMost
+ * maximum wait time, which may be negative (no waiting is done),
+ * [[Duration.Inf]] for unbounded waiting, or a finite positive
+ * duration
+ * @return the Awaitable itself
+ * @throws InterruptedException if the wait call was interrupted
+ * @throws TimeoutException if after waiting for the specified time this Awaitable is still not ready
+ * @throws IllegalArgumentException if `atMost` is [[Duration.Undefined]]
*/
@throws(classOf[TimeoutException])
@throws(classOf[InterruptedException])
def ready(atMost: Duration)(implicit permit: CanAwait): this.type
/**
- * Throws exceptions if it cannot produce a T within the specified time.
+ * Await and return the result of this Awaitable, which is either of type T or a thrown exception (any Throwable).
* This method should not be called directly.
*
- * @throws InterruptedException if the wait call was interrupted
+ * @param atMost
+ * maximum wait time, which may be negative (no waiting is done),
+ * [[Duration.Inf]] for unbounded waiting, or a finite positive
+ * duration
+ * @return the value if the Awaitable was successful within the specific maximum wait time
+ * @throws InterruptedException if the wait call was interrupted
+ * @throws TimeoutException if after waiting for the specified time this Awaitable is still not ready
+ * @throws IllegalArgumentException if `atMost` is [[Duration.Undefined]]
*/
@throws(classOf[Exception])
def result(atMost: Duration)(implicit permit: CanAwait): T
diff --git a/src/library/scala/concurrent/impl/Promise.scala b/src/library/scala/concurrent/impl/Promise.scala
index 35aac974ec..f7ab85dc0c 100644
--- a/src/library/scala/concurrent/impl/Promise.scala
+++ b/src/library/scala/concurrent/impl/Promise.scala
@@ -12,7 +12,7 @@ package scala.concurrent.impl
import java.util.concurrent.TimeUnit.NANOSECONDS
import scala.concurrent.{ ExecutionContext, CanAwait, OnCompleteRunnable, TimeoutException, ExecutionException }
-import scala.concurrent.util.Duration
+import scala.concurrent.util.{ Duration, Deadline }
import scala.annotation.tailrec
import scala.util.control.NonFatal
import scala.util.{ Try, Success, Failure }
@@ -64,16 +64,14 @@ private[concurrent] object Promise {
protected final def tryAwait(atMost: Duration): Boolean = {
@tailrec
- def awaitUnsafe(waitTimeNanos: Long): Boolean = {
- if (!isCompleted && waitTimeNanos > 0) {
- val ms = NANOSECONDS.toMillis(waitTimeNanos)
- val ns = (waitTimeNanos % 1000000l).toInt // as per object.wait spec
- val start = System.nanoTime()
- synchronized {
- if (!isCompleted) wait(ms, ns) // previously - this was a `while`, ending up in an infinite loop
- }
+ def awaitUnsafe(deadline: Deadline, nextWait: Duration): Boolean = {
+ if (!isCompleted && nextWait > Duration.Zero) {
+ val ms = nextWait.toMillis
+ val ns = (nextWait.toNanos % 1000000l).toInt // as per object.wait spec
+
+ synchronized { if (!isCompleted) wait(ms, ns) }
- awaitUnsafe(waitTimeNanos - (System.nanoTime() - start))
+ awaitUnsafe(deadline, deadline.timeLeft)
} else
isCompleted
}
@@ -81,21 +79,19 @@ private[concurrent] object Promise {
def awaitUnbounded(): Boolean = {
if (isCompleted) true
else {
- synchronized {
- if (!isCompleted) wait()
- }
+ synchronized { if (!isCompleted) wait() }
awaitUnbounded()
}
}
- if (atMost <= Duration.Zero)
- isCompleted
- else if (atMost eq Duration.Undefined)
+ if (atMost eq Duration.Undefined)
throw new IllegalArgumentException("cannot wait for Undefined period")
+ else if (atMost <= Duration.Zero)
+ isCompleted
else if (atMost == Duration.Inf)
awaitUnbounded()
else
- awaitUnsafe(atMost.toNanos)
+ awaitUnsafe(atMost.fromNow, atMost)
}
@throws(classOf[TimeoutException])
diff --git a/src/library/scala/concurrent/package.scala b/src/library/scala/concurrent/package.scala
index 3681109653..1d06341d4d 100644
--- a/src/library/scala/concurrent/package.scala
+++ b/src/library/scala/concurrent/package.scala
@@ -67,14 +67,19 @@ package concurrent {
*/
object Await {
/**
+ * Await the "resolved" state of this Awaitable.
* Invokes ready() on the awaitable, properly wrapped by a call to `scala.concurrent.blocking`.
- * ready() blocks until the awaitable has completed or the timeout expires.
*
- * Throws a TimeoutException if the timeout expires, as that is in the contract of `Awaitable.ready`.
- * @param awaitable the `Awaitable` on which `ready` is to be called
- * @param atMost the maximum timeout for which to wait
- * @return the result of `awaitable.ready` which is defined to be the awaitable itself.
- * @throws InterruptedException if the wait call was interrupted
+ * @param awaitable
+ * the `Awaitable` on which `ready` is to be called
+ * @param atMost
+ * maximum wait time, which may be negative (no waiting is done),
+ * [[Duration.Inf]] for unbounded waiting, or a finite positive
+ * duration
+ * @return the awaitable itself
+ * @throws InterruptedException if the wait call was interrupted
+ * @throws TimeoutException if after waiting for the specified time this Awaitable is still not ready
+ * @throws IllegalArgumentException if `atMost` is [[Duration.Undefined]]
*/
@throws(classOf[TimeoutException])
@throws(classOf[InterruptedException])
@@ -82,14 +87,19 @@ package concurrent {
blocking(awaitable.ready(atMost)(AwaitPermission))
/**
+ * Await and return the result of this Awaitable, which is either of type T or a thrown exception (any Throwable).
* Invokes result() on the awaitable, properly wrapped by a call to `scala.concurrent.blocking`.
- * result() blocks until the awaitable has completed or the timeout expires.
*
- * Throws a TimeoutException if the timeout expires, or any exception thrown by `Awaitable.result`.
- * @param awaitable the `Awaitable` on which `result` is to be called
- * @param atMost the maximum timeout for which to wait
- * @return the result of `awaitable.result`
- * @throws InterruptedException if the wait call was interrupted
+ * @param awaitable
+ * the `Awaitable` on which `result` is to be called
+ * @param atMost
+ * maximum wait time, which may be negative (no waiting is done),
+ * [[Duration.Inf]] for unbounded waiting, or a finite positive
+ * duration
+ * @return the value if the Awaitable was successful within the specific maximum wait time
+ * @throws InterruptedException if the wait call was interrupted
+ * @throws TimeoutException if after waiting for the specified time this Awaitable is still not ready
+ * @throws IllegalArgumentException if `atMost` is [[Duration.Undefined]]
*/
@throws(classOf[Exception])
def result[T](awaitable: Awaitable[T], atMost: Duration): T =
diff --git a/src/partest/scala/tools/partest/TestUtil.scala b/src/partest/scala/tools/partest/TestUtil.scala
index b86a8e2c7f..146e6fc69f 100644
--- a/src/partest/scala/tools/partest/TestUtil.scala
+++ b/src/partest/scala/tools/partest/TestUtil.scala
@@ -1,5 +1,7 @@
package scala.tools.partest
+import reflect.{ classTag, ClassTag }
+
trait TestUtil {
/** Given function and block of code, evaluates code block,
* calls function with nanoseconds elapsed, and returns block result.
@@ -29,8 +31,16 @@ trait TestUtil {
assert(mult <= acceptableMultiple, "Performance difference too great: multiple = " + mult)
}
+
+ def intercept[T <: Exception : ClassTag](code: => Unit): Unit =
+ try {
+ code
+ assert(false, "did not throw " + classTag[T])
+ } catch {
+ case ex: Exception if classTag[T].runtimeClass isInstance ex =>
+ }
}
object TestUtil extends TestUtil {
-} \ No newline at end of file
+}
diff --git a/test/files/jvm/scala-concurrent-tck.scala b/test/files/jvm/scala-concurrent-tck.scala
index a60f3c8a63..0e76b711de 100644
--- a/test/files/jvm/scala-concurrent-tck.scala
+++ b/test/files/jvm/scala-concurrent-tck.scala
@@ -12,6 +12,7 @@ import scala.concurrent.{ future, promise, blocking }
import scala.util.{ Try, Success, Failure }
import scala.concurrent.util.Duration
import scala.reflect.{ classTag, ClassTag }
+import scala.tools.partest.TestUtil.intercept
trait TestBase {
@@ -21,14 +22,6 @@ trait TestBase {
sv.take(2000)
}
- def intercept[T <: Exception : ClassTag](code: => Unit): Unit =
- try {
- code
- assert(false, "did not throw " + classTag[T])
- } catch {
- case ex: Exception if classTag[T].runtimeClass isInstance ex =>
- }
-
// def assert(cond: => Boolean) {
// try {
// Predef.assert(cond)