diff options
Diffstat (limited to 'src')
227 files changed, 2586 insertions, 19479 deletions
diff --git a/src/actors/scala/actors/AbstractActor.scala b/src/actors/scala/actors/AbstractActor.scala deleted file mode 100644 index 28fe689e91..0000000000 --- a/src/actors/scala/actors/AbstractActor.scala +++ /dev/null @@ -1,30 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2005-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - -package scala.actors - -import scala.language.higherKinds - -/** - * @author Philipp Haller - * - * @define actor actor - */ -@deprecated("Use the akka.actor package instead. For migration from the scala.actors package refer to the Actors Migration Guide.", "2.11.0") -trait AbstractActor extends OutputChannel[Any] with CanReply[Any, Any] { - - type Future[+R] <: scala.actors.Future[R] - - private[actors] def exiting: Boolean = false - - private[actors] def linkTo(to: AbstractActor): Unit - - private[actors] def unlinkFrom(from: AbstractActor): Unit - - private[actors] def exit(from: AbstractActor, reason: AnyRef): Unit -} diff --git a/src/actors/scala/actors/Actor.scala b/src/actors/scala/actors/Actor.scala deleted file mode 100644 index 293335f720..0000000000 --- a/src/actors/scala/actors/Actor.scala +++ /dev/null @@ -1,411 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2005-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - -package scala.actors - -import scala.util.control.ControlThrowable -import java.util.{Timer, TimerTask} -import scala.language.implicitConversions - -/** - * Provides functions for the definition of actors, as well as actor - * operations, such as `receive`, `react`, `reply`, etc. - * - * @author Philipp Haller - */ -@deprecated("Use the akka.actor package instead. For migration from the scala.actors package refer to the Actors Migration Guide.", "2.11.0") -object Actor extends Combinators { - - /** State of an actor. - * - * - '''New''' - - * Not yet started - * - '''Runnable''' - - * Executing - * - '''Suspended''' - - * Suspended, waiting in a `react` - * - '''TimedSuspended''' - - * Suspended, waiting in a `reactWithin` - * - '''Blocked''' - - * Blocked waiting in a `receive` - * - '''TimedBlocked''' - - * Blocked waiting in a `receiveWithin` - * - '''Terminated''' - - * Actor has terminated - */ - object State extends Enumeration { - val New, - Runnable, - Suspended, - TimedSuspended, - Blocked, - TimedBlocked, - Terminated = Value - } - - private[actors] val tl = new ThreadLocal[InternalReplyReactor] - - // timer thread runs as daemon - private[actors] val timer = new Timer(true) - - private[actors] val suspendException = new SuspendActorControl - - /** - * Returns the currently executing actor. Should be used instead - * of `'''this'''` in all blocks of code executed by actors. - * - * @return returns the currently executing actor. - */ - def self: Actor = self(Scheduler).asInstanceOf[Actor] - - private[actors] def self(sched: IScheduler): InternalActor = - rawSelf(sched).asInstanceOf[InternalActor] - - private[actors] def rawSelf: InternalReplyReactor = - rawSelf(Scheduler) - - private[actors] def rawSelf(sched: IScheduler): InternalReplyReactor = { - val s = tl.get - if (s eq null) { - val r = new ActorProxy(Thread.currentThread, sched) - tl.set(r) - r - } else - s - } - - private def parentScheduler: IScheduler = { - val s = tl.get - if (s eq null) Scheduler else s.scheduler - } - - /** - * Resets an actor proxy associated with the current thread. - * It replaces the implicit `ActorProxy` instance - * of the current thread (if any) with a new instance. - * - * This permits to re-use the current thread as an actor - * even if its `ActorProxy` has died for some reason. - */ - def resetProxy() { - val a = tl.get - if ((null ne a) && a.isInstanceOf[ActorProxy]) - tl.set(new ActorProxy(Thread.currentThread, parentScheduler)) - } - - /** - * Removes any reference to an `Actor` instance - * currently stored in thread-local storage. - * - * This allows to release references from threads that are potentially - * long-running or being re-used (e.g. inside a thread pool). Permanent - * references in thread-local storage are a potential memory leak. - */ - def clearSelf() { - tl set null - } - - /** - * Factory method for creating and starting an actor. - * - * @example {{{ - * import scala.actors.Actor._ - * ... - * val a = actor { - * ... - * } - * }}} - * - * @param body the code block to be executed by the newly created actor - * @return the newly created actor. Note that it is automatically started. - */ - def actor(body: => Unit): Actor = { - val a = new Actor { - def act() = body - override final val scheduler: IScheduler = parentScheduler - } - a.start() - a - } - - /** - * Factory method for creating actors whose - * body is defined using a `Responder`. - * - * @example {{{ - * import scala.actors.Actor._ - * import Responder.exec - * ... - * val a = reactor { - * for { - * res <- b !! MyRequest; - * if exec(println("result: "+res)) - * } yield {} - * } - * }}} - * - * @param body the `Responder` to be executed by the newly created actor - * @return the newly created actor. Note that it is automatically started. - */ - def reactor(body: => Responder[Unit]): Actor = { - val a = new Actor { - def act() { - Responder.run(body) - } - override final val scheduler: IScheduler = parentScheduler - } - a.start() - a - } - - /** - * Receives the next message from the mailbox of the current actor `self`. - */ - def ? : Any = self.? - - /** - * Receives a message from the mailbox of `self`. Blocks if no message - * matching any of the cases of `f` can be received. - * - * @example {{{ - * receive { - * case "exit" => println("exiting") - * case 42 => println("got the answer") - * case x:Int => println("got an answer") - * } - * }}} - * - * @param f a partial function specifying patterns and actions - * @return the result of processing the received message - */ - def receive[A](f: PartialFunction[Any, A]): A = - self.receive(f) - - /** - * Receives a message from the mailbox of `self`. Blocks at most `msec` - * milliseconds if no message matching any of the cases of `f` can be - * received. If no message could be received the `TIMEOUT` action is - * executed if specified. - * - * @param msec the time span before timeout - * @param f a partial function specifying patterns and actions - * @return the result of processing the received message - */ - def receiveWithin[R](msec: Long)(f: PartialFunction[Any, R]): R = - self.receiveWithin(msec)(f) - - /** - * Lightweight variant of `receive`. - * - * Actions in `f` have to contain the rest of the computation of `self`, - * as this method will never return. - * - * A common method of continuing the computation is to send a message - * to another actor: - * {{{ - * react { - * case Get(from) => - * react { - * case Put(x) => from ! x - * } - * } - * }}} - * - * Another common method is to use `loop` to continuously `react` to messages: - * {{{ - * loop { - * react { - * case Msg(data) => // process data - * } - * } - * }}} - * - * @param f a partial function specifying patterns and actions - * @return this function never returns - */ - def react(f: PartialFunction[Any, Unit]): Nothing = - rawSelf.react(f) - - /** - * Lightweight variant of `receiveWithin`. - * - * Actions in `f` have to contain the rest of the computation of `self`, - * as this method will never return. - * - * @param msec the time span before timeout - * @param f a partial function specifying patterns and actions - * @return this function never returns - */ - def reactWithin(msec: Long)(f: PartialFunction[Any, Unit]): Nothing = - self.reactWithin(msec)(f) - - def eventloop(f: PartialFunction[Any, Unit]): Nothing = - rawSelf.react(new RecursiveProxyHandler(rawSelf, f)) - - private class RecursiveProxyHandler(a: InternalReplyReactor, f: PartialFunction[Any, Unit]) - extends PartialFunction[Any, Unit] { - def isDefinedAt(m: Any): Boolean = - true // events are immediately removed from the mailbox - def apply(m: Any) { - if (f.isDefinedAt(m)) f(m) - a.react(this) - } - } - - /** - * Returns the actor which sent the last received message. - */ - def sender: OutputChannel[Any] = - rawSelf.internalSender - - /** - * Sends `msg` to the actor waiting in a call to `!?`. - */ - def reply(msg: Any): Unit = - rawSelf.reply(msg) - - /** - * Sends `()` to the actor waiting in a call to `!?`. - */ - def reply(): Unit = - rawSelf.reply(()) - - /** - * Returns the number of messages in `self`'s mailbox - * - * @return the number of messages in `self`'s mailbox - */ - def mailboxSize: Int = rawSelf.mailboxSize - - /** - * Converts a synchronous event-based operation into - * an asynchronous `Responder`. - * - * @example {{{ - * val adder = reactor { - * for { - * _ <- respondOn(react) { case Add(a, b) => reply(a+b) } - * } yield {} - * } - * }}} - */ - def respondOn[A, B](fun: PartialFunction[A, Unit] => Nothing): - PartialFunction[A, B] => Responder[B] = - (caseBlock: PartialFunction[A, B]) => new Responder[B] { - def respond(k: B => Unit) = fun(caseBlock andThen k) - } - - private[actors] trait Body[a] { - def andThen[b](other: => b): Unit - } - - implicit def mkBody[a](body: => a) = new InternalActor.Body[a] { - def andThen[b](other: => b): Unit = rawSelf.seq(body, other) - } - - /** - * Links `self` to actor `to`. - * - * @param to the actor to link to - * @return the parameter actor - */ - def link(to: AbstractActor): AbstractActor = self.link(to) - - /** - * Links `self` to the actor defined by `body`. - * - * @param body the body of the actor to link to - * @return the parameter actor - */ - def link(body: => Unit): Actor = self.link(body) - - /** - * Unlinks `self` from actor `from`. - * - * @param from the actor to unlink from - */ - def unlink(from: AbstractActor): Unit = self.unlink(from) - - /** - * Terminates execution of `self` with the following effect on - * linked actors: - * - * For each linked actor `a` with `trapExit` set to `'''true'''`, - * send message `Exit(self, reason)` to `a`. - * - * For each linked actor `a` with `trapExit` set to `'''false'''` - * (default), call `a.exit(reason)` if `reason != 'normal`. - */ - def exit(reason: AnyRef): Nothing = self.exit(reason) - - /** - * Terminates execution of `self` with the following effect on - * linked actors: - * - * For each linked actor `a` with `trapExit` set to `'''true'''`, - * send message `Exit(self, 'normal)` to `a`. - */ - def exit(): Nothing = rawSelf.exit() - -} - -/** Provides lightweight, concurrent actors. Actors are created by extending - * the `Actor` trait (alternatively, one of the factory methods in its - * companion object can be used). The behavior of an `Actor` subclass is - * defined by implementing its `act` method: - * {{{ - * class MyActor extends Actor { - * def act() { - * // actor behavior goes here - * } - * } - * }}} - * A new `Actor` instance is started by invoking its `start` method. - * - * '''Note:''' care must be taken when invoking thread-blocking methods other - * than those provided by the `Actor` trait or its companion object (such as - * `receive`). Blocking the underlying thread inside an actor may lead to - * starvation of other actors. This also applies to actors hogging their - * thread for a long time between invoking `receive`/`react`. - * - * If actors use blocking operations (for example, methods for blocking I/O), - * there are several options: - * - * - The run-time system can be configured to use a larger thread pool size - * (for example, by setting the `actors.corePoolSize` JVM property). - * - The `scheduler` method of the `Actor` trait can be overridden to return a - * `ResizableThreadPoolScheduler`, which resizes its thread pool to - * avoid starvation caused by actors that invoke arbitrary blocking methods. - * - The `actors.enableForkJoin` JVM property can be set to `false`, in which - * case a `ResizableThreadPoolScheduler` is used by default to execute actors. - * - * The main ideas of the implementation are explained in the two papers - * - * - [[http://lampwww.epfl.ch/~odersky/papers/jmlc06.pdf Event-Based - * Programming without Inversion of Control]], - * Philipp Haller and Martin Odersky, ''Proc. JMLC 2006'', and - * - [[http://lamp.epfl.ch/~phaller/doc/haller07coord.pdf Actors that - * Unify Threads and Events]], - * Philipp Haller and Martin Odersky, ''Proc. COORDINATION 2007''. - * - * @author Philipp Haller - * - * @define actor actor - * @define channel actor's mailbox - */ -@SerialVersionUID(-781154067877019505L) -@deprecated("Use the akka.actor package instead. For migration from the scala.actors package refer to the Actors Migration Guide.", "2.11.0") -trait Actor extends InternalActor with ReplyReactor { - - override def start(): Actor = synchronized { - super.start() - this - } - - } - diff --git a/src/actors/scala/actors/ActorCanReply.scala b/src/actors/scala/actors/ActorCanReply.scala deleted file mode 100644 index 07191ec65c..0000000000 --- a/src/actors/scala/actors/ActorCanReply.scala +++ /dev/null @@ -1,66 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2005-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - - -package scala.actors - -import scala.concurrent.SyncVar - -/** - * Provides message send operations that - * may result in a response from the receiver. - * - * @author Philipp Haller - */ -private[actors] trait ActorCanReply extends ReactorCanReply { - this: AbstractActor with InternalReplyReactor => - - override def !?(msg: Any): Any = { - val replyCh = new Channel[Any](Actor.self(scheduler)) - send(msg, replyCh) - replyCh.? - } - - override def !?(msec: Long, msg: Any): Option[Any] = { - val replyCh = new Channel[Any](Actor.self(scheduler)) - send(msg, replyCh) - replyCh.receiveWithin(msec) { - case TIMEOUT => None - case x => Some(x) - } - } - - override def !![A](msg: Any, handler: PartialFunction[Any, A]): Future[A] = { - val c = new Channel[A](Actor.self(scheduler)) - val fun = (res: SyncVar[A]) => { - val ftch = new Channel[A](Actor.self(scheduler)) - send(msg, new OutputChannel[Any] { - def !(msg: Any) = - ftch ! handler(msg) - def send(msg: Any, replyTo: OutputChannel[Any]) = - ftch.send(handler(msg), replyTo) - def forward(msg: Any) = - ftch.forward(handler(msg)) - def receiver = - ftch.receiver - }) - ftch.react { - case any => res.set(any) - } - } - val a = new FutureActor[A](fun, c) - a.start() - a - } - - override def !!(msg: Any): Future[Any] = { - val noTransform: PartialFunction[Any, Any] = { case x => x } - this !! (msg, noTransform) - } - -} diff --git a/src/actors/scala/actors/ActorProxy.scala b/src/actors/scala/actors/ActorProxy.scala deleted file mode 100644 index 5e1d3e61de..0000000000 --- a/src/actors/scala/actors/ActorProxy.scala +++ /dev/null @@ -1,34 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2005-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - - -package scala.actors - -import java.lang.Thread - -/** - * Provides a dynamic actor proxy for normal Java threads. - * - * @author Philipp Haller - */ -private[actors] class ActorProxy(t: Thread, override final val scheduler: IScheduler) extends Actor { - - def act() {} - - /** - * Terminates with exit reason `'normal`. - */ - override def exit(): Nothing = { - shouldExit = false - // links - if (!links.isEmpty) - exitLinked() - throw new InterruptedException - } - -} diff --git a/src/actors/scala/actors/ActorRef.scala b/src/actors/scala/actors/ActorRef.scala deleted file mode 100644 index 0da167aede..0000000000 --- a/src/actors/scala/actors/ActorRef.scala +++ /dev/null @@ -1,53 +0,0 @@ -package scala.actors - -import java.util.concurrent.TimeoutException -import scala.concurrent.duration.Duration - -/** - * Trait used for migration of Scala actors to Akka. - */ -@deprecated("ActorRef ought to be used only with the Actor Migration Kit.", "2.10.0") -trait ActorRef { - - /** - * Sends a one-way asynchronous message. E.g. fire-and-forget semantics. - * <p/> - * - * If invoked from within an actor then the actor reference is implicitly passed on as the implicit 'sender' argument. - * <p/> - * - * This actor 'sender' reference is then available in the receiving actor in the 'sender' member variable, - * if invoked from within an Actor. If not then no sender is available. - * <pre> - * actor ! message - * </pre> - * <p/> - */ - def !(message: Any)(implicit sender: ActorRef = null): Unit - - /** - * Sends a message asynchronously, returning a future which may eventually hold the reply. - */ - private[actors] def ?(message: Any, timeout: Duration): scala.concurrent.Future[Any] - - /** - * Forwards the message and passes the original sender actor as the sender. - * <p/> - * Works with '!' and '?'. - */ - def forward(message: Any) - - private[actors] def localActor: AbstractActor - -} - -/** - * This is what is used to complete a Future that is returned from an ask/? call, - * when it times out. - */ -@deprecated("Use the akka.actor package instead. For migration from the scala.actors package refer to the Actors Migration Guide.", "2.11.0") -class AskTimeoutException(message: String, cause: Throwable) extends TimeoutException { - def this(message: String) = this(message, null: Throwable) -} -@deprecated("Use the akka.actor package instead. For migration from the scala.actors package refer to the Actors Migration Guide.", "2.11.0") -object PoisonPill diff --git a/src/actors/scala/actors/ActorTask.scala b/src/actors/scala/actors/ActorTask.scala deleted file mode 100644 index 21d7a0a1ad..0000000000 --- a/src/actors/scala/actors/ActorTask.scala +++ /dev/null @@ -1,60 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2005-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - - - -package scala.actors - -/** - * @author Philipp Haller - * @note This class inherits a public var called 'msg' from ReactorTask, - * and also defines a constructor parameter which shadows it (which makes any - * changes to the underlying var invisible.) I can't figure out what's supposed - * to happen, so I renamed the constructor parameter to at least be less confusing. - */ -private[actors] class ActorTask(actor: InternalActor, - fun: () => Unit, - handler: PartialFunction[Any, Any], - initialMsg: Any) - extends ReplyReactorTask(actor, fun, handler, initialMsg) { - - protected override def beginExecution() { - super.beginExecution() - actor.synchronized { // shouldExit guarded by actor - if (actor.shouldExit) - actor.exit() - } - } - - protected override def terminateExecution(e: Throwable) { - val senderInfo = try { Some(actor.internalSender) } catch { - case _: Exception => None - } - // !!! If this is supposed to be setting the current contents of the - // inherited mutable var rather than always the value given in the constructor, - // then it should be changed from initialMsg to msg. - val uncaught = UncaughtException(actor, - if (initialMsg != null) Some(initialMsg) else None, - senderInfo, - Thread.currentThread, - e) - - val todo = actor.synchronized { - val res = if (!actor.links.isEmpty) - actor.exitLinked(uncaught) - else { - super.terminateExecution(e) - () => {} - } - res - } - - todo() - } - -} diff --git a/src/actors/scala/actors/CanReply.scala b/src/actors/scala/actors/CanReply.scala deleted file mode 100644 index 3f2c53f423..0000000000 --- a/src/actors/scala/actors/CanReply.scala +++ /dev/null @@ -1,65 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2005-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - -package scala.actors - -import scala.language.higherKinds - -/** - * Defines result-bearing message send operations. - * - * @author Philipp Haller - * - * @define actor `CanReply` - */ -@deprecated("Use the akka.actor package instead. For migration from the scala.actors package refer to the Actors Migration Guide.", "2.11.0") -trait CanReply[-T, +R] { - - type Future[+P] <: () => P - - /** - * Sends `msg` to this $actor and awaits reply (synchronous). - * - * @param msg the message to be sent - * @return the reply - */ - def !?(msg: T): R - - /** - * Sends `msg` to this $actor and awaits reply (synchronous) within - * `msec` milliseconds. - * - * @param msec the time span before timeout - * @param msg the message to be sent - * @return `None` in case of timeout, otherwise - * `Some(x)` where `x` is the reply - */ - def !?(msec: Long, msg: T): Option[R] - - /** - * Sends `msg` to this $actor and immediately returns a future representing - * the reply value. - * - * @param msg the message to be sent - * @return the future - */ - def !!(msg: T): Future[R] - - /** - * Sends `msg` to this $actor and immediately returns a future representing - * the reply value. The reply is post-processed using the partial function - * `handler`. This also allows to recover a more precise type for the reply - * value. - * - * @param msg the message to be sent - * @param handler the function to be applied to the response - * @return the future - */ - def !![P](msg: T, handler: PartialFunction[R, P]): Future[P] - -} diff --git a/src/actors/scala/actors/Channel.scala b/src/actors/scala/actors/Channel.scala deleted file mode 100644 index ddf7b329c8..0000000000 --- a/src/actors/scala/actors/Channel.scala +++ /dev/null @@ -1,136 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2005-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - -package scala.actors - -import scala.concurrent.SyncVar - -/** - * Used to pattern match on values that were sent to some channel `Chan,,n,,` - * by the current actor `self`. - * - * @example {{{ - * receive { - * case Chan1 ! msg1 => ... - * case Chan2 ! msg2 => ... - * } - * }}} - * - * @author Philipp Haller - */ -@deprecated("Use the akka.actor package instead. For migration from the scala.actors package refer to the Actors Migration Guide.", "2.11.0") -case class ! [a](ch: Channel[a], msg: a) - -/** - * Provides a means for typed communication among actors. Only the - * actor creating an instance of a `Channel` may receive from it. - * - * @author Philipp Haller - * - * @define actor channel - * @define channel channel - */ -@deprecated("Use the akka.actor package instead. For migration from the scala.actors package refer to the Actors Migration Guide.", "2.11.0") -class Channel[Msg](val receiver: InternalActor) extends InputChannel[Msg] with OutputChannel[Msg] with CanReply[Msg, Any] { - - type Future[+P] = scala.actors.Future[P] - - def this() = this(Actor.self) - - def !(msg: Msg) { - receiver ! scala.actors.!(this, msg) - } - - def send(msg: Msg, replyTo: OutputChannel[Any]) { - receiver.send(scala.actors.!(this, msg), replyTo) - } - - def forward(msg: Msg) { - receiver forward scala.actors.!(this, msg) - } - - def receive[R](f: PartialFunction[Msg, R]): R = { - val C = this.asInstanceOf[Channel[Any]] - receiver.receive { - case C ! msg if (f.isDefinedAt(msg.asInstanceOf[Msg])) => f(msg.asInstanceOf[Msg]) - } - } - - def ? : Msg = receive { - case x => x - } - - def receiveWithin[R](msec: Long)(f: PartialFunction[Any, R]): R = { - val C = this.asInstanceOf[Channel[Any]] - receiver.receiveWithin(msec) { - case C ! msg if (f.isDefinedAt(msg)) => f(msg) - case TIMEOUT => f(TIMEOUT) - } - } - - def react(f: PartialFunction[Msg, Unit]): Nothing = { - val C = this.asInstanceOf[Channel[Any]] - receiver.react { - case C ! msg if (f.isDefinedAt(msg.asInstanceOf[Msg])) => f(msg.asInstanceOf[Msg]) - } - } - - def reactWithin(msec: Long)(f: PartialFunction[Any, Unit]): Nothing = { - val C = this.asInstanceOf[Channel[Any]] - receiver.reactWithin(msec) { - case C ! msg if (f.isDefinedAt(msg)) => f(msg) - case TIMEOUT => f(TIMEOUT) - } - } - - def !?(msg: Msg): Any = { - val replyCh = new Channel[Any](Actor.self(receiver.scheduler)) - receiver.send(scala.actors.!(this, msg), replyCh) - replyCh.receive { - case x => x - } - } - - def !?(msec: Long, msg: Msg): Option[Any] = { - val replyCh = new Channel[Any](Actor.self(receiver.scheduler)) - receiver.send(scala.actors.!(this, msg), replyCh) - replyCh.receiveWithin(msec) { - case TIMEOUT => None - case x => Some(x) - } - } - - def !![A](msg: Msg, handler: PartialFunction[Any, A]): Future[A] = { - val c = new Channel[A](Actor.self(receiver.scheduler)) - val fun = (res: SyncVar[A]) => { - val ftch = new Channel[A](Actor.self(receiver.scheduler)) - receiver.send(scala.actors.!(this, msg), new OutputChannel[Any] { - def !(msg: Any) = - ftch ! handler(msg) - def send(msg: Any, replyTo: OutputChannel[Any]) = - ftch.send(handler(msg), replyTo) - def forward(msg: Any) = - ftch.forward(handler(msg)) - def receiver = - ftch.receiver - }) - ftch.react { - case any => res.set(any) - } - } - val a = new FutureActor[A](fun, c) - a.start() - a - } - - def !!(msg: Msg): Future[Any] = { - val noTransform: PartialFunction[Any, Any] = { case x => x } - this !! (msg, noTransform) - } - -} diff --git a/src/actors/scala/actors/Combinators.scala b/src/actors/scala/actors/Combinators.scala deleted file mode 100644 index 64dbaf06e4..0000000000 --- a/src/actors/scala/actors/Combinators.scala +++ /dev/null @@ -1,48 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2005-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - -// $Id$ - -package scala.actors - -import scala.language.implicitConversions - -private[actors] trait Combinators { - - /** - * Enables the composition of suspendable closures using `andThen`, - * `loop`, `loopWhile`, etc. - */ - implicit def mkBody[a](body: => a): InternalActor.Body[a] - - /** - * Repeatedly executes `body`. - * - * @param body the block to be executed - */ - def loop(body: => Unit): Unit = body andThen loop(body) - - /** - * Repeatedly executes `body` while the condition `cond` is `true`. - * - * @param cond the condition to test - * @param body the block to be executed - */ - def loopWhile(cond: => Boolean)(body: => Unit): Unit = - if (cond) { body andThen loopWhile(cond)(body) } - else continue - - /** - * Continues with the execution of the closure registered as - * continuation following `andThen`. Continues with the execution - * of the next loop iteration when invoked inside the body of `loop` - * or `loopWhile`. - */ - def continue(): Unit = throw new KillActorControl - -} diff --git a/src/actors/scala/actors/DaemonActor.scala b/src/actors/scala/actors/DaemonActor.scala deleted file mode 100644 index 04a4b4a40c..0000000000 --- a/src/actors/scala/actors/DaemonActor.scala +++ /dev/null @@ -1,24 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2005-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - -package scala.actors - -import scheduler.DaemonScheduler - -/** - * Base trait for actors with daemon semantics. - * - * Unlike a regular `Actor`, an active `DaemonActor` will not - * prevent an application terminating, much like a daemon thread. - * - * @author Erik Engbrecht - */ -@deprecated("Use the akka.actor package instead. For migration from the scala.actors package refer to the Actors Migration Guide.", "2.11.0") -trait DaemonActor extends Actor { - override def scheduler: IScheduler = DaemonScheduler -} diff --git a/src/actors/scala/actors/Debug.scala b/src/actors/scala/actors/Debug.scala deleted file mode 100644 index 31ef53bdbe..0000000000 --- a/src/actors/scala/actors/Debug.scala +++ /dev/null @@ -1,45 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2005-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - - -package scala.actors - -/** - * Provides methods for generating debugging output. - * - * @author Philipp Haller - */ -@deprecated("Use the akka.actor package instead. For migration from the scala.actors package refer to the Actors Migration Guide.", "2.11.0") -object Debug extends Logger("") {} - -private[actors] class Logger(tag: String) { - private var lev = 2 - - def level = lev - def level_= (lev: Int) = { this.lev = lev } - - private val tagString = if (tag == "") "" else " ["+tag+"]" - - def info(s: String) = - if (lev > 2) System.out.println("Info" + tagString + ": " + s) - - def warning(s: String) = - if (lev > 1) System.err.println("Warning" + tagString + ": " + s) - - def error(s: String) = - if (lev > 0) System.err.println("Error" + tagString + ": " + s) - - def doInfo(b: => Unit) = - if (lev > 2) b - - def doWarning(b: => Unit) = - if (lev > 1) b - - def doError(b: => Unit) = - if (lev > 0) b -} diff --git a/src/actors/scala/actors/Future.scala b/src/actors/scala/actors/Future.scala deleted file mode 100644 index 4421c7a07a..0000000000 --- a/src/actors/scala/actors/Future.scala +++ /dev/null @@ -1,243 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2005-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - - -package scala.actors - -import scala.actors.scheduler.DaemonScheduler -import scala.concurrent.SyncVar - -/** A function of arity 0, returing a value of type `T` that, - * when applied, blocks the current actor (`Actor.self`) - * until the future's value is available. - * - * A future can be queried to find out whether its value - * is already available without blocking. - * - * @author Philipp Haller - */ -@deprecated("Use the scala.concurrent.Future instead. For migration from the scala.actors package refer to the Actors Migration Guide.", "2.11.0") -abstract class Future[+T] extends Responder[T] with Function0[T] { - - @volatile - private[actors] var fvalue: Option[Any] = None - private[actors] def fvalueTyped = fvalue.get.asInstanceOf[T] - - /** Tests whether the future's result is available. - * - * @return `true` if the future's result is available, - * `false` otherwise. - */ - def isSet: Boolean - - /** Returns an input channel that can be used to receive the future's result. - * - * @return the future's input channel - */ - def inputChannel: InputChannel[T] - -} - -private case object Eval - -private class FutureActor[T](fun: SyncVar[T] => Unit, channel: Channel[T]) extends Future[T] with DaemonActor { - - var enableChannel = false // guarded by this - - def isSet = !fvalue.isEmpty - - def apply(): T = { - if (fvalue.isEmpty) { - this !? Eval - } - fvalueTyped - } - - def respond(k: T => Unit) { - if (isSet) k(fvalueTyped) - else { - val ft = this !! Eval - ft.inputChannel.react { - case _ => k(fvalueTyped) - } - } - } - - def inputChannel: InputChannel[T] = { - synchronized { - if (!enableChannel) { - if (isSet) - channel ! fvalueTyped - enableChannel = true - } - } - channel - } - - def act() { - val res = new SyncVar[T] - - { - fun(res) - } andThen { - - synchronized { - val v = res.get - fvalue = Some(v) - if (enableChannel) - channel ! v - } - - loop { - react { - // This is calling ReplyReactor#reply(msg: Any). - // Was: reply(). Now: reply(()). - case Eval => reply(()) - } - } - } - } -} - -/** Methods that operate on futures. - * - * @author Philipp Haller - */ -@deprecated("Use the object scala.concurrent.Future instead. For migration from the scala.actors package refer to the Actors Migration Guide.", "2.11.0") -object Futures { - - /** Arranges for the asynchronous execution of `body`, - * returning a future representing the result. - * - * @param body the computation to be carried out asynchronously - * @return the future representing the result of the - * computation - */ - def future[T](body: => T): Future[T] = { - val c = new Channel[T](Actor.self(DaemonScheduler)) - val a = new FutureActor[T](_.set(body), c) - a.start() - a - } - - /** Creates a future that resolves after a given time span. - * - * @param timespan the time span in ms after which the future resolves - * @return the future - */ - def alarm(timespan: Long): Future[Unit] = { - val c = new Channel[Unit](Actor.self(DaemonScheduler)) - val fun = (res: SyncVar[Unit]) => { - Actor.reactWithin(timespan) { - case TIMEOUT => res.set({}) - } - } - val a = new FutureActor[Unit](fun, c) - a.start() - a - } - - /** Waits for the first result returned by one of two - * given futures. - * - * @param ft1 the first future - * @param ft2 the second future - * @return the result of the future that resolves first - */ - def awaitEither[A, B >: A](ft1: Future[A], ft2: Future[B]): B = { - val FutCh1 = ft1.inputChannel - val FutCh2 = ft2.inputChannel - Actor.receive { - case FutCh1 ! arg1 => arg1.asInstanceOf[B] - case FutCh2 ! arg2 => arg2.asInstanceOf[B] - } - } - - /** Waits until either all futures are resolved or a given - * time span has passed. Results are collected in a list of - * options. The result of a future that resolved during the - * time span is its value wrapped in `Some`. The result of a - * future that did not resolve during the time span is `None`. - * - * Note that some of the futures might already have been awaited, - * in which case their value is returned wrapped in `Some`. - * Passing a timeout of 0 causes `awaitAll` to return immediately. - * - * @param timeout the time span in ms after which waiting is - * aborted - * @param fts the futures to be awaited - * @return the list of optional future values - * @throws java.lang.IllegalArgumentException if timeout is negative, - * or timeout + `System.currentTimeMillis()` is negative. - */ - def awaitAll(timeout: Long, fts: Future[Any]*): List[Option[Any]] = { - val resultsMap: scala.collection.mutable.Map[Int, Option[Any]] = new scala.collection.mutable.HashMap[Int, Option[Any]] - - var cnt = 0 - val mappedFts = fts.map(ft => - ({cnt+=1; cnt-1}, ft)) - - val unsetFts = mappedFts.filter((p: Tuple2[Int, Future[Any]]) => { - if (p._2.isSet) { resultsMap(p._1) = Some(p._2()); false } - else { resultsMap(p._1) = None; true } - }) - - val partFuns = unsetFts.map((p: Tuple2[Int, Future[Any]]) => { - val FutCh = p._2.inputChannel - val singleCase: PartialFunction[Any, Tuple2[Int, Any]] = { - case FutCh ! any => (p._1, any) - } - singleCase - }) - - val thisActor = Actor.self - val timerTask = new java.util.TimerTask { - def run() { thisActor ! TIMEOUT } - } - Actor.timer.schedule(timerTask, timeout) - - def awaitWith(partFuns: Seq[PartialFunction[Any, Tuple2[Int, Any]]]) { - val reaction: PartialFunction[Any, Unit] = new PartialFunction[Any, Unit] { - def isDefinedAt(msg: Any) = msg match { - case TIMEOUT => true - case _ => partFuns exists (_ isDefinedAt msg) - } - def apply(msg: Any): Unit = msg match { - case TIMEOUT => // do nothing - case _ => { - val pfOpt = partFuns find (_ isDefinedAt msg) - val pf = pfOpt.get // succeeds always - val (idx, subres) = pf(msg) - resultsMap(idx) = Some(subres) - - val partFunsRest = partFuns filter (_ != pf) - // wait on rest of partial functions - if (partFunsRest.length > 0) - awaitWith(partFunsRest) - } - } - } - Actor.receive(reaction) - } - - if (partFuns.length > 0) - awaitWith(partFuns) - - var results: List[Option[Any]] = Nil - val size = resultsMap.size - for (i <- 0 until size) { - results = resultsMap(size - i - 1) :: results - } - - // cancel scheduled timer task - timerTask.cancel() - - results - } - -} diff --git a/src/actors/scala/actors/IScheduler.scala b/src/actors/scala/actors/IScheduler.scala deleted file mode 100644 index 9d61d48561..0000000000 --- a/src/actors/scala/actors/IScheduler.scala +++ /dev/null @@ -1,70 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2005-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - - -package scala.actors - -/** - * A common interface for all schedulers used to execute actor tasks. - * - * Subclasses of `Actor` that override its `scheduler` member must provide - * an `IScheduler` implementation. - * - * @author Philipp Haller - */ -@deprecated("Use the akka.actor package instead. For migration from the scala.actors package refer to the Actors Migration Guide.", "2.11.0") -trait IScheduler { - - /** Submits a closure for execution. - * - * @param fun the closure to be executed - */ - def execute(fun: => Unit): Unit - - /** Submits a `Runnable` for execution. - * - * @param task the task to be executed - */ - def execute(task: Runnable): Unit - - def executeFromActor(task: Runnable): Unit = - execute(task) - - /** Shuts down the scheduler. */ - def shutdown(): Unit - - /** When the scheduler is active, it can execute tasks. - * - * @return `'''true'''`, if the scheduler is active, otherwise false. - */ - def isActive: Boolean - - /** Registers a newly created actor with this scheduler. - * - * @param a the actor to be registered - */ - def newActor(a: TrackedReactor): Unit - - /** Unregisters an actor from this scheduler, because it - * has terminated. - * - * @param a the actor to be registered - */ - def terminated(a: TrackedReactor): Unit - - /** Registers a closure to be executed when the specified - * actor terminates. - * - * @param a the actor - * @param f the closure to be registered - */ - def onTerminate(a: TrackedReactor)(f: => Unit): Unit - - def managedBlock(blocker: scala.concurrent.ManagedBlocker): Unit - -} diff --git a/src/actors/scala/actors/InputChannel.scala b/src/actors/scala/actors/InputChannel.scala deleted file mode 100644 index d2dd6d24df..0000000000 --- a/src/actors/scala/actors/InputChannel.scala +++ /dev/null @@ -1,66 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2005-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - - -package scala.actors - -/** - * A common interface for all channels from which values can be received. - * - * @author Philipp Haller - * - * @define channel `InputChannel` - */ -@deprecated("Use the akka.actor package instead. For migration from the scala.actors package refer to the Actors Migration Guide.", "2.11.0") -trait InputChannel[+Msg] { - - /** - * Receives a message from this $channel. - * - * @param f a partial function with message patterns and actions - * @return result of processing the received value - */ - def receive[R](f: PartialFunction[Msg, R]): R - - /** - * Receives a message from this $channel within - * a certain time span. - * - * @param msec the time span before timeout - * @param f a partial function with message patterns and actions - * @return result of processing the received value - */ - def receiveWithin[R](msec: Long)(f: PartialFunction[Any, R]): R - - /** - * Receives a message from this $channel. - * - * This method never returns. Therefore, the rest of the computation - * has to be contained in the actions of the partial function. - * - * @param f a partial function with message patterns and actions - */ - def react(f: PartialFunction[Msg, Unit]): Nothing - - /** - * Receives a message from this $channel within - * a certain time span. - * - * This method never returns. Therefore, the rest of the computation - * has to be contained in the actions of the partial function. - * - * @param msec the time span before timeout - * @param f a partial function with message patterns and actions - */ - def reactWithin(msec: Long)(f: PartialFunction[Any, Unit]): Nothing - - /** - * Receives the next message from this $channel. - */ - def ? : Msg -} diff --git a/src/actors/scala/actors/InternalActor.scala b/src/actors/scala/actors/InternalActor.scala deleted file mode 100644 index 5045ea56e8..0000000000 --- a/src/actors/scala/actors/InternalActor.scala +++ /dev/null @@ -1,546 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2005-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ -package scala.actors -import java.util.TimerTask -import scala.util.control.ControlThrowable - -private[actors] object InternalActor { - private[actors] trait Body[a] { - def andThen[b](other: => b): Unit - } -} - -private[actors] trait InternalActor extends AbstractActor with InternalReplyReactor with ActorCanReply with InputChannel[Any] with Serializable { - - /* The following two fields are only used when the actor - * suspends by blocking its underlying thread, for example, - * when waiting in a receive or synchronous send. - */ - @volatile - private[actors] var isSuspended = false - - /* This field is used to communicate the received message from - * the invocation of send to the place where the thread of - * the receiving actor resumes inside receive/receiveWithin. - */ - @volatile - private var received: Option[Any] = None - - protected[actors] override def scheduler: IScheduler = Scheduler - - private[actors] override def startSearch(msg: Any, replyTo: OutputChannel[Any], handler: PartialFunction[Any, Any]) = - if (isSuspended) { - () => - synchronized { - mailbox.append(msg, replyTo) - resumeActor() - } - } else super.startSearch(msg, replyTo, handler) - - // we override this method to check `shouldExit` before suspending - private[actors] override def searchMailbox(startMbox: MQueue[Any], - handler: PartialFunction[Any, Any], - resumeOnSameThread: Boolean) { - var tmpMbox = startMbox - var done = false - while (!done) { - val qel = tmpMbox.extractFirst((msg: Any, replyTo: OutputChannel[Any]) => { - senders = List(replyTo) - handler.isDefinedAt(msg) - }) - if (tmpMbox ne mailbox) - tmpMbox.foreach((m, s) => mailbox.append(m, s)) - if (null eq qel) { - synchronized { - // in mean time new stuff might have arrived - if (!sendBuffer.isEmpty) { - tmpMbox = new MQueue[Any]("Temp") - drainSendBuffer(tmpMbox) - // keep going - } else { - // very important to check for `shouldExit` at this point - // since linked actors might have set it after we checked - // last time (e.g., at the beginning of `react`) - if (shouldExit) exit() - waitingFor = handler - // see Reactor.searchMailbox - throw Actor.suspendException - } - } - } else { - resumeReceiver((qel.msg, qel.session), handler, resumeOnSameThread) - done = true - } - } - } - - private[actors] override def makeReaction(fun: () => Unit, handler: PartialFunction[Any, Any], msg: Any): Runnable = - new ActorTask(this, fun, handler, msg) - - /** See the companion object's `receive` method. */ - def receive[R](f: PartialFunction[Any, R]): R = { - assert(Actor.self(scheduler) == this, "receive from channel belonging to other actor") - - synchronized { - if (shouldExit) exit() // links - drainSendBuffer(mailbox) - } - - var done = false - while (!done) { - val qel = mailbox.extractFirst((m: Any, replyTo: OutputChannel[Any]) => { - senders = replyTo :: senders - val matches = f.isDefinedAt(m) - senders = senders.tail - matches - }) - if (null eq qel) { - synchronized { - // in mean time new stuff might have arrived - if (!sendBuffer.isEmpty) { - drainSendBuffer(mailbox) - // keep going - } else { - waitingFor = f - isSuspended = true - scheduler.managedBlock(blocker) - drainSendBuffer(mailbox) - // keep going - } - } - } else { - received = Some(qel.msg) - senders = qel.session :: senders - done = true - } - } - - val result = f(received.get) - received = None - senders = senders.tail - result - } - - /** See the companion object's `receiveWithin` method. */ - def receiveWithin[R](msec: Long)(f: PartialFunction[Any, R]): R = { - assert(Actor.self(scheduler) == this, "receive from channel belonging to other actor") - - synchronized { - if (shouldExit) exit() // links - drainSendBuffer(mailbox) - } - - // first, remove spurious TIMEOUT message from mailbox if any - mailbox.extractFirst((m: Any, replyTo: OutputChannel[Any]) => m == TIMEOUT) - - val receiveTimeout = () => { - if (f.isDefinedAt(TIMEOUT)) { - received = Some(TIMEOUT) - senders = this :: senders - } else - sys.error("unhandled timeout") - } - - var done = false - while (!done) { - val qel = mailbox.extractFirst((m: Any, replyTo: OutputChannel[Any]) => { - senders = replyTo :: senders - val matches = f.isDefinedAt(m) - senders = senders.tail - matches - }) - if (null eq qel) { - val todo = synchronized { - // in mean time new stuff might have arrived - if (!sendBuffer.isEmpty) { - drainSendBuffer(mailbox) - // keep going - () => {} - } else if (msec == 0L) { - done = true - receiveTimeout - } else { - if (onTimeout.isEmpty) { - if (!f.isDefinedAt(TIMEOUT)) - sys.error("unhandled timeout") - - val thisActor = this - onTimeout = Some(new TimerTask { - def run() { - thisActor.send(TIMEOUT, thisActor) - } - }) - Actor.timer.schedule(onTimeout.get, msec) - } - - // It is possible that !onTimeout.isEmpty, but TIMEOUT is not yet in mailbox - // See SI-4759 - waitingFor = f - received = None - isSuspended = true - scheduler.managedBlock(blocker) - drainSendBuffer(mailbox) - // keep going - () => {} - } - } - todo() - } else { - synchronized { - if (!onTimeout.isEmpty) { - onTimeout.get.cancel() - onTimeout = None - } - } - received = Some(qel.msg) - senders = qel.session :: senders - done = true - } - } - - val result = f(received.get) - received = None - senders = senders.tail - result - } - - /** See the companion object's `react` method. */ - override def react(handler: PartialFunction[Any, Unit]): Nothing = { - synchronized { - if (shouldExit) exit() - } - super.react(handler) - } - - /** See the companion object's `reactWithin` method. */ - override def reactWithin(msec: Long)(handler: PartialFunction[Any, Unit]): Nothing = { - synchronized { - if (shouldExit) exit() - } - super.reactWithin(msec)(handler) - } - - /** Receives the next message from the mailbox */ - def ? : Any = receive { - case x => x - } - - // guarded by lock of this - // never throws SuspendActorControl - private[actors] override def scheduleActor(f: PartialFunction[Any, Any], msg: Any) = - if (f eq null) { - // do nothing (timeout is handled instead) - } else { - val task = new ActorTask(this, null, f, msg) - scheduler executeFromActor task - } - - /* Used for notifying scheduler when blocking inside receive/receiveWithin. */ - private object blocker extends scala.concurrent.ManagedBlocker { - def block() = { - InternalActor.this.suspendActor() - true - } - def isReleasable = - !InternalActor.this.isSuspended - } - - private def suspendActor() = synchronized { - while (isSuspended) { - try { - wait() - } catch { - case _: InterruptedException => - } - } - // links: check if we should exit - if (shouldExit) exit() - } - - private def resumeActor() { - isSuspended = false - notify() - } - - private[actors] override def exiting = synchronized { - _state == Actor.State.Terminated - } - - // guarded by this - private[actors] override def dostart() { - // Reset various flags. - // - // Note that we do *not* reset `trapExit`. The reason is that - // users should be able to set the field in the constructor - // and before `act` is called. - exitReason = 'normal - shouldExit = false - - super.dostart() - } - - override def start(): InternalActor = synchronized { - super.start() - this - } - - /** State of this actor */ - override def getState: Actor.State.Value = synchronized { - if (isSuspended) { - if (onTimeout.isEmpty) - Actor.State.Blocked - else - Actor.State.TimedBlocked - } else - super.getState - } - - // guarded by this - private[actors] var links: List[AbstractActor] = Nil - - /** - * Links <code>self</code> to actor <code>to</code>. - * - * @param to the actor to link to - * @return the parameter actor - */ - def link(to: AbstractActor): AbstractActor = { - assert(Actor.self(scheduler) == this, "link called on actor different from self") - this linkTo to - to linkTo this - to - } - - /** - * Links <code>self</code> to actor <code>to</code>. - * - * @param to the actor to link to - * @return the parameter actor - */ - def link(to: ActorRef): ActorRef = { - this.link(to.localActor) - to - } - - /** - * Unidirectional linking. For migration purposes only - */ - private[actors] def watch(subject: ActorRef): ActorRef = { - assert(Actor.self(scheduler) == this, "link called on actor different from self") - subject.localActor linkTo this - subject - } - - /** - * Unidirectional linking. For migration purposes only - */ - private[actors] def unwatch(subject: ActorRef): ActorRef = { - assert(Actor.self(scheduler) == this, "link called on actor different from self") - subject.localActor unlinkFrom this - subject - } - - /** - * Links <code>self</code> to the actor defined by <code>body</code>. - * - * @param body the body of the actor to link to - * @return the parameter actor - */ - def link(body: => Unit): Actor = { - assert(Actor.self(scheduler) == this, "link called on actor different from self") - val a = new Actor { - def act() = body - override final val scheduler: IScheduler = InternalActor.this.scheduler - } - link(a) - a.start() - a - } - - private[actors] def linkTo(to: AbstractActor) = synchronized { - links = to :: links - } - - /** - * Unlinks <code>self</code> from actor <code>from</code>. - */ - def unlink(from: AbstractActor) { - assert(Actor.self(scheduler) == this, "unlink called on actor different from self") - this unlinkFrom from - from unlinkFrom this - } - - /** - * Unlinks <code>self</code> from actor <code>from</code>. - */ - def unlink(from: ActorRef) { - unlink(from.localActor) - } - - private[actors] def unlinkFrom(from: AbstractActor) = synchronized { - links = links.filterNot(from.==) - } - - @volatile - private[actors] var _trapExit = false - - def trapExit = _trapExit - - def trapExit_=(value: Boolean) = _trapExit = value - - // guarded by this - private var exitReason: AnyRef = 'normal - // guarded by this - private[actors] var shouldExit = false - - /** - * <p> - * Terminates execution of <code>self</code> with the following - * effect on linked actors: - * </p> - * <p> - * For each linked actor <code>a</code> with - * <code>trapExit</code> set to <code>true</code>, send message - * <code>Exit(self, reason)</code> to <code>a</code>. - * </p> - * <p> - * For each linked actor <code>a</code> with - * <code>trapExit</code> set to <code>false</code> (default), - * call <code>a.exit(reason)</code> if - * <code>reason != 'normal</code>. - * </p> - */ - protected[actors] def exit(reason: AnyRef): Nothing = { - synchronized { - exitReason = reason - } - exit() - } - - /** - * Terminates with exit reason <code>'normal</code>. - */ - protected[actors] override def exit(): Nothing = { - val todo = synchronized { - if (!links.isEmpty) - exitLinked() - else - () => {} - } - todo() - super.exit() - } - - // Assume !links.isEmpty - // guarded by this - private[actors] def exitLinked(): () => Unit = { - _state = Actor.State.Terminated - // reset waitingFor, otherwise getState returns Suspended - waitingFor = Reactor.waitingForNone - // remove this from links - val mylinks = links.filterNot(this.==) - // unlink actors - mylinks.foreach(unlinkFrom(_)) - // return closure that locks linked actors - () => { - mylinks.foreach((linked: AbstractActor) => { - linked.synchronized { - if (!linked.exiting) { - linked.unlinkFrom(this) - linked.exit(this, exitReason) - } - } - }) - } - } - - // Assume !links.isEmpty - // guarded by this - private[actors] def exitLinked(reason: AnyRef): () => Unit = { - exitReason = reason - exitLinked() - } - - // Assume !this.exiting - private[actors] def exit(from: AbstractActor, reason: AnyRef) { - if (trapExit) { - this ! Exit(from, reason) - } else if (reason != 'normal) - stop(reason) - } - - /* Requires qualified private, because <code>RemoteActor</code> must - * register a termination handler. - */ - private[actors] def onTerminate(f: => Unit) { - scheduler.onTerminate(this) { f } - } - - - private[actors] def stop(reason: AnyRef): Unit = { - synchronized { - shouldExit = true - exitReason = reason - // resume this Actor in a way that - // causes it to exit - // (because shouldExit == true) - if (isSuspended) - resumeActor() - else if (waitingFor ne Reactor.waitingForNone) { - waitingFor = Reactor.waitingForNone - // it doesn't matter what partial function we are passing here - val task = new ActorTask(this, null, waitingFor, null) - scheduler execute task - /* Here we should not throw a SuspendActorControl, - since the current method is called from an actor that - is in the process of exiting. - - Therefore, the contract for scheduleActor is that - it never throws a SuspendActorControl. - */ - } - } - } -} - -/** - * Used as the timeout pattern in - * <a href="Actor.html#receiveWithin(Long)" target="contentFrame"> - * <code>receiveWithin</code></a> and - * <a href="Actor.html#reactWithin(Long)" target="contentFrame"> - * <code>reactWithin</code></a>. - * - * @example {{{ - * receiveWithin(500) { - * case (x, y) => ... - * case TIMEOUT => ... - * } - * }}} - * - * @author Philipp Haller - */ -@deprecated("Use the akka.actor package instead. For migration from the scala.actors package refer to the Actors Migration Guide.", "2.11.0") -case object TIMEOUT - -/** - * Sent to an actor - * with `trapExit` set to `true` whenever one of its linked actors - * terminates. - * - * @param from the actor that terminated - * @param reason the reason that caused the actor to terminate - */ -@deprecated("Use the akka.actor package instead. For migration from the scala.actors package refer to the Actors Migration Guide.", "2.11.0") -case class Exit(from: AbstractActor, reason: AnyRef) - -/** - * Manages control flow of actor executions. - * - * @author Philipp Haller - */ -private[actors] class SuspendActorControl extends ControlThrowable diff --git a/src/actors/scala/actors/InternalReplyReactor.scala b/src/actors/scala/actors/InternalReplyReactor.scala deleted file mode 100644 index c744984fd8..0000000000 --- a/src/actors/scala/actors/InternalReplyReactor.scala +++ /dev/null @@ -1,162 +0,0 @@ -package scala.actors - -import java.util.{TimerTask} - -/** - * Extends the [[scala.actors.Reactor]] - * trait with methods to reply to the sender of a message. - * Sending a message to a <code>ReplyReactor</code> implicitly - * passes a reference to the sender together with the message. - * - * @author Philipp Haller - * - * @define actor `ReplyReactor` - */ -@deprecated("Use the akka.actor package instead. For migration from the scala.actors package refer to the Actors Migration Guide.", "2.11.0") -trait InternalReplyReactor extends Reactor[Any] with ReactorCanReply { - - /* A list of the current senders. The head of the list is - * the sender of the message that was received last. - */ - @volatile - private[actors] var senders: List[OutputChannel[Any]] = List() - - /* This option holds a TimerTask when the actor waits in a - * reactWithin. The TimerTask is cancelled when the actor - * resumes. - * - * guarded by this - */ - private[actors] var onTimeout: Option[TimerTask] = None - - /** - * Returns the $actor which sent the last received message. - */ - protected[actors] def internalSender: OutputChannel[Any] = senders.head - - /** - * Replies with <code>msg</code> to the sender. - */ - protected[actors] def reply(msg: Any) { - internalSender ! msg - } - - override def !(msg: Any) { - send(msg, Actor.rawSelf(scheduler)) - } - - override def forward(msg: Any) { - send(msg, Actor.sender) - } - - private[actors] override def resumeReceiver(item: (Any, OutputChannel[Any]), handler: PartialFunction[Any, Any], onSameThread: Boolean) { - synchronized { - if (!onTimeout.isEmpty) { - onTimeout.get.cancel() - onTimeout = None - } - } - senders = List(item._2) - super.resumeReceiver(item, handler, onSameThread) - } - - private[actors] override def searchMailbox(startMbox: MQueue[Any], - handler: PartialFunction[Any, Any], - resumeOnSameThread: Boolean) { - var tmpMbox = startMbox - var done = false - while (!done) { - val qel = tmpMbox.extractFirst((msg: Any, replyTo: OutputChannel[Any]) => { - senders = List(replyTo) - handler.isDefinedAt(msg) - }) - if (tmpMbox ne mailbox) - tmpMbox.foreach((m, s) => mailbox.append(m, s)) - if (null eq qel) { - synchronized { - // in mean time new stuff might have arrived - if (!sendBuffer.isEmpty) { - tmpMbox = new MQueue[Any]("Temp") - drainSendBuffer(tmpMbox) - // keep going - } else { - waitingFor = handler - // see Reactor.searchMailbox - throw Actor.suspendException - } - } - } else { - resumeReceiver((qel.msg, qel.session), handler, resumeOnSameThread) - done = true - } - } - } - - private[actors] override def makeReaction(fun: () => Unit, handler: PartialFunction[Any, Any], msg: Any): Runnable = - new ReplyReactorTask(this, fun, handler, msg) - - protected[actors] override def react(handler: PartialFunction[Any, Unit]): Nothing = { - assert(Actor.rawSelf(scheduler) == this, "react on channel belonging to other actor") - super.react(handler) - } - - - /** - * Receives a message from this $actor's mailbox within a certain - * time span. - * - * This method never returns. Therefore, the rest of the computation - * has to be contained in the actions of the partial function. - * - * @param msec the time span before timeout - * @param handler a partial function with message patterns and actions - */ - protected[actors] def reactWithin(msec: Long)(handler: PartialFunction[Any, Unit]): Nothing = { - assert(Actor.rawSelf(scheduler) == this, "react on channel belonging to other actor") - - synchronized { drainSendBuffer(mailbox) } - - // first, remove spurious TIMEOUT message from mailbox if any - mailbox.extractFirst((m: Any, replyTo: OutputChannel[Any]) => m == TIMEOUT) - - while (true) { - val qel = mailbox.extractFirst((m: Any, replyTo: OutputChannel[Any]) => { - senders = List(replyTo) - handler isDefinedAt m - }) - if (null eq qel) { - synchronized { - // in mean time new messages might have arrived - if (!sendBuffer.isEmpty) { - drainSendBuffer(mailbox) - // keep going - } else if (msec == 0L) { - // throws Actor.suspendException - resumeReceiver((TIMEOUT, this), handler, false) - } else { - waitingFor = handler - val thisActor = this - onTimeout = Some(new TimerTask { - def run() { thisActor.send(TIMEOUT, thisActor) } - }) - Actor.timer.schedule(onTimeout.get, msec) - throw Actor.suspendException - } - } - } else - resumeReceiver((qel.msg, qel.session), handler, false) - } - throw Actor.suspendException - } - - override def getState: Actor.State.Value = synchronized { - if (waitingFor ne Reactor.waitingForNone) { - if (onTimeout.isEmpty) - Actor.State.Suspended - else - Actor.State.TimedSuspended - } else - _state - } - -} diff --git a/src/actors/scala/actors/KillActorControl.scala b/src/actors/scala/actors/KillActorControl.scala deleted file mode 100644 index 0f94bbc8dc..0000000000 --- a/src/actors/scala/actors/KillActorControl.scala +++ /dev/null @@ -1,14 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2005-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - -package scala.actors - -import scala.util.control.ControlThrowable -import java.lang.{InterruptedException, Runnable} - -private[actors] class KillActorControl extends ControlThrowable diff --git a/src/actors/scala/actors/LinkedNode.java b/src/actors/scala/actors/LinkedNode.java deleted file mode 100644 index bf8ca02a74..0000000000 --- a/src/actors/scala/actors/LinkedNode.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - File: LinkedNode.java - - Originally written by Doug Lea and released into the public domain. - This may be used for any purposes whatsoever without acknowledgment. - Thanks for the assistance and support of Sun Microsystems Labs, - and everyone contributing, testing, and using this code. - - History: - Date Who What - 11Jun1998 dl Create public version - 25may2000 dl Change class access to public - 26nov2001 dl Added no-arg constructor, all public access. -*/ - -package scala.actors; - -/** A standard linked list node used in various queue classes **/ -public class LinkedNode { - public Object value; - public LinkedNode next; - public LinkedNode() {} - public LinkedNode(Object x) { value = x; } - public LinkedNode(Object x, LinkedNode n) { value = x; next = n; } -} diff --git a/src/actors/scala/actors/LinkedQueue.java b/src/actors/scala/actors/LinkedQueue.java deleted file mode 100644 index 3f7b93c386..0000000000 --- a/src/actors/scala/actors/LinkedQueue.java +++ /dev/null @@ -1,185 +0,0 @@ -/* - File: LinkedQueue.java - - Originally written by Doug Lea and released into the public domain. - This may be used for any purposes whatsoever without acknowledgment. - Thanks for the assistance and support of Sun Microsystems Labs, - and everyone contributing, testing, and using this code. - - History: - Date Who What - 11Jun1998 dl Create public version - 25aug1998 dl added peek - 10dec1998 dl added isEmpty - 10oct1999 dl lock on node object to ensure visibility -*/ - -package scala.actors; - -/** - * A linked list based channel implementation. - * The algorithm avoids contention between puts - * and takes when the queue is not empty. - * Normally a put and a take can proceed simultaneously. - * (Although it does not allow multiple concurrent puts or takes.) - * This class tends to perform more efficiently than - * other Channel implementations in producer/consumer - * applications. - * <p>[<a href="http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html"> Introduction to this package. </a>] - **/ - -public class LinkedQueue { - - - /** - * Dummy header node of list. The first actual node, if it exists, is always - * at head_.next. After each take, the old first node becomes the head. - **/ - protected LinkedNode head_; - - /** - * Helper monitor for managing access to last node. - **/ - protected final Object putLock_ = new Object(); - - /** - * The last node of list. Put() appends to list, so modifies last_ - **/ - protected LinkedNode last_; - - /** - * The number of threads waiting for a take. - * Notifications are provided in put only if greater than zero. - * The bookkeeping is worth it here since in reasonably balanced - * usages, the notifications will hardly ever be necessary, so - * the call overhead to notify can be eliminated. - **/ - protected int waitingForTake_ = 0; - - public LinkedQueue() { - head_ = new LinkedNode(null); - last_ = head_; - } - - /** Main mechanics for put/offer **/ - protected void insert(Object x) { - synchronized(putLock_) { - LinkedNode p = new LinkedNode(x); - synchronized(last_) { - last_.next = p; - last_ = p; - } - if (waitingForTake_ > 0) - putLock_.notify(); - } - } - - /** Main mechanics for take/poll **/ - protected synchronized Object extract() { - synchronized(head_) { - Object x = null; - LinkedNode first = head_.next; - if (first != null) { - x = first.value; - first.value = null; - head_ = first; - } - return x; - } - } - - - public void put(Object x) throws InterruptedException { - if (x == null) throw new IllegalArgumentException(); - if (Thread.interrupted()) throw new InterruptedException(); - insert(x); - } - - public boolean offer(Object x, long msecs) throws InterruptedException { - if (x == null) throw new IllegalArgumentException(); - if (Thread.interrupted()) throw new InterruptedException(); - insert(x); - return true; - } - - public Object take() throws InterruptedException { - if (Thread.interrupted()) throw new InterruptedException(); - // try to extract. If fail, then enter wait-based retry loop - Object x = extract(); - if (x != null) - return x; - else { - synchronized(putLock_) { - try { - ++waitingForTake_; - for (;;) { - x = extract(); - if (x != null) { - --waitingForTake_; - return x; - } - else { - putLock_.wait(); - } - } - } - catch(InterruptedException ex) { - --waitingForTake_; - putLock_.notify(); - throw ex; - } - } - } - } - - public Object peek() { - synchronized(head_) { - LinkedNode first = head_.next; - if (first != null) - return first.value; - else - return null; - } - } - - - public boolean isEmpty() { - synchronized(head_) { - return head_.next == null; - } - } - - public Object poll(long msecs) throws InterruptedException { - if (Thread.interrupted()) throw new InterruptedException(); - Object x = extract(); - if (x != null) - return x; - else { - synchronized(putLock_) { - try { - long waitTime = msecs; - long start = (msecs <= 0)? 0 : System.currentTimeMillis(); - ++waitingForTake_; - for (;;) { - x = extract(); - if (x != null || waitTime <= 0) { - --waitingForTake_; - return x; - } - else { - putLock_.wait(waitTime); - waitTime = msecs - (System.currentTimeMillis() - start); - } - } - } - catch(InterruptedException ex) { - --waitingForTake_; - putLock_.notify(); - throw ex; - } - } - } - } -} - - diff --git a/src/actors/scala/actors/MQueue.scala b/src/actors/scala/actors/MQueue.scala deleted file mode 100644 index d766ecc6e8..0000000000 --- a/src/actors/scala/actors/MQueue.scala +++ /dev/null @@ -1,250 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2005-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - -package scala.actors - -private[actors] class MQueueElement[Msg >: Null](val msg: Msg, val session: OutputChannel[Any], var next: MQueueElement[Msg]) { - def this() = this(null, null, null) - def this(msg: Msg, session: OutputChannel[Any]) = this(msg, session, null) -} - -private[actors] class MQueue[Msg >: Null](protected val label: String) { - protected var first: MQueueElement[Msg] = null - protected var last: MQueueElement[Msg] = null // last eq null iff list is empty - private var _size = 0 - - def size = _size - final def isEmpty = last eq null - - protected def changeSize(diff: Int) { - _size += diff - } - - def prepend(other: MQueue[Msg]) { - if (!other.isEmpty) { - other.last.next = first - first = other.first - } - } - - def clear() { - first = null - last = null - _size = 0 - } - - - def append(msg: Msg, session: OutputChannel[Any]) { - changeSize(1) // size always increases by 1 - val el = new MQueueElement(msg, session) - - if (isEmpty) first = el - else last.next = el - - last = el - } - - def append(el: MQueueElement[Msg]) { - changeSize(1) // size always increases by 1 - - if (isEmpty) first = el - else last.next = el - - last = el - } - - def foreach(f: (Msg, OutputChannel[Any]) => Unit) { - var curr = first - while (curr != null) { - f(curr.msg, curr.session) - curr = curr.next - } - } - - def foreachAppend(target: MQueue[Msg]) { - var curr = first - while (curr != null) { - target.append(curr) - curr = curr.next - } - } - - def foreachDequeue(target: MQueue[Msg]) { - var curr = first - while (curr != null) { - target.append(curr) - curr = curr.next - } - first = null - last = null - _size = 0 - } - - def foldLeft[B](z: B)(f: (B, Msg) => B): B = { - var acc = z - var curr = first - while (curr != null) { - acc = f(acc, curr.msg) - curr = curr.next - } - acc - } - - /** Returns the n-th message that satisfies the predicate `p` - * without removing it. - */ - def get(n: Int)(p: Msg => Boolean): Option[Msg] = { - var pos = 0 - - def test(msg: Msg): Boolean = - p(msg) && (pos == n || { pos += 1; false }) - - var curr = first - while (curr != null) - if (test(curr.msg)) return Some(curr.msg) // early return - else curr = curr.next - - None - } - - /** Removes the n-th message that satisfies the predicate <code>p</code>. - */ - def remove(n: Int)(p: (Msg, OutputChannel[Any]) => Boolean): Option[(Msg, OutputChannel[Any])] = - removeInternal(n)(p) map (x => (x.msg, x.session)) - - /** Extracts the first message that satisfies the predicate `p` - * or `'''null'''` if `p` fails for all of them. - */ - def extractFirst(p: (Msg, OutputChannel[Any]) => Boolean): MQueueElement[Msg] = - removeInternal(0)(p).orNull - - def extractFirst(pf: PartialFunction[Msg, Any]): MQueueElement[Msg] = { - if (isEmpty) // early return - return null - - // special handling if returning the head - if (pf.isDefinedAt(first.msg)) { - val res = first - first = first.next - if (res eq last) - last = null - - changeSize(-1) - res - } - else { - var curr = first.next // init to element #2 - var prev = first - - while (curr != null) { - if (pf.isDefinedAt(curr.msg)) { - prev.next = curr.next - if (curr eq last) - last = prev - - changeSize(-1) - return curr // early return - } - else { - prev = curr - curr = curr.next - } - } - // not found - null - } - } - - private def removeInternal(n: Int)(p: (Msg, OutputChannel[Any]) => Boolean): Option[MQueueElement[Msg]] = { - var pos = 0 - - def foundMsg(x: MQueueElement[Msg]) = { - changeSize(-1) - Some(x) - } - def test(msg: Msg, session: OutputChannel[Any]): Boolean = - p(msg, session) && (pos == n || { pos += 1 ; false }) - - if (isEmpty) // early return - return None - - // special handling if returning the head - if (test(first.msg, first.session)) { - val res = first - first = first.next - if (res eq last) - last = null - - foundMsg(res) - } - else { - var curr = first.next // init to element #2 - var prev = first - - while (curr != null) { - if (test(curr.msg, curr.session)) { - prev.next = curr.next - if (curr eq last) - last = prev - - return foundMsg(curr) // early return - } - else { - prev = curr - curr = curr.next - } - } - // not found - None - } - } -} - -/** Debugging trait. - */ -private[actors] trait MessageQueueTracer extends MQueue[Any] -{ - private val queueNumber = MessageQueueTracer.getQueueNumber - - override def append(msg: Any, session: OutputChannel[Any]) { - super.append(msg, session) - printQueue("APPEND %s" format msg) - } - override def get(n: Int)(p: Any => Boolean): Option[Any] = { - val res = super.get(n)(p) - printQueue("GET %s" format res) - res - } - override def remove(n: Int)(p: (Any, OutputChannel[Any]) => Boolean): Option[(Any, OutputChannel[Any])] = { - val res = super.remove(n)(p) - printQueue("REMOVE %s" format res) - res - } - override def extractFirst(p: (Any, OutputChannel[Any]) => Boolean): MQueueElement[Any] = { - val res = super.extractFirst(p) - printQueue("EXTRACT_FIRST %s" format res) - res - } - - private def printQueue(msg: String) = { - def firstMsg = if (first eq null) "null" else first.msg - def lastMsg = if (last eq null) "null" else last.msg - - println("[%s size=%d] [%s] first = %s, last = %s".format(this, size, msg, firstMsg, lastMsg)) - } - override def toString() = "%s:%d".format(label, queueNumber) -} - -private[actors] object MessageQueueTracer { - // for tracing purposes - private var queueNumberAssigner = 0 - private def getQueueNumber = synchronized { - queueNumberAssigner += 1 - queueNumberAssigner - } -} diff --git a/src/actors/scala/actors/OutputChannel.scala b/src/actors/scala/actors/OutputChannel.scala deleted file mode 100644 index f0f475e123..0000000000 --- a/src/actors/scala/actors/OutputChannel.scala +++ /dev/null @@ -1,48 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2005-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - -package scala.actors - -/** - * A common interface for all channels to which values can be sent. - * - * @author Philipp Haller - * - * @define actor `OutputChannel` - */ -@deprecated("Use the akka.actor package instead. For migration from the scala.actors package refer to the Actors Migration Guide.", "2.11.0") -trait OutputChannel[-Msg] { - - /** - * Sends `msg` to this $actor (asynchronous). - * - * @param msg the message to send - */ - def !(msg: Msg): Unit - - /** - * Sends `msg` to this $actor (asynchronous) supplying - * explicit reply destination. - * - * @param msg the message to send - * @param replyTo the reply destination - */ - def send(msg: Msg, replyTo: OutputChannel[Any]): Unit - - /** - * Forwards `msg` to this $actor (asynchronous). - * - * @param msg the message to forward - */ - def forward(msg: Msg): Unit - - /** - * Returns the `Actor` that is receiving from this $actor. - */ - def receiver: InternalActor -} diff --git a/src/actors/scala/actors/ReactChannel.scala b/src/actors/scala/actors/ReactChannel.scala deleted file mode 100644 index 7e34681fb6..0000000000 --- a/src/actors/scala/actors/ReactChannel.scala +++ /dev/null @@ -1,121 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2005-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - - -package scala.actors - -/** - * @author Philipp Haller - */ -private[actors] class ReactChannel[Msg](receiver: InternalReplyReactor) extends InputChannel[Msg] { - - private case class SendToReactor(channel: ReactChannel[Msg], msg: Msg) - - /** - * Sends a message to this <code>ReactChannel</code>. - * - * @param msg the message to be sent - */ - def !(msg: Msg) { - receiver ! SendToReactor(this, msg) - } - - /** - * Sends a message to this `ReactChannel` (asynchronous) supplying - * explicit reply destination. - * - * @param msg the message to send - * @param replyTo the reply destination - */ - def send(msg: Msg, replyTo: OutputChannel[Any]) { - receiver.send(SendToReactor(this, msg), replyTo) - } - - /** - * Forwards `msg` to `'''this'''` keeping the last sender as sender - * instead of `self`. - */ - def forward(msg: Msg) { - receiver forward SendToReactor(this, msg) - } - - /** - * Receives a message from this `ReactChannel`. - * - * This method ''never'' returns. Therefore, the rest of the computation - * has to be contained in the actions of the partial function. - * - * @param f a partial function with message patterns and actions - */ - def react(f: PartialFunction[Msg, Unit]): Nothing = { - val C = this - receiver.react { - case SendToReactor(C, msg) if (f.isDefinedAt(msg.asInstanceOf[Msg])) => - f(msg.asInstanceOf[Msg]) - } - } - - /** - * Receives a message from this `ReactChannel` within a certain time span. - * - * This method ''never'' returns. Therefore, the rest of the computation - * has to be contained in the actions of the partial function. - * - * @param msec the time span before timeout - * @param f a partial function with message patterns and actions - */ - def reactWithin(msec: Long)(f: PartialFunction[Any, Unit]): Nothing = { - val C = this - val recvActor = receiver.asInstanceOf[Actor] - recvActor.reactWithin(msec) { - case C ! msg if (f.isDefinedAt(msg.asInstanceOf[Msg])) => - f(msg.asInstanceOf[Msg]) - case TIMEOUT => f(TIMEOUT) - } - } - - /** - * Receives a message from this `ReactChannel`. - * - * @param f a partial function with message patterns and actions - * @return result of processing the received value - */ - def receive[R](f: PartialFunction[Msg, R]): R = { - val C = this - val recvActor = receiver.asInstanceOf[Actor] - recvActor.receive { - case C ! msg if (f.isDefinedAt(msg.asInstanceOf[Msg])) => - f(msg.asInstanceOf[Msg]) - } - } - - /** - * Receives a message from this `ReactChannel` within a certain time span. - * - * @param msec the time span before timeout - * @param f a partial function with message patterns and actions - * @return result of processing the received value - */ - def receiveWithin[R](msec: Long)(f: PartialFunction[Any, R]): R = { - val C = this - val recvActor = receiver.asInstanceOf[Actor] - recvActor.receiveWithin(msec) { - case C ! msg if (f.isDefinedAt(msg.asInstanceOf[Msg])) => - f(msg.asInstanceOf[Msg]) - case TIMEOUT => f(TIMEOUT) - } - } - - /** - * Receives the next message from this `ReactChannel`. - */ - def ? : Msg = receive { - case x => x - } - -} diff --git a/src/actors/scala/actors/Reactor.scala b/src/actors/scala/actors/Reactor.scala deleted file mode 100644 index aa985b3a17..0000000000 --- a/src/actors/scala/actors/Reactor.scala +++ /dev/null @@ -1,307 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2005-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - - -package scala.actors - -import scala.actors.scheduler.{DelegatingScheduler, ExecutorScheduler, - ForkJoinScheduler, ThreadPoolConfig} -import java.util.concurrent.{ThreadPoolExecutor, TimeUnit, LinkedBlockingQueue} -import scala.language.implicitConversions - -private[actors] object Reactor { - - val scheduler = new DelegatingScheduler { - def makeNewScheduler: IScheduler = { - val sched = if (!ThreadPoolConfig.useForkJoin) { - // default is non-daemon - val workQueue = new LinkedBlockingQueue[Runnable] - ExecutorScheduler( - new ThreadPoolExecutor(ThreadPoolConfig.corePoolSize, - ThreadPoolConfig.maxPoolSize, - 60000L, - TimeUnit.MILLISECONDS, - workQueue, - new ThreadPoolExecutor.CallerRunsPolicy)) - } else { - // default is non-daemon, non-fair - val s = new ForkJoinScheduler(ThreadPoolConfig.corePoolSize, ThreadPoolConfig.maxPoolSize, false, false) - s.start() - s - } - Debug.info(this+": starting new "+sched+" ["+sched.getClass+"]") - sched - } - } - - val waitingForNone: PartialFunction[Any, Unit] = new PartialFunction[Any, Unit] { - def isDefinedAt(x: Any) = false - def apply(x: Any) {} - } -} - -/** - * Super trait of all actor traits. - * - * @author Philipp Haller - * - * @define actor reactor - */ -@deprecated("Use the akka.actor package instead. For migration from the scala.actors package refer to the Actors Migration Guide.", "2.11.0") -trait Reactor[Msg >: Null] extends OutputChannel[Msg] with Combinators { - - /* The $actor's mailbox. */ - private[actors] val mailbox = new MQueue[Msg]("Reactor") - - // guarded by this - private[actors] val sendBuffer = new MQueue[Msg]("SendBuffer") - - /* Whenever this $actor executes on some thread, `waitingFor` is - * guaranteed to be equal to `Reactor.waitingForNone`. - * - * In other words, whenever `waitingFor` is not equal to - * `Reactor.waitingForNone`, this $actor is guaranteed not to execute - * on some thread. - * - * If the $actor waits in a `react`, `waitingFor` holds the - * message handler that `react` was called with. - * - * guarded by this - */ - private[actors] var waitingFor: PartialFunction[Msg, Any] = - Reactor.waitingForNone - - // guarded by this - private[actors] var _state: Actor.State.Value = Actor.State.New - - /** - * The $actor's behavior is specified by implementing this method. - */ - def act(): Unit - - /** - * This partial function is applied to exceptions that propagate out of - * this $actor's body. - */ - protected[actors] def exceptionHandler: PartialFunction[Exception, Unit] = - Map() - - protected[actors] def scheduler: IScheduler = - Reactor.scheduler - - protected[actors] def mailboxSize: Int = - mailbox.size - - def send(msg: Msg, replyTo: OutputChannel[Any]) { - val todo = synchronized { - if (waitingFor ne Reactor.waitingForNone) { - val savedWaitingFor = waitingFor - waitingFor = Reactor.waitingForNone - startSearch(msg, replyTo, savedWaitingFor) - } else { - sendBuffer.append(msg, replyTo) - () => { /* do nothing */ } - } - } - todo() - } - - private[actors] def startSearch(msg: Msg, replyTo: OutputChannel[Any], handler: PartialFunction[Msg, Any]) = - () => scheduler execute makeReaction(() => { - val startMbox = new MQueue[Msg]("Start") - synchronized { startMbox.append(msg, replyTo) } - searchMailbox(startMbox, handler, true) - }) - - private[actors] final def makeReaction(fun: () => Unit): Runnable = - makeReaction(fun, null, null) - - /* This method is supposed to be overridden. */ - private[actors] def makeReaction(fun: () => Unit, handler: PartialFunction[Msg, Any], msg: Msg): Runnable = - new ReactorTask(this, fun, handler, msg) - - private[actors] def resumeReceiver(item: (Msg, OutputChannel[Any]), handler: PartialFunction[Msg, Any], onSameThread: Boolean) { - if (onSameThread) - makeReaction(null, handler, item._1).run() - else - scheduleActor(handler, item._1) - - /* Here, we throw a SuspendActorControl to avoid - terminating this actor when the current ReactorTask - is finished. - - The SuspendActorControl skips the termination code - in ReactorTask. - */ - throw Actor.suspendException - } - - def !(msg: Msg) { - send(msg, null) - } - - def forward(msg: Msg) { - send(msg, null) - } - - def receiver: Actor = this.asInstanceOf[Actor] - - // guarded by this - private[actors] def drainSendBuffer(mbox: MQueue[Msg]) { - sendBuffer.foreachDequeue(mbox) - } - - private[actors] def searchMailbox(startMbox: MQueue[Msg], - handler: PartialFunction[Msg, Any], - resumeOnSameThread: Boolean) { - var tmpMbox = startMbox - var done = false - while (!done) { - val qel = tmpMbox.extractFirst(handler) - if (tmpMbox ne mailbox) - tmpMbox.foreachAppend(mailbox) - if (null eq qel) { - synchronized { - // in mean time new stuff might have arrived - if (!sendBuffer.isEmpty) { - tmpMbox = new MQueue[Msg]("Temp") - drainSendBuffer(tmpMbox) - // keep going - } else { - waitingFor = handler - /* Here, we throw a SuspendActorControl to avoid - terminating this actor when the current ReactorTask - is finished. - - The SuspendActorControl skips the termination code - in ReactorTask. - */ - throw Actor.suspendException - } - } - } else { - resumeReceiver((qel.msg, qel.session), handler, resumeOnSameThread) - done = true - } - } - } - - /** - * Receives a message from this $actor's mailbox. - * - * This method never returns. Therefore, the rest of the computation - * has to be contained in the actions of the partial function. - * - * @param handler a partial function with message patterns and actions - */ - protected def react(handler: PartialFunction[Msg, Unit]): Nothing = { - synchronized { drainSendBuffer(mailbox) } - searchMailbox(mailbox, handler, false) - throw Actor.suspendException - } - - /* This method is guaranteed to be executed from inside - * an $actor's act method. - * - * assume handler != null - * - * never throws SuspendActorControl - */ - private[actors] def scheduleActor(handler: PartialFunction[Msg, Any], msg: Msg) { - scheduler executeFromActor makeReaction(null, handler, msg) - } - - private[actors] def preAct() = {} - - // guarded by this - private[actors] def dostart() { - _state = Actor.State.Runnable - scheduler newActor this - scheduler execute makeReaction(() => { - preAct() - act() - }, null, null) - } - - /** - * Starts this $actor. This method is idempotent. - */ - def start(): Reactor[Msg] = synchronized { - if (_state == Actor.State.New) - dostart() - this - } - - /** - * Restarts this $actor. - * - * @throws java.lang.IllegalStateException if the $actor is not in state `Actor.State.Terminated` - */ - def restart(): Unit = synchronized { - if (_state == Actor.State.Terminated) - dostart() - else - throw new IllegalStateException("restart only in state "+Actor.State.Terminated) - } - - /** Returns the execution state of this $actor. - * - * @return the execution state - */ - def getState: Actor.State.Value = synchronized { - if (waitingFor ne Reactor.waitingForNone) - Actor.State.Suspended - else - _state - } - - implicit def mkBody[A](body: => A) = new InternalActor.Body[A] { - def andThen[B](other: => B): Unit = Reactor.this.seq(body, other) - } - - /* This closure is used to implement control-flow operations - * built on top of `seq`. Note that the only invocation of - * `kill` is supposed to be inside `ReactorTask.run`. - */ - @volatile - private[actors] var kill: () => Unit = - () => { exit() } - - private[actors] def seq[a, b](first: => a, next: => b): Unit = { - val killNext = this.kill - this.kill = () => { - this.kill = killNext - - // to avoid stack overflow: - // instead of directly executing `next`, - // schedule as continuation - scheduleActor({ case _ => next }, null) - throw Actor.suspendException - } - first - throw new KillActorControl - } - - protected[actors] def exit(): Nothing = { - terminated() - throw Actor.suspendException - } - - private[actors] def internalPostStop() = {} - - private[actors] def terminated() { - synchronized { - _state = Actor.State.Terminated - // reset waitingFor, otherwise getState returns Suspended - waitingFor = Reactor.waitingForNone - } - internalPostStop() - scheduler.terminated(this) - } - -} diff --git a/src/actors/scala/actors/ReactorCanReply.scala b/src/actors/scala/actors/ReactorCanReply.scala deleted file mode 100644 index e30efcbed8..0000000000 --- a/src/actors/scala/actors/ReactorCanReply.scala +++ /dev/null @@ -1,90 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2005-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - - -package scala.actors - -/** - * Provides message send operations that - * may result in a response from the receiver. - * - * @author Philipp Haller - */ -private[actors] trait ReactorCanReply extends CanReply[Any, Any] { - _: InternalReplyReactor => - - type Future[+P] = scala.actors.Future[P] - - def !?(msg: Any): Any = - (this !! msg)() - - def !?(msec: Long, msg: Any): Option[Any] = { - val myself = Actor.rawSelf(this.scheduler) - val res = new scala.concurrent.SyncVar[Any] - val out = new OutputChannel[Any] { - def !(msg: Any) = - res set msg - def send(msg: Any, replyTo: OutputChannel[Any]) = - res set msg - def forward(msg: Any) = - res set msg - def receiver = - myself.asInstanceOf[Actor] - } - this.send(msg, out) - res.get(msec) - } - - def !!(msg: Any): Future[Any] = - this !! (msg, { case x => x }) - - def !![A](msg: Any, handler: PartialFunction[Any, A]): Future[A] = { - val myself = Actor.rawSelf(this.scheduler) - val ftch = new ReactChannel[A](myself) - val res = new scala.concurrent.SyncVar[A] - - val out = new OutputChannel[Any] { - def !(msg: Any) = { - val msg1 = handler(msg) - ftch ! msg1 - res set msg1 - } - def send(msg: Any, replyTo: OutputChannel[Any]) = { - val msg1 = handler(msg) - ftch.send(msg1, replyTo) - res set msg1 - } - def forward(msg: Any) = { - val msg1 = handler(msg) - ftch forward msg1 - res set msg1 - } - def receiver = - myself.asInstanceOf[Actor] - } - - this.send(msg, out) - - new Future[A] { - def apply() = { - if (!isSet) - fvalue = Some(res.get) - - fvalueTyped - } - def respond(k: A => Unit): Unit = - if (isSet) k(fvalueTyped) - else inputChannel.react { - case any => fvalue = Some(any); k(fvalueTyped) - } - def isSet = - !fvalue.isEmpty - def inputChannel = ftch - } - } -} diff --git a/src/actors/scala/actors/ReactorTask.scala b/src/actors/scala/actors/ReactorTask.scala deleted file mode 100644 index 1ca061b40d..0000000000 --- a/src/actors/scala/actors/ReactorTask.scala +++ /dev/null @@ -1,74 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2005-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - - -package scala.actors - -import java.lang.Runnable -import java.util.concurrent.Callable - -import scala.concurrent.forkjoin.RecursiveAction - -/** - * @author Philipp Haller - */ -private[actors] class ReactorTask[Msg >: Null](var reactor: Reactor[Msg], - var fun: () => Any, - var handler: PartialFunction[Msg, Any], - var msg: Msg) - extends RecursiveAction with Callable[Unit] with Runnable { - - def run() { - try { - beginExecution() - try { - if (fun eq null) - handler(msg) - else - fun() - } catch { - case _: KillActorControl => - // do nothing - - case e: Exception if reactor.exceptionHandler.isDefinedAt(e) => - reactor.exceptionHandler(e) - } - reactor.kill() - } - catch { - case _: SuspendActorControl => - // do nothing (continuation is already saved) - - case e: Throwable => - terminateExecution(e) - reactor.terminated() - if (!e.isInstanceOf[Exception]) - throw e - } finally { - suspendExecution() - this.reactor = null - this.fun = null - this.handler = null - this.msg = null - } - } - - def call() = run() - - def compute() = run() - - protected def beginExecution() {} - - protected def suspendExecution() {} - - protected def terminateExecution(e: Throwable) { - Console.err.println(reactor+": caught "+e) - e.printStackTrace() - } - -} diff --git a/src/actors/scala/actors/ReplyReactor.scala b/src/actors/scala/actors/ReplyReactor.scala deleted file mode 100644 index 01e6da000f..0000000000 --- a/src/actors/scala/actors/ReplyReactor.scala +++ /dev/null @@ -1,13 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2005-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ -package scala.actors - -@deprecated("Use the akka.actor package instead. For migration from the scala.actors package refer to the Actors Migration Guide.", "2.11.0") -trait ReplyReactor extends InternalReplyReactor { - protected[actors] def sender: OutputChannel[Any] = super.internalSender -} diff --git a/src/actors/scala/actors/ReplyReactorTask.scala b/src/actors/scala/actors/ReplyReactorTask.scala deleted file mode 100644 index ea9070fab7..0000000000 --- a/src/actors/scala/actors/ReplyReactorTask.scala +++ /dev/null @@ -1,40 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2005-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - -// $Id$ - -package scala.actors - -/** - * @author Philipp Haller - * @note This class inherits a public var called 'reactor' from ReactorTask, - * and also defines a constructor parameter which shadows it (which makes any - * changes to the underlying var invisible.) I can't figure out what's supposed - * to happen, so I renamed the constructor parameter to at least be less confusing. - */ -private[actors] class ReplyReactorTask(replyReactor: InternalReplyReactor, - fun: () => Unit, - handler: PartialFunction[Any, Any], - msg: Any) - extends ReactorTask(replyReactor, fun, handler, msg) { - - var saved: InternalReplyReactor = _ - - protected override def beginExecution() { - saved = Actor.tl.get - // !!! If this is supposed to be setting the current contents of the - // inherited mutable var rather than always the value given in the constructor, - // then it should be changed to "set reactor". - Actor.tl set replyReactor - } - - protected override def suspendExecution() { - Actor.tl set saved - } - -} diff --git a/src/actors/scala/actors/Scheduler.scala b/src/actors/scala/actors/Scheduler.scala deleted file mode 100644 index 67c8e5cd10..0000000000 --- a/src/actors/scala/actors/Scheduler.scala +++ /dev/null @@ -1,40 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2005-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - - -package scala.actors - -import scheduler.{DelegatingScheduler, ForkJoinScheduler, ResizableThreadPoolScheduler, ThreadPoolConfig} - -/** - * Used by [[scala.actors.Actor]] instances to - * execute tasks of an actor execution. - * - * @author Philipp Haller - */ -@deprecated("Use the akka.actor package instead. For migration from the scala.actors package refer to the Actors Migration Guide.", "2.11.0") -object Scheduler extends DelegatingScheduler { - - Debug.info("initializing "+this+"...") - - def makeNewScheduler: IScheduler = { - val sched = if (!ThreadPoolConfig.useForkJoin) { - // default is non-daemon - val s = new ResizableThreadPoolScheduler(false) - s.start() - s - } else { - // default is non-daemon, fair - val s = new ForkJoinScheduler - s.start() - s - } - Debug.info(this+": starting new "+sched+" ["+sched.getClass+"]") - sched - } -} diff --git a/src/actors/scala/actors/SchedulerAdapter.scala b/src/actors/scala/actors/SchedulerAdapter.scala deleted file mode 100644 index b8e66dd6cc..0000000000 --- a/src/actors/scala/actors/SchedulerAdapter.scala +++ /dev/null @@ -1,68 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2005-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - - -package scala.actors - -/** Adapts - * the behavior of the standard [[scala.actors.Scheduler]] object. - * - * Providing an implementation for the - * <code>execute(f: => Unit)</code> method is sufficient to - * obtain a concrete <code>IScheduler</code> implementation. - * - * @author Philipp Haller - */ -@deprecated("Use the akka.actor package instead. For migration from the scala.actors package refer to the Actors Migration Guide.", "2.11.0") -trait SchedulerAdapter extends IScheduler { - - /** Submits a <code>Runnable</code> for execution. - * - * @param task the task to be executed - */ - def execute(task: Runnable): Unit = - execute { task.run() } - - /** Shuts down the scheduler. - */ - def shutdown(): Unit = - Scheduler.shutdown() - - /** When the scheduler is active, it can execute tasks. - */ - def isActive: Boolean = - Scheduler.isActive - - /** Registers a newly created actor with this scheduler. - * - * @param a the actor to be registered - */ - def newActor(a: TrackedReactor) = - Scheduler.newActor(a) - - /** Unregisters an actor from this scheduler, because it - * has terminated. - * - * @param a the actor to be unregistered - */ - def terminated(a: TrackedReactor) = - Scheduler.terminated(a) - - /** Registers a closure to be executed when the specified - * actor terminates. - * - * @param a the actor - * @param f the closure to be registered - */ - def onTerminate(a: TrackedReactor)(f: => Unit) = - Scheduler.onTerminate(a)(f) - - def managedBlock(blocker: scala.concurrent.ManagedBlocker) { - blocker.block() - } -} diff --git a/src/actors/scala/actors/UncaughtException.scala b/src/actors/scala/actors/UncaughtException.scala deleted file mode 100644 index 02b916a3b5..0000000000 --- a/src/actors/scala/actors/UncaughtException.scala +++ /dev/null @@ -1,34 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2005-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - -package scala.actors - -/** - * The exit reason when an actor fails to catch an exception. - * - * @param actor the actor that threw the exception - * @param message the message the actor was processing, or None if no message (e.g. on initial startup) - * @param sender the sender of the most recent message - * @param thread the thread on which the actor was running - * @param cause the uncaught exception - * - * @author Philipp Haller - * @author Erik Engbrecht - */ -@deprecated("Use the akka.actor package instead. For migration from the scala.actors package refer to the Actors Migration Guide.", "2.11.0") -case class UncaughtException(actor: InternalActor, - message: Option[Any], - sender: Option[OutputChannel[Any]], - thread: Thread, - cause: Throwable) -extends Exception(cause) { - - override def toString() = - "UncaughtException("+actor+","+message+","+sender+","+cause+")" - -} diff --git a/src/actors/scala/actors/package.scala b/src/actors/scala/actors/package.scala deleted file mode 100644 index ae960860cf..0000000000 --- a/src/actors/scala/actors/package.scala +++ /dev/null @@ -1,23 +0,0 @@ -package scala - -/** - * A library that provides both asynchronous and synchronous messaging to allow - * for concurrent programming without explicit synchronization. - * - * == Guide == - * - * A detailed guide for the actors library is available - * [[http://docs.scala-lang.org/overviews/core/actors.html]]. - * - * == Getting Started == - * - * A starting point for using the actors library would be [[scala.actors.Reactor]], - * [[scala.actors.ReplyReactor]], or [[scala.actors.Actor]] or their companion objects. - * - * @note As of release 2.10.1, replaced by <code>akka.actor</code> package. For migration of existing actors refer to the Actors Migration Guide. - */ -package object actors { - - // type of Reactors tracked by termination detector - private[actors] type TrackedReactor = Reactor[A] forSome { type A >: Null } -} diff --git a/src/actors/scala/actors/remote/FreshNameCreator.scala b/src/actors/scala/actors/remote/FreshNameCreator.scala deleted file mode 100644 index f7cf29387e..0000000000 --- a/src/actors/scala/actors/remote/FreshNameCreator.scala +++ /dev/null @@ -1,36 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2005-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - - -package scala.actors -package remote - -object FreshNameCreator { - - protected var counter = 0 - protected val counters = new scala.collection.mutable.HashMap[String, Int] - - /** - * Create a fresh name with the given prefix. It is guaranteed - * that the returned name has never been returned by a previous - * call to this function (provided the prefix does not end in a digit). - */ - def newName(prefix: String): Symbol = { - val count = counters.get(prefix) match { - case Some(last) => last + 1 - case None => 0 - } - counters.update(prefix, count) - Symbol(prefix + count) - } - - def newName(): Symbol = { - counter += 1 - Symbol("$" + counter + "$") - } -} diff --git a/src/actors/scala/actors/remote/JavaSerializer.scala b/src/actors/scala/actors/remote/JavaSerializer.scala deleted file mode 100644 index 7549bbf429..0000000000 --- a/src/actors/scala/actors/remote/JavaSerializer.scala +++ /dev/null @@ -1,63 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2005-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - - -package scala.actors -package remote - -import java.io.{ByteArrayInputStream, ByteArrayOutputStream, - ObjectInputStream, ObjectOutputStream, InputStream, - ObjectStreamClass} - -/** - * @author Guy Oliver - */ -private[remote] class CustomObjectInputStream(in: InputStream, cl: ClassLoader) -extends ObjectInputStream(in) { - override def resolveClass(cd: ObjectStreamClass): Class[_] = - try { - cl.loadClass(cd.getName()) - } catch { - case cnf: ClassNotFoundException => - super.resolveClass(cd) - } - override def resolveProxyClass(interfaces: Array[String]): Class[_] = - try { - val ifaces = interfaces map { iface => cl.loadClass(iface) } - java.lang.reflect.Proxy.getProxyClass(cl, ifaces: _*) - } catch { - case e: ClassNotFoundException => - super.resolveProxyClass(interfaces) - } -} - -/** - * @author Philipp Haller - */ -@deprecated("Use the akka.actor package instead. For migration from the scala.actors package refer to the Actors Migration Guide.", "2.11.0") -class JavaSerializer(serv: Service, cl: ClassLoader) extends Serializer(serv) { - def serialize(o: AnyRef): Array[Byte] = { - val bos = new ByteArrayOutputStream() - val out = new ObjectOutputStream(bos) - out.writeObject(o) - out.flush() - bos.toByteArray() - } - - def deserialize(bytes: Array[Byte]): AnyRef = { - val bis = new ByteArrayInputStream(bytes) - - // use custom stream only if cl != null - val in = if (cl != null) - new CustomObjectInputStream(bis, cl) - else - new ObjectInputStream(bis) - - in.readObject() - } -} diff --git a/src/actors/scala/actors/remote/NetKernel.scala b/src/actors/scala/actors/remote/NetKernel.scala deleted file mode 100644 index 57d7af6d26..0000000000 --- a/src/actors/scala/actors/remote/NetKernel.scala +++ /dev/null @@ -1,147 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2005-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - - -package scala.actors -package remote - -import scala.collection.mutable - -case class NamedSend(senderLoc: Locator, receiverLoc: Locator, data: Array[Byte], session: Symbol) - -case class RemoteApply0(senderLoc: Locator, receiverLoc: Locator, rfun: Function2[AbstractActor, Proxy, Unit]) -case class LocalApply0(rfun: Function2[AbstractActor, Proxy, Unit], a: AbstractActor) - -case class SendTo(a: OutputChannel[Any], msg: Any, session: Symbol) -case object Terminate - -case class Locator(node: Node, name: Symbol) - -/** - * @version 0.9.17 - * @author Philipp Haller - */ -private[remote] class NetKernel(service: Service) { - - def sendToNode(node: Node, msg: AnyRef) = { - val bytes = service.serializer.serialize(msg) - service.send(node, bytes) - } - - def namedSend(senderLoc: Locator, receiverLoc: Locator, - msg: AnyRef, session: Symbol) { - val bytes = service.serializer.serialize(msg) - sendToNode(receiverLoc.node, NamedSend(senderLoc, receiverLoc, bytes, session)) - } - - private val actors = new mutable.HashMap[Symbol, OutputChannel[Any]] - private val names = new mutable.HashMap[OutputChannel[Any], Symbol] - - def register(name: Symbol, a: OutputChannel[Any]): Unit = synchronized { - actors(name) = a - names(a) = name - } - - def getOrCreateName(from: OutputChannel[Any]) = names.get(from) match { - case None => - val freshName = FreshNameCreator.newName("remotesender") - register(freshName, from) - freshName - case Some(name) => - name - } - - def send(node: Node, name: Symbol, msg: AnyRef): Unit = - send(node, name, msg, 'nosession) - - def send(node: Node, name: Symbol, msg: AnyRef, session: Symbol) { - val senderLoc = Locator(service.node, getOrCreateName(Actor.self(Scheduler))) - val receiverLoc = Locator(node, name) - namedSend(senderLoc, receiverLoc, msg, session) - } - - def forward(from: OutputChannel[Any], node: Node, name: Symbol, msg: AnyRef, session: Symbol) { - val senderLoc = Locator(service.node, getOrCreateName(from)) - val receiverLoc = Locator(node, name) - namedSend(senderLoc, receiverLoc, msg, session) - } - - def remoteApply(node: Node, name: Symbol, from: OutputChannel[Any], rfun: Function2[AbstractActor, Proxy, Unit]) { - val senderLoc = Locator(service.node, getOrCreateName(from)) - val receiverLoc = Locator(node, name) - sendToNode(receiverLoc.node, RemoteApply0(senderLoc, receiverLoc, rfun)) - } - - def createProxy(node: Node, sym: Symbol): Proxy = { - val p = new Proxy(node, sym, this) - proxies((node, sym)) = p - p - } - - val proxies = new mutable.HashMap[(Node, Symbol), Proxy] - - def getOrCreateProxy(senderNode: Node, senderName: Symbol): Proxy = - proxies.synchronized { - proxies.get((senderNode, senderName)) match { - case Some(senderProxy) => senderProxy - case None => createProxy(senderNode, senderName) - } - } - - /* Register proxy if no other proxy has been registered. - */ - def registerProxy(senderNode: Node, senderName: Symbol, p: Proxy): Unit = - proxies.synchronized { - proxies.get((senderNode, senderName)) match { - case Some(senderProxy) => // do nothing - case None => proxies((senderNode, senderName)) = p - } - } - - def processMsg(senderNode: Node, msg: AnyRef): Unit = synchronized { - msg match { - case cmd@RemoteApply0(senderLoc, receiverLoc, rfun) => - Debug.info(this+": processing "+cmd) - actors.get(receiverLoc.name) match { - case Some(a) => - val senderProxy = getOrCreateProxy(senderLoc.node, senderLoc.name) - senderProxy.send(LocalApply0(rfun, a.asInstanceOf[AbstractActor]), null) - - case None => - // message is lost - Debug.info(this+": lost message") - } - - case cmd@NamedSend(senderLoc, receiverLoc, data, session) => - Debug.info(this+": processing "+cmd) - actors.get(receiverLoc.name) match { - case Some(a) => - try { - val msg = service.serializer.deserialize(data) - val senderProxy = getOrCreateProxy(senderLoc.node, senderLoc.name) - senderProxy.send(SendTo(a, msg, session), null) - } catch { - case e: Exception => - Debug.error(this+": caught "+e) - } - - case None => - // message is lost - Debug.info(this+": lost message") - } - } - } - - def terminate() { - // tell all proxies to terminate - proxies.values foreach { _.send(Terminate, null) } - - // tell service to terminate - service.terminate() - } -} diff --git a/src/actors/scala/actors/remote/Proxy.scala b/src/actors/scala/actors/remote/Proxy.scala deleted file mode 100644 index 2cb03544f2..0000000000 --- a/src/actors/scala/actors/remote/Proxy.scala +++ /dev/null @@ -1,190 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2005-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - - -package scala.actors -package remote - -import scala.collection.mutable - -/** - * @author Philipp Haller - */ -private[remote] class Proxy(node: Node, name: Symbol, @transient var kernel: NetKernel) extends AbstractActor with Serializable { - import java.io.{IOException, ObjectOutputStream, ObjectInputStream} - - type Future[+P] = scala.actors.Future[P] - - @transient - private[remote] var del: Actor = null - startDelegate() - - @throws(classOf[IOException]) - private def writeObject(out: ObjectOutputStream) { - out.defaultWriteObject() - } - - @throws(classOf[ClassNotFoundException]) @throws(classOf[IOException]) - private def readObject(in: ObjectInputStream) { - in.defaultReadObject() - setupKernel() - startDelegate() - } - - private def startDelegate() { - del = new DelegateActor(this, node, name, kernel) - del.start() - } - - private def setupKernel() { - kernel = RemoteActor.someNetKernel - kernel.registerProxy(node, name, this) - } - - def !(msg: Any): Unit = - del ! msg - - def send(msg: Any, replyCh: OutputChannel[Any]): Unit = - del.send(msg, replyCh) - - def forward(msg: Any): Unit = - del.forward(msg) - - def receiver: Actor = - del - - def !?(msg: Any): Any = - del !? msg - - def !?(msec: Long, msg: Any): Option[Any] = - del !? (msec, msg) - - def !!(msg: Any): Future[Any] = - del !! msg - - def !![A](msg: Any, f: PartialFunction[Any, A]): Future[A] = - del !! (msg, f) - - def linkTo(to: AbstractActor): Unit = - del ! Apply0(new LinkToFun) - - def unlinkFrom(from: AbstractActor): Unit = - del ! Apply0(new UnlinkFromFun) - - def exit(from: AbstractActor, reason: AnyRef): Unit = - del ! Apply0(new ExitFun(reason)) - - override def toString() = - name+"@"+node -} - -// Proxy is private[remote], but these classes are public and use it in a public -// method signature. That makes the only method they have non-overridable. -// So I made them final, which seems appropriate anyway. - -final class LinkToFun extends Function2[AbstractActor, Proxy, Unit] with Serializable { - def apply(target: AbstractActor, creator: Proxy) { - target.linkTo(creator) - } - override def toString = - "<LinkToFun>" -} - -final class UnlinkFromFun extends Function2[AbstractActor, Proxy, Unit] with Serializable { - def apply(target: AbstractActor, creator: Proxy) { - target.unlinkFrom(creator) - } - override def toString = - "<UnlinkFromFun>" -} - -final class ExitFun(reason: AnyRef) extends Function2[AbstractActor, Proxy, Unit] with Serializable { - def apply(target: AbstractActor, creator: Proxy) { - target.exit(creator, reason) - } - override def toString = - "<ExitFun>("+reason.toString+")" -} - -private[remote] case class Apply0(rfun: Function2[AbstractActor, Proxy, Unit]) - -/** - * @author Philipp Haller - */ -private[remote] class DelegateActor(creator: Proxy, node: Node, name: Symbol, kernel: NetKernel) extends Actor { - var channelMap = new mutable.HashMap[Symbol, OutputChannel[Any]] - var sessionMap = new mutable.HashMap[OutputChannel[_], Symbol] - - def act() { - Actor.loop { - react { - case cmd@Apply0(rfun) => - kernel.remoteApply(node, name, sender, rfun) - - case cmd@LocalApply0(rfun, target) => - rfun(target, creator) - - // Request from remote proxy. - // `this` is local proxy. - case cmd@SendTo(out, msg, session) => - if (session.name == "nosession") { - // local send - out.send(msg, this) - } else { - // is this an active session? - channelMap.get(session) match { - case None => - // create a new reply channel... - val replyCh = new Channel[Any](this) - // ...that maps to session - sessionMap(replyCh) = session - // local send - out.send(msg, replyCh) - - // finishes request-reply cycle - case Some(replyCh) => - channelMap -= session - replyCh ! msg - } - } - - case cmd@Terminate => - exit() - - // local proxy receives response to - // reply channel - case ch ! resp => - // lookup session ID - sessionMap.get(ch) match { - case Some(sid) => - sessionMap -= ch - val msg = resp.asInstanceOf[AnyRef] - // send back response - kernel.forward(sender, node, name, msg, sid) - - case None => - Debug.info(this+": cannot find session for "+ch) - } - - // remote proxy receives request - case msg: AnyRef => - // find out whether it's a synchronous send - if (sender.getClass.toString.contains("Channel")) { - // create fresh session ID... - val fresh = FreshNameCreator.newName(node+"@"+name) - // ...that maps to reply channel - channelMap(fresh) = sender - kernel.forward(sender, node, name, msg, fresh) - } else { - kernel.forward(sender, node, name, msg, 'nosession) - } - } - } - } - -} diff --git a/src/actors/scala/actors/remote/RemoteActor.scala b/src/actors/scala/actors/remote/RemoteActor.scala deleted file mode 100644 index 2daf9ceb43..0000000000 --- a/src/actors/scala/actors/remote/RemoteActor.scala +++ /dev/null @@ -1,132 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2005-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - - - -package scala.actors -package remote - - -/** - * This object provides methods for creating, registering, and - * selecting remotely accessible actors. - * - * A remote actor is typically created like this: - * {{{ - * actor { - * alive(9010) - * register('myName, self) - * - * // behavior - * } - * }}} - * It can be accessed by an actor running on a (possibly) - * different node by selecting it in the following way: - * {{{ - * actor { - * // ... - * val c = select(Node("127.0.0.1", 9010), 'myName) - * c ! msg - * // ... - * } - * }}} - * - * @author Philipp Haller - */ -@deprecated("Use the akka.actor package instead. For migration from the scala.actors package refer to the Actors Migration Guide.", "2.11.0") -object RemoteActor { - - private val kernels = new scala.collection.mutable.HashMap[InternalActor, NetKernel] - - /* If set to <code>null</code> (default), the default class loader - * of <code>java.io.ObjectInputStream</code> is used for deserializing - * objects sent as messages. - */ - private var cl: ClassLoader = null - - def classLoader: ClassLoader = cl - def classLoader_=(x: ClassLoader) { cl = x } - - /** - * Makes <code>self</code> remotely accessible on TCP port - * <code>port</code>. - */ - def alive(port: Int): Unit = synchronized { - createNetKernelOnPort(port) - } - - private def createNetKernelOnPort(port: Int): NetKernel = { - val serv = TcpService(port, cl) - val kern = serv.kernel - val s = Actor.self(Scheduler) - kernels(s) = kern - - s.onTerminate { - Debug.info("alive actor "+s+" terminated") - // remove mapping for `s` - kernels -= s - // terminate `kern` when it does - // not appear as value any more - if (!kernels.valuesIterator.contains(kern)) { - Debug.info("terminating "+kern) - // terminate NetKernel - kern.terminate() - } - } - - kern - } - - /** - * Registers <code>a</code> under <code>name</code> on this - * node. - */ - def register(name: Symbol, a: Actor): Unit = synchronized { - val kernel = kernels.get(Actor.self(Scheduler)) match { - case None => - val serv = TcpService(TcpService.generatePort, cl) - kernels(Actor.self(Scheduler)) = serv.kernel - serv.kernel - case Some(k) => - k - } - kernel.register(name, a) - } - - private def selfKernel = kernels.get(Actor.self(Scheduler)) match { - case None => - // establish remotely accessible - // return path (sender) - createNetKernelOnPort(TcpService.generatePort) - case Some(k) => - k - } - - /** - * Returns (a proxy for) the actor registered under - * <code>name</code> on <code>node</code>. - */ - def select(node: Node, sym: Symbol): AbstractActor = synchronized { - selfKernel.getOrCreateProxy(node, sym) - } - - private[remote] def someNetKernel: NetKernel = - kernels.valuesIterator.next -} - - -/** - * This class represents a machine node on a TCP network. - * - * @param address the host name, or <code>null</code> for the loopback address. - * @param port the port number. - * - * @author Philipp Haller - */ -@deprecated("Use the akka.actor package instead. For migration from the scala.actors package refer to the Actors Migration Guide.", "2.11.0") -case class Node(address: String, port: Int) diff --git a/src/actors/scala/actors/remote/Serializer.scala b/src/actors/scala/actors/remote/Serializer.scala deleted file mode 100644 index 7be4aa6583..0000000000 --- a/src/actors/scala/actors/remote/Serializer.scala +++ /dev/null @@ -1,58 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2005-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - - - -package scala.actors -package remote - - -import java.lang.ClassNotFoundException - -import java.io.{DataInputStream, DataOutputStream, EOFException, IOException} - -@deprecated("Use the akka.actor package instead. For migration from the scala.actors package refer to the Actors Migration Guide.", "2.11.0") -abstract class Serializer(val service: Service) { - def serialize(o: AnyRef): Array[Byte] - def deserialize(a: Array[Byte]): AnyRef - - @throws(classOf[IOException]) - private def readBytes(inputStream: DataInputStream): Array[Byte] = { - try { - val length = inputStream.readInt() - val bytes = new Array[Byte](length) - inputStream.readFully(bytes, 0, length) - bytes - } - catch { - case npe: NullPointerException => - throw new EOFException("Connection closed.") - } - } - - @throws(classOf[IOException]) @throws(classOf[ClassNotFoundException]) - def readObject(inputStream: DataInputStream): AnyRef = { - val bytes = readBytes(inputStream) - deserialize(bytes) - } - - @throws(classOf[IOException]) - private def writeBytes(outputStream: DataOutputStream, bytes: Array[Byte]) { - val length = bytes.length; - // original length - outputStream.writeInt(length) - outputStream.write(bytes, 0, length) - outputStream.flush() - } - - @throws(classOf[IOException]) - def writeObject(outputStream: DataOutputStream, obj: AnyRef) { - val bytes = serialize(obj) - writeBytes(outputStream, bytes) - } -} diff --git a/src/actors/scala/actors/remote/Service.scala b/src/actors/scala/actors/remote/Service.scala deleted file mode 100644 index d102df1970..0000000000 --- a/src/actors/scala/actors/remote/Service.scala +++ /dev/null @@ -1,24 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2005-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - - -package scala.actors -package remote - -/** - * @version 0.9.10 - * @author Philipp Haller - */ -@deprecated("Use the akka.actor package instead. For migration from the scala.actors package refer to the Actors Migration Guide.", "2.11.0") -trait Service { - val kernel = new NetKernel(this) - val serializer: Serializer - def node: Node - def send(node: Node, data: Array[Byte]): Unit - def terminate(): Unit -} diff --git a/src/actors/scala/actors/remote/TcpService.scala b/src/actors/scala/actors/remote/TcpService.scala deleted file mode 100644 index 69e5c46c52..0000000000 --- a/src/actors/scala/actors/remote/TcpService.scala +++ /dev/null @@ -1,292 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2005-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - - - -package scala.actors -package remote - - -import java.io.{DataInputStream, DataOutputStream, IOException} -import java.lang.{Thread, SecurityException} -import java.net.{InetAddress, InetSocketAddress, ServerSocket, Socket, SocketTimeoutException, UnknownHostException} - -import scala.collection.mutable -import scala.util.Random - -/* Object TcpService. - * - * @version 0.9.9 - * @author Philipp Haller - */ -@deprecated("Use the akka.actor package instead. For migration from the scala.actors package refer to the Actors Migration Guide.", "2.11.0") -object TcpService { - private val random = new Random - private val ports = new mutable.HashMap[Int, TcpService] - - def apply(port: Int, cl: ClassLoader): TcpService = - ports.get(port) match { - case Some(service) => - service - case None => - val service = new TcpService(port, cl) - ports(port) = service - service.start() - Debug.info("created service at "+service.node) - service - } - - def generatePort: Int = { - var portnum = 0 - try { - portnum = 8000 + random.nextInt(500) - val socket = new ServerSocket(portnum) - socket.close() - } - catch { - case ioe: IOException => - // this happens when trying to open a socket twice - // at the same port - // try again - generatePort - case se: SecurityException => - // do nothing - } - portnum - } - - private val connectTimeoutMillis = { - val propName = "scala.actors.tcpSocket.connectTimeoutMillis" - val defaultTimeoutMillis = 0 - sys.props get propName flatMap { - timeout => - try { - val to = timeout.toInt - Debug.info(s"Using socket timeout $to") - Some(to) - } catch { - case e: NumberFormatException => - Debug.warning(s"""Could not parse $propName = "$timeout" as an Int""") - None - } - } getOrElse defaultTimeoutMillis - } - - var BufSize: Int = 65536 -} - -/* Class TcpService. - * - * @version 0.9.10 - * @author Philipp Haller - */ -@deprecated("Use the akka.actor package instead. For migration from the scala.actors package refer to the Actors Migration Guide.", "2.11.0") -class TcpService(port: Int, cl: ClassLoader) extends Thread with Service { - val serializer: JavaSerializer = new JavaSerializer(this, cl) - - private val internalNode = new Node(InetAddress.getLocalHost().getHostAddress(), port) - def node: Node = internalNode - - private val pendingSends = new mutable.HashMap[Node, List[Array[Byte]]] - - /** - * Sends a byte array to another node on the network. - * If the node is not yet up, up to `TcpService.BufSize` - * messages are buffered. - */ - def send(node: Node, data: Array[Byte]): Unit = synchronized { - - def bufferMsg(t: Throwable) { - // buffer message, so that it can be re-sent - // when remote net kernel comes up - (pendingSends.get(node): @unchecked) match { - case None => - pendingSends(node) = List(data) - case Some(msgs) if msgs.length < TcpService.BufSize => - pendingSends(node) = data :: msgs - } - } - - // retrieve worker thread (if any) that already has connection - getConnection(node) match { - case None => - // we are not connected, yet - try { - val newWorker = connect(node) - - // any pending sends? - pendingSends.get(node) match { - case None => - // do nothing - case Some(msgs) => - msgs.reverse foreach {newWorker transmit _} - pendingSends -= node - } - - newWorker transmit data - } catch { - case uhe: UnknownHostException => - bufferMsg(uhe) - case ioe: IOException => - bufferMsg(ioe) - case se: SecurityException => - // do nothing - } - case Some(worker) => - worker transmit data - } - } - - def terminate() { - shouldTerminate = true - try { - new Socket(internalNode.address, internalNode.port) - } catch { - case ce: java.net.ConnectException => - Debug.info(this+": caught "+ce) - } - } - - private var shouldTerminate = false - - override def run() { - try { - val socket = new ServerSocket(port) - while (!shouldTerminate) { - Debug.info(this+": waiting for new connection on port "+port+"...") - val nextClient = socket.accept() - if (!shouldTerminate) { - val worker = new TcpServiceWorker(this, nextClient) - Debug.info("Started new "+worker) - worker.readNode - worker.start() - } else - nextClient.close() - } - } catch { - case e: Exception => - Debug.info(this+": caught "+e) - } finally { - Debug.info(this+": shutting down...") - connections foreach { case (_, worker) => worker.halt } - } - } - - // connection management - - private val connections = - new mutable.HashMap[Node, TcpServiceWorker] - - private[actors] def addConnection(node: Node, worker: TcpServiceWorker) = synchronized { - connections(node) = worker - } - - def getConnection(n: Node) = synchronized { - connections.get(n) - } - - def isConnected(n: Node): Boolean = synchronized { - !connections.get(n).isEmpty - } - - def connect(n: Node): TcpServiceWorker = synchronized { - val socket = new Socket() - val start = System.nanoTime - try { - socket.connect(new InetSocketAddress(n.address, n.port), TcpService.connectTimeoutMillis) - } catch { - case e: SocketTimeoutException => - Debug.warning(f"Timed out connecting to $n after ${(System.nanoTime - start) / math.pow(10, 9)}%.3f seconds") - throw e - } - val worker = new TcpServiceWorker(this, socket) - worker.sendNode(n) - worker.start() - addConnection(n, worker) - worker - } - - def disconnectNode(n: Node) = synchronized { - connections.get(n) match { - case None => - // do nothing - case Some(worker) => - connections -= n - worker.halt - } - } - - def isReachable(node: Node): Boolean = - if (isConnected(node)) true - else try { - connect(node) - return true - } catch { - case uhe: UnknownHostException => false - case ioe: IOException => false - case se: SecurityException => false - } - - def nodeDown(mnode: Node): Unit = synchronized { - connections -= mnode - } -} - - -private[actors] class TcpServiceWorker(parent: TcpService, so: Socket) extends Thread { - val datain = new DataInputStream(so.getInputStream) - val dataout = new DataOutputStream(so.getOutputStream) - - var connectedNode: Node = _ - - def sendNode(n: Node) { - connectedNode = n - parent.serializer.writeObject(dataout, parent.node) - } - - def readNode() { - val node = parent.serializer.readObject(datain) - node match { - case n: Node => - connectedNode = n - parent.addConnection(n, this) - } - } - - def transmit(data: Array[Byte]): Unit = synchronized { - Debug.info(this+": transmitting data...") - dataout.writeInt(data.length) - dataout.write(data) - dataout.flush() - } - - var running = true - - def halt() = synchronized { - so.close() - running = false - } - - override def run() { - try { - while (running) { - val msg = parent.serializer.readObject(datain); - parent.kernel.processMsg(connectedNode, msg) - } - } - catch { - case ioe: IOException => - Debug.info(this+": caught "+ioe) - parent nodeDown connectedNode - case e: Exception => - Debug.info(this+": caught "+e) - parent nodeDown connectedNode - } - Debug.info(this+": service terminated at "+parent.node) - } -} diff --git a/src/actors/scala/actors/scheduler/ActorGC.scala b/src/actors/scala/actors/scheduler/ActorGC.scala deleted file mode 100644 index a27799d132..0000000000 --- a/src/actors/scala/actors/scheduler/ActorGC.scala +++ /dev/null @@ -1,101 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2005-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - - -package scala.actors -package scheduler - -import java.lang.ref.{Reference, WeakReference, ReferenceQueue} -import scala.collection.mutable - -/** - * ActorGC keeps track of the number of live actors being managed by a - * a scheduler so that it can shutdown when all of the actors it manages have - * either been explicitly terminated or garbage collected. - * - * When an actor is started, it is registered with the ActorGC via the - * `newActor` method, and when an actor is knowingly terminated - * (e.g. act method finishes, exit explicitly called, an exception is thrown), - * the ActorGC is informed via the `terminated` method. - */ -@deprecated("Use the akka.actor package instead. For migration from the scala.actors package refer to the Actors Migration Guide.", "2.11.0") -trait ActorGC extends TerminationMonitor { - self: IScheduler => - - /** Actors are added to refQ in newActor. */ - private val refQ = new ReferenceQueue[TrackedReactor] - - /** - * This is a set of references to all the actors registered with - * this ActorGC. It is maintained so that the WeakReferences will - * not be GC'd before the actors to which they point. - */ - private val refSet = new mutable.HashSet[Reference[t] forSome { type t <: TrackedReactor }] - - /** newActor is invoked whenever a new actor is started. */ - override def newActor(a: TrackedReactor) = synchronized { - // registers a reference to the actor with the ReferenceQueue - val wr = new WeakReference[TrackedReactor](a, refQ) - refSet += wr - activeActors += 1 - } - - /** Checks for actors that have become garbage. */ - protected override def gc() = synchronized { - // check for unreachable actors - def drainRefQ() { - val wr = refQ.poll - if (wr != null) { - activeActors -= 1 - refSet -= wr - // continue draining - drainRefQ() - } - } - drainRefQ() - } - - /** Prints some status information on currently managed actors. */ - protected def status() { - println(this+": size of refSet: "+refSet.size) - } - - /** Checks whether all actors have terminated. */ - override private[actors] def allActorsTerminated: Boolean = synchronized { - activeActors <= 0 - } - - override def onTerminate(a: TrackedReactor)(f: => Unit): Unit = synchronized { - terminationHandlers += (a -> (() => f)) - } - - override def terminated(a: TrackedReactor) = { - super.terminated(a) - - synchronized { - // find the weak reference that points to the terminated actor, if any - refSet.find((ref: Reference[t] forSome { type t <: TrackedReactor }) => ref.get() == a) match { - case Some(r) => - // invoking clear will not cause r to be enqueued - r.clear() - refSet -= r.asInstanceOf[Reference[t] forSome { type t <: TrackedReactor }] - case None => - // do nothing - } - } - } - - private[actors] def getPendingCount = synchronized { - activeActors - } - - private[actors] def setPendingCount(cnt: Int) = synchronized { - activeActors = cnt - } - -} diff --git a/src/actors/scala/actors/scheduler/DaemonScheduler.scala b/src/actors/scala/actors/scheduler/DaemonScheduler.scala deleted file mode 100644 index b21a1aa3e6..0000000000 --- a/src/actors/scala/actors/scheduler/DaemonScheduler.scala +++ /dev/null @@ -1,34 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2005-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - -package scala.actors -package scheduler - -/** - * Default scheduler for actors with daemon semantics, such as those backing futures. - * - * @author Erik Engbrecht - */ -@deprecated("Use the akka.actor package instead. For migration from the scala.actors package refer to the Actors Migration Guide.", "2.11.0") -object DaemonScheduler extends DelegatingScheduler { - - protected def makeNewScheduler(): IScheduler = { - val sched = if (!ThreadPoolConfig.useForkJoin) { - val s = new ResizableThreadPoolScheduler(true) - s.start() - s - } else { - val s = new ForkJoinScheduler(true) - s.start() - s - } - Debug.info(this+": starting new "+sched+" ["+sched.getClass+"]") - sched - } - -} diff --git a/src/actors/scala/actors/scheduler/DelegatingScheduler.scala b/src/actors/scala/actors/scheduler/DelegatingScheduler.scala deleted file mode 100644 index b8a81d11a9..0000000000 --- a/src/actors/scala/actors/scheduler/DelegatingScheduler.scala +++ /dev/null @@ -1,74 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2005-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - -package scala.actors -package scheduler - -import scala.concurrent.ManagedBlocker - -/** - * @author Erik Engbrecht - */ -private[actors] trait DelegatingScheduler extends IScheduler { - protected def makeNewScheduler(): IScheduler - - protected var sched: IScheduler = null - - final def impl = synchronized { - if ((sched eq null) || (!sched.isActive)) - sched = makeNewScheduler() - sched - } - - final def impl_= (scheduler: IScheduler): Unit = synchronized { - //TODO: if there is already a scheduler, should it be shutdown? - sched = scheduler - } - - /** - * Always active because it will just make a new scheduler if required - */ - def isActive: Boolean = true - - def execute(fun: => Unit) = impl.execute(fun) - - def execute(task: Runnable) = impl.execute(task) - - override def executeFromActor(task: Runnable) = impl.executeFromActor(task) - - def shutdown(): Unit = synchronized { - if (sched ne null) { - sched.shutdown() - sched = null - } - } - - def newActor(actor: TrackedReactor) = synchronized { - val createNew = if (sched eq null) - true - else sched.synchronized { - if (!sched.isActive) - true - else { - sched.newActor(actor) - false - } - } - if (createNew) { - sched = makeNewScheduler() - sched.newActor(actor) - } - } - - def terminated(actor: TrackedReactor) = impl.terminated(actor) - - def onTerminate(actor: TrackedReactor)(f: => Unit) = impl.onTerminate(actor)(f) - - override def managedBlock(blocker: ManagedBlocker): Unit = - impl.managedBlock(blocker) -} diff --git a/src/actors/scala/actors/scheduler/DrainableForkJoinPool.scala b/src/actors/scala/actors/scheduler/DrainableForkJoinPool.scala deleted file mode 100644 index 37710ec037..0000000000 --- a/src/actors/scala/actors/scheduler/DrainableForkJoinPool.scala +++ /dev/null @@ -1,11 +0,0 @@ -package scala.actors -package scheduler - -import java.util.Collection -import scala.concurrent.forkjoin.{ForkJoinPool, ForkJoinTask} - -private class DrainableForkJoinPool(parallelism: Int, maxPoolSize: Int) extends ForkJoinPool(parallelism, ForkJoinPool.defaultForkJoinWorkerThreadFactory, null, true) { - - override def drainTasksTo(c: Collection[ _ >: ForkJoinTask[_]]): Int = - super.drainTasksTo(c) -} diff --git a/src/actors/scala/actors/scheduler/ExecutorScheduler.scala b/src/actors/scala/actors/scheduler/ExecutorScheduler.scala deleted file mode 100644 index 4d3ebc3c04..0000000000 --- a/src/actors/scala/actors/scheduler/ExecutorScheduler.scala +++ /dev/null @@ -1,95 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2005-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - - -package scala.actors -package scheduler - -import java.util.concurrent.{Callable, ExecutorService} -import scala.concurrent.ThreadPoolRunner - -/** - * The <code>ExecutorScheduler</code> object is used to create - * <code>ExecutorScheduler</code> instances. - * - * @author Philipp Haller - */ -@deprecated("Use the akka.actor package instead. For migration from the scala.actors package refer to the Actors Migration Guide.", "2.11.0") -object ExecutorScheduler { - - private def start(sched: ExecutorScheduler): ExecutorScheduler = { - sched.start() - sched - } - - /** Creates an <code>ExecutorScheduler</code> using the provided - * <code>ExecutorService</code>. - * - * @param exec the executor to use - * @return the scheduler - */ - def apply(exec: ExecutorService): ExecutorScheduler = - start(new ExecutorScheduler { - val executor: ExecutorService = exec - }) - - /** Creates an <code>ExecutorScheduler</code> using the provided - * <code>ExecutorService</code>. - * - * @param exec the executor to use - * @param term whether the scheduler should automatically terminate - * @return the scheduler - */ - def apply(exec: ExecutorService, term: Boolean): ExecutorScheduler = - start(new ExecutorScheduler { - val executor: ExecutorService = exec - override val terminate = term - }) - -} - -/** - * The <code>ExecutorScheduler</code> class uses an - * <code>ExecutorService</code> to execute <code>Actor</code>s. - * - * @author Philipp Haller - */ -@deprecated("Use the akka.actor package instead. For migration from the scala.actors package refer to the Actors Migration Guide.", "2.11.0") -trait ExecutorScheduler extends Thread - with IScheduler with TerminationService - with ThreadPoolRunner { - - def execute(task: Runnable) { - super[ThreadPoolRunner].execute(task.asInstanceOf[Task[Unit]]) - } - - private class RunCallable(fun: => Unit) extends Callable[Unit] with Runnable { - def call() { fun } - def run() { fun } - } - - /** Submits a closure for execution. - * - * @param fun the closure to be executed - */ - override def execute(fun: => Unit) { - super[ThreadPoolRunner].execute((new RunCallable(fun)).asInstanceOf[Task[Unit]]) - } - - /** This method is called when the scheduler shuts down. - */ - def onShutdown(): Unit = - executor.shutdown() - - /** The scheduler is active if the underlying <code>ExecutorService</code> - * has not been shut down. - */ - def isActive = - (executor ne null) && !executor.isShutdown - -} diff --git a/src/actors/scala/actors/scheduler/ForkJoinScheduler.scala b/src/actors/scala/actors/scheduler/ForkJoinScheduler.scala deleted file mode 100644 index 75a98db6c8..0000000000 --- a/src/actors/scala/actors/scheduler/ForkJoinScheduler.scala +++ /dev/null @@ -1,174 +0,0 @@ -package scala.actors -package scheduler - -import java.util.{Collection, ArrayList} -import scala.concurrent.forkjoin._ - -/** The <code>ForkJoinScheduler</code> is backed by a lightweight - * fork-join task execution framework. - * - * @author Philipp Haller - */ -@deprecated("Use the akka.actor package instead. For migration from the scala.actors package refer to the Actors Migration Guide.", "2.11.0") -class ForkJoinScheduler(val initCoreSize: Int, val maxSize: Int, daemon: Boolean, fair: Boolean) - extends Runnable with IScheduler with TerminationMonitor { - - private var pool = makeNewPool() // guarded by this - private var terminating = false // guarded by this - private var snapshoting = false // guarded by this - - // this has to be a java.util.Collection, since this is what - // the ForkJoinPool returns. - private var drainedTasks: Collection[ForkJoinTask[_]] = null - - protected val CHECK_FREQ = 10 - - // this random number generator is only used in fair mode - private lazy val random = new java.util.Random // guarded by random - - def this(d: Boolean, f: Boolean) { - this(ThreadPoolConfig.corePoolSize, ThreadPoolConfig.maxPoolSize, d, f) - } - - def this(d: Boolean) { - this(d, true) // default is fair - } - - def this() { - this(false) // default is non-daemon - } - - private def makeNewPool(): DrainableForkJoinPool = { - val p = new DrainableForkJoinPool(initCoreSize, maxSize) - Debug.info(this+": parallelism "+p.getParallelism()) - p - } - - /** Starts this scheduler. - */ - def start() { - try { - val t = new Thread(this) - t.setDaemon(daemon) - t.setName("ForkJoinScheduler") - t.start() - } catch { - case e: Exception => - Debug.info(this+": could not create scheduler thread: "+e) - } - } - - override def run() { - try { - while (true) { - this.synchronized { - try { - wait(CHECK_FREQ.toLong) - } catch { - case _: InterruptedException => - } - - if (terminating) - throw new QuitControl - - if (allActorsTerminated) { - Debug.info(this+": all actors terminated") - terminating = true - throw new QuitControl - } - - if (!snapshoting) { - gc() - } else if (pool.isQuiescent()) { - val list = new ArrayList[ForkJoinTask[_]] - val num = pool.drainTasksTo(list) - Debug.info(this+": drained "+num+" tasks") - drainedTasks = list - terminating = true - throw new QuitControl - } - } - } - } catch { - case _: QuitControl => - Debug.info(this+": initiating shutdown...") - while (!pool.isQuiescent()) { - try { - Thread.sleep(10) - } catch { - case ignore: InterruptedException => - } - } - pool.shutdown() - // allow thread to exit - } - } - - // TODO: when do we pass a task that is not a RecursiveAction? - def execute(task: Runnable) { - pool.execute(task) - } - - override def executeFromActor(task: Runnable) { - // in fair mode: 2% chance of submitting to global task queue - if (fair && random.synchronized { random.nextInt(50) == 1 }) - pool.execute(task) - else - task.asInstanceOf[RecursiveAction].fork() - } - - /** Submits a closure for execution. - * - * @param fun the closure to be executed - */ - def execute(fun: => Unit): Unit = - execute(new Runnable { - def run() { fun } - }) - - /** Shuts down the scheduler. - */ - def shutdown(): Unit = synchronized { - terminating = true - } - - def isActive = synchronized { - !terminating && (pool ne null) && !pool.isShutdown() - } - - override def managedBlock(blocker: scala.concurrent.ManagedBlocker) { - ForkJoinPool.managedBlock(new ForkJoinPool.ManagedBlocker { - def block = blocker.block() - def isReleasable() = blocker.isReleasable - }) - } - - /** Suspends the scheduler. All threads that were in use by the - * scheduler and its internal thread pool are terminated. - */ - def snapshot() = synchronized { - snapshoting = true - } - - /** Resumes the execution of the scheduler if it was previously - * suspended using <code>ForkJoinScheduler.snapshot</code>. - */ - def restart() { - synchronized { - if (!snapshoting) - sys.error("snapshot has not been invoked") - else if (isActive) - sys.error("scheduler is still active") - else - snapshoting = false - - pool = makeNewPool() - } - val iter = drainedTasks.iterator() - while (iter.hasNext()) { - pool.execute(iter.next()) - } - start() - } - -} diff --git a/src/actors/scala/actors/scheduler/QuitControl.scala b/src/actors/scala/actors/scheduler/QuitControl.scala deleted file mode 100644 index b3e288aaff..0000000000 --- a/src/actors/scala/actors/scheduler/QuitControl.scala +++ /dev/null @@ -1,19 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2005-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - -package scala.actors.scheduler - -import scala.util.control.ControlThrowable - -/** - * The `QuitControl` class is used to manage control flow of certain - * schedulers. - * - * @author Philipp Haller - */ -private[scheduler] class QuitControl extends ControlThrowable diff --git a/src/actors/scala/actors/scheduler/ResizableThreadPoolScheduler.scala b/src/actors/scala/actors/scheduler/ResizableThreadPoolScheduler.scala deleted file mode 100644 index 342579db6c..0000000000 --- a/src/actors/scala/actors/scheduler/ResizableThreadPoolScheduler.scala +++ /dev/null @@ -1,197 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2005-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - -package scala.actors.scheduler - -import scala.actors.threadpool.{ThreadPoolExecutor, TimeUnit, LinkedBlockingQueue, - ThreadFactory} -import scala.actors.{Debug, IScheduler} -import scala.concurrent.ManagedBlocker - -/** - * This scheduler class uses a `ThreadPoolExecutor` to execute `Actor`s. - * - * The scheduler attempts to shut down itself and the underlying - * `ThreadPoolExecutor` only if `terminate` is set to true. Otherwise, - * the scheduler must be shut down explicitly. - * - * @author Philipp Haller - */ -@deprecated("Use the akka.actor package instead. For migration from the scala.actors package refer to the Actors Migration Guide.", "2.11.0") -class ResizableThreadPoolScheduler(protected val terminate: Boolean, - protected val daemon: Boolean) - extends Thread with IScheduler with TerminationMonitor { - - setDaemon(daemon) - - // guarded by this - private var terminating = false - // guarded by this - private var suspending = false - - // this has to be a java.util.Collection, since this is what - // the ForkJoinPool returns. - @volatile - private var drainedTasks: java.util.List[_] = null - - // guarded by this - private var coreSize = ThreadPoolConfig.corePoolSize - private val maxSize = ThreadPoolConfig.maxPoolSize - private val numCores = Runtime.getRuntime().availableProcessors() - - protected val CHECK_FREQ = 10 - - private class DaemonThreadFactory extends ThreadFactory { - def newThread(r: Runnable): Thread = { - val t = new Thread(r) - t.setDaemon(daemon) - t - } - } - private val threadFac = new DaemonThreadFactory - - private def makeNewPool(): ThreadPoolExecutor = { - val workQueue = new LinkedBlockingQueue - new ThreadPoolExecutor(coreSize, - maxSize, - 60000L, - TimeUnit.MILLISECONDS, - workQueue, - threadFac, - new ThreadPoolExecutor.CallerRunsPolicy) - } - - // guarded by this - private var executor = makeNewPool() - - Debug.info(this+": corePoolSize = "+coreSize+", maxPoolSize = "+maxSize) - - def this(d: Boolean) { - this(true, d) - } - - def this() { - this(false) - } - - private def numWorkersBlocked = { - executor.mainLock.lock() - val iter = executor.workers.iterator() - var numBlocked = 0 - while (iter.hasNext()) { - val w = iter.next().asInstanceOf[ThreadPoolExecutor#Worker] - if (w.tryLock()) { - // worker is idle - w.unlock() - } else { - val s = w.thread.getState() - if (s == Thread.State.WAITING || s == Thread.State.TIMED_WAITING) - numBlocked += 1 - } - } - executor.mainLock.unlock() - numBlocked - } - - override def run() { - try { - while (true) { - this.synchronized { - try { - wait(CHECK_FREQ.toLong) - } catch { - case _: InterruptedException => - } - - if (terminating) - throw new QuitControl - - if (!suspending) { - gc() - - // check if we need more worker threads - val activeBlocked = numWorkersBlocked - if (coreSize - activeBlocked < numCores && coreSize < maxSize) { - coreSize = numCores + activeBlocked - executor.setCorePoolSize(coreSize) - } else if (terminate && allActorsTerminated) { - // if all worker threads idle terminate - if (executor.getActiveCount() == 0) { - Debug.info(this+": initiating shutdown...") - Debug.info(this+": corePoolSize = "+coreSize+", maxPoolSize = "+maxSize) - - terminating = true - throw new QuitControl - } - } - } else { - drainedTasks = executor.shutdownNow() - Debug.info(this+": drained "+drainedTasks.size()+" tasks") - terminating = true - throw new QuitControl - } - } // sync - } - } catch { - case _: QuitControl => - executor.shutdown() - // allow thread to exit - } - } - - def execute(task: Runnable): Unit = - executor execute task - - def execute(fun: => Unit): Unit = - executor.execute(new Runnable { - def run() { fun } - }) - - /** Shuts down the scheduler. - */ - def shutdown(): Unit = synchronized { - terminating = true - } - - def isActive = synchronized { - !terminating && (executor ne null) && !executor.isShutdown() - } - - def managedBlock(blocker: ManagedBlocker) { - blocker.block() - } - - /** Suspends the scheduler. All threads that were in use by the - * scheduler and its internal thread pool are terminated. - */ - def snapshot() = synchronized { - suspending = true - } - - /** Resumes the execution of the scheduler if it was previously - * suspended using `snapshot`. - */ - def restart() { - synchronized { - if (!suspending) - sys.error("snapshot has not been invoked") - else if (isActive) - sys.error("scheduler is still active") - else - suspending = false - - executor = makeNewPool() - } - val iter = drainedTasks.iterator() - while (iter.hasNext()) { - executor.execute(iter.next().asInstanceOf[Runnable]) - } - start() - } - -} diff --git a/src/actors/scala/actors/scheduler/SingleThreadedScheduler.scala b/src/actors/scala/actors/scheduler/SingleThreadedScheduler.scala deleted file mode 100644 index 03b235fe74..0000000000 --- a/src/actors/scala/actors/scheduler/SingleThreadedScheduler.scala +++ /dev/null @@ -1,69 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2005-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - - -package scala.actors -package scheduler - -import scala.collection.mutable - -/** - * This scheduler executes actor tasks on the current thread. - * - * @author Philipp Haller - */ -@deprecated("Use the akka.actor package instead. For migration from the scala.actors package refer to the Actors Migration Guide.", "2.11.0") -class SingleThreadedScheduler extends IScheduler { - - private val tasks = new mutable.Queue[Runnable] - - /** The maximum number of nested tasks that are run - * without unwinding the call stack. - */ - protected val maxNesting = 10 - - private var curNest = 0 - private var isShutdown = false - - def execute(task: Runnable) { - if (curNest < maxNesting) { - curNest += 1 - task.run() - } else { - curNest = 0 - tasks += task - } - } - - def execute(fun: => Unit): Unit = - execute(new Runnable { - def run() { fun } - }) - - def shutdown() { - isShutdown = false - while (!tasks.isEmpty) { - val task = tasks.dequeue() - task.run() - } - isShutdown = true - } - - def newActor(actor: TrackedReactor) {} - def terminated(actor: TrackedReactor) {} - - // TODO: run termination handlers at end of shutdown. - def onTerminate(actor: TrackedReactor)(f: => Unit) {} - - def isActive = - !isShutdown - - def managedBlock(blocker: scala.concurrent.ManagedBlocker) { - blocker.block() - } -} diff --git a/src/actors/scala/actors/scheduler/TerminationMonitor.scala b/src/actors/scala/actors/scheduler/TerminationMonitor.scala deleted file mode 100644 index 9f26ca8d69..0000000000 --- a/src/actors/scala/actors/scheduler/TerminationMonitor.scala +++ /dev/null @@ -1,69 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2005-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - -package scala.actors -package scheduler - -import scala.collection.mutable - -private[scheduler] trait TerminationMonitor { - _: IScheduler => - - protected var activeActors = 0 - protected val terminationHandlers = new mutable.HashMap[TrackedReactor, () => Unit] - private var started = false - - /** newActor is invoked whenever a new actor is started. */ - def newActor(a: TrackedReactor) = synchronized { - activeActors += 1 - if (!started) - started = true - } - - /** Registers a closure to be executed when the specified - * actor terminates. - * - * @param a the actor - * @param f the closure to be registered - */ - def onTerminate(a: TrackedReactor)(f: => Unit): Unit = synchronized { - terminationHandlers += (a -> (() => f)) - } - - /** Registers that the specified actor has terminated. - * - * @param a the actor that has terminated - */ - def terminated(a: TrackedReactor) = { - // obtain termination handler (if any) - val todo = synchronized { - terminationHandlers.get(a) match { - case Some(handler) => - terminationHandlers -= a - handler - case None => - () => { /* do nothing */ } - } - } - - // invoke termination handler (if any) - todo() - - synchronized { - activeActors -= 1 - } - } - - /** Checks whether all actors have terminated. */ - private[actors] def allActorsTerminated: Boolean = synchronized { - started && activeActors <= 0 - } - - /** Checks for actors that have become garbage. */ - protected def gc() {} -} diff --git a/src/actors/scala/actors/scheduler/TerminationService.scala b/src/actors/scala/actors/scheduler/TerminationService.scala deleted file mode 100644 index ed1805ee1e..0000000000 --- a/src/actors/scala/actors/scheduler/TerminationService.scala +++ /dev/null @@ -1,68 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2005-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - - -package scala.actors -package scheduler - -import java.lang.{Thread, InterruptedException} - -/** - * The <code>TerminationService</code> class starts a new thread - * that is used to check regularly if the scheduler can be - * shut down, because all started actors are known to - * have terminated. - * - * @author Philipp Haller - */ -private[scheduler] trait TerminationService extends TerminationMonitor { - _: Thread with IScheduler => - - private var terminating = false - - /** Indicates whether the scheduler should terminate when all - * actors have terminated. - */ - protected val terminate = true - - protected val CHECK_FREQ = 50 - - def onShutdown(): Unit - - override def run() { - try { - while (true) { - this.synchronized { - try { - wait(CHECK_FREQ.toLong) - } catch { - case _: InterruptedException => - } - - if (terminating || (terminate && allActorsTerminated)) - throw new QuitControl - - gc() - } - } - } catch { - case _: QuitControl => - Debug.info(this+": initiating shutdown...") - // invoke shutdown hook - onShutdown() - // allow thread to exit - } - } - - /** Shuts down the scheduler. - */ - def shutdown(): Unit = synchronized { - terminating = true - } - -} diff --git a/src/actors/scala/actors/scheduler/ThreadPoolConfig.scala b/src/actors/scala/actors/scheduler/ThreadPoolConfig.scala deleted file mode 100644 index bfd4e7ac40..0000000000 --- a/src/actors/scala/actors/scheduler/ThreadPoolConfig.scala +++ /dev/null @@ -1,50 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2005-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - - -package scala.actors -package scheduler - -import scala.util.Properties.{ javaVersion, javaVmVendor, isJavaAtLeast, propIsSetTo, propOrNone } - -/** - * @author Erik Engbrecht - * @author Philipp Haller - */ -private[actors] object ThreadPoolConfig { - private val rt = Runtime.getRuntime() - private val minNumThreads = 4 - - private def getIntegerProp(propName: String): Option[Int] = - try propOrNone(propName) map (_.toInt) - catch { case _: SecurityException | _: NumberFormatException => None } - - val corePoolSize = getIntegerProp("actors.corePoolSize") match { - case Some(i) if i > 0 => i - case _ => { - val byCores = rt.availableProcessors() * 2 - if (byCores > minNumThreads) byCores else minNumThreads - } - } - - val maxPoolSize = { - val preMaxSize = getIntegerProp("actors.maxPoolSize") getOrElse 256 - if (preMaxSize >= corePoolSize) preMaxSize else corePoolSize - } - - private[actors] def useForkJoin: Boolean = - try !propIsSetTo("actors.enableForkJoin", "false") && - (propIsSetTo("actors.enableForkJoin", "true") || { - Debug.info(this+": java.version = "+javaVersion) - Debug.info(this+": java.vm.vendor = "+javaVmVendor) - isJavaAtLeast("1.6") - }) - catch { - case _: SecurityException => false - } -} diff --git a/src/actors/scala/actors/threadpool/AbstractCollection.java b/src/actors/scala/actors/threadpool/AbstractCollection.java deleted file mode 100644 index 195a0064ab..0000000000 --- a/src/actors/scala/actors/threadpool/AbstractCollection.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Written by Dawid Kurzyniec, based on public domain code written by Doug Lea - * and publicly available documentation, and released to the public domain, as - * explained at http://creativecommons.org/licenses/publicdomain - */ - -package scala.actors.threadpool; -import scala.actors.threadpool.helpers.Utils; - -/** - * Overrides toArray() and toArray(Object[]) in AbstractCollection to provide - * implementations valid for concurrent collections. - * - * @author Doug Lea - * @author Dawid Kurzyniec - */ -public abstract class AbstractCollection extends java.util.AbstractCollection { - - /** - * Sole constructor. (For invocation by subclass constructors, typically - * implicit.) - */ - protected AbstractCollection() { super(); } - - public Object[] toArray() { - return Utils.collectionToArray(this); - } - - public Object[] toArray(Object[] a) { - return Utils.collectionToArray(this, a); - } -} diff --git a/src/actors/scala/actors/threadpool/AbstractExecutorService.java b/src/actors/scala/actors/threadpool/AbstractExecutorService.java deleted file mode 100644 index 4a12aa3c28..0000000000 --- a/src/actors/scala/actors/threadpool/AbstractExecutorService.java +++ /dev/null @@ -1,292 +0,0 @@ -/* - * Written by Doug Lea with assistance from members of JCP JSR-166 - * Expert Group and released to the public domain, as explained at - * http://creativecommons.org/licenses/publicdomain - */ - -package scala.actors.threadpool; - -import scala.actors.threadpool.helpers.*; -import java.util.Collection; -import java.util.ArrayList; -import java.util.List; -import java.util.Iterator; - -/** - * Provides default implementations of {@link ExecutorService} - * execution methods. This class implements the <tt>submit</tt>, - * <tt>invokeAny</tt> and <tt>invokeAll</tt> methods using a - * {@link RunnableFuture} returned by <tt>newTaskFor</tt>, which defaults - * to the {@link FutureTask} class provided in this package. For example, - * the implementation of <tt>submit(Runnable)</tt> creates an - * associated <tt>RunnableFuture</tt> that is executed and - * returned. Subclasses may override the <tt>newTaskFor</tt> methods - * to return <tt>RunnableFuture</tt> implementations other than - * <tt>FutureTask</tt>. - * - * <p> <b>Extension example</b>. Here is a sketch of a class - * that customizes {@link ThreadPoolExecutor} to use - * a <tt>CustomTask</tt> class instead of the default <tt>FutureTask</tt>: - * <pre> - * public class CustomThreadPoolExecutor extends ThreadPoolExecutor { - * - * static class CustomTask<V> implements RunnableFuture<V> {...} - * - * protected <V> RunnableFuture<V> newTaskFor(Callable<V> c) { - * return new CustomTask<V>(c); - * } - * protected <V> RunnableFuture<V> newTaskFor(Runnable r, V v) { - * return new CustomTask<V>(r, v); - * } - * // ... add constructors, etc. - * } - * </pre> - * @since 1.5 - * @author Doug Lea - */ -public abstract class AbstractExecutorService implements ExecutorService { - - /** - * Returns a <tt>RunnableFuture</tt> for the given runnable and default - * value. - * - * @param runnable the runnable task being wrapped - * @param value the default value for the returned future - * @return a <tt>RunnableFuture</tt> which when run will run the - * underlying runnable and which, as a <tt>Future</tt>, will yield - * the given value as its result and provide for cancellation of - * the underlying task. - * @since 1.6 - */ - protected RunnableFuture newTaskFor(Runnable runnable, Object value) { - return new FutureTask(runnable, value); - } - - /** - * Returns a <tt>RunnableFuture</tt> for the given callable task. - * - * @param callable the callable task being wrapped - * @return a <tt>RunnableFuture</tt> which when run will call the - * underlying callable and which, as a <tt>Future</tt>, will yield - * the callable's result as its result and provide for - * cancellation of the underlying task. - * @since 1.6 - */ - protected RunnableFuture newTaskFor(Callable callable) { - return new FutureTask(callable); - } - - /** - * @throws RejectedExecutionException {@inheritDoc} - * @throws NullPointerException {@inheritDoc} - */ - public Future submit(Runnable task) { - if (task == null) throw new NullPointerException(); - RunnableFuture ftask = newTaskFor(task, null); - execute(ftask); - return ftask; - } - - /** - * @throws RejectedExecutionException {@inheritDoc} - * @throws NullPointerException {@inheritDoc} - */ - public Future submit(Runnable task, Object result) { - if (task == null) throw new NullPointerException(); - RunnableFuture ftask = newTaskFor(task, result); - execute(ftask); - return ftask; - } - - /** - * @throws RejectedExecutionException {@inheritDoc} - * @throws NullPointerException {@inheritDoc} - */ - public Future submit(Callable task) { - if (task == null) throw new NullPointerException(); - RunnableFuture ftask = newTaskFor(task); - execute(ftask); - return ftask; - } - - /** - * the main mechanics of invokeAny. - */ - private Object doInvokeAny(Collection tasks, - boolean timed, long nanos) - throws InterruptedException, ExecutionException, TimeoutException { - if (tasks == null) - throw new NullPointerException(); - int ntasks = tasks.size(); - if (ntasks == 0) - throw new IllegalArgumentException(); - List<Future> futures = new ArrayList<Future>(ntasks); - ExecutorCompletionService ecs = - new ExecutorCompletionService(this); - - // For efficiency, especially in executors with limited - // parallelism, check to see if previously submitted tasks are - // done before submitting more of them. This interleaving - // plus the exception mechanics account for messiness of main - // loop. - - try { - // Record exceptions so that if we fail to obtain any - // result, we can throw the last exception we got. - ExecutionException ee = null; - long lastTime = (timed)? Utils.nanoTime() : 0; - Iterator it = tasks.iterator(); - - // Start one task for sure; the rest incrementally - futures.add(ecs.submit((Callable)it.next())); - --ntasks; - int active = 1; - - for (;;) { - Future f = ecs.poll(); - if (f == null) { - if (ntasks > 0) { - --ntasks; - futures.add(ecs.submit((Callable)it.next())); - ++active; - } - else if (active == 0) - break; - else if (timed) { - f = ecs.poll(nanos, TimeUnit.NANOSECONDS); - if (f == null) - throw new TimeoutException(); - long now = Utils.nanoTime(); - nanos -= now - lastTime; - lastTime = now; - } - else - f = ecs.take(); - } - if (f != null) { - --active; - try { - return f.get(); - } catch (InterruptedException ie) { - throw ie; - } catch (ExecutionException eex) { - ee = eex; - } catch (RuntimeException rex) { - ee = new ExecutionException(rex); - } - } - } - - if (ee == null) - ee = new ExecutionException(); - throw ee; - - } finally { - for (Iterator f = futures.iterator(); f.hasNext();) - ((Future)f.next()).cancel(true); - } - } - - public Object invokeAny(Collection tasks) - throws InterruptedException, ExecutionException { - try { - return doInvokeAny(tasks, false, 0); - } catch (TimeoutException cannotHappen) { - assert false; - return null; - } - } - - public Object invokeAny(Collection tasks, - long timeout, TimeUnit unit) - throws InterruptedException, ExecutionException, TimeoutException { - return doInvokeAny(tasks, true, unit.toNanos(timeout)); - } - - public List<Future> invokeAll(Collection tasks) throws InterruptedException { - if (tasks == null) - throw new NullPointerException(); - List<Future> futures = new ArrayList<Future>(tasks.size()); - boolean done = false; - try { - for (Iterator t = tasks.iterator(); t.hasNext();) { - RunnableFuture f = newTaskFor((Callable)t.next()); - futures.add(f); - execute(f); - } - for (Iterator i = futures.iterator(); i.hasNext();) { - Future f = (Future) i.next(); - if (!f.isDone()) { - try { - f.get(); - } catch (CancellationException ignore) { - } catch (ExecutionException ignore) { - } - } - } - done = true; - return futures; - } finally { - if (!done) - for (Iterator i = futures.iterator(); i.hasNext();) { - Future f = (Future) i.next(); - f.cancel(true); - } - } - } - - public List<Future> invokeAll(Collection tasks, - long timeout, TimeUnit unit) - throws InterruptedException { - if (tasks == null || unit == null) - throw new NullPointerException(); - long nanos = unit.toNanos(timeout); - List<Future> futures = new ArrayList<Future>(tasks.size()); - boolean done = false; - try { - for (Iterator t = tasks.iterator(); t.hasNext();) - futures.add(newTaskFor((Callable)t.next())); - - long lastTime = Utils.nanoTime(); - - // Interleave time checks and calls to execute in case - // executor doesn't have any/much parallelism. - Iterator it = futures.iterator(); - while (it.hasNext()) { - execute((Runnable)(it.next())); - long now = Utils.nanoTime(); - nanos -= (now - lastTime); - lastTime = now; - if (nanos <= 0) - return futures; - } - - for (Iterator i = futures.iterator(); i.hasNext();) { - Future f = (Future)i.next(); - if (!f.isDone()) { - if (nanos <= 0) - return futures; - try { - f.get(nanos, TimeUnit.NANOSECONDS); - } catch (CancellationException ignore) { - } catch (ExecutionException ignore) { - } catch (TimeoutException toe) { - return futures; - } - long now = Utils.nanoTime(); - nanos -= now - lastTime; - lastTime = now; - } - } - done = true; - return futures; - } finally { - if (!done) - for (Iterator i = futures.iterator(); i.hasNext();) { - Future f = (Future) i.next(); - f.cancel(true); - } - } - } - -} diff --git a/src/actors/scala/actors/threadpool/AbstractQueue.java b/src/actors/scala/actors/threadpool/AbstractQueue.java deleted file mode 100644 index 84ddc136bc..0000000000 --- a/src/actors/scala/actors/threadpool/AbstractQueue.java +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Written by Doug Lea with assistance from members of JCP JSR-166 - * Expert Group and released to the public domain, as explained at - * http://creativecommons.org/licenses/publicdomain - */ - -package scala.actors.threadpool; - -import java.util.Iterator; -import java.util.Collection; -import java.util.NoSuchElementException; - -/** - * This class provides skeletal implementations of some {@link Queue} - * operations. The implementations in this class are appropriate when - * the base implementation does <em>not</em> allow <tt>null</tt> - * elements. Methods {@link #add add}, {@link #remove remove}, and - * {@link #element element} are based on {@link #offer offer}, {@link - * #poll poll}, and {@link #peek peek}, respectively but throw - * exceptions instead of indicating failure via <tt>false</tt> or - * <tt>null</tt> returns. - * - * <p> A <tt>Queue</tt> implementation that extends this class must - * minimally define a method {@link Queue#offer} which does not permit - * insertion of <tt>null</tt> elements, along with methods {@link - * Queue#peek}, {@link Queue#poll}, {@link Collection#size}, and a - * {@link Collection#iterator} supporting {@link - * Iterator#remove}. Typically, additional methods will be overridden - * as well. If these requirements cannot be met, consider instead - * subclassing {@link AbstractCollection}. - * - * <p>This class is a member of the - * <a href="{@docRoot}/../technotes/guides/collections/index.html"> - * Java Collections Framework</a>. - * - * @since 1.5 - * @author Doug Lea - */ -public abstract class AbstractQueue - extends AbstractCollection - implements Queue { - - /** - * Constructor for use by subclasses. - */ - protected AbstractQueue() { - } - - /** - * Inserts the specified element into this queue if it is possible to do so - * immediately without violating capacity restrictions, returning - * <tt>true</tt> upon success and throwing an <tt>IllegalStateException</tt> - * if no space is currently available. - * - * <p>This implementation returns <tt>true</tt> if <tt>offer</tt> succeeds, - * else throws an <tt>IllegalStateException</tt>. - * - * @param e the element to add - * @return <tt>true</tt> (as specified by {@link Collection#add}) - * @throws IllegalStateException if the element cannot be added at this - * time due to capacity restrictions - * @throws ClassCastException if the class of the specified element - * prevents it from being added to this queue - * @throws NullPointerException if the specified element is null and - * this queue does not permit null elements - * @throws IllegalArgumentException if some property of this element - * prevents it from being added to this queue - */ - public boolean add(Object e) { - if (offer(e)) - return true; - else - throw new IllegalStateException("Queue full"); - } - - /** - * Retrieves and removes the head of this queue. This method differs - * from {@link #poll poll} only in that it throws an exception if this - * queue is empty. - * - * <p>This implementation returns the result of <tt>poll</tt> - * unless the queue is empty. - * - * @return the head of this queue - * @throws NoSuchElementException if this queue is empty - */ - public Object remove() { - Object x = poll(); - if (x != null) - return x; - else - throw new NoSuchElementException(); - } - - - /** - * Retrieves, but does not remove, the head of this queue. This method - * differs from {@link #peek peek} only in that it throws an exception if - * this queue is empty. - * - * <p>This implementation returns the result of <tt>peek</tt> - * unless the queue is empty. - * - * @return the head of this queue - * @throws NoSuchElementException if this queue is empty - */ - public Object element() { - Object x = peek(); - if (x != null) - return x; - else - throw new NoSuchElementException(); - } - - /** - * Removes all of the elements from this queue. - * The queue will be empty after this call returns. - * - * <p>This implementation repeatedly invokes {@link #poll poll} until it - * returns <tt>null</tt>. - */ - public void clear() { - while (poll() != null) - ; - } - - /** - * Adds all of the elements in the specified collection to this - * queue. Attempts to addAll of a queue to itself result in - * <tt>IllegalArgumentException</tt>. Further, the behavior of - * this operation is undefined if the specified collection is - * modified while the operation is in progress. - * - * <p>This implementation iterates over the specified collection, - * and adds each element returned by the iterator to this - * queue, in turn. A runtime exception encountered while - * trying to add an element (including, in particular, a - * <tt>null</tt> element) may result in only some of the elements - * having been successfully added when the associated exception is - * thrown. - * - * @param c collection containing elements to be added to this queue - * @return <tt>true</tt> if this queue changed as a result of the call - * @throws ClassCastException if the class of an element of the specified - * collection prevents it from being added to this queue - * @throws NullPointerException if the specified collection contains a - * null element and this queue does not permit null elements, - * or if the specified collection is null - * @throws IllegalArgumentException if some property of an element of the - * specified collection prevents it from being added to this - * queue, or if the specified collection is this queue - * @throws IllegalStateException if not all the elements can be added at - * this time due to insertion restrictions - * @see #add(Object) - */ - public boolean addAll(Collection c) { - if (c == null) - throw new NullPointerException(); - if (c == this) - throw new IllegalArgumentException(); - boolean modified = false; - Iterator e = c.iterator(); - while (e.hasNext()) { - if (add(e.next())) - modified = true; - } - return modified; - } - -} diff --git a/src/actors/scala/actors/threadpool/Arrays.java b/src/actors/scala/actors/threadpool/Arrays.java deleted file mode 100644 index 85e7c8fa00..0000000000 --- a/src/actors/scala/actors/threadpool/Arrays.java +++ /dev/null @@ -1,811 +0,0 @@ -/* - * Written by Dawid Kurzyniec, based on code written by Doug Lea with assistance - * from members of JCP JSR-166 Expert Group. Released to the public domain, - * as explained at http://creativecommons.org/licenses/publicdomain. - */ - -package scala.actors.threadpool; - -import java.lang.reflect.Array; -import java.util.List; -import java.util.ArrayList; -import java.util.Comparator; - -public class Arrays { - - private Arrays() {} - - public static void sort(long[] a) { - java.util.Arrays.sort(a); - } - - public static void sort(long[] a, int fromIndex, int toIndex) { - java.util.Arrays.sort(a, fromIndex, toIndex); - } - - public static void sort(int[] a) { - java.util.Arrays.sort(a); - } - - public static void sort(int[] a, int fromIndex, int toIndex) { - java.util.Arrays.sort(a, fromIndex, toIndex); - } - - public static void sort(short[] a) { - java.util.Arrays.sort(a); - } - - public static void sort(short[] a, int fromIndex, int toIndex) { - java.util.Arrays.sort(a, fromIndex, toIndex); - } - - public static void sort(char[] a) { - java.util.Arrays.sort(a); - } - - public static void sort(char[] a, int fromIndex, int toIndex) { - java.util.Arrays.sort(a, fromIndex, toIndex); - } - - public static void sort(byte[] a) { - java.util.Arrays.sort(a); - } - - public static void sort(byte[] a, int fromIndex, int toIndex) { - java.util.Arrays.sort(a, fromIndex, toIndex); - } - - public static void sort(double[] a) { - java.util.Arrays.sort(a); - } - - public static void sort(double[] a, int fromIndex, int toIndex) { - java.util.Arrays.sort(a, fromIndex, toIndex); - } - - public static void sort(float[] a) { - java.util.Arrays.sort(a); - } - - public static void sort(float[] a, int fromIndex, int toIndex) { - java.util.Arrays.sort(a, fromIndex, toIndex); - } - - - public static void sort(Object[] a) { - java.util.Arrays.sort(a); - } - - public static void sort(Object[] a, int fromIndex, int toIndex) { - java.util.Arrays.sort(a, fromIndex, toIndex); - } - - public static void sort(Object[] a, Comparator c) { - java.util.Arrays.sort(a, c); - } - - public static void sort(Object[] a, int fromIndex, int toIndex, Comparator c) { - java.util.Arrays.sort(a, fromIndex, toIndex, c); - } - - - // Searching - - public static int binarySearch(long[] a, long key) { - return java.util.Arrays.binarySearch(a, key); - } - - public static int binarySearch(int[] a, int key) { - return java.util.Arrays.binarySearch(a, key); - } - - public static int binarySearch(short[] a, short key) { - return java.util.Arrays.binarySearch(a, key); - } - - public static int binarySearch(char[] a, char key) { - return java.util.Arrays.binarySearch(a, key); - } - - public static int binarySearch(byte[] a, byte key) { - return java.util.Arrays.binarySearch(a, key); - } - - public static int binarySearch(double[] a, double key) { - return java.util.Arrays.binarySearch(a, key); - } - - public static int binarySearch(float[] a, float key) { - return java.util.Arrays.binarySearch(a, key); - } - - public static int binarySearch(Object[] a, Object key) { - return java.util.Arrays.binarySearch(a, key); - } - - public static int binarySearch(Object[] a, Object key, Comparator c) { - return java.util.Arrays.binarySearch(a, key, c); - } - - - // Equality Testing - - public static boolean equals(long[] a, long[] a2) { - return java.util.Arrays.equals(a, a2); - } - - public static boolean equals(int[] a, int[] a2) { - return java.util.Arrays.equals(a, a2); - } - - public static boolean equals(short[] a, short a2[]) { - return java.util.Arrays.equals(a, a2); - } - - public static boolean equals(char[] a, char[] a2) { - return java.util.Arrays.equals(a, a2); - } - - public static boolean equals(byte[] a, byte[] a2) { - return java.util.Arrays.equals(a, a2); - } - - public static boolean equals(boolean[] a, boolean[] a2) { - return java.util.Arrays.equals(a, a2); - } - - public static boolean equals(double[] a, double[] a2) { - return java.util.Arrays.equals(a, a2); - } - - public static boolean equals(float[] a, float[] a2) { - return java.util.Arrays.equals(a, a2); - } - - public static boolean equals(Object[] a, Object[] a2) { - return java.util.Arrays.equals(a, a2); - } - - - // Filling - - public static void fill(long[] a, long val) { - java.util.Arrays.fill(a, val); - } - - public static void fill(long[] a, int fromIndex, int toIndex, long val) { - java.util.Arrays.fill(a, fromIndex, toIndex, val); - } - - public static void fill(int[] a, int val) { - java.util.Arrays.fill(a, val); - } - - public static void fill(int[] a, int fromIndex, int toIndex, int val) { - java.util.Arrays.fill(a, fromIndex, toIndex, val); - } - - public static void fill(short[] a, short val) { - java.util.Arrays.fill(a, val); - } - - public static void fill(short[] a, int fromIndex, int toIndex, short val) { - java.util.Arrays.fill(a, fromIndex, toIndex, val); - } - - public static void fill(char[] a, char val) { - java.util.Arrays.fill(a, val); - } - - public static void fill(char[] a, int fromIndex, int toIndex, char val) { - java.util.Arrays.fill(a, fromIndex, toIndex, val); - } - - public static void fill(byte[] a, byte val) { - java.util.Arrays.fill(a, val); - } - - public static void fill(byte[] a, int fromIndex, int toIndex, byte val) { - java.util.Arrays.fill(a, fromIndex, toIndex, val); - } - - public static void fill(boolean[] a, boolean val) { - java.util.Arrays.fill(a, val); - } - - public static void fill(boolean[] a, int fromIndex, int toIndex, - boolean val) { - java.util.Arrays.fill(a, fromIndex, toIndex, val); - } - - public static void fill(double[] a, double val) { - java.util.Arrays.fill(a, val); - } - - public static void fill(double[] a, int fromIndex, int toIndex,double val) { - java.util.Arrays.fill(a, fromIndex, toIndex, val); - } - - public static void fill(float[] a, float val) { - java.util.Arrays.fill(a, val); - } - - public static void fill(float[] a, int fromIndex, int toIndex, float val) { - java.util.Arrays.fill(a, fromIndex, toIndex, val); - } - - public static void fill(Object[] a, Object val) { - java.util.Arrays.fill(a, val); - } - - public static void fill(Object[] a, int fromIndex, int toIndex, Object val) { - java.util.Arrays.fill(a, fromIndex, toIndex, val); - } - - - // Cloning - - /** - * @since 1.6 - */ - public static Object[] copyOf(Object[] original, int newLength) { - return copyOf(original, newLength, original.getClass()); - } - - /** - * @since 1.6 - */ - public static Object[] copyOf(Object[] original, int newLength, Class newType) { - Object[] arr = (newType == Object[].class) ? new Object[newLength] : - (Object[])Array.newInstance(newType.getComponentType(), newLength); - int len = (original.length < newLength ? original.length : newLength); - System.arraycopy(original, 0, arr, 0, len); - return arr; - } - - /** - * @since 1.6 - */ - public static byte[] copyOf(byte[] original, int newLength) { - byte[] arr = new byte[newLength]; - int len = (original.length < newLength ? original.length : newLength); - System.arraycopy(original, 0, arr, 0, len); - return arr; - } - - /** - * @since 1.6 - */ - public static short[] copyOf(short[] original, int newLength) { - short[] arr = new short[newLength]; - int len = (original.length < newLength ? original.length : newLength); - System.arraycopy(original, 0, arr, 0, len); - return arr; - } - - /** - * @since 1.6 - */ - public static int[] copyOf(int[] original, int newLength) { - int[] arr = new int[newLength]; - int len = (original.length < newLength ? original.length : newLength); - System.arraycopy(original, 0, arr, 0, len); - return arr; - } - - /** - * @since 1.6 - */ - public static long[] copyOf(long[] original, int newLength) { - long[] arr = new long[newLength]; - int len = (original.length < newLength ? original.length : newLength); - System.arraycopy(original, 0, arr, 0, len); - return arr; - } - - /** - * @since 1.6 - */ - public static char[] copyOf(char[] original, int newLength) { - char[] arr = new char[newLength]; - int len = (original.length < newLength ? original.length : newLength); - System.arraycopy(original, 0, arr, 0, len); - return arr; - } - - /** - * @since 1.6 - */ - public static float[] copyOf(float[] original, int newLength) { - float[] arr = new float[newLength]; - int len = (original.length < newLength ? original.length : newLength); - System.arraycopy(original, 0, arr, 0, len); - return arr; - } - - /** - * @since 1.6 - */ - public static double[] copyOf(double[] original, int newLength) { - double[] arr = new double[newLength]; - int len = (original.length < newLength ? original.length : newLength); - System.arraycopy(original, 0, arr, 0, len); - return arr; - } - - /** - * @since 1.6 - */ - public static boolean[] copyOf(boolean[] original, int newLength) { - boolean[] arr = new boolean[newLength]; - int len = (original.length < newLength ? original.length : newLength); - System.arraycopy(original, 0, arr, 0, len); - return arr; - } - - /** - * @since 1.6 - */ - public static Object[] copyOfRange(Object[] original, int from, int to) { - return copyOfRange(original, from, to, original.getClass()); - } - - /** - * @since 1.6 - */ - public static Object[] copyOfRange(Object[] original, int from, int to, Class newType) { - int newLength = to - from; - if (newLength < 0) throw new IllegalArgumentException(from + " > " + to); - Object[] arr = (newType == Object[].class) ? new Object[newLength] : - (Object[])Array.newInstance(newType.getComponentType(), newLength); - int ceil = original.length-from; - int len = (ceil < newLength) ? ceil : newLength; - System.arraycopy(original, from, arr, 0, len); - return arr; - } - - /** - * @since 1.6 - */ - public static byte[] copyOfRange(byte[] original, int from, int to) { - int newLength = to - from; - if (newLength < 0) throw new IllegalArgumentException(from + " > " + to); - byte[] arr = new byte[newLength]; - int ceil = original.length-from; - int len = (ceil < newLength) ? ceil : newLength; - System.arraycopy(original, from, arr, 0, len); - return arr; - } - - /** - * @since 1.6 - */ - public static short[] copyOfRange(short[] original, int from, int to) { - int newLength = to - from; - if (newLength < 0) throw new IllegalArgumentException(from + " > " + to); - short[] arr = new short[newLength]; - int ceil = original.length-from; - int len = (ceil < newLength) ? ceil : newLength; - System.arraycopy(original, from, arr, 0, len); - return arr; - } - - /** - * @since 1.6 - */ - public static int[] copyOfRange(int[] original, int from, int to) { - int newLength = to - from; - if (newLength < 0) throw new IllegalArgumentException(from + " > " + to); - int[] arr = new int[newLength]; - int ceil = original.length-from; - int len = (ceil < newLength) ? ceil : newLength; - System.arraycopy(original, from, arr, 0, len); - return arr; - } - - /** - * @since 1.6 - */ - public static long[] copyOfRange(long[] original, int from, int to) { - int newLength = to - from; - if (newLength < 0) throw new IllegalArgumentException(from + " > " + to); - long[] arr = new long[newLength]; - int ceil = original.length-from; - int len = (ceil < newLength) ? ceil : newLength; - System.arraycopy(original, from, arr, 0, len); - return arr; - } - - /** - * @since 1.6 - */ - public static char[] copyOfRange(char[] original, int from, int to) { - int newLength = to - from; - if (newLength < 0) throw new IllegalArgumentException(from + " > " + to); - char[] arr = new char[newLength]; - int ceil = original.length-from; - int len = (ceil < newLength) ? ceil : newLength; - System.arraycopy(original, from, arr, 0, len); - return arr; - } - - /** - * @since 1.6 - */ - public static float[] copyOfRange(float[] original, int from, int to) { - int newLength = to - from; - if (newLength < 0) throw new IllegalArgumentException(from + " > " + to); - float[] arr = new float[newLength]; - int ceil = original.length-from; - int len = (ceil < newLength) ? ceil : newLength; - System.arraycopy(original, from, arr, 0, len); - return arr; - } - - /** - * @since 1.6 - */ - public static double[] copyOfRange(double[] original, int from, int to) { - int newLength = to - from; - if (newLength < 0) throw new IllegalArgumentException(from + " > " + to); - double[] arr = new double[newLength]; - int ceil = original.length-from; - int len = (ceil < newLength) ? ceil : newLength; - System.arraycopy(original, from, arr, 0, len); - return arr; - } - - /** - * @since 1.6 - */ - public static boolean[] copyOfRange(boolean[] original, int from, int to) { - int newLength = to - from; - if (newLength < 0) throw new IllegalArgumentException(from + " > " + to); - boolean[] arr = new boolean[newLength]; - int ceil = original.length-from; - int len = (ceil < newLength) ? ceil : newLength; - System.arraycopy(original, from, arr, 0, len); - return arr; - } - - - public static List asList(Object[] a) { - return java.util.Arrays.asList(a); - } - - /** - * @since 1.5 - */ - public static int hashCode(long a[]) { - if (a == null) return 0; - int hash = 1; - for (int i=0; i<a.length; i++) { - long e = a[i]; - hash = 31*hash + (int)(e ^ (e >>> 32)); - } - return hash; - } - - /** - * @since 1.5 - */ - public static int hashCode(int a[]) { - if (a == null) return 0; - int hash = 1; - for (int i=0; i<a.length; i++) { - hash = 31*hash + a[i]; - } - return hash; - } - - /** - * @since 1.5 - */ - public static int hashCode(short a[]) { - if (a == null) return 0; - int hash = 1; - for (int i=0; i<a.length; i++) { - hash = 31*hash + a[i]; - } - return hash; - } - - /** - * @since 1.5 - */ - public static int hashCode(char a[]) { - if (a == null) return 0; - int hash = 1; - for (int i=0; i<a.length; i++) { - hash = 31*hash + a[i]; - } - return hash; - } - - /** - * @since 1.5 - */ - public static int hashCode(byte a[]) { - if (a == null) return 0; - int hash = 1; - for (int i=0; i<a.length; i++) { - hash = 31*hash + a[i]; - } - return hash; - } - - /** - * @since 1.5 - */ - public static int hashCode(boolean a[]) { - if (a == null) return 0; - int hash = 1; - for (int i=0; i<a.length; i++) { - hash = 31*hash + (a[i] ? 1231 : 1237); - } - return hash; - } - - /** - * @since 1.5 - */ - public static int hashCode(float a[]) { - if (a == null) return 0; - int hash = 1; - for (int i=0; i<a.length; i++) { - hash = 31*hash + Float.floatToIntBits(a[i]); - } - return hash; - } - - /** - * @since 1.5 - */ - public static int hashCode(double a[]) { - if (a == null) return 0; - int hash = 1; - for (int i=0; i<a.length; i++) { - long e = Double.doubleToLongBits(a[i]); - hash = 31*hash + (int)(e ^ (e >>> 32)); - } - return hash; - } - - /** - * @since 1.5 - */ - public static int hashCode(Object a[]) { - if (a == null) return 0; - int hash = 1; - for (int i=0; i<a.length; i++) { - Object e = a[i]; - hash = 31*hash + (e == null ? 0 : e.hashCode()); - } - return hash; - } - - /** - * @since 1.5 - */ - public static int deepHashCode(Object a[]) { - if (a == null) return 0; - int hash = 1; - for (int i=0; i<a.length; i++) { - Object e = a[i]; - hash = 31*hash + - (e instanceof Object[] ? deepHashCode((Object[])e) : - (e instanceof byte[] ? hashCode((byte[])e) : - (e instanceof short[] ? hashCode((short[])e) : - (e instanceof int[] ? hashCode((int[])e) : - (e instanceof long[] ? hashCode((long[])e) : - (e instanceof char[] ? hashCode((char[])e) : - (e instanceof boolean[] ? hashCode((boolean[])e) : - (e instanceof float[] ? hashCode((float[])e) : - (e instanceof double[] ? hashCode((double[])e) : - (e != null ? e.hashCode() : 0)))))))))); - } - return hash; - - } - - /** - * @since 1.5 - */ - public static boolean deepEquals(Object[] a1, Object[] a2) { - if (a1 == a2) return true; - if (a1 == null || a2==null) return false; - int len = a1.length; - if (len != a2.length) return false; - for (int i = 0; i < len; i++) { - Object e1 = a1[i]; - Object e2 = a2[i]; - if (e1 == e2) continue; - if (e1 == null) return false; - boolean eq = - (e1.getClass() != e2.getClass() || e1.getClass().isArray()) ? - e1.equals(e2) : - (e1 instanceof Object[] && e2 instanceof Object[]) ? - deepEquals((Object[])e1, (Object[])e2) : - (e1 instanceof byte[] && e2 instanceof byte[]) ? - equals((byte[])e1, (byte[])e2) : - (e1 instanceof short[] && e2 instanceof short[]) ? - equals((short[])e1, (short[])e2) : - (e1 instanceof int[] && e2 instanceof int[]) ? - equals((int[])e1, (int[])e2) : - (e1 instanceof long[] && e2 instanceof long[]) ? - equals((long[])e1, (long[])e2) : - (e1 instanceof char[] && e2 instanceof char[]) ? - equals((char[])e1, (char[])e2) : - (e1 instanceof boolean[] && e2 instanceof boolean[]) ? - equals((boolean[])e1, (boolean[])e2) : - (e1 instanceof float[] && e2 instanceof float[]) ? - equals((float[])e1, (float[])e2) : - (e1 instanceof double[] && e2 instanceof double[]) ? - equals((double[])e1, (double[])e2) : - e1.equals(e2); - - if (!eq) return false; - } - return true; - } - - /** - * @since 1.5 - */ - public static String toString(long[] a) { - if (a == null) return "null"; - if (a.length == 0) return "[]"; - StringBuffer buf = new StringBuffer(); - buf.append('[').append(a[0]); - for (int i=1; i<a.length; i++) buf.append(", ").append(a[i]); - buf.append(']'); - return buf.toString(); - } - - /** - * @since 1.5 - */ - public static String toString(int[] a) { - if (a == null) return "null"; - if (a.length == 0) return "[]"; - StringBuffer buf = new StringBuffer(); - buf.append('[').append(a[0]); - for (int i=1; i<a.length; i++) buf.append(", ").append(a[i]); - buf.append(']'); - return buf.toString(); - } - - /** - * @since 1.5 - */ - public static String toString(short[] a) { - if (a == null) return "null"; - if (a.length == 0) return "[]"; - StringBuffer buf = new StringBuffer(); - buf.append('[').append(a[0]); - for (int i=1; i<a.length; i++) buf.append(", ").append(a[i]); - buf.append(']'); - return buf.toString(); - } - - /** - * @since 1.5 - */ - public static String toString(char[] a) { - if (a == null) return "null"; - if (a.length == 0) return "[]"; - StringBuffer buf = new StringBuffer(); - buf.append('[').append(a[0]); - for (int i=1; i<a.length; i++) buf.append(", ").append(a[i]); - buf.append(']'); - return buf.toString(); - } - - /** - * @since 1.5 - */ - public static String toString(byte[] a) { - if (a == null) return "null"; - if (a.length == 0) return "[]"; - StringBuffer buf = new StringBuffer(); - buf.append('[').append(a[0]); - for (int i=1; i<a.length; i++) buf.append(", ").append(a[i]); - buf.append(']'); - return buf.toString(); - } - - /** - * @since 1.5 - */ - public static String toString(boolean[] a) { - if (a == null) return "null"; - if (a.length == 0) return "[]"; - StringBuffer buf = new StringBuffer(); - buf.append('[').append(a[0]); - for (int i=1; i<a.length; i++) buf.append(", ").append(a[i]); - buf.append(']'); - return buf.toString(); - } - - /** - * @since 1.5 - */ - public static String toString(float[] a) { - if (a == null) return "null"; - if (a.length == 0) return "[]"; - StringBuffer buf = new StringBuffer(); - buf.append('[').append(a[0]); - for (int i=1; i<a.length; i++) buf.append(", ").append(a[i]); - buf.append(']'); - return buf.toString(); - } - - /** - * @since 1.5 - */ - public static String toString(double[] a) { - if (a == null) return "null"; - if (a.length == 0) return "[]"; - StringBuffer buf = new StringBuffer(); - buf.append('[').append(a[0]); - for (int i=1; i<a.length; i++) buf.append(", ").append(a[i]); - buf.append(']'); - return buf.toString(); - } - - /** - * @since 1.5 - */ - public static String toString(Object[] a) { - if (a == null) return "null"; - if (a.length == 0) return "[]"; - StringBuffer buf = new StringBuffer(); - buf.append('[').append(a[0]); - for (int i=1; i<a.length; i++) buf.append(", ").append(a[i]); - buf.append(']'); - return buf.toString(); - } - - /** - * @since 1.5 - */ - public static String deepToString(Object[] a) { - if (a == null) return "null"; - StringBuffer buf = new StringBuffer(); - deepToString(a, buf, new ArrayList()); - return buf.toString(); - } - - private static void deepToString(Object[] a, StringBuffer buf, List seen) { - seen.add(a); - buf.append('['); - for (int i = 0; i < a.length; i++) { - if (i>0) buf.append(", "); - Object e = a[i]; - if (e == null) { - buf.append("null"); - } - else if (!e.getClass().isArray()) { - buf.append(e.toString()); - } - else if (e instanceof Object[]) { - if (seen.contains(e)) buf.append("[...]"); - else deepToString((Object[])e, buf, seen); - } - else { - // primitive arr - buf.append( - (e instanceof byte[]) ? toString( (byte[]) e) : - (e instanceof short[]) ? toString( (short[]) e) : - (e instanceof int[]) ? toString( (int[]) e) : - (e instanceof long[]) ? toString( (long[]) e) : - (e instanceof char[]) ? toString( (char[]) e) : - (e instanceof boolean[]) ? toString( (boolean[]) e) : - (e instanceof float[]) ? toString( (float[]) e) : - (e instanceof double[]) ? toString( (double[]) e) : ""); - } - } - buf.append(']'); - seen.remove(seen.size()-1); - } -} diff --git a/src/actors/scala/actors/threadpool/AtomicInteger.java b/src/actors/scala/actors/threadpool/AtomicInteger.java deleted file mode 100644 index eedb84512a..0000000000 --- a/src/actors/scala/actors/threadpool/AtomicInteger.java +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Written by Doug Lea with assistance from members of JCP JSR-166 - * Expert Group and released to the public domain, as explained at - * http://creativecommons.org/licenses/publicdomain - */ - -package scala.actors.threadpool; - -/** - * An {@code int} value that may be updated atomically. See the - * {@link edu.emory.mathcs.backport.java.util.concurrent.atomic} package specification for - * description of the properties of atomic variables. An - * {@code AtomicInteger} is used in applications such as atomically - * incremented counters, and cannot be used as a replacement for an - * {@link java.lang.Integer}. However, this class does extend - * {@code Number} to allow uniform access by tools and utilities that - * deal with numerically-based classes. - * - * @since 1.5 - * @author Doug Lea -*/ -public class AtomicInteger extends Number implements java.io.Serializable { - private static final long serialVersionUID = 6214790243416807050L; - - private volatile int value; - - /** - * Creates a new AtomicInteger with the given initial value. - * - * @param initialValue the initial value - */ - public AtomicInteger(int initialValue) { - value = initialValue; - } - - /** - * Creates a new AtomicInteger with initial value {@code 0}. - */ - public AtomicInteger() { - } - - /** - * Gets the current value. - * - * @return the current value - */ - public final int get() { - return value; - } - - /** - * Sets to the given value. - * - * @param newValue the new value - */ - public final synchronized void set(int newValue) { - value = newValue; - } - - /** - * Eventually sets to the given value. - * - * @param newValue the new value - * @since 1.6 - */ - public final synchronized void lazySet(int newValue) { - value = newValue; - } - - /** - * Atomically sets to the given value and returns the old value. - * - * @param newValue the new value - * @return the previous value - */ - public final synchronized int getAndSet(int newValue) { - int old = value; - value = newValue; - return old; - } - - /** - * Atomically sets the value to the given updated value - * if the current value {@code ==} the expected value. - * - * @param expect the expected value - * @param update the new value - * @return true if successful. False return indicates that - * the actual value was not equal to the expected value. - */ - public final synchronized boolean compareAndSet(int expect, int update) { - if (value == expect) { - value = update; - return true; - } - else { - return false; - } - } - - /** - * Atomically sets the value to the given updated value - * if the current value {@code ==} the expected value. - * - * <p>May <a href="package-summary.html#Spurious">fail spuriously</a> - * and does not provide ordering guarantees, so is only rarely an - * appropriate alternative to {@code compareAndSet}. - * - * @param expect the expected value - * @param update the new value - * @return true if successful. - */ - public final synchronized boolean weakCompareAndSet(int expect, int update) { - if (value == expect) { - value = update; - return true; - } - else { - return false; - } - } - - - /** - * Atomically increments by one the current value. - * - * @return the previous value - */ - public final synchronized int getAndIncrement() { - return value++; - } - - - /** - * Atomically decrements by one the current value. - * - * @return the previous value - */ - public final synchronized int getAndDecrement() { - return value--; - } - - - /** - * Atomically adds the given value to the current value. - * - * @param delta the value to add - * @return the previous value - */ - public final synchronized int getAndAdd(int delta) { - int old = value; - value += delta; - return old; - } - - /** - * Atomically increments by one the current value. - * - * @return the updated value - */ - public final synchronized int incrementAndGet() { - return ++value; - } - - /** - * Atomically decrements by one the current value. - * - * @return the updated value - */ - public final synchronized int decrementAndGet() { - return --value; - } - - - /** - * Atomically adds the given value to the current value. - * - * @param delta the value to add - * @return the updated value - */ - public final synchronized int addAndGet(int delta) { - return value += delta; - } - - /** - * Returns the String representation of the current value. - * @return the String representation of the current value. - */ - public String toString() { - return Integer.toString(get()); - } - - - public int intValue() { - return get(); - } - - public long longValue() { - return (long)get(); - } - - public float floatValue() { - return (float)get(); - } - - public double doubleValue() { - return (double)get(); - } - -} diff --git a/src/actors/scala/actors/threadpool/BlockingQueue.java b/src/actors/scala/actors/threadpool/BlockingQueue.java deleted file mode 100644 index 4b8c201b85..0000000000 --- a/src/actors/scala/actors/threadpool/BlockingQueue.java +++ /dev/null @@ -1,344 +0,0 @@ -/* - * Written by Doug Lea with assistance from members of JCP JSR-166 - * Expert Group and released to the public domain, as explained at - * http://creativecommons.org/licenses/publicdomain - */ - -package scala.actors.threadpool; - -import java.util.Collection; -import java.util.Queue; - -/** - * A {@link java.util.Queue} that additionally supports operations - * that wait for the queue to become non-empty when retrieving an - * element, and wait for space to become available in the queue when - * storing an element. - * - * <p><tt>BlockingQueue</tt> methods come in four forms, with different ways - * of handling operations that cannot be satisfied immediately, but may be - * satisfied at some point in the future: - * one throws an exception, the second returns a special value (either - * <tt>null</tt> or <tt>false</tt>, depending on the operation), the third - * blocks the current thread indefinitely until the operation can succeed, - * and the fourth blocks for only a given maximum time limit before giving - * up. These methods are summarized in the following table: - * - * <p> - * <table BORDER CELLPADDING=3 CELLSPACING=1> - * <tr> - * <td></td> - * <td ALIGN=CENTER><em>Throws exception</em></td> - * <td ALIGN=CENTER><em>Special value</em></td> - * <td ALIGN=CENTER><em>Blocks</em></td> - * <td ALIGN=CENTER><em>Times out</em></td> - * </tr> - * <tr> - * <td><b>Insert</b></td> - * <td>{@link #add add(e)}</td> - * <td>{@link #offer offer(e)}</td> - * <td>{@link #put put(e)}</td> - * <td>{@link #offer(Object, long, TimeUnit) offer(e, time, unit)}</td> - * </tr> - * <tr> - * <td><b>Remove</b></td> - * <td>{@link #remove remove()}</td> - * <td>{@link #poll poll()}</td> - * <td>{@link #take take()}</td> - * <td>{@link #poll(long, TimeUnit) poll(time, unit)}</td> - * </tr> - * <tr> - * <td><b>Examine</b></td> - * <td>{@link #element element()}</td> - * <td>{@link #peek peek()}</td> - * <td><em>not applicable</em></td> - * <td><em>not applicable</em></td> - * </tr> - * </table> - * - * <p>A <tt>BlockingQueue</tt> does not accept <tt>null</tt> elements. - * Implementations throw <tt>NullPointerException</tt> on attempts - * to <tt>add</tt>, <tt>put</tt> or <tt>offer</tt> a <tt>null</tt>. A - * <tt>null</tt> is used as a sentinel value to indicate failure of - * <tt>poll</tt> operations. - * - * <p>A <tt>BlockingQueue</tt> may be capacity bounded. At any given - * time it may have a <tt>remainingCapacity</tt> beyond which no - * additional elements can be <tt>put</tt> without blocking. - * A <tt>BlockingQueue</tt> without any intrinsic capacity constraints always - * reports a remaining capacity of <tt>Integer.MAX_VALUE</tt>. - * - * <p> <tt>BlockingQueue</tt> implementations are designed to be used - * primarily for producer-consumer queues, but additionally support - * the {@link java.util.Collection} interface. So, for example, it is - * possible to remove an arbitrary element from a queue using - * <tt>remove(x)</tt>. However, such operations are in general - * <em>not</em> performed very efficiently, and are intended for only - * occasional use, such as when a queued message is cancelled. - * - * <p> <tt>BlockingQueue</tt> implementations are thread-safe. All - * queuing methods achieve their effects atomically using internal - * locks or other forms of concurrency control. However, the - * <em>bulk</em> Collection operations <tt>addAll</tt>, - * <tt>containsAll</tt>, <tt>retainAll</tt> and <tt>removeAll</tt> are - * <em>not</em> necessarily performed atomically unless specified - * otherwise in an implementation. So it is possible, for example, for - * <tt>addAll(c)</tt> to fail (throwing an exception) after adding - * only some of the elements in <tt>c</tt>. - * - * <p>A <tt>BlockingQueue</tt> does <em>not</em> intrinsically support - * any kind of "close" or "shutdown" operation to - * indicate that no more items will be added. The needs and usage of - * such features tend to be implementation-dependent. For example, a - * common tactic is for producers to insert special - * <em>end-of-stream</em> or <em>poison</em> objects, that are - * interpreted accordingly when taken by consumers. - * - * <p> - * Usage example, based on a typical producer-consumer scenario. - * Note that a <tt>BlockingQueue</tt> can safely be used with multiple - * producers and multiple consumers. - * <pre> - * class Producer implements Runnable { - * private final BlockingQueue queue; - * Producer(BlockingQueue q) { queue = q; } - * public void run() { - * try { - * while (true) { queue.put(produce()); } - * } catch (InterruptedException ex) { ... handle ...} - * } - * Object produce() { ... } - * } - * - * class Consumer implements Runnable { - * private final BlockingQueue queue; - * Consumer(BlockingQueue q) { queue = q; } - * public void run() { - * try { - * while (true) { consume(queue.take()); } - * } catch (InterruptedException ex) { ... handle ...} - * } - * void consume(Object x) { ... } - * } - * - * class Setup { - * void main() { - * BlockingQueue q = new SomeQueueImplementation(); - * Producer p = new Producer(q); - * Consumer c1 = new Consumer(q); - * Consumer c2 = new Consumer(q); - * new Thread(p).start(); - * new Thread(c1).start(); - * new Thread(c2).start(); - * } - * } - * </pre> - * - * <p>Memory consistency effects: As with other concurrent - * collections, actions in a thread prior to placing an object into a - * {@code BlockingQueue} - * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a> - * actions subsequent to the access or removal of that element from - * the {@code BlockingQueue} in another thread. - * - * <p>This interface is a member of the - * <a href="{@docRoot}/../technotes/guides/collections/index.html"> - * Java Collections Framework</a>. - * - * @since 1.5 - * @author Doug Lea - * @param <E> the type of elements held in this collection - */ -public interface BlockingQueue<E> extends java.util.Queue<E> { - /** - * Inserts the specified element into this queue if it is possible to do - * so immediately without violating capacity restrictions, returning - * <tt>true</tt> upon success and throwing an - * <tt>IllegalStateException</tt> if no space is currently available. - * When using a capacity-restricted queue, it is generally preferable to - * use {@link #offer(Object) offer}. - * - * @param e the element to add - * @return <tt>true</tt> (as specified by {@link Collection#add}) - * @throws IllegalStateException if the element cannot be added at this - * time due to capacity restrictions - * @throws ClassCastException if the class of the specified element - * prevents it from being added to this queue - * @throws NullPointerException if the specified element is null - * @throws IllegalArgumentException if some property of the specified - * element prevents it from being added to this queue - */ - boolean add(E e); - - /** - * Inserts the specified element into this queue if it is possible to do - * so immediately without violating capacity restrictions, returning - * <tt>true</tt> upon success and <tt>false</tt> if no space is currently - * available. When using a capacity-restricted queue, this method is - * generally preferable to {@link #add}, which can fail to insert an - * element only by throwing an exception. - * - * @param e the element to add - * @return <tt>true</tt> if the element was added to this queue, else - * <tt>false</tt> - * @throws ClassCastException if the class of the specified element - * prevents it from being added to this queue - * @throws NullPointerException if the specified element is null - * @throws IllegalArgumentException if some property of the specified - * element prevents it from being added to this queue - */ - boolean offer(E e); - - /** - * Inserts the specified element into this queue, waiting if necessary - * for space to become available. - * - * @param e the element to add - * @throws InterruptedException if interrupted while waiting - * @throws ClassCastException if the class of the specified element - * prevents it from being added to this queue - * @throws NullPointerException if the specified element is null - * @throws IllegalArgumentException if some property of the specified - * element prevents it from being added to this queue - */ - void put(E e) throws InterruptedException; - - /** - * Inserts the specified element into this queue, waiting up to the - * specified wait time if necessary for space to become available. - * - * @param e the element to add - * @param timeout how long to wait before giving up, in units of - * <tt>unit</tt> - * @param unit a <tt>TimeUnit</tt> determining how to interpret the - * <tt>timeout</tt> parameter - * @return <tt>true</tt> if successful, or <tt>false</tt> if - * the specified waiting time elapses before space is available - * @throws InterruptedException if interrupted while waiting - * @throws ClassCastException if the class of the specified element - * prevents it from being added to this queue - * @throws NullPointerException if the specified element is null - * @throws IllegalArgumentException if some property of the specified - * element prevents it from being added to this queue - */ - boolean offer(E e, long timeout, TimeUnit unit) - throws InterruptedException; - - /** - * Retrieves and removes the head of this queue, waiting if necessary - * until an element becomes available. - * - * @return the head of this queue - * @throws InterruptedException if interrupted while waiting - */ - E take() throws InterruptedException; - - /** - * Retrieves and removes the head of this queue, waiting up to the - * specified wait time if necessary for an element to become available. - * - * @param timeout how long to wait before giving up, in units of - * <tt>unit</tt> - * @param unit a <tt>TimeUnit</tt> determining how to interpret the - * <tt>timeout</tt> parameter - * @return the head of this queue, or <tt>null</tt> if the - * specified waiting time elapses before an element is available - * @throws InterruptedException if interrupted while waiting - */ - E poll(long timeout, TimeUnit unit) - throws InterruptedException; - - /** - * Returns the number of additional elements that this queue can ideally - * (in the absence of memory or resource constraints) accept without - * blocking, or <tt>Integer.MAX_VALUE</tt> if there is no intrinsic - * limit. - * - * <p>Note that you <em>cannot</em> always tell if an attempt to insert - * an element will succeed by inspecting <tt>remainingCapacity</tt> - * because it may be the case that another thread is about to - * insert or remove an element. - * - * @return the remaining capacity - */ - int remainingCapacity(); - - /** - * Removes a single instance of the specified element from this queue, - * if it is present. More formally, removes an element <tt>e</tt> such - * that <tt>o.equals(e)</tt>, if this queue contains one or more such - * elements. - * Returns <tt>true</tt> if this queue contained the specified element - * (or equivalently, if this queue changed as a result of the call). - * - * @param o element to be removed from this queue, if present - * @return <tt>true</tt> if this queue changed as a result of the call - * @throws ClassCastException if the class of the specified element - * is incompatible with this queue (optional) - * @throws NullPointerException if the specified element is null (optional) - */ - boolean remove(Object o); - - /** - * Returns <tt>true</tt> if this queue contains the specified element. - * More formally, returns <tt>true</tt> if and only if this queue contains - * at least one element <tt>e</tt> such that <tt>o.equals(e)</tt>. - * - * @param o object to be checked for containment in this queue - * @return <tt>true</tt> if this queue contains the specified element - * @throws ClassCastException if the class of the specified element - * is incompatible with this queue (optional) - * @throws NullPointerException if the specified element is null (optional) - */ - public boolean contains(Object o); - - /** - * Removes all available elements from this queue and adds them - * to the given collection. This operation may be more - * efficient than repeatedly polling this queue. A failure - * encountered while attempting to add elements to - * collection <tt>c</tt> may result in elements being in neither, - * either or both collections when the associated exception is - * thrown. Attempts to drain a queue to itself result in - * <tt>IllegalArgumentException</tt>. Further, the behavior of - * this operation is undefined if the specified collection is - * modified while the operation is in progress. - * - * @param c the collection to transfer elements into - * @return the number of elements transferred - * @throws UnsupportedOperationException if addition of elements - * is not supported by the specified collection - * @throws ClassCastException if the class of an element of this queue - * prevents it from being added to the specified collection - * @throws NullPointerException if the specified collection is null - * @throws IllegalArgumentException if the specified collection is this - * queue, or some property of an element of this queue prevents - * it from being added to the specified collection - */ - int drainTo(Collection<? super E> c); - - /** - * Removes at most the given number of available elements from - * this queue and adds them to the given collection. A failure - * encountered while attempting to add elements to - * collection <tt>c</tt> may result in elements being in neither, - * either or both collections when the associated exception is - * thrown. Attempts to drain a queue to itself result in - * <tt>IllegalArgumentException</tt>. Further, the behavior of - * this operation is undefined if the specified collection is - * modified while the operation is in progress. - * - * @param c the collection to transfer elements into - * @param maxElements the maximum number of elements to transfer - * @return the number of elements transferred - * @throws UnsupportedOperationException if addition of elements - * is not supported by the specified collection - * @throws ClassCastException if the class of an element of this queue - * prevents it from being added to the specified collection - * @throws NullPointerException if the specified collection is null - * @throws IllegalArgumentException if the specified collection is this - * queue, or some property of an element of this queue prevents - * it from being added to the specified collection - */ - int drainTo(Collection<? super E> c, int maxElements); -} diff --git a/src/actors/scala/actors/threadpool/Callable.java b/src/actors/scala/actors/threadpool/Callable.java deleted file mode 100644 index f1b200c022..0000000000 --- a/src/actors/scala/actors/threadpool/Callable.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Written by Doug Lea with assistance from members of JCP JSR-166 - * Expert Group and released to the public domain, as explained at - * http://creativecommons.org/licenses/publicdomain - */ - -package scala.actors.threadpool; - -/** - * A task that returns a result and may throw an exception. - * Implementors define a single method with no arguments called - * <tt>call</tt>. - * - * <p>The <tt>Callable</tt> interface is similar to {@link - * java.lang.Runnable}, in that both are designed for classes whose - * instances are potentially executed by another thread. A - * <tt>Runnable</tt>, however, does not return a result and cannot - * throw a checked exception. - * - * <p> The {@link Executors} class contains utility methods to - * convert from other common forms to <tt>Callable</tt> classes. - * - * @see Executor - * @since 1.5 - * @author Doug Lea - */ -public interface Callable { - /** - * Computes a result, or throws an exception if unable to do so. - * - * @return computed result - * @throws Exception if unable to compute a result - */ - Object call() throws Exception; -} diff --git a/src/actors/scala/actors/threadpool/CancellationException.java b/src/actors/scala/actors/threadpool/CancellationException.java deleted file mode 100644 index c2163b83c7..0000000000 --- a/src/actors/scala/actors/threadpool/CancellationException.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Written by Doug Lea with assistance from members of JCP JSR-166 - * Expert Group and released to the public domain, as explained at - * http://creativecommons.org/licenses/publicdomain - */ - -package scala.actors.threadpool; - -/** - * Exception indicating that the result of a value-producing task, - * such as a {@link FutureTask}, cannot be retrieved because the task - * was cancelled. - * - * @since 1.5 - * @author Doug Lea - */ -public class CancellationException extends IllegalStateException { - private static final long serialVersionUID = -9202173006928992231L; - - /** - * Constructs a <tt>CancellationException</tt> with no detail message. - */ - public CancellationException() {} - - /** - * Constructs a <tt>CancellationException</tt> with the specified detail - * message. - * - * @param message the detail message - */ - public CancellationException(String message) { - super(message); - } -} diff --git a/src/actors/scala/actors/threadpool/CompletionService.java b/src/actors/scala/actors/threadpool/CompletionService.java deleted file mode 100644 index 219ab7affa..0000000000 --- a/src/actors/scala/actors/threadpool/CompletionService.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Written by Doug Lea with assistance from members of JCP JSR-166 - * Expert Group and released to the public domain, as explained at - * http://creativecommons.org/licenses/publicdomain - */ - -package scala.actors.threadpool; - -/** - * A service that decouples the production of new asynchronous tasks - * from the consumption of the results of completed tasks. Producers - * <tt>submit</tt> tasks for execution. Consumers <tt>take</tt> - * completed tasks and process their results in the order they - * complete. A <tt>CompletionService</tt> can for example be used to - * manage asynchronous IO, in which tasks that perform reads are - * submitted in one part of a program or system, and then acted upon - * in a different part of the program when the reads complete, - * possibly in a different order than they were requested. - * - * <p>Typically, a <tt>CompletionService</tt> relies on a separate - * {@link Executor} to actually execute the tasks, in which case the - * <tt>CompletionService</tt> only manages an internal completion - * queue. The {@link ExecutorCompletionService} class provides an - * implementation of this approach. - * - * <p>Memory consistency effects: Actions in a thread prior to - * submitting a task to a {@code CompletionService} - * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a> - * actions taken by that task, which in turn <i>happen-before</i> - * actions following a successful return from the corresponding {@code take()}. - * - */ -public interface CompletionService { - /** - * Submits a value-returning task for execution and returns a Future - * representing the pending results of the task. Upon completion, - * this task may be taken or polled. - * - * @param task the task to submit - * @return a Future representing pending completion of the task - * @throws RejectedExecutionException if the task cannot be - * scheduled for execution - * @throws NullPointerException if the task is null - */ - Future submit(Callable task); - - /** - * Submits a Runnable task for execution and returns a Future - * representing that task. Upon completion, this task may be - * taken or polled. - * - * @param task the task to submit - * @param result the result to return upon successful completion - * @return a Future representing pending completion of the task, - * and whose <tt>get()</tt> method will return the given - * result value upon completion - * @throws RejectedExecutionException if the task cannot be - * scheduled for execution - * @throws NullPointerException if the task is null - */ - Future submit(Runnable task, Object result); - - /** - * Retrieves and removes the Future representing the next - * completed task, waiting if none are yet present. - * - * @return the Future representing the next completed task - * @throws InterruptedException if interrupted while waiting - */ - Future take() throws InterruptedException; - - - /** - * Retrieves and removes the Future representing the next - * completed task or <tt>null</tt> if none are present. - * - * @return the Future representing the next completed task, or - * <tt>null</tt> if none are present - */ - Future poll(); - - /** - * Retrieves and removes the Future representing the next - * completed task, waiting if necessary up to the specified wait - * time if none are yet present. - * - * @param timeout how long to wait before giving up, in units of - * <tt>unit</tt> - * @param unit a <tt>TimeUnit</tt> determining how to interpret the - * <tt>timeout</tt> parameter - * @return the Future representing the next completed task or - * <tt>null</tt> if the specified waiting time elapses - * before one is present - * @throws InterruptedException if interrupted while waiting - */ - Future poll(long timeout, TimeUnit unit) throws InterruptedException; -} diff --git a/src/actors/scala/actors/threadpool/ExecutionException.java b/src/actors/scala/actors/threadpool/ExecutionException.java deleted file mode 100644 index 912f965acf..0000000000 --- a/src/actors/scala/actors/threadpool/ExecutionException.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Written by Doug Lea with assistance from members of JCP JSR-166 - * Expert Group and released to the public domain, as explained at - * http://creativecommons.org/licenses/publicdomain - */ - -package scala.actors.threadpool; - -/** - * Exception thrown when attempting to retrieve the result of a task - * that aborted by throwing an exception. This exception can be - * inspected using the {@link #getCause()} method. - * - * @see Future - * @since 1.5 - * @author Doug Lea - */ -public class ExecutionException extends Exception { - private static final long serialVersionUID = 7830266012832686185L; - - /** - * Constructs an <tt>ExecutionException</tt> with no detail message. - * The cause is not initialized, and may subsequently be - * initialized by a call to {@link #initCause(Throwable) initCause}. - */ - protected ExecutionException() { } - - /** - * Constructs an <tt>ExecutionException</tt> with the specified detail - * message. The cause is not initialized, and may subsequently be - * initialized by a call to {@link #initCause(Throwable) initCause}. - * - * @param message the detail message - */ - protected ExecutionException(String message) { - super(message); - } - - /** - * Constructs an <tt>ExecutionException</tt> with the specified detail - * message and cause. - * - * @param message the detail message - * @param cause the cause (which is saved for later retrieval by the - * {@link #getCause()} method) - */ - public ExecutionException(String message, Throwable cause) { - super(message, cause); - } - - /** - * Constructs an <tt>ExecutionException</tt> with the specified cause. - * The detail message is set to: - * <pre> - * (cause == null ? null : cause.toString())</pre> - * (which typically contains the class and detail message of - * <tt>cause</tt>). - * - * @param cause the cause (which is saved for later retrieval by the - * {@link #getCause()} method) - */ - public ExecutionException(Throwable cause) { - super(cause); - } -} diff --git a/src/actors/scala/actors/threadpool/Executor.java b/src/actors/scala/actors/threadpool/Executor.java deleted file mode 100644 index e444e64dff..0000000000 --- a/src/actors/scala/actors/threadpool/Executor.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Written by Doug Lea with assistance from members of JCP JSR-166 - * Expert Group and released to the public domain, as explained at - * http://creativecommons.org/licenses/publicdomain - */ - -package scala.actors.threadpool; - -/** - * An object that executes submitted {@link Runnable} tasks. This - * interface provides a way of decoupling task submission from the - * mechanics of how each task will be run, including details of thread - * use, scheduling, etc. An <tt>Executor</tt> is normally used - * instead of explicitly creating threads. For example, rather than - * invoking <tt>new Thread(new(RunnableTask())).start()</tt> for each - * of a set of tasks, you might use: - * - * <pre> - * Executor executor = <em>anExecutor</em>; - * executor.execute(new RunnableTask1()); - * executor.execute(new RunnableTask2()); - * ... - * </pre> - * - * However, the <tt>Executor</tt> interface does not strictly - * require that execution be asynchronous. In the simplest case, an - * executor can run the submitted task immediately in the caller's - * thread: - * - * <pre> - * class DirectExecutor implements Executor { - * public void execute(Runnable r) { - * r.run(); - * } - * }</pre> - * - * More typically, tasks are executed in some thread other - * than the caller's thread. The executor below spawns a new thread - * for each task. - * - * <pre> - * class ThreadPerTaskExecutor implements Executor { - * public void execute(Runnable r) { - * new Thread(r).start(); - * } - * }</pre> - * - * Many <tt>Executor</tt> implementations impose some sort of - * limitation on how and when tasks are scheduled. The executor below - * serializes the submission of tasks to a second executor, - * illustrating a composite executor. - * - * <pre> - * class SerialExecutor implements Executor { - * final Queue<Runnable> tasks = new ArrayDeque<Runnable>(); - * final Executor executor; - * Runnable active; - * - * SerialExecutor(Executor executor) { - * this.executor = executor; - * } - * - * public synchronized void execute(final Runnable r) { - * tasks.offer(new Runnable() { - * public void run() { - * try { - * r.run(); - * } finally { - * scheduleNext(); - * } - * } - * }); - * if (active == null) { - * scheduleNext(); - * } - * } - * - * protected synchronized void scheduleNext() { - * if ((active = tasks.poll()) != null) { - * executor.execute(active); - * } - * } - * }</pre> - * - * The <tt>Executor</tt> implementations provided in this package - * implement {@link ExecutorService}, which is a more extensive - * interface. The {@link ThreadPoolExecutor} class provides an - * extensible thread pool implementation. The {@link Executors} class - * provides convenient factory methods for these Executors. - * - * <p>Memory consistency effects: Actions in a thread prior to - * submitting a {@code Runnable} object to an {@code Executor} - * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a> - * its execution begins, perhaps in another thread. - * - * @since 1.5 - * @author Doug Lea - */ -public interface Executor { - - /** - * Executes the given command at some time in the future. The command - * may execute in a new thread, in a pooled thread, or in the calling - * thread, at the discretion of the <tt>Executor</tt> implementation. - * - * @param command the runnable task - * @throws RejectedExecutionException if this task cannot be - * accepted for execution. - * @throws NullPointerException if command is null - */ - void execute(Runnable command); -} diff --git a/src/actors/scala/actors/threadpool/ExecutorCompletionService.java b/src/actors/scala/actors/threadpool/ExecutorCompletionService.java deleted file mode 100644 index 02e9bbe297..0000000000 --- a/src/actors/scala/actors/threadpool/ExecutorCompletionService.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Written by Doug Lea with assistance from members of JCP JSR-166 - * Expert Group and released to the public domain, as explained at - * http://creativecommons.org/licenses/publicdomain - */ - -package scala.actors.threadpool; -import scala.actors.threadpool.*; // for javadoc (till 6280605 is fixed) - -/** - * A {@link CompletionService} that uses a supplied {@link Executor} - * to execute tasks. This class arranges that submitted tasks are, - * upon completion, placed on a queue accessible using <tt>take</tt>. - * The class is lightweight enough to be suitable for transient use - * when processing groups of tasks. - * - * <p> - * - * <b>Usage Examples.</b> - * - * Suppose you have a set of solvers for a certain problem, each - * returning a value of some type <tt>Result</tt>, and would like to - * run them concurrently, processing the results of each of them that - * return a non-null value, in some method <tt>use(Result r)</tt>. You - * could write this as: - * - * <pre> - * void solve(Executor e, - * Collection<Callable<Result>> solvers) - * throws InterruptedException, ExecutionException { - * CompletionService<Result> ecs - * = new ExecutorCompletionService<Result>(e); - * for (Callable<Result> s : solvers) - * ecs.submit(s); - * int n = solvers.size(); - * for (int i = 0; i < n; ++i) { - * Result r = ecs.take().get(); - * if (r != null) - * use(r); - * } - * } - * </pre> - * - * Suppose instead that you would like to use the first non-null result - * of the set of tasks, ignoring any that encounter exceptions, - * and cancelling all other tasks when the first one is ready: - * - * <pre> - * void solve(Executor e, - * Collection<Callable<Result>> solvers) - * throws InterruptedException { - * CompletionService<Result> ecs - * = new ExecutorCompletionService<Result>(e); - * int n = solvers.size(); - * List<Future<Result>> futures - * = new ArrayList<Future<Result>>(n); - * Result result = null; - * try { - * for (Callable<Result> s : solvers) - * futures.add(ecs.submit(s)); - * for (int i = 0; i < n; ++i) { - * try { - * Result r = ecs.take().get(); - * if (r != null) { - * result = r; - * break; - * } - * } catch (ExecutionException ignore) {} - * } - * } - * finally { - * for (Future<Result> f : futures) - * f.cancel(true); - * } - * - * if (result != null) - * use(result); - * } - * </pre> - */ -public class ExecutorCompletionService implements CompletionService { - private final Executor executor; - private final AbstractExecutorService aes; - private final BlockingQueue completionQueue; - - /** - * FutureTask extension to enqueue upon completion - */ - private class QueueingFuture extends FutureTask { - QueueingFuture(RunnableFuture task) { - super(task, null); - this.task = task; - } - protected void done() { completionQueue.add(task); } - private final Future task; - } - - private RunnableFuture newTaskFor(Callable task) { - if (aes == null) - return new FutureTask(task); - else - return aes.newTaskFor(task); - } - - private RunnableFuture newTaskFor(Runnable task, Object result) { - if (aes == null) - return new FutureTask(task, result); - else - return aes.newTaskFor(task, result); - } - - /** - * Creates an ExecutorCompletionService using the supplied - * executor for base task execution and a - * {@link LinkedBlockingQueue} as a completion queue. - * - * @param executor the executor to use - * @throws NullPointerException if executor is <tt>null</tt> - */ - public ExecutorCompletionService(Executor executor) { - if (executor == null) - throw new NullPointerException(); - this.executor = executor; - this.aes = (executor instanceof AbstractExecutorService) ? - (AbstractExecutorService) executor : null; - this.completionQueue = new LinkedBlockingQueue(); - } - - /** - * Creates an ExecutorCompletionService using the supplied - * executor for base task execution and the supplied queue as its - * completion queue. - * - * @param executor the executor to use - * @param completionQueue the queue to use as the completion queue - * normally one dedicated for use by this service. This queue is - * treated as unbounded -- failed attempted <tt>Queue.add</tt> - * operations for completed tasks cause them not to be - * retrievable. - * @throws NullPointerException if executor or completionQueue are <tt>null</tt> - */ - public ExecutorCompletionService(Executor executor, - BlockingQueue completionQueue) { - if (executor == null || completionQueue == null) - throw new NullPointerException(); - this.executor = executor; - this.aes = (executor instanceof AbstractExecutorService) ? - (AbstractExecutorService) executor : null; - this.completionQueue = completionQueue; - } - - public Future submit(Callable task) { - if (task == null) throw new NullPointerException(); - RunnableFuture f = newTaskFor(task); - executor.execute(new QueueingFuture(f)); - return f; - } - - public Future submit(Runnable task, Object result) { - if (task == null) throw new NullPointerException(); - RunnableFuture f = newTaskFor(task, result); - executor.execute(new QueueingFuture(f)); - return f; - } - - public Future take() throws InterruptedException { - return (Future)completionQueue.take(); - } - - public Future poll() { - return (Future)completionQueue.poll(); - } - - public Future poll(long timeout, TimeUnit unit) throws InterruptedException { - return (Future)completionQueue.poll(timeout, unit); - } - -} diff --git a/src/actors/scala/actors/threadpool/ExecutorService.java b/src/actors/scala/actors/threadpool/ExecutorService.java deleted file mode 100644 index d3a9a3b8a8..0000000000 --- a/src/actors/scala/actors/threadpool/ExecutorService.java +++ /dev/null @@ -1,331 +0,0 @@ -/* - * Written by Doug Lea with assistance from members of JCP JSR-166 - * Expert Group and released to the public domain, as explained at - * http://creativecommons.org/licenses/publicdomain - */ - -package scala.actors.threadpool; - -import scala.actors.threadpool.*; // for javadoc (till 6280605 is fixed) -import java.util.List; -import java.util.Collection; - -/** - * An {@link Executor} that provides methods to manage termination and - * methods that can produce a {@link Future} for tracking progress of - * one or more asynchronous tasks. - * - * <p> An <tt>ExecutorService</tt> can be shut down, which will cause - * it to reject new tasks. Two different methods are provided for - * shutting down an <tt>ExecutorService</tt>. The {@link #shutdown} - * method will allow previously submitted tasks to execute before - * terminating, while the {@link #shutdownNow} method prevents waiting - * tasks from starting and attempts to stop currently executing tasks. - * Upon termination, an executor has no tasks actively executing, no - * tasks awaiting execution, and no new tasks can be submitted. An - * unused <tt>ExecutorService</tt> should be shut down to allow - * reclamation of its resources. - * - * <p> Method <tt>submit</tt> extends base method {@link - * Executor#execute} by creating and returning a {@link Future} that - * can be used to cancel execution and/or wait for completion. - * Methods <tt>invokeAny</tt> and <tt>invokeAll</tt> perform the most - * commonly useful forms of bulk execution, executing a collection of - * tasks and then waiting for at least one, or all, to - * complete. (Class {@link ExecutorCompletionService} can be used to - * write customized variants of these methods.) - * - * <p>The {@link Executors} class provides factory methods for the - * executor services provided in this package. - * - * <h3>Usage Example</h3> - * - * Here is a sketch of a network service in which threads in a thread - * pool service incoming requests. It uses the preconfigured {@link - * Executors#newFixedThreadPool} factory method: - * - * <pre> - * class NetworkService implements Runnable { - * private final ServerSocket serverSocket; - * private final ExecutorService pool; - * - * public NetworkService(int port, int poolSize) - * throws IOException { - * serverSocket = new ServerSocket(port); - * pool = Executors.newFixedThreadPool(poolSize); - * } - * - * public void run() { // run the service - * try { - * for (;;) { - * pool.execute(new Handler(serverSocket.accept())); - * } - * } catch (IOException ex) { - * pool.shutdown(); - * } - * } - * } - * - * class Handler implements Runnable { - * private final Socket socket; - * Handler(Socket socket) { this.socket = socket; } - * public void run() { - * // read and service request on socket - * } - * } - * </pre> - * - * The following method shuts down an <tt>ExecutorService</tt> in two phases, - * first by calling <tt>shutdown</tt> to reject incoming tasks, and then - * calling <tt>shutdownNow</tt>, if necessary, to cancel any lingering tasks: - * - * <pre> - * void shutdownAndAwaitTermination(ExecutorService pool) { - * pool.shutdown(); // Disable new tasks from being submitted - * try { - * // Wait a while for existing tasks to terminate - * if (!pool.awaitTermination(60, TimeUnit.SECONDS)) { - * pool.shutdownNow(); // Cancel currently executing tasks - * // Wait a while for tasks to respond to being cancelled - * if (!pool.awaitTermination(60, TimeUnit.SECONDS)) - * System.err.println("Pool did not terminate"); - * } - * } catch (InterruptedException ie) { - * // (Re-)Cancel if current thread also interrupted - * pool.shutdownNow(); - * // Preserve interrupt status - * Thread.currentThread().interrupt(); - * } - * } - * </pre> - * - * <p>Memory consistency effects: Actions in a thread prior to the - * submission of a {@code Runnable} or {@code Callable} task to an - * {@code ExecutorService} - * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a> - * any actions taken by that task, which in turn <i>happen-before</i> the - * result is retrieved via {@code Future.get()}. - * - * @since 1.5 - * @author Doug Lea - */ -public interface ExecutorService extends Executor { - - /** - * Initiates an orderly shutdown in which previously submitted - * tasks are executed, but no new tasks will be accepted. - * Invocation has no additional effect if already shut down. - * - * @throws SecurityException if a security manager exists and - * shutting down this ExecutorService may manipulate - * threads that the caller is not permitted to modify - * because it does not hold {@link - * java.lang.RuntimePermission}<tt>("modifyThread")</tt>, - * or the security manager's <tt>checkAccess</tt> method - * denies access. - */ - void shutdown(); - - /** - * Attempts to stop all actively executing tasks, halts the - * processing of waiting tasks, and returns a list of the tasks that were - * awaiting execution. - * - * <p>There are no guarantees beyond best-effort attempts to stop - * processing actively executing tasks. For example, typical - * implementations will cancel via {@link Thread#interrupt}, so any - * task that fails to respond to interrupts may never terminate. - * - * @return list of tasks that never commenced execution - * @throws SecurityException if a security manager exists and - * shutting down this ExecutorService may manipulate - * threads that the caller is not permitted to modify - * because it does not hold {@link - * java.lang.RuntimePermission}<tt>("modifyThread")</tt>, - * or the security manager's <tt>checkAccess</tt> method - * denies access. - */ - List shutdownNow(); - - /** - * Returns <tt>true</tt> if this executor has been shut down. - * - * @return <tt>true</tt> if this executor has been shut down - */ - boolean isShutdown(); - - /** - * Returns <tt>true</tt> if all tasks have completed following shut down. - * Note that <tt>isTerminated</tt> is never <tt>true</tt> unless - * either <tt>shutdown</tt> or <tt>shutdownNow</tt> was called first. - * - * @return <tt>true</tt> if all tasks have completed following shut down - */ - boolean isTerminated(); - - /** - * Blocks until all tasks have completed execution after a shutdown - * request, or the timeout occurs, or the current thread is - * interrupted, whichever happens first. - * - * @param timeout the maximum time to wait - * @param unit the time unit of the timeout argument - * @return <tt>true</tt> if this executor terminated and - * <tt>false</tt> if the timeout elapsed before termination - * @throws InterruptedException if interrupted while waiting - */ - boolean awaitTermination(long timeout, TimeUnit unit) - throws InterruptedException; - - - /** - * Submits a value-returning task for execution and returns a - * Future representing the pending results of the task. The - * Future's <tt>get</tt> method will return the task's result upon - * successful completion. - * - * <p> - * If you would like to immediately block waiting - * for a task, you can use constructions of the form - * <tt>result = exec.submit(aCallable).get();</tt> - * - * <p> Note: The {@link Executors} class includes a set of methods - * that can convert some other common closure-like objects, - * for example, {@link java.security.PrivilegedAction} to - * {@link Callable} form so they can be submitted. - * - * @param task the task to submit - * @return a Future representing pending completion of the task - * @throws RejectedExecutionException if the task cannot be - * scheduled for execution - * @throws NullPointerException if the task is null - */ - Future submit(Callable task); - - /** - * Submits a Runnable task for execution and returns a Future - * representing that task. The Future's <tt>get</tt> method will - * return the given result upon successful completion. - * - * @param task the task to submit - * @param result the result to return - * @return a Future representing pending completion of the task - * @throws RejectedExecutionException if the task cannot be - * scheduled for execution - * @throws NullPointerException if the task is null - */ - Future submit(Runnable task, Object result); - - /** - * Submits a Runnable task for execution and returns a Future - * representing that task. The Future's <tt>get</tt> method will - * return <tt>null</tt> upon <em>successful</em> completion. - * - * @param task the task to submit - * @return a Future representing pending completion of the task - * @throws RejectedExecutionException if the task cannot be - * scheduled for execution - * @throws NullPointerException if the task is null - */ - Future submit(Runnable task); - - /** - * Executes the given tasks, returning a list of Futures holding - * their status and results when all complete. - * {@link Future#isDone} is <tt>true</tt> for each - * element of the returned list. - * Note that a <em>completed</em> task could have - * terminated either normally or by throwing an exception. - * The results of this method are undefined if the given - * collection is modified while this operation is in progress. - * - * @param tasks the collection of tasks - * @return A list of Futures representing the tasks, in the same - * sequential order as produced by the iterator for the - * given task list, each of which has completed. - * @throws InterruptedException if interrupted while waiting, in - * which case unfinished tasks are cancelled. - * @throws NullPointerException if tasks or any of its elements are <tt>null</tt> - * @throws RejectedExecutionException if any task cannot be - * scheduled for execution - */ - - List invokeAll(Collection tasks) - throws InterruptedException; - - /** - * Executes the given tasks, returning a list of Futures holding - * their status and results - * when all complete or the timeout expires, whichever happens first. - * {@link Future#isDone} is <tt>true</tt> for each - * element of the returned list. - * Upon return, tasks that have not completed are cancelled. - * Note that a <em>completed</em> task could have - * terminated either normally or by throwing an exception. - * The results of this method are undefined if the given - * collection is modified while this operation is in progress. - * - * @param tasks the collection of tasks - * @param timeout the maximum time to wait - * @param unit the time unit of the timeout argument - * @return a list of Futures representing the tasks, in the same - * sequential order as produced by the iterator for the - * given task list. If the operation did not time out, - * each task will have completed. If it did time out, some - * of these tasks will not have completed. - * @throws InterruptedException if interrupted while waiting, in - * which case unfinished tasks are cancelled - * @throws NullPointerException if tasks, any of its elements, or - * unit are <tt>null</tt> - * @throws RejectedExecutionException if any task cannot be scheduled - * for execution - */ - List invokeAll(Collection tasks, long timeout, TimeUnit unit) - throws InterruptedException; - - /** - * Executes the given tasks, returning the result - * of one that has completed successfully (i.e., without throwing - * an exception), if any do. Upon normal or exceptional return, - * tasks that have not completed are cancelled. - * The results of this method are undefined if the given - * collection is modified while this operation is in progress. - * - * @param tasks the collection of tasks - * @return the result returned by one of the tasks - * @throws InterruptedException if interrupted while waiting - * @throws NullPointerException if tasks or any of its elements - * are <tt>null</tt> - * @throws IllegalArgumentException if tasks is empty - * @throws ExecutionException if no task successfully completes - * @throws RejectedExecutionException if tasks cannot be scheduled - * for execution - */ - Object invokeAny(Collection tasks) - throws InterruptedException, ExecutionException; - - /** - * Executes the given tasks, returning the result - * of one that has completed successfully (i.e., without throwing - * an exception), if any do before the given timeout elapses. - * Upon normal or exceptional return, tasks that have not - * completed are cancelled. - * The results of this method are undefined if the given - * collection is modified while this operation is in progress. - * - * @param tasks the collection of tasks - * @param timeout the maximum time to wait - * @param unit the time unit of the timeout argument - * @return the result returned by one of the tasks. - * @throws InterruptedException if interrupted while waiting - * @throws NullPointerException if tasks, any of its elements, or - * unit are <tt>null</tt> - * @throws TimeoutException if the given timeout elapses before - * any task successfully completes - * @throws ExecutionException if no task successfully completes - * @throws RejectedExecutionException if tasks cannot be scheduled - * for execution - */ - Object invokeAny(Collection tasks, long timeout, TimeUnit unit) - throws InterruptedException, ExecutionException, TimeoutException; -} diff --git a/src/actors/scala/actors/threadpool/Executors.java b/src/actors/scala/actors/threadpool/Executors.java deleted file mode 100644 index 49a127a8db..0000000000 --- a/src/actors/scala/actors/threadpool/Executors.java +++ /dev/null @@ -1,667 +0,0 @@ -/* - * Written by Doug Lea with assistance from members of JCP JSR-166 - * Expert Group and released to the public domain, as explained at - * http://creativecommons.org/licenses/publicdomain - */ - -package scala.actors.threadpool; -//import edu.emory.mathcs.backport.java.util.*; -import java.security.AccessControlContext; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.security.PrivilegedExceptionAction; -import java.security.AccessControlException; -import java.util.List; -import java.util.Collection; - -/** - * Factory and utility methods for {@link Executor}, {@link - * ExecutorService}, {@link ScheduledExecutorService}, {@link - * ThreadFactory}, and {@link Callable} classes defined in this - * package. This class supports the following kinds of methods: - * - * <ul> - * <li> Methods that create and return an {@link ExecutorService} - * set up with commonly useful configuration settings. - * <li> Methods that create and return a {@link ScheduledExecutorService} - * set up with commonly useful configuration settings. - * <li> Methods that create and return a "wrapped" ExecutorService, that - * disables reconfiguration by making implementation-specific methods - * inaccessible. - * <li> Methods that create and return a {@link ThreadFactory} - * that sets newly created threads to a known state. - * <li> Methods that create and return a {@link Callable} - * out of other closure-like forms, so they can be used - * in execution methods requiring <tt>Callable</tt>. - * </ul> - * - * @since 1.5 - * @author Doug Lea - */ -public class Executors { - - /** - * Creates a thread pool that reuses a fixed number of threads - * operating off a shared unbounded queue. At any point, at most - * <tt>nThreads</tt> threads will be active processing tasks. - * If additional tasks are submitted when all threads are active, - * they will wait in the queue until a thread is available. - * If any thread terminates due to a failure during execution - * prior to shutdown, a new one will take its place if needed to - * execute subsequent tasks. The threads in the pool will exist - * until it is explicitly {@link ExecutorService#shutdown shutdown}. - * - * @param nThreads the number of threads in the pool - * @return the newly created thread pool - * @throws IllegalArgumentException if <tt>nThreads <= 0</tt> - */ - public static ExecutorService newFixedThreadPool(int nThreads) { - return new ThreadPoolExecutor(nThreads, nThreads, - 0L, TimeUnit.MILLISECONDS, - new LinkedBlockingQueue()); - } - - /** - * Creates a thread pool that reuses a fixed number of threads - * operating off a shared unbounded queue, using the provided - * ThreadFactory to create new threads when needed. At any point, - * at most <tt>nThreads</tt> threads will be active processing - * tasks. If additional tasks are submitted when all threads are - * active, they will wait in the queue until a thread is - * available. If any thread terminates due to a failure during - * execution prior to shutdown, a new one will take its place if - * needed to execute subsequent tasks. The threads in the pool will - * exist until it is explicitly {@link ExecutorService#shutdown - * shutdown}. - * - * @param nThreads the number of threads in the pool - * @param threadFactory the factory to use when creating new threads - * @return the newly created thread pool - * @throws NullPointerException if threadFactory is null - * @throws IllegalArgumentException if <tt>nThreads <= 0</tt> - */ - public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) { - return new ThreadPoolExecutor(nThreads, nThreads, - 0L, TimeUnit.MILLISECONDS, - new LinkedBlockingQueue(), - threadFactory); - } - - /** - * Creates an Executor that uses a single worker thread operating - * off an unbounded queue. (Note however that if this single - * thread terminates due to a failure during execution prior to - * shutdown, a new one will take its place if needed to execute - * subsequent tasks.) Tasks are guaranteed to execute - * sequentially, and no more than one task will be active at any - * given time. Unlike the otherwise equivalent - * <tt>newFixedThreadPool(1)</tt> the returned executor is - * guaranteed not to be reconfigurable to use additional threads. - * - * @return the newly created single-threaded Executor - */ - public static ExecutorService newSingleThreadExecutor() { - return new FinalizableDelegatedExecutorService - (new ThreadPoolExecutor(1, 1, - 0L, TimeUnit.MILLISECONDS, - new LinkedBlockingQueue())); - } - - /** - * Creates an Executor that uses a single worker thread operating - * off an unbounded queue, and uses the provided ThreadFactory to - * create a new thread when needed. Unlike the otherwise - * equivalent <tt>newFixedThreadPool(1, threadFactory)</tt> the - * returned executor is guaranteed not to be reconfigurable to use - * additional threads. - * - * @param threadFactory the factory to use when creating new - * threads - * - * @return the newly created single-threaded Executor - * @throws NullPointerException if threadFactory is null - */ - public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) { - return new FinalizableDelegatedExecutorService - (new ThreadPoolExecutor(1, 1, - 0L, TimeUnit.MILLISECONDS, - new LinkedBlockingQueue(), - threadFactory)); - } - - /** - * Creates a thread pool that creates new threads as needed, but - * will reuse previously constructed threads when they are - * available. These pools will typically improve the performance - * of programs that execute many short-lived asynchronous tasks. - * Calls to <tt>execute</tt> will reuse previously constructed - * threads if available. If no existing thread is available, a new - * thread will be created and added to the pool. Threads that have - * not been used for sixty seconds are terminated and removed from - * the cache. Thus, a pool that remains idle for long enough will - * not consume any resources. Note that pools with similar - * properties but different details (for example, timeout parameters) - * may be created using {@link ThreadPoolExecutor} constructors. - * - * @return the newly created thread pool - */ - public static ExecutorService newCachedThreadPool() { - return new ThreadPoolExecutor(0, Integer.MAX_VALUE, - 60L, TimeUnit.SECONDS, - new SynchronousQueue()); - } - - /** - * Creates a thread pool that creates new threads as needed, but - * will reuse previously constructed threads when they are - * available, and uses the provided - * ThreadFactory to create new threads when needed. - * @param threadFactory the factory to use when creating new threads - * @return the newly created thread pool - * @throws NullPointerException if threadFactory is null - */ - public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) { - return new ThreadPoolExecutor(0, Integer.MAX_VALUE, - 60L, TimeUnit.SECONDS, - new SynchronousQueue(), - threadFactory); - } - - /** - * Creates a single-threaded executor that can schedule commands - * to run after a given delay, or to execute periodically. - * (Note however that if this single - * thread terminates due to a failure during execution prior to - * shutdown, a new one will take its place if needed to execute - * subsequent tasks.) Tasks are guaranteed to execute - * sequentially, and no more than one task will be active at any - * given time. Unlike the otherwise equivalent - * <tt>newScheduledThreadPool(1)</tt> the returned executor is - * guaranteed not to be reconfigurable to use additional threads. - * @return the newly created scheduled executor - */ - /* public static ScheduledExecutorService newSingleThreadScheduledExecutor() { - return new DelegatedScheduledExecutorService - (new ScheduledThreadPoolExecutor(1)); - } - */ - /** - * Creates a single-threaded executor that can schedule commands - * to run after a given delay, or to execute periodically. (Note - * however that if this single thread terminates due to a failure - * during execution prior to shutdown, a new one will take its - * place if needed to execute subsequent tasks.) Tasks are - * guaranteed to execute sequentially, and no more than one task - * will be active at any given time. Unlike the otherwise - * equivalent <tt>newScheduledThreadPool(1, threadFactory)</tt> - * the returned executor is guaranteed not to be reconfigurable to - * use additional threads. - * @param threadFactory the factory to use when creating new - * threads - * @return a newly created scheduled executor - * @throws NullPointerException if threadFactory is null - */ - /* public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory) { - return new DelegatedScheduledExecutorService - (new ScheduledThreadPoolExecutor(1, threadFactory)); - } - */ - /** - * Creates a thread pool that can schedule commands to run after a - * given delay, or to execute periodically. - * @param corePoolSize the number of threads to keep in the pool, - * even if they are idle. - * @return a newly created scheduled thread pool - * @throws IllegalArgumentException if <tt>corePoolSize < 0</tt> - */ - /* public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) { - return new ScheduledThreadPoolExecutor(corePoolSize); - } - */ - /** - * Creates a thread pool that can schedule commands to run after a - * given delay, or to execute periodically. - * @param corePoolSize the number of threads to keep in the pool, - * even if they are idle. - * @param threadFactory the factory to use when the executor - * creates a new thread. - * @return a newly created scheduled thread pool - * @throws IllegalArgumentException if <tt>corePoolSize < 0</tt> - * @throws NullPointerException if threadFactory is null - */ - /* public static ScheduledExecutorService newScheduledThreadPool( - int corePoolSize, ThreadFactory threadFactory) { - return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory); - } - */ - - /** - * Returns an object that delegates all defined {@link - * ExecutorService} methods to the given executor, but not any - * other methods that might otherwise be accessible using - * casts. This provides a way to safely "freeze" configuration and - * disallow tuning of a given concrete implementation. - * @param executor the underlying implementation - * @return an <tt>ExecutorService</tt> instance - * @throws NullPointerException if executor null - */ - public static ExecutorService unconfigurableExecutorService(ExecutorService executor) { - if (executor == null) - throw new NullPointerException(); - return new DelegatedExecutorService(executor); - } - - /** - * Returns an object that delegates all defined {@link - * ScheduledExecutorService} methods to the given executor, but - * not any other methods that might otherwise be accessible using - * casts. This provides a way to safely "freeze" configuration and - * disallow tuning of a given concrete implementation. - * @param executor the underlying implementation - * @return a <tt>ScheduledExecutorService</tt> instance - * @throws NullPointerException if executor null - */ - /* public static ScheduledExecutorService unconfigurableScheduledExecutorService(ScheduledExecutorService executor) { - if (executor == null) - throw new NullPointerException(); - return new DelegatedScheduledExecutorService(executor); - } - */ - /** - * Returns a default thread factory used to create new threads. - * This factory creates all new threads used by an Executor in the - * same {@link ThreadGroup}. If there is a {@link - * java.lang.SecurityManager}, it uses the group of {@link - * System#getSecurityManager}, else the group of the thread - * invoking this <tt>defaultThreadFactory</tt> method. Each new - * thread is created as a non-daemon thread with priority set to - * the smaller of <tt>Thread.NORM_PRIORITY</tt> and the maximum - * priority permitted in the thread group. New threads have names - * accessible via {@link Thread#getName} of - * <em>pool-N-thread-M</em>, where <em>N</em> is the sequence - * number of this factory, and <em>M</em> is the sequence number - * of the thread created by this factory. - * @return a thread factory - */ - public static ThreadFactory defaultThreadFactory() { - return new DefaultThreadFactory(); - } - - /** - * Returns a thread factory used to create new threads that - * have the same permissions as the current thread. - * This factory creates threads with the same settings as {@link - * Executors#defaultThreadFactory}, additionally setting the - * AccessControlContext and contextClassLoader of new threads to - * be the same as the thread invoking this - * <tt>privilegedThreadFactory</tt> method. A new - * <tt>privilegedThreadFactory</tt> can be created within an - * {@link AccessController#doPrivileged} action setting the - * current thread's access control context to create threads with - * the selected permission settings holding within that action. - * - * <p> Note that while tasks running within such threads will have - * the same access control and class loader settings as the - * current thread, they need not have the same {@link - * java.lang.ThreadLocal} or {@link - * java.lang.InheritableThreadLocal} values. If necessary, - * particular values of thread locals can be set or reset before - * any task runs in {@link ThreadPoolExecutor} subclasses using - * {@link ThreadPoolExecutor#beforeExecute}. Also, if it is - * necessary to initialize worker threads to have the same - * InheritableThreadLocal settings as some other designated - * thread, you can create a custom ThreadFactory in which that - * thread waits for and services requests to create others that - * will inherit its values. - * - * @return a thread factory - * @throws AccessControlException if the current access control - * context does not have permission to both get and set context - * class loader. - */ - public static ThreadFactory privilegedThreadFactory() { - return new PrivilegedThreadFactory(); - } - - /** - * Returns a {@link Callable} object that, when - * called, runs the given task and returns the given result. This - * can be useful when applying methods requiring a - * <tt>Callable</tt> to an otherwise resultless action. - * @param task the task to run - * @param result the result to return - * @return a callable object - * @throws NullPointerException if task null - */ - public static Callable callable(Runnable task, Object result) { - if (task == null) - throw new NullPointerException(); - return new RunnableAdapter(task, result); - } - - /** - * Returns a {@link Callable} object that, when - * called, runs the given task and returns <tt>null</tt>. - * @param task the task to run - * @return a callable object - * @throws NullPointerException if task null - */ - public static Callable callable(Runnable task) { - if (task == null) - throw new NullPointerException(); - return new RunnableAdapter(task, null); - } - - /** - * Returns a {@link Callable} object that, when - * called, runs the given privileged action and returns its result. - * @param action the privileged action to run - * @return a callable object - * @throws NullPointerException if action null - */ - public static Callable callable(final PrivilegedAction action) { - if (action == null) - throw new NullPointerException(); - return new Callable() { - public Object call() { return action.run(); }}; - } - - /** - * Returns a {@link Callable} object that, when - * called, runs the given privileged exception action and returns - * its result. - * @param action the privileged exception action to run - * @return a callable object - * @throws NullPointerException if action null - */ - public static Callable callable(final PrivilegedExceptionAction action) { - if (action == null) - throw new NullPointerException(); - return new Callable() { - public Object call() throws Exception { return action.run(); }}; - } - - /** - * Returns a {@link Callable} object that will, when - * called, execute the given <tt>callable</tt> under the current - * access control context. This method should normally be - * invoked within an {@link AccessController#doPrivileged} action - * to create callables that will, if possible, execute under the - * selected permission settings holding within that action; or if - * not possible, throw an associated {@link - * AccessControlException}. - * @param callable the underlying task - * @return a callable object - * @throws NullPointerException if callable null - * - */ - public static Callable privilegedCallable(Callable callable) { - if (callable == null) - throw new NullPointerException(); - return new PrivilegedCallable(callable); - } - - /** - * Returns a {@link Callable} object that will, when - * called, execute the given <tt>callable</tt> under the current - * access control context, with the current context class loader - * as the context class loader. This method should normally be - * invoked within an {@link AccessController#doPrivileged} action - * to create callables that will, if possible, execute under the - * selected permission settings holding within that action; or if - * not possible, throw an associated {@link - * AccessControlException}. - * @param callable the underlying task - * - * @return a callable object - * @throws NullPointerException if callable null - * @throws AccessControlException if the current access control - * context does not have permission to both set and get context - * class loader. - */ - public static Callable privilegedCallableUsingCurrentClassLoader(Callable callable) { - if (callable == null) - throw new NullPointerException(); - return new PrivilegedCallableUsingCurrentClassLoader(callable); - } - - // Non-public classes supporting the public methods - - /** - * A callable that runs given task and returns given result - */ - static final class RunnableAdapter implements Callable { - final Runnable task; - final Object result; - RunnableAdapter(Runnable task, Object result) { - this.task = task; - this.result = result; - } - public Object call() { - task.run(); - return result; - } - } - - /** - * A callable that runs under established access control settings - */ - static final class PrivilegedCallable implements Callable { - private final AccessControlContext acc; - private final Callable task; - private Object result; - private Exception exception; - PrivilegedCallable(Callable task) { - this.task = task; - this.acc = AccessController.getContext(); - } - - public Object call() throws Exception { - AccessController.doPrivileged(new PrivilegedAction() { - public Object run() { - try { - result = task.call(); - } catch (Exception ex) { - exception = ex; - } - return null; - } - }, acc); - if (exception != null) - throw exception; - else - return result; - } - } - - /** - * A callable that runs under established access control settings and - * current ClassLoader - */ - static final class PrivilegedCallableUsingCurrentClassLoader implements Callable { - private final ClassLoader ccl; - private final AccessControlContext acc; - private final Callable task; - private Object result; - private Exception exception; - PrivilegedCallableUsingCurrentClassLoader(Callable task) { - this.task = task; - this.ccl = Thread.currentThread().getContextClassLoader(); - this.acc = AccessController.getContext(); - acc.checkPermission(new RuntimePermission("getContextClassLoader")); - acc.checkPermission(new RuntimePermission("setContextClassLoader")); - } - - public Object call() throws Exception { - AccessController.doPrivileged(new PrivilegedAction() { - public Object run() { - ClassLoader savedcl = null; - Thread t = Thread.currentThread(); - try { - ClassLoader cl = t.getContextClassLoader(); - if (ccl != cl) { - t.setContextClassLoader(ccl); - savedcl = cl; - } - result = task.call(); - } catch (Exception ex) { - exception = ex; - } finally { - if (savedcl != null) - t.setContextClassLoader(savedcl); - } - return null; - } - }, acc); - if (exception != null) - throw exception; - else - return result; - } - } - - /** - * The default thread factory - */ - static class DefaultThreadFactory implements ThreadFactory { - static final AtomicInteger poolNumber = new AtomicInteger(1); - final ThreadGroup group; - final AtomicInteger threadNumber = new AtomicInteger(1); - final String namePrefix; - - DefaultThreadFactory() { - SecurityManager s = System.getSecurityManager(); - group = (s != null)? s.getThreadGroup() : - Thread.currentThread().getThreadGroup(); - namePrefix = "pool-" + - poolNumber.getAndIncrement() + - "-thread-"; - } - - public Thread newThread(Runnable r) { - Thread t = new Thread(group, r, - namePrefix + threadNumber.getAndIncrement(), - 0); - if (t.isDaemon()) - t.setDaemon(false); - if (t.getPriority() != Thread.NORM_PRIORITY) - t.setPriority(Thread.NORM_PRIORITY); - return t; - } - } - - /** - * Thread factory capturing access control and class loader - */ - static class PrivilegedThreadFactory extends DefaultThreadFactory { - private final ClassLoader ccl; - private final AccessControlContext acc; - - PrivilegedThreadFactory() { - super(); - this.ccl = Thread.currentThread().getContextClassLoader(); - this.acc = AccessController.getContext(); - acc.checkPermission(new RuntimePermission("setContextClassLoader")); - } - - public Thread newThread(final Runnable r) { - return super.newThread(new Runnable() { - public void run() { - AccessController.doPrivileged(new PrivilegedAction() { - public Object run() { - Thread.currentThread().setContextClassLoader(ccl); - r.run(); - return null; - } - }, acc); - } - }); - } - - } - - /** - * A wrapper class that exposes only the ExecutorService methods - * of an ExecutorService implementation. - */ - static class DelegatedExecutorService extends AbstractExecutorService { - private final ExecutorService e; - DelegatedExecutorService(ExecutorService executor) { e = executor; } - public void execute(Runnable command) { e.execute(command); } - public void shutdown() { e.shutdown(); } - public List shutdownNow() { return e.shutdownNow(); } - public boolean isShutdown() { return e.isShutdown(); } - public boolean isTerminated() { return e.isTerminated(); } - public boolean awaitTermination(long timeout, TimeUnit unit) - throws InterruptedException { - return e.awaitTermination(timeout, unit); - } - public Future submit(Runnable task) { - return e.submit(task); - } - public Future submit(Callable task) { - return e.submit(task); - } - public Future submit(Runnable task, Object result) { - return e.submit(task, result); - } - public List<Future> invokeAll(Collection tasks) - throws InterruptedException { - return e.invokeAll(tasks); - } - public List<Future> invokeAll(Collection tasks, - long timeout, TimeUnit unit) - throws InterruptedException { - return e.invokeAll(tasks, timeout, unit); - } - public Object invokeAny(Collection tasks) - throws InterruptedException, ExecutionException { - return e.invokeAny(tasks); - } - public Object invokeAny(Collection tasks, - long timeout, TimeUnit unit) - throws InterruptedException, ExecutionException, TimeoutException { - return e.invokeAny(tasks, timeout, unit); - } - } - - static class FinalizableDelegatedExecutorService - extends DelegatedExecutorService { - FinalizableDelegatedExecutorService(ExecutorService executor) { - super(executor); - } - protected void finalize() { - super.shutdown(); - } - } - - /** - * A wrapper class that exposes only the ScheduledExecutorService - * methods of a ScheduledExecutorService implementation. - */ - /* static class DelegatedScheduledExecutorService - extends DelegatedExecutorService - implements ScheduledExecutorService { - private final ScheduledExecutorService e; - DelegatedScheduledExecutorService(ScheduledExecutorService executor) { - super(executor); - e = executor; - } - public ScheduledFuture schedule(Runnable command, long delay, TimeUnit unit) { - return e.schedule(command, delay, unit); - } - public ScheduledFuture schedule(Callable callable, long delay, TimeUnit unit) { - return e.schedule(callable, delay, unit); - } - public ScheduledFuture scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) { - return e.scheduleAtFixedRate(command, initialDelay, period, unit); - } - public ScheduledFuture scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) { - return e.scheduleWithFixedDelay(command, initialDelay, delay, unit); - } - } -*/ - - /** Cannot instantiate. */ - private Executors() {} -} diff --git a/src/actors/scala/actors/threadpool/Future.java b/src/actors/scala/actors/threadpool/Future.java deleted file mode 100644 index 5e1b3d414a..0000000000 --- a/src/actors/scala/actors/threadpool/Future.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Written by Doug Lea with assistance from members of JCP JSR-166 - * Expert Group and released to the public domain, as explained at - * http://creativecommons.org/licenses/publicdomain - */ - -package scala.actors.threadpool; -import scala.actors.threadpool.*; // for javadoc (till 6280605 is fixed) - -/** - * A <tt>Future</tt> represents the result of an asynchronous - * computation. Methods are provided to check if the computation is - * complete, to wait for its completion, and to retrieve the result of - * the computation. The result can only be retrieved using method - * <tt>get</tt> when the computation has completed, blocking if - * necessary until it is ready. Cancellation is performed by the - * <tt>cancel</tt> method. Additional methods are provided to - * determine if the task completed normally or was cancelled. Once a - * computation has completed, the computation cannot be cancelled. - * If you would like to use a <tt>Future</tt> for the sake - * of cancellability but not provide a usable result, you can - * declare types of the form <tt>Future<?></tt> and - * return <tt>null</tt> as a result of the underlying task. - * - * <p> - * <b>Sample Usage</b> (Note that the following classes are all - * made-up.) <p> - * <pre> - * interface ArchiveSearcher { String search(String target); } - * class App { - * ExecutorService executor = ... - * ArchiveSearcher searcher = ... - * void showSearch(final String target) - * throws InterruptedException { - * Future<String> future - * = executor.submit(new Callable<String>() { - * public String call() { - * return searcher.search(target); - * }}); - * displayOtherThings(); // do other things while searching - * try { - * displayText(future.get()); // use future - * } catch (ExecutionException ex) { cleanup(); return; } - * } - * } - * </pre> - * - * The {@link FutureTask} class is an implementation of <tt>Future</tt> that - * implements <tt>Runnable</tt>, and so may be executed by an <tt>Executor</tt>. - * For example, the above construction with <tt>submit</tt> could be replaced by: - * <pre> - * FutureTask<String> future = - * new FutureTask<String>(new Callable<String>() { - * public String call() { - * return searcher.search(target); - * }}); - * executor.execute(future); - * </pre> - * - * <p>Memory consistency effects: Actions taken by the asynchronous computation - * <a href="package-summary.html#MemoryVisibility"> <i>happen-before</i></a> - * actions following the corresponding {@code Future.get()} in another thread. - * - * @see FutureTask - * @see Executor - * @since 1.5 - * @author Doug Lea - */ -public interface Future { - - /** - * Attempts to cancel execution of this task. This attempt will - * fail if the task has already completed, has already been cancelled, - * or could not be cancelled for some other reason. If successful, - * and this task has not started when <tt>cancel</tt> is called, - * this task should never run. If the task has already started, - * then the <tt>mayInterruptIfRunning</tt> parameter determines - * whether the thread executing this task should be interrupted in - * an attempt to stop the task. - * - * <p>After this method returns, subsequent calls to {@link #isDone} will - * always return <tt>true</tt>. Subsequent calls to {@link #isCancelled} - * will always return <tt>true</tt> if this method returned <tt>true</tt>. - * - * @param mayInterruptIfRunning <tt>true</tt> if the thread executing this - * task should be interrupted; otherwise, in-progress tasks are allowed - * to complete - * @return <tt>false</tt> if the task could not be cancelled, - * typically because it has already completed normally; - * <tt>true</tt> otherwise - */ - boolean cancel(boolean mayInterruptIfRunning); - - /** - * Returns <tt>true</tt> if this task was cancelled before it completed - * normally. - * - * @return <tt>true</tt> if this task was cancelled before it completed - */ - boolean isCancelled(); - - /** - * Returns <tt>true</tt> if this task completed. - * - * Completion may be due to normal termination, an exception, or - * cancellation -- in all of these cases, this method will return - * <tt>true</tt>. - * - * @return <tt>true</tt> if this task completed - */ - boolean isDone(); - - /** - * Waits if necessary for the computation to complete, and then - * retrieves its result. - * - * @return the computed result - * @throws CancellationException if the computation was cancelled - * @throws ExecutionException if the computation threw an - * exception - * @throws InterruptedException if the current thread was interrupted - * while waiting - */ - Object get() throws InterruptedException, ExecutionException; - - /** - * Waits if necessary for at most the given time for the computation - * to complete, and then retrieves its result, if available. - * - * @param timeout the maximum time to wait - * @param unit the time unit of the timeout argument - * @return the computed result - * @throws CancellationException if the computation was cancelled - * @throws ExecutionException if the computation threw an - * exception - * @throws InterruptedException if the current thread was interrupted - * while waiting - * @throws TimeoutException if the wait timed out - */ - Object get(long timeout, TimeUnit unit) - throws InterruptedException, ExecutionException, TimeoutException; -} diff --git a/src/actors/scala/actors/threadpool/FutureTask.java b/src/actors/scala/actors/threadpool/FutureTask.java deleted file mode 100644 index d4dcfe38b3..0000000000 --- a/src/actors/scala/actors/threadpool/FutureTask.java +++ /dev/null @@ -1,310 +0,0 @@ -/* - * Written by Doug Lea with assistance from members of JCP JSR-166 - * Expert Group and released to the public domain. Use, modify, and - * redistribute this code in any way without acknowledgement. - */ - -package scala.actors.threadpool; - -import scala.actors.threadpool.*; // for javadoc -import scala.actors.threadpool.helpers.*; - -/** - * A cancellable asynchronous computation. This class provides a base - * implementation of {@link Future}, with methods to start and cancel - * a computation, query to see if the computation is complete, and - * retrieve the result of the computation. The result can only be - * retrieved when the computation has completed; the <tt>get</tt> - * method will block if the computation has not yet completed. Once - * the computation has completed, the computation cannot be restarted - * or cancelled. - * - * <p>A <tt>FutureTask</tt> can be used to wrap a {@link Callable} or - * {@link java.lang.Runnable} object. Because <tt>FutureTask</tt> - * implements <tt>Runnable</tt>, a <tt>FutureTask</tt> can be - * submitted to an {@link Executor} for execution. - * - * <p>In addition to serving as a standalone class, this class provides - * <tt>protected</tt> functionality that may be useful when creating - * customized task classes. - * - * @since 1.5 - * @author Doug Lea - */ -public class FutureTask implements RunnableFuture { - - /** State value representing that task is ready to run */ - private static final int READY = 0; - /** State value representing that task is running */ - private static final int RUNNING = 1; - /** State value representing that task ran */ - private static final int RAN = 2; - /** State value representing that task was cancelled */ - private static final int CANCELLED = 4; - - /** The underlying callable */ - private final Callable callable; - /** The result to return from get() */ - private Object result; - /** The exception to throw from get() */ - private Throwable exception; - - private int state; - - /** - * The thread running task. When nulled after set/cancel, this - * indicates that the results are accessible. Must be - * volatile, to ensure visibility upon completion. - */ - private volatile Thread runner; - - /** - * Creates a <tt>FutureTask</tt> that will, upon running, execute the - * given <tt>Callable</tt>. - * - * @param callable the callable task - * @throws NullPointerException if callable is null - */ - public FutureTask(Callable callable) { - if (callable == null) - throw new NullPointerException(); - this.callable = callable; - } - - /** - * Creates a <tt>FutureTask</tt> that will, upon running, execute the - * given <tt>Runnable</tt>, and arrange that <tt>get</tt> will return the - * given result on successful completion. - * - * @param runnable the runnable task - * @param result the result to return on successful completion. If - * you don't need a particular result, consider using - * constructions of the form: - * <tt>Future<?> f = new FutureTask<Object>(runnable, null)</tt> - * @throws NullPointerException if runnable is null - */ - public FutureTask(Runnable runnable, Object result) { - this(Executors.callable(runnable, result)); - } - - public synchronized boolean isCancelled() { - return state == CANCELLED; - } - - public synchronized boolean isDone() { - return ranOrCancelled() && runner == null; - } - - public boolean cancel(boolean mayInterruptIfRunning) { - synchronized (this) { - if (ranOrCancelled()) return false; - state = CANCELLED; - if (mayInterruptIfRunning) { - Thread r = runner; - if (r != null) r.interrupt(); - } - runner = null; - notifyAll(); - } - done(); - return true; - } - - /** - * @throws CancellationException {@inheritDoc} - */ - public synchronized Object get() - throws InterruptedException, ExecutionException - { - waitFor(); - return getResult(); - } - - /** - * @throws CancellationException {@inheritDoc} - */ - public synchronized Object get(long timeout, TimeUnit unit) - throws InterruptedException, ExecutionException, TimeoutException - { - waitFor(unit.toNanos(timeout)); - return getResult(); - } - - /** - * Protected method invoked when this task transitions to state - * <tt>isDone</tt> (whether normally or via cancellation). The - * default implementation does nothing. Subclasses may override - * this method to invoke completion callbacks or perform - * bookkeeping. Note that you can query status inside the - * implementation of this method to determine whether this task - * has been cancelled. - */ - protected void done() { } - - /** - * Sets the result of this Future to the given value unless - * this future has already been set or has been cancelled. - * This method is invoked internally by the <tt>run</tt> method - * upon successful completion of the computation. - * @param v the value - */ - protected void set(Object v) { - setCompleted(v); - } - - /** - * Causes this future to report an <tt>ExecutionException</tt> - * with the given throwable as its cause, unless this Future has - * already been set or has been cancelled. - * This method is invoked internally by the <tt>run</tt> method - * upon failure of the computation. - * @param t the cause of failure - */ - protected void setException(Throwable t) { - setFailed(t); - } - - /** - * Sets this Future to the result of its computation - * unless it has been cancelled. - */ - public void run() { - synchronized (this) { - if (state != READY) return; - state = RUNNING; - runner = Thread.currentThread(); - } - try { - set(callable.call()); - } - catch (Throwable ex) { - setException(ex); - } - } - - /** - * Executes the computation without setting its result, and then - * resets this Future to initial state, failing to do so if the - * computation encounters an exception or is cancelled. This is - * designed for use with tasks that intrinsically execute more - * than once. - * @return true if successfully run and reset - */ - protected boolean runAndReset() { - synchronized (this) { - if (state != READY) return false; - state = RUNNING; - runner = Thread.currentThread(); - } - try { - callable.call(); // don't set result - synchronized (this) { - runner = null; - if (state == RUNNING) { - state = READY; - return true; - } - else { - return false; - } - } - } - catch (Throwable ex) { - setException(ex); - return false; - } - } - - // PRE: lock owned - private boolean ranOrCancelled() { - return (state & (RAN | CANCELLED)) != 0; - } - - /** - * Marks the task as completed. - * @param result the result of a task. - */ - private void setCompleted(Object result) { - synchronized (this) { - if (ranOrCancelled()) return; - this.state = RAN; - this.result = result; - this.runner = null; - notifyAll(); - } - - // invoking callbacks *after* setting future as completed and - // outside the synchronization block makes it safe to call - // interrupt() from within callback code (in which case it will be - // ignored rather than cause deadlock / illegal state exception) - done(); - } - - /** - * Marks the task as failed. - * @param exception the cause of abrupt completion. - */ - private void setFailed(Throwable exception) { - synchronized (this) { - if (ranOrCancelled()) return; - this.state = RAN; - this.exception = exception; - this.runner = null; - notifyAll(); - } - - // invoking callbacks *after* setting future as completed and - // outside the synchronization block makes it safe to call - // interrupt() from within callback code (in which case it will be - // ignored rather than cause deadlock / illegal state exception) - done(); - } - - /** - * Waits for the task to complete. - * PRE: lock owned - */ - private void waitFor() throws InterruptedException { - while (!isDone()) { - wait(); - } - } - - /** - * Waits for the task to complete for timeout nanoseconds or throw - * TimeoutException if still not completed after that - * PRE: lock owned - */ - private void waitFor(long nanos) throws InterruptedException, TimeoutException { - if (nanos < 0) throw new IllegalArgumentException(); - if (isDone()) return; - long deadline = Utils.nanoTime() + nanos; - while (nanos > 0) { - TimeUnit.NANOSECONDS.timedWait(this, nanos); - if (isDone()) return; - nanos = deadline - Utils.nanoTime(); - } - throw new TimeoutException(); - } - - /** - * Gets the result of the task. - * - * PRE: task completed - * PRE: lock owned - */ - private Object getResult() throws ExecutionException { - if (state == CANCELLED) { - throw new CancellationException(); - } - if (exception != null) { - throw new ExecutionException(exception); - } - return result; - } - - // todo: consider - //public String toString() { - // return callable.toString(); - //} -} diff --git a/src/actors/scala/actors/threadpool/LinkedBlockingQueue.java b/src/actors/scala/actors/threadpool/LinkedBlockingQueue.java deleted file mode 100644 index 15f1085ec6..0000000000 --- a/src/actors/scala/actors/threadpool/LinkedBlockingQueue.java +++ /dev/null @@ -1,843 +0,0 @@ -/* - * Written by Doug Lea with assistance from members of JCP JSR-166 - * Expert Group and released to the public domain, as explained at - * http://creativecommons.org/licenses/publicdomain - */ - -package scala.actors.threadpool; - -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.locks.Condition; -import java.util.concurrent.locks.ReentrantLock; -import java.util.AbstractQueue; -import java.util.Collection; -import java.util.Iterator; -import java.util.NoSuchElementException; - -/** - * An optionally-bounded {@linkplain BlockingQueue blocking queue} based on - * linked nodes. - * This queue orders elements FIFO (first-in-first-out). - * The <em>head</em> of the queue is that element that has been on the - * queue the longest time. - * The <em>tail</em> of the queue is that element that has been on the - * queue the shortest time. New elements - * are inserted at the tail of the queue, and the queue retrieval - * operations obtain elements at the head of the queue. - * Linked queues typically have higher throughput than array-based queues but - * less predictable performance in most concurrent applications. - * - * <p> The optional capacity bound constructor argument serves as a - * way to prevent excessive queue expansion. The capacity, if unspecified, - * is equal to {@link Integer#MAX_VALUE}. Linked nodes are - * dynamically created upon each insertion unless this would bring the - * queue above capacity. - * - * <p>This class and its iterator implement all of the - * <em>optional</em> methods of the {@link Collection} and {@link - * Iterator} interfaces. - * - * <p>This class is a member of the - * <a href="{@docRoot}/../technotes/guides/collections/index.html"> - * Java Collections Framework</a>. - * - * @since 1.5 - * @author Doug Lea - * @param <E> the type of elements held in this collection - * - */ -public class LinkedBlockingQueue<E> extends java.util.AbstractQueue<E> - implements BlockingQueue<E>, java.io.Serializable { - private static final long serialVersionUID = -6903933977591709194L; - - /* - * A variant of the "two lock queue" algorithm. The putLock gates - * entry to put (and offer), and has an associated condition for - * waiting puts. Similarly for the takeLock. The "count" field - * that they both rely on is maintained as an atomic to avoid - * needing to get both locks in most cases. Also, to minimize need - * for puts to get takeLock and vice-versa, cascading notifies are - * used. When a put notices that it has enabled at least one take, - * it signals taker. That taker in turn signals others if more - * items have been entered since the signal. And symmetrically for - * takes signalling puts. Operations such as remove(Object) and - * iterators acquire both locks. - * - * Visibility between writers and readers is provided as follows: - * - * Whenever an element is enqueued, the putLock is acquired and - * count updated. A subsequent reader guarantees visibility to the - * enqueued Node by either acquiring the putLock (via fullyLock) - * or by acquiring the takeLock, and then reading n = count.get(); - * this gives visibility to the first n items. - * - * To implement weakly consistent iterators, it appears we need to - * keep all Nodes GC-reachable from a predecessor dequeued Node. - * That would cause two problems: - * - allow a rogue Iterator to cause unbounded memory retention - * - cause cross-generational linking of old Nodes to new Nodes if - * a Node was tenured while live, which generational GCs have a - * hard time dealing with, causing repeated major collections. - * However, only non-deleted Nodes need to be reachable from - * dequeued Nodes, and reachability does not necessarily have to - * be of the kind understood by the GC. We use the trick of - * linking a Node that has just been dequeued to itself. Such a - * self-link implicitly means to advance to head.next. - */ - - /** - * Linked list node class - */ - static class Node<E> { - E item; - - /** - * One of: - * - the real successor Node - * - this Node, meaning the successor is head.next - * - null, meaning there is no successor (this is the last node) - */ - Node<E> next; - - Node(E x) { item = x; } - } - - /** The capacity bound, or Integer.MAX_VALUE if none */ - private final int capacity; - - /** Current number of elements */ - private final AtomicInteger count = new AtomicInteger(0); - - /** - * Head of linked list. - * Invariant: head.item == null - */ - private transient Node<E> head; - - /** - * Tail of linked list. - * Invariant: last.next == null - */ - private transient Node<E> last; - - /** Lock held by take, poll, etc */ - private final ReentrantLock takeLock = new ReentrantLock(); - - /** Wait queue for waiting takes */ - private final Condition notEmpty = takeLock.newCondition(); - - /** Lock held by put, offer, etc */ - private final ReentrantLock putLock = new ReentrantLock(); - - /** Wait queue for waiting puts */ - private final Condition notFull = putLock.newCondition(); - - /** - * Signals a waiting take. Called only from put/offer (which do not - * otherwise ordinarily lock takeLock.) - */ - private void signalNotEmpty() { - final ReentrantLock takeLock = this.takeLock; - takeLock.lock(); - try { - notEmpty.signal(); - } finally { - takeLock.unlock(); - } - } - - /** - * Signals a waiting put. Called only from take/poll. - */ - private void signalNotFull() { - final ReentrantLock putLock = this.putLock; - putLock.lock(); - try { - notFull.signal(); - } finally { - putLock.unlock(); - } - } - - /** - * Creates a node and links it at end of queue. - * - * @param x the item - */ - private void enqueue(E x) { - // assert putLock.isHeldByCurrentThread(); - // assert last.next == null; - last = last.next = new Node<E>(x); - } - - /** - * Removes a node from head of queue. - * - * @return the node - */ - private E dequeue() { - // assert takeLock.isHeldByCurrentThread(); - // assert head.item == null; - Node<E> h = head; - Node<E> first = h.next; - h.next = h; // help GC - head = first; - E x = first.item; - first.item = null; - return x; - } - - /** - * Lock to prevent both puts and takes. - */ - void fullyLock() { - putLock.lock(); - takeLock.lock(); - } - - /** - * Unlock to allow both puts and takes. - */ - void fullyUnlock() { - takeLock.unlock(); - putLock.unlock(); - } - -// /** -// * Tells whether both locks are held by current thread. -// */ -// boolean isFullyLocked() { -// return (putLock.isHeldByCurrentThread() && -// takeLock.isHeldByCurrentThread()); -// } - - /** - * Creates a {@code LinkedBlockingQueue} with a capacity of - * {@link Integer#MAX_VALUE}. - */ - public LinkedBlockingQueue() { - this(Integer.MAX_VALUE); - } - - /** - * Creates a {@code LinkedBlockingQueue} with the given (fixed) capacity. - * - * @param capacity the capacity of this queue - * @throws IllegalArgumentException if {@code capacity} is not greater - * than zero - */ - public LinkedBlockingQueue(int capacity) { - if (capacity <= 0) throw new IllegalArgumentException(); - this.capacity = capacity; - last = head = new Node<E>(null); - } - - /** - * Creates a {@code LinkedBlockingQueue} with a capacity of - * {@link Integer#MAX_VALUE}, initially containing the elements of the - * given collection, - * added in traversal order of the collection's iterator. - * - * @param c the collection of elements to initially contain - * @throws NullPointerException if the specified collection or any - * of its elements are null - */ - public LinkedBlockingQueue(Collection<? extends E> c) { - this(Integer.MAX_VALUE); - final ReentrantLock putLock = this.putLock; - putLock.lock(); // Never contended, but necessary for visibility - try { - int n = 0; - for (E e : c) { - if (e == null) - throw new NullPointerException(); - if (n == capacity) - throw new IllegalStateException("Queue full"); - enqueue(e); - ++n; - } - count.set(n); - } finally { - putLock.unlock(); - } - } - - - // this doc comment is overridden to remove the reference to collections - // greater in size than Integer.MAX_VALUE - /** - * Returns the number of elements in this queue. - * - * @return the number of elements in this queue - */ - public int size() { - return count.get(); - } - - // this doc comment is a modified copy of the inherited doc comment, - // without the reference to unlimited queues. - /** - * Returns the number of additional elements that this queue can ideally - * (in the absence of memory or resource constraints) accept without - * blocking. This is always equal to the initial capacity of this queue - * less the current {@code size} of this queue. - * - * <p>Note that you <em>cannot</em> always tell if an attempt to insert - * an element will succeed by inspecting {@code remainingCapacity} - * because it may be the case that another thread is about to - * insert or remove an element. - */ - public int remainingCapacity() { - return capacity - count.get(); - } - - /** - * Inserts the specified element at the tail of this queue, waiting if - * necessary for space to become available. - * - * @throws InterruptedException {@inheritDoc} - * @throws NullPointerException {@inheritDoc} - */ - public void put(E e) throws InterruptedException { - if (e == null) throw new NullPointerException(); - // Note: convention in all put/take/etc is to preset local var - // holding count negative to indicate failure unless set. - int c = -1; - final ReentrantLock putLock = this.putLock; - final AtomicInteger count = this.count; - putLock.lockInterruptibly(); - try { - /* - * Note that count is used in wait guard even though it is - * not protected by lock. This works because count can - * only decrease at this point (all other puts are shut - * out by lock), and we (or some other waiting put) are - * signalled if it ever changes from capacity. Similarly - * for all other uses of count in other wait guards. - */ - while (count.get() == capacity) { - notFull.await(); - } - enqueue(e); - c = count.getAndIncrement(); - if (c + 1 < capacity) - notFull.signal(); - } finally { - putLock.unlock(); - } - if (c == 0) - signalNotEmpty(); - } - - /** - * Inserts the specified element at the tail of this queue, waiting if - * necessary up to the specified wait time for space to become available. - * - * @return {@code true} if successful, or {@code false} if - * the specified waiting time elapses before space is available. - * @throws InterruptedException {@inheritDoc} - * @throws NullPointerException {@inheritDoc} - */ - public boolean offer(E e, long timeout, TimeUnit unit) - throws InterruptedException { - - if (e == null) throw new NullPointerException(); - long nanos = unit.toNanos(timeout); - int c = -1; - final ReentrantLock putLock = this.putLock; - final AtomicInteger count = this.count; - putLock.lockInterruptibly(); - try { - while (count.get() == capacity) { - if (nanos <= 0) - return false; - nanos = notFull.awaitNanos(nanos); - } - enqueue(e); - c = count.getAndIncrement(); - if (c + 1 < capacity) - notFull.signal(); - } finally { - putLock.unlock(); - } - if (c == 0) - signalNotEmpty(); - return true; - } - - /** - * Inserts the specified element at the tail of this queue if it is - * possible to do so immediately without exceeding the queue's capacity, - * returning {@code true} upon success and {@code false} if this queue - * is full. - * When using a capacity-restricted queue, this method is generally - * preferable to method {@link BlockingQueue#add add}, which can fail to - * insert an element only by throwing an exception. - * - * @throws NullPointerException if the specified element is null - */ - public boolean offer(E e) { - if (e == null) throw new NullPointerException(); - final AtomicInteger count = this.count; - if (count.get() == capacity) - return false; - int c = -1; - final ReentrantLock putLock = this.putLock; - putLock.lock(); - try { - if (count.get() < capacity) { - enqueue(e); - c = count.getAndIncrement(); - if (c + 1 < capacity) - notFull.signal(); - } - } finally { - putLock.unlock(); - } - if (c == 0) - signalNotEmpty(); - return c >= 0; - } - - - public E take() throws InterruptedException { - E x; - int c = -1; - final AtomicInteger count = this.count; - final ReentrantLock takeLock = this.takeLock; - takeLock.lockInterruptibly(); - try { - while (count.get() == 0) { - notEmpty.await(); - } - x = dequeue(); - c = count.getAndDecrement(); - if (c > 1) - notEmpty.signal(); - } finally { - takeLock.unlock(); - } - if (c == capacity) - signalNotFull(); - return x; - } - - public E poll(long timeout, TimeUnit unit) throws InterruptedException { - E x = null; - int c = -1; - long nanos = unit.toNanos(timeout); - final AtomicInteger count = this.count; - final ReentrantLock takeLock = this.takeLock; - takeLock.lockInterruptibly(); - try { - while (count.get() == 0) { - if (nanos <= 0) - return null; - nanos = notEmpty.awaitNanos(nanos); - } - x = dequeue(); - c = count.getAndDecrement(); - if (c > 1) - notEmpty.signal(); - } finally { - takeLock.unlock(); - } - if (c == capacity) - signalNotFull(); - return x; - } - - public E poll() { - final AtomicInteger count = this.count; - if (count.get() == 0) - return null; - E x = null; - int c = -1; - final ReentrantLock takeLock = this.takeLock; - takeLock.lock(); - try { - if (count.get() > 0) { - x = dequeue(); - c = count.getAndDecrement(); - if (c > 1) - notEmpty.signal(); - } - } finally { - takeLock.unlock(); - } - if (c == capacity) - signalNotFull(); - return x; - } - - public E peek() { - if (count.get() == 0) - return null; - final ReentrantLock takeLock = this.takeLock; - takeLock.lock(); - try { - Node<E> first = head.next; - if (first == null) - return null; - else - return first.item; - } finally { - takeLock.unlock(); - } - } - - /** - * Unlinks interior Node p with predecessor trail. - */ - void unlink(Node<E> p, Node<E> trail) { - // assert isFullyLocked(); - // p.next is not changed, to allow iterators that are - // traversing p to maintain their weak-consistency guarantee. - p.item = null; - trail.next = p.next; - if (last == p) - last = trail; - if (count.getAndDecrement() == capacity) - notFull.signal(); - } - - /** - * Removes a single instance of the specified element from this queue, - * if it is present. More formally, removes an element {@code e} such - * that {@code o.equals(e)}, if this queue contains one or more such - * elements. - * Returns {@code true} if this queue contained the specified element - * (or equivalently, if this queue changed as a result of the call). - * - * @param o element to be removed from this queue, if present - * @return {@code true} if this queue changed as a result of the call - */ - public boolean remove(Object o) { - if (o == null) return false; - fullyLock(); - try { - for (Node<E> trail = head, p = trail.next; - p != null; - trail = p, p = p.next) { - if (o.equals(p.item)) { - unlink(p, trail); - return true; - } - } - return false; - } finally { - fullyUnlock(); - } - } - - /** - * Returns an array containing all of the elements in this queue, in - * proper sequence. - * - * <p>The returned array will be "safe" in that no references to it are - * maintained by this queue. (In other words, this method must allocate - * a new array). The caller is thus free to modify the returned array. - * - * <p>This method acts as bridge between array-based and collection-based - * APIs. - * - * @return an array containing all of the elements in this queue - */ - public Object[] toArray() { - fullyLock(); - try { - int size = count.get(); - Object[] a = new Object[size]; - int k = 0; - for (Node<E> p = head.next; p != null; p = p.next) - a[k++] = p.item; - return a; - } finally { - fullyUnlock(); - } - } - - /** - * Returns an array containing all of the elements in this queue, in - * proper sequence; the runtime type of the returned array is that of - * the specified array. If the queue fits in the specified array, it - * is returned therein. Otherwise, a new array is allocated with the - * runtime type of the specified array and the size of this queue. - * - * <p>If this queue fits in the specified array with room to spare - * (i.e., the array has more elements than this queue), the element in - * the array immediately following the end of the queue is set to - * {@code null}. - * - * <p>Like the {@link #toArray()} method, this method acts as bridge between - * array-based and collection-based APIs. Further, this method allows - * precise control over the runtime type of the output array, and may, - * under certain circumstances, be used to save allocation costs. - * - * <p>Suppose {@code x} is a queue known to contain only strings. - * The following code can be used to dump the queue into a newly - * allocated array of {@code String}: - * - * <pre> - * String[] y = x.toArray(new String[0]);</pre> - * - * Note that {@code toArray(new Object[0])} is identical in function to - * {@code toArray()}. - * - * @param a the array into which the elements of the queue are to - * be stored, if it is big enough; otherwise, a new array of the - * same runtime type is allocated for this purpose - * @return an array containing all of the elements in this queue - * @throws ArrayStoreException if the runtime type of the specified array - * is not a supertype of the runtime type of every element in - * this queue - * @throws NullPointerException if the specified array is null - */ - @SuppressWarnings("unchecked") - public <T> T[] toArray(T[] a) { - fullyLock(); - try { - int size = count.get(); - if (a.length < size) - a = (T[])java.lang.reflect.Array.newInstance - (a.getClass().getComponentType(), size); - - int k = 0; - for (Node<E> p = head.next; p != null; p = p.next) - a[k++] = (T)p.item; - if (a.length > k) - a[k] = null; - return a; - } finally { - fullyUnlock(); - } - } - - public String toString() { - fullyLock(); - try { - return super.toString(); - } finally { - fullyUnlock(); - } - } - - /** - * Atomically removes all of the elements from this queue. - * The queue will be empty after this call returns. - */ - public void clear() { - fullyLock(); - try { - for (Node<E> p, h = head; (p = h.next) != null; h = p) { - h.next = h; - p.item = null; - } - head = last; - // assert head.item == null && head.next == null; - if (count.getAndSet(0) == capacity) - notFull.signal(); - } finally { - fullyUnlock(); - } - } - - /** - * @throws UnsupportedOperationException {@inheritDoc} - * @throws ClassCastException {@inheritDoc} - * @throws NullPointerException {@inheritDoc} - * @throws IllegalArgumentException {@inheritDoc} - */ - public int drainTo(Collection<? super E> c) { - return drainTo(c, Integer.MAX_VALUE); - } - - /** - * @throws UnsupportedOperationException {@inheritDoc} - * @throws ClassCastException {@inheritDoc} - * @throws NullPointerException {@inheritDoc} - * @throws IllegalArgumentException {@inheritDoc} - */ - public int drainTo(Collection<? super E> c, int maxElements) { - if (c == null) - throw new NullPointerException(); - if (c == this) - throw new IllegalArgumentException(); - boolean signalNotFull = false; - final ReentrantLock takeLock = this.takeLock; - takeLock.lock(); - try { - int n = Math.min(maxElements, count.get()); - // count.get provides visibility to first n Nodes - Node<E> h = head; - int i = 0; - try { - while (i < n) { - Node<E> p = h.next; - c.add(p.item); - p.item = null; - h.next = h; - h = p; - ++i; - } - return n; - } finally { - // Restore invariants even if c.add() threw - if (i > 0) { - // assert h.item == null; - head = h; - signalNotFull = (count.getAndAdd(-i) == capacity); - } - } - } finally { - takeLock.unlock(); - if (signalNotFull) - signalNotFull(); - } - } - - /** - * Returns an iterator over the elements in this queue in proper sequence. - * The returned {@code Iterator} is a "weakly consistent" iterator that - * will never throw {@link java.util.ConcurrentModificationException - * ConcurrentModificationException}, - * and guarantees to traverse elements as they existed upon - * construction of the iterator, and may (but is not guaranteed to) - * reflect any modifications subsequent to construction. - * - * @return an iterator over the elements in this queue in proper sequence - */ - public Iterator<E> iterator() { - return new Itr(); - } - - private class Itr implements Iterator<E> { - /* - * Basic weakly-consistent iterator. At all times hold the next - * item to hand out so that if hasNext() reports true, we will - * still have it to return even if lost race with a take etc. - */ - private Node<E> current; - private Node<E> lastRet; - private E currentElement; - - Itr() { - fullyLock(); - try { - current = head.next; - if (current != null) - currentElement = current.item; - } finally { - fullyUnlock(); - } - } - - public boolean hasNext() { - return current != null; - } - - /** - * Returns the next live successor of p, or null if no such. - * - * Unlike other traversal methods, iterators need to handle both: - * - dequeued nodes (p.next == p) - * - (possibly multiple) interior removed nodes (p.item == null) - */ - private Node<E> nextNode(Node<E> p) { - for (;;) { - Node<E> s = p.next; - if (s == p) - return head.next; - if (s == null || s.item != null) - return s; - p = s; - } - } - - public E next() { - fullyLock(); - try { - if (current == null) - throw new NoSuchElementException(); - E x = currentElement; - lastRet = current; - current = nextNode(current); - currentElement = (current == null) ? null : current.item; - return x; - } finally { - fullyUnlock(); - } - } - - public void remove() { - if (lastRet == null) - throw new IllegalStateException(); - fullyLock(); - try { - Node<E> node = lastRet; - lastRet = null; - for (Node<E> trail = head, p = trail.next; - p != null; - trail = p, p = p.next) { - if (p == node) { - unlink(p, trail); - break; - } - } - } finally { - fullyUnlock(); - } - } - } - - /** - * Save the state to a stream (that is, serialize it). - * - * @serialData The capacity is emitted (int), followed by all of - * its elements (each an {@code Object}) in the proper order, - * followed by a null - * @param s the stream - */ - private void writeObject(java.io.ObjectOutputStream s) - throws java.io.IOException { - - fullyLock(); - try { - // Write out any hidden stuff, plus capacity - s.defaultWriteObject(); - - // Write out all elements in the proper order. - for (Node<E> p = head.next; p != null; p = p.next) - s.writeObject(p.item); - - // Use trailing null as sentinel - s.writeObject(null); - } finally { - fullyUnlock(); - } - } - - /** - * Reconstitute this queue instance from a stream (that is, - * deserialize it). - * - * @param s the stream - */ - private void readObject(java.io.ObjectInputStream s) - throws java.io.IOException, ClassNotFoundException { - // Read in capacity, and any hidden stuff - s.defaultReadObject(); - - count.set(0); - last = head = new Node<E>(null); - - // Read in all elements and place in queue - for (;;) { - @SuppressWarnings("unchecked") - E item = (E)s.readObject(); - if (item == null) - break; - add(item); - } - } -} diff --git a/src/actors/scala/actors/threadpool/Perf.java b/src/actors/scala/actors/threadpool/Perf.java deleted file mode 100644 index 0f262b444f..0000000000 --- a/src/actors/scala/actors/threadpool/Perf.java +++ /dev/null @@ -1,28 +0,0 @@ -package scala.actors.threadpool; - -/** - * Compilation stub for pre-1.4.2 JREs. Thanks to it, the whole backport - * package compiles and works with 1.4.2 as well as wih earlier JREs, and takes - * advantage of native Perf class when running on 1.4.2 while seamlessly - * falling back to System.currentTimeMillis() on previous JREs. This class - * should NOT be included in the binary distribution of backport. - * - * @author Dawid Kurzyniec - * @version 1.0 - */ -public final class Perf { - - private static final Perf perf = new Perf(); - - public static Perf getPerf() { return perf; } - - private Perf() {} - - public long highResCounter() { - return System.currentTimeMillis(); - } - - public long highResFrequency() { - return 1000L; - } -} diff --git a/src/actors/scala/actors/threadpool/Queue.java b/src/actors/scala/actors/threadpool/Queue.java deleted file mode 100644 index f952e9d94c..0000000000 --- a/src/actors/scala/actors/threadpool/Queue.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Written by Doug Lea with assistance from members of JCP JSR-166 - * Expert Group and released to the public domain, as explained at - * http://creativecommons.org/licenses/publicdomain - */ - -package scala.actors.threadpool; - -import java.util.Collection; - -/** - * A collection designed for holding elements prior to processing. - * Besides basic {@link java.util.Collection Collection} operations, - * queues provide additional insertion, extraction, and inspection - * operations. Each of these methods exists in two forms: one throws - * an exception if the operation fails, the other returns a special - * value (either <tt>null</tt> or <tt>false</tt>, depending on the - * operation). The latter form of the insert operation is designed - * specifically for use with capacity-restricted <tt>Queue</tt> - * implementations; in most implementations, insert operations cannot - * fail. - * - * <p> - * <table BORDER CELLPADDING=3 CELLSPACING=1> - * <tr> - * <td></td> - * <td ALIGN=CENTER><em>Throws exception</em></td> - * <td ALIGN=CENTER><em>Returns special value</em></td> - * </tr> - * <tr> - * <td><b>Insert</b></td> - * <td>{@link #add add(e)}</td> - * <td>{@link #offer offer(e)}</td> - * </tr> - * <tr> - * <td><b>Remove</b></td> - * <td>{@link #remove remove()}</td> - * <td>{@link #poll poll()}</td> - * </tr> - * <tr> - * <td><b>Examine</b></td> - * <td>{@link #element element()}</td> - * <td>{@link #peek peek()}</td> - * </tr> - * </table> - * - * <p>Queues typically, but do not necessarily, order elements in a - * FIFO (first-in-first-out) manner. Among the exceptions are - * priority queues, which order elements according to a supplied - * comparator, or the elements' natural ordering, and LIFO queues (or - * stacks) which order the elements LIFO (last-in-first-out). - * Whatever the ordering used, the <em>head</em> of the queue is that - * element which would be removed by a call to {@link #remove() } or - * {@link #poll()}. In a FIFO queue, all new elements are inserted at - * the <em> tail</em> of the queue. Other kinds of queues may use - * different placement rules. Every <tt>Queue</tt> implementation - * must specify its ordering properties. - * - * <p>The {@link #offer offer} method inserts an element if possible, - * otherwise returning <tt>false</tt>. This differs from the {@link - * java.util.Collection#add Collection.add} method, which can fail to - * add an element only by throwing an unchecked exception. The - * <tt>offer</tt> method is designed for use when failure is a normal, - * rather than exceptional occurrence, for example, in fixed-capacity - * (or "bounded") queues. - * - * <p>The {@link #remove()} and {@link #poll()} methods remove and - * return the head of the queue. - * Exactly which element is removed from the queue is a - * function of the queue's ordering policy, which differs from - * implementation to implementation. The <tt>remove()</tt> and - * <tt>poll()</tt> methods differ only in their behavior when the - * queue is empty: the <tt>remove()</tt> method throws an exception, - * while the <tt>poll()</tt> method returns <tt>null</tt>. - * - * <p>The {@link #element()} and {@link #peek()} methods return, but do - * not remove, the head of the queue. - * - * <p>The <tt>Queue</tt> interface does not define the <i>blocking queue - * methods</i>, which are common in concurrent programming. These methods, - * which wait for elements to appear or for space to become available, are - * defined in the {@link edu.emory.mathcs.backport.java.util.concurrent.BlockingQueue} interface, which - * extends this interface. - * - * <p><tt>Queue</tt> implementations generally do not allow insertion - * of <tt>null</tt> elements, although some implementations, such as - * {@link LinkedList}, do not prohibit insertion of <tt>null</tt>. - * Even in the implementations that permit it, <tt>null</tt> should - * not be inserted into a <tt>Queue</tt>, as <tt>null</tt> is also - * used as a special return value by the <tt>poll</tt> method to - * indicate that the queue contains no elements. - * - * <p><tt>Queue</tt> implementations generally do not define - * element-based versions of methods <tt>equals</tt> and - * <tt>hashCode</tt> but instead inherit the identity based versions - * from class <tt>Object</tt>, because element-based equality is not - * always well-defined for queues with the same elements but different - * ordering properties. - * - * - * <p>This interface is a member of the - * <a href="{@docRoot}/../technotes/guides/collections/index.html"> - * Java Collections Framework</a>. - * - * @see java.util.Collection - * @see LinkedList - * @see PriorityQueue - * @see edu.emory.mathcs.backport.java.util.concurrent.LinkedBlockingQueue - * @see edu.emory.mathcs.backport.java.util.concurrent.BlockingQueue - * @see edu.emory.mathcs.backport.java.util.concurrent.ArrayBlockingQueue - * @see edu.emory.mathcs.backport.java.util.concurrent.LinkedBlockingQueue - * @see edu.emory.mathcs.backport.java.util.concurrent.PriorityBlockingQueue - * @since 1.5 - * @author Doug Lea - */ -public interface Queue extends Collection { - /** - * Inserts the specified element into this queue if it is possible to do so - * immediately without violating capacity restrictions, returning - * <tt>true</tt> upon success and throwing an <tt>IllegalStateException</tt> - * if no space is currently available. - * - * @param e the element to add - * @return <tt>true</tt> (as specified by {@link Collection#add}) - * @throws IllegalStateException if the element cannot be added at this - * time due to capacity restrictions - * @throws ClassCastException if the class of the specified element - * prevents it from being added to this queue - * @throws NullPointerException if the specified element is null and - * this queue not permit null elements - * @throws IllegalArgumentException if some property of this element - * prevents it from being added to this queue - */ - boolean add(Object e); - - /** - * Inserts the specified element into this queue if it is possible to do - * so immediately without violating capacity restrictions. - * When using a capacity-restricted queue, this method is generally - * preferable to {@link #add}, which can fail to insert an element only - * by throwing an exception. - * - * @param e the element to add - * @return <tt>true</tt> if the element was added to this queue, else - * <tt>false</tt> - * @throws ClassCastException if the class of the specified element - * prevents it from being added to this queue - * @throws NullPointerException if the specified element is null and - * this queue does not permit null elements - * @throws IllegalArgumentException if some property of this element - * prevents it from being added to this queue - */ - boolean offer(Object e); - - /** - * Retrieves and removes the head of this queue. This method differs - * from {@link #poll poll} only in that it throws an exception if this - * queue is empty. - * is empty. - * - * @return the head of this queue - * @throws NoSuchElementException if this queue is empty - */ - Object remove(); - - /** - * Retrieves and removes the head of this queue, - * or returns <tt>null</tt> if this queue is empty. - * - * @return the head of this queue, or <tt>null</tt> if this queue is empty - */ - Object poll(); - - /** - * Retrieves, but does not remove, the head of this queue. This method - * differs from {@link #peek peek} only in that it throws an exception - * if this queue is empty. - * - * @return the head of this queue - * @throws NoSuchElementException if this queue is empty - */ - Object element(); - - /** - * Retrieves, but does not remove, the head of this queue, - * or returns <tt>null</tt> if this queue is empty. - * - * @return the head of this queue, or <tt>null</tt> if this queue is empty - */ - Object peek(); -} diff --git a/src/actors/scala/actors/threadpool/RejectedExecutionException.java b/src/actors/scala/actors/threadpool/RejectedExecutionException.java deleted file mode 100644 index 1b61d35974..0000000000 --- a/src/actors/scala/actors/threadpool/RejectedExecutionException.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Written by Doug Lea with assistance from members of JCP JSR-166 - * Expert Group and released to the public domain, as explained at - * http://creativecommons.org/licenses/publicdomain - */ - -package scala.actors.threadpool; - -/** - * Exception thrown by an {@link Executor} when a task cannot be - * accepted for execution. - * - * @since 1.5 - * @author Doug Lea - */ -public class RejectedExecutionException extends RuntimeException { - private static final long serialVersionUID = -375805702767069545L; - - /** - * Constructs a <tt>RejectedExecutionException</tt> with no detail message. - * The cause is not initialized, and may subsequently be - * initialized by a call to {@link #initCause(Throwable) initCause}. - */ - public RejectedExecutionException() { } - - /** - * Constructs a <tt>RejectedExecutionException</tt> with the - * specified detail message. The cause is not initialized, and may - * subsequently be initialized by a call to {@link - * #initCause(Throwable) initCause}. - * - * @param message the detail message - */ - public RejectedExecutionException(String message) { - super(message); - } - - /** - * Constructs a <tt>RejectedExecutionException</tt> with the - * specified detail message and cause. - * - * @param message the detail message - * @param cause the cause (which is saved for later retrieval by the - * {@link #getCause()} method) - */ - public RejectedExecutionException(String message, Throwable cause) { - super(message, cause); - } - - /** - * Constructs a <tt>RejectedExecutionException</tt> with the - * specified cause. The detail message is set to: <pre> (cause == - * null ? null : cause.toString())</pre> (which typically contains - * the class and detail message of <tt>cause</tt>). - * - * @param cause the cause (which is saved for later retrieval by the - * {@link #getCause()} method) - */ - public RejectedExecutionException(Throwable cause) { - super(cause); - } -} diff --git a/src/actors/scala/actors/threadpool/RejectedExecutionHandler.java b/src/actors/scala/actors/threadpool/RejectedExecutionHandler.java deleted file mode 100644 index 86e6d18a40..0000000000 --- a/src/actors/scala/actors/threadpool/RejectedExecutionHandler.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Written by Doug Lea with assistance from members of JCP JSR-166 - * Expert Group and released to the public domain, as explained at - * http://creativecommons.org/licenses/publicdomain - */ - -package scala.actors.threadpool; - -/** - * A handler for tasks that cannot be executed by a {@link ThreadPoolExecutor}. - * - * @since 1.5 - * @author Doug Lea - */ -public interface RejectedExecutionHandler { - - /** - * Method that may be invoked by a {@link ThreadPoolExecutor} when - * {@link ThreadPoolExecutor#execute execute} cannot accept a - * task. This may occur when no more threads or queue slots are - * available because their bounds would be exceeded, or upon - * shutdown of the Executor. - * - * <p>In the absence of other alternatives, the method may throw - * an unchecked {@link RejectedExecutionException}, which will be - * propagated to the caller of {@code execute}. - * - * @param r the runnable task requested to be executed - * @param executor the executor attempting to execute this task - * @throws RejectedExecutionException if there is no remedy - */ - - void rejectedExecution(Runnable r, ThreadPoolExecutor executor); -} diff --git a/src/actors/scala/actors/threadpool/RunnableFuture.java b/src/actors/scala/actors/threadpool/RunnableFuture.java deleted file mode 100644 index bbd63a2d92..0000000000 --- a/src/actors/scala/actors/threadpool/RunnableFuture.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Written by Doug Lea with assistance from members of JCP JSR-166 - * Expert Group and released to the public domain, as explained at - * http://creativecommons.org/licenses/publicdomain - */ - -package scala.actors.threadpool; - -/** - * A {@link Future} that is {@link Runnable}. Successful execution of - * the <tt>run</tt> method causes completion of the <tt>Future</tt> - * and allows access to its results. - * @see FutureTask - * @see Executor - * @since 1.6 - * @author Doug Lea - */ -public interface RunnableFuture extends Runnable, Future { - /** - * Sets this Future to the result of its computation - * unless it has been cancelled. - */ - void run(); -} diff --git a/src/actors/scala/actors/threadpool/SynchronousQueue.java b/src/actors/scala/actors/threadpool/SynchronousQueue.java deleted file mode 100644 index 739b0043dd..0000000000 --- a/src/actors/scala/actors/threadpool/SynchronousQueue.java +++ /dev/null @@ -1,833 +0,0 @@ -/* - * Written by Doug Lea with assistance from members of JCP JSR-166 - * Expert Group and released to the public domain, as explained at - * http://creativecommons.org/licenses/publicdomain - */ - -package scala.actors.threadpool; -import scala.actors.threadpool.locks.*; -//import edu.emory.mathcs.backport.java.util.*; -import java.util.Collection; -import java.util.Iterator; -import scala.actors.threadpool.helpers.Utils; -import java.util.NoSuchElementException; - -/** - * A {@linkplain BlockingQueue blocking queue} in which each insert - * operation must wait for a corresponding remove operation by another - * thread, and vice versa. A synchronous queue does not have any - * internal capacity, not even a capacity of one. You cannot - * <tt>peek</tt> at a synchronous queue because an element is only - * present when you try to remove it; you cannot insert an element - * (using any method) unless another thread is trying to remove it; - * you cannot iterate as there is nothing to iterate. The - * <em>head</em> of the queue is the element that the first queued - * inserting thread is trying to add to the queue; if there is no such - * queued thread then no element is available for removal and - * <tt>poll()</tt> will return <tt>null</tt>. For purposes of other - * <tt>Collection</tt> methods (for example <tt>contains</tt>), a - * <tt>SynchronousQueue</tt> acts as an empty collection. This queue - * does not permit <tt>null</tt> elements. - * - * <p>Synchronous queues are similar to rendezvous channels used in - * CSP and Ada. They are well suited for handoff designs, in which an - * object running in one thread must sync up with an object running - * in another thread in order to hand it some information, event, or - * task. - * - * <p> This class supports an optional fairness policy for ordering - * waiting producer and consumer threads. By default, this ordering - * is not guaranteed. However, a queue constructed with fairness set - * to <tt>true</tt> grants threads access in FIFO order. Fairness - * generally decreases throughput but reduces variability and avoids - * starvation. - * - * <p>This class and its iterator implement all of the - * <em>optional</em> methods of the {@link Collection} and {@link - * Iterator} interfaces. - * - * <p>This class is a member of the - * <a href="{@docRoot}/../technotes/guides/collections/index.html"> - * Java Collections Framework</a>. - * - * @since 1.5 - * @author Doug Lea - */ -public class SynchronousQueue extends AbstractQueue - implements BlockingQueue, java.io.Serializable { - private static final long serialVersionUID = -3223113410248163686L; - - /* - This implementation divides actions into two cases for puts: - - * An arriving producer that does not already have a waiting consumer - creates a node holding item, and then waits for a consumer to take it. - * An arriving producer that does already have a waiting consumer fills - the slot node created by the consumer, and notifies it to continue. - - And symmetrically, two for takes: - - * An arriving consumer that does not already have a waiting producer - creates an empty slot node, and then waits for a producer to fill it. - * An arriving consumer that does already have a waiting producer takes - item from the node created by the producer, and notifies it to continue. - - When a put or take waiting for the actions of its counterpart - aborts due to interruption or timeout, it marks the node - it created as "CANCELLED", which causes its counterpart to retry - the entire put or take sequence. - - This requires keeping two simple queues, waitingProducers and - waitingConsumers. Each of these can be FIFO (preserves fairness) - or LIFO (improves throughput). - */ - - /** Lock protecting both wait queues */ - private final ReentrantLock qlock; - /** Queue holding waiting puts */ - private final WaitQueue waitingProducers; - /** Queue holding waiting takes */ - private final WaitQueue waitingConsumers; - - /** - * Creates a <tt>SynchronousQueue</tt> with nonfair access policy. - */ - public SynchronousQueue() { - this(false); - } - - /** - * Creates a <tt>SynchronousQueue</tt> with specified fairness policy. - * @param fair if true, threads contend in FIFO order for access; - * otherwise the order is unspecified. - */ - public SynchronousQueue(boolean fair) { - if (fair) { - qlock = new ReentrantLock(true); - waitingProducers = new FifoWaitQueue(); - waitingConsumers = new FifoWaitQueue(); - } - else { - qlock = new ReentrantLock(); - waitingProducers = new LifoWaitQueue(); - waitingConsumers = new LifoWaitQueue(); - } - } - - /** - * Queue to hold waiting puts/takes; specialized to Fifo/Lifo below. - * These queues have all transient fields, but are serializable - * in order to recover fairness settings when deserialized. - */ - static abstract class WaitQueue implements java.io.Serializable { - /** Creates, adds, and returns node for x. */ - abstract Node enq(Object x); - /** Removes and returns node, or null if empty. */ - abstract Node deq(); - /** Removes a cancelled node to avoid garbage retention. */ - abstract void unlink(Node node); - /** Returns true if a cancelled node might be on queue. */ - abstract boolean shouldUnlink(Node node); - } - - /** - * FIFO queue to hold waiting puts/takes. - */ - static final class FifoWaitQueue extends WaitQueue implements java.io.Serializable { - private static final long serialVersionUID = -3623113410248163686L; - private transient Node head; - private transient Node last; - - Node enq(Object x) { - Node p = new Node(x); - if (last == null) - last = head = p; - else - last = last.next = p; - return p; - } - - Node deq() { - Node p = head; - if (p != null) { - if ((head = p.next) == null) - last = null; - p.next = null; - } - return p; - } - - boolean shouldUnlink(Node node) { - return (node == last || node.next != null); - } - - void unlink(Node node) { - Node p = head; - Node trail = null; - while (p != null) { - if (p == node) { - Node next = p.next; - if (trail == null) - head = next; - else - trail.next = next; - if (last == node) - last = trail; - break; - } - trail = p; - p = p.next; - } - } - } - - /** - * LIFO queue to hold waiting puts/takes. - */ - static final class LifoWaitQueue extends WaitQueue implements java.io.Serializable { - private static final long serialVersionUID = -3633113410248163686L; - private transient Node head; - - Node enq(Object x) { - return head = new Node(x, head); - } - - Node deq() { - Node p = head; - if (p != null) { - head = p.next; - p.next = null; - } - return p; - } - - boolean shouldUnlink(Node node) { - // Return false if already dequeued or is bottom node (in which - // case we might retain at most one garbage node) - return (node == head || node.next != null); - } - - void unlink(Node node) { - Node p = head; - Node trail = null; - while (p != null) { - if (p == node) { - Node next = p.next; - if (trail == null) - head = next; - else - trail.next = next; - break; - } - trail = p; - p = p.next; - } - } - } - - /** - * Unlinks the given node from consumer queue. Called by cancelled - * (timeout, interrupt) waiters to avoid garbage retention in the - * absence of producers. - */ - private void unlinkCancelledConsumer(Node node) { - // Use a form of double-check to avoid unnecessary locking and - // traversal. The first check outside lock might - // conservatively report true. - if (waitingConsumers.shouldUnlink(node)) { - qlock.lock(); - try { - if (waitingConsumers.shouldUnlink(node)) - waitingConsumers.unlink(node); - } finally { - qlock.unlock(); - } - } - } - - /** - * Unlinks the given node from producer queue. Symmetric - * to unlinkCancelledConsumer. - */ - private void unlinkCancelledProducer(Node node) { - if (waitingProducers.shouldUnlink(node)) { - qlock.lock(); - try { - if (waitingProducers.shouldUnlink(node)) - waitingProducers.unlink(node); - } finally { - qlock.unlock(); - } - } - } - - /** - * Nodes each maintain an item and handle waits and signals for - * getting and setting it. The class extends - * AbstractQueuedSynchronizer to manage blocking, using AQS state - * 0 for waiting, 1 for ack, -1 for cancelled. - */ - static final class Node implements java.io.Serializable { - private static final long serialVersionUID = -3223113410248163686L; - - /** Synchronization state value representing that node acked */ - private static final int ACK = 1; - /** Synchronization state value representing that node cancelled */ - private static final int CANCEL = -1; - - int state = 0; - - /** The item being transferred */ - Object item; - /** Next node in wait queue */ - Node next; - - /** Creates a node with initial item */ - Node(Object x) { item = x; } - - /** Creates a node with initial item and next */ - Node(Object x, Node n) { item = x; next = n; } - - /** - * Takes item and nulls out field (for sake of GC) - * - * PRE: lock owned - */ - private Object extract() { - Object x = item; - item = null; - return x; - } - - /** - * Tries to cancel on interrupt; if so rethrowing, - * else setting interrupt state - * - * PRE: lock owned - */ - private void checkCancellationOnInterrupt(InterruptedException ie) - throws InterruptedException - { - if (state == 0) { - state = CANCEL; - notify(); - throw ie; - } - Thread.currentThread().interrupt(); - } - - /** - * Fills in the slot created by the consumer and signal consumer to - * continue. - */ - synchronized boolean setItem(Object x) { - if (state != 0) return false; - item = x; - state = ACK; - notify(); - return true; - } - - /** - * Removes item from slot created by producer and signal producer - * to continue. - */ - synchronized Object getItem() { - if (state != 0) return null; - state = ACK; - notify(); - return extract(); - } - - /** - * Waits for a consumer to take item placed by producer. - */ - synchronized void waitForTake() throws InterruptedException { - try { - while (state == 0) wait(); - } catch (InterruptedException ie) { - checkCancellationOnInterrupt(ie); - } - } - - /** - * Waits for a producer to put item placed by consumer. - */ - synchronized Object waitForPut() throws InterruptedException { - try { - while (state == 0) wait(); - } catch (InterruptedException ie) { - checkCancellationOnInterrupt(ie); - } - return extract(); - } - - private boolean attempt(long nanos) throws InterruptedException { - if (state != 0) return true; - if (nanos <= 0) { - state = CANCEL; - notify(); - return false; - } - long deadline = Utils.nanoTime() + nanos; - while (true) { - TimeUnit.NANOSECONDS.timedWait(this, nanos); - if (state != 0) return true; - nanos = deadline - Utils.nanoTime(); - if (nanos <= 0) { - state = CANCEL; - notify(); - return false; - } - } - } - - /** - * Waits for a consumer to take item placed by producer or time out. - */ - synchronized boolean waitForTake(long nanos) throws InterruptedException { - try { - if (!attempt(nanos)) return false; - } catch (InterruptedException ie) { - checkCancellationOnInterrupt(ie); - } - return true; - } - - /** - * Waits for a producer to put item placed by consumer, or time out. - */ - synchronized Object waitForPut(long nanos) throws InterruptedException { - try { - if (!attempt(nanos)) return null; - } catch (InterruptedException ie) { - checkCancellationOnInterrupt(ie); - } - return extract(); - } - } - - /** - * Adds the specified element to this queue, waiting if necessary for - * another thread to receive it. - * - * @throws InterruptedException {@inheritDoc} - * @throws NullPointerException {@inheritDoc} - */ - public void put(Object e) throws InterruptedException { - if (e == null) throw new NullPointerException(); - final ReentrantLock qlock = this.qlock; - - for (;;) { - Node node; - boolean mustWait; - if (Thread.interrupted()) throw new InterruptedException(); - qlock.lock(); - try { - node = waitingConsumers.deq(); - if ( (mustWait = (node == null)) ) - node = waitingProducers.enq(e); - } finally { - qlock.unlock(); - } - - if (mustWait) { - try { - node.waitForTake(); - return; - } catch (InterruptedException ex) { - unlinkCancelledProducer(node); - throw ex; - } - } - - else if (node.setItem(e)) - return; - - // else consumer cancelled, so retry - } - } - - /** - * Inserts the specified element into this queue, waiting if necessary - * up to the specified wait time for another thread to receive it. - * - * @return <tt>true</tt> if successful, or <tt>false</tt> if the - * specified waiting time elapses before a consumer appears. - * @throws InterruptedException {@inheritDoc} - * @throws NullPointerException {@inheritDoc} - */ - public boolean offer(Object e, long timeout, TimeUnit unit) throws InterruptedException { - if (e == null) throw new NullPointerException(); - long nanos = unit.toNanos(timeout); - final ReentrantLock qlock = this.qlock; - for (;;) { - Node node; - boolean mustWait; - if (Thread.interrupted()) throw new InterruptedException(); - qlock.lock(); - try { - node = waitingConsumers.deq(); - if ( (mustWait = (node == null)) ) - node = waitingProducers.enq(e); - } finally { - qlock.unlock(); - } - - if (mustWait) { - try { - boolean x = node.waitForTake(nanos); - if (!x) - unlinkCancelledProducer(node); - return x; - } catch (InterruptedException ex) { - unlinkCancelledProducer(node); - throw ex; - } - } - - else if (node.setItem(e)) - return true; - - // else consumer cancelled, so retry - } - } - - /** - * Retrieves and removes the head of this queue, waiting if necessary - * for another thread to insert it. - * - * @return the head of this queue - * @throws InterruptedException {@inheritDoc} - */ - public Object take() throws InterruptedException { - final ReentrantLock qlock = this.qlock; - for (;;) { - Node node; - boolean mustWait; - - if (Thread.interrupted()) throw new InterruptedException(); - qlock.lock(); - try { - node = waitingProducers.deq(); - if ( (mustWait = (node == null)) ) - node = waitingConsumers.enq(null); - } finally { - qlock.unlock(); - } - - if (mustWait) { - try { - Object x = node.waitForPut(); - return (Object)x; - } catch (InterruptedException ex) { - unlinkCancelledConsumer(node); - throw ex; - } - } - else { - Object x = node.getItem(); - if (x != null) - return (Object)x; - // else cancelled, so retry - } - } - } - - /** - * Retrieves and removes the head of this queue, waiting - * if necessary up to the specified wait time, for another thread - * to insert it. - * - * @return the head of this queue, or <tt>null</tt> if the - * specified waiting time elapses before an element is present. - * @throws InterruptedException {@inheritDoc} - */ - public Object poll(long timeout, TimeUnit unit) throws InterruptedException { - long nanos = unit.toNanos(timeout); - final ReentrantLock qlock = this.qlock; - - for (;;) { - Node node; - boolean mustWait; - - if (Thread.interrupted()) throw new InterruptedException(); - qlock.lock(); - try { - node = waitingProducers.deq(); - if ( (mustWait = (node == null)) ) - node = waitingConsumers.enq(null); - } finally { - qlock.unlock(); - } - - if (mustWait) { - try { - Object x = node.waitForPut(nanos); - if (x == null) - unlinkCancelledConsumer(node); - return (Object)x; - } catch (InterruptedException ex) { - unlinkCancelledConsumer(node); - throw ex; - } - } - else { - Object x = node.getItem(); - if (x != null) - return (Object)x; - // else cancelled, so retry - } - } - } - - // Untimed nonblocking versions - - /** - * Inserts the specified element into this queue, if another thread is - * waiting to receive it. - * - * @param e the element to add - * @return <tt>true</tt> if the element was added to this queue, else - * <tt>false</tt> - * @throws NullPointerException if the specified element is null - */ - public boolean offer(Object e) { - if (e == null) throw new NullPointerException(); - final ReentrantLock qlock = this.qlock; - - for (;;) { - Node node; - qlock.lock(); - try { - node = waitingConsumers.deq(); - } finally { - qlock.unlock(); - } - if (node == null) - return false; - - else if (node.setItem(e)) - return true; - // else retry - } - } - - /** - * Retrieves and removes the head of this queue, if another thread - * is currently making an element available. - * - * @return the head of this queue, or <tt>null</tt> if no - * element is available. - */ - public Object poll() { - final ReentrantLock qlock = this.qlock; - for (;;) { - Node node; - qlock.lock(); - try { - node = waitingProducers.deq(); - } finally { - qlock.unlock(); - } - if (node == null) - return null; - - else { - Object x = node.getItem(); - if (x != null) - return (Object)x; - // else retry - } - } - } - - /** - * Always returns <tt>true</tt>. - * A <tt>SynchronousQueue</tt> has no internal capacity. - * - * @return <tt>true</tt> - */ - public boolean isEmpty() { - return true; - } - - /** - * Always returns zero. - * A <tt>SynchronousQueue</tt> has no internal capacity. - * - * @return zero - */ - public int size() { - return 0; - } - - /** - * Always returns zero. - * A <tt>SynchronousQueue</tt> has no internal capacity. - * - * @return zero - */ - public int remainingCapacity() { - return 0; - } - - /** - * Does nothing. - * A <tt>SynchronousQueue</tt> has no internal capacity. - */ - public void clear() {} - - /** - * Always returns <tt>false</tt>. - * A <tt>SynchronousQueue</tt> has no internal capacity. - * - * @param o object to be checked for containment in this queue - * @return <tt>false</tt> - */ - public boolean contains(Object o) { - return false; - } - - /** - * Always returns <tt>false</tt>. - * A <tt>SynchronousQueue</tt> has no internal capacity. - * - * @param o the element to remove - * @return <tt>false</tt> - */ - public boolean remove(Object o) { - return false; - } - - /** - * Returns <tt>false</tt> unless the given collection is empty. - * A <tt>SynchronousQueue</tt> has no internal capacity. - * - * @param c the collection - * @return <tt>false</tt> unless the given collection is empty - * @throws NullPointerException if the specified collection is null - */ - public boolean containsAll(Collection c) { - return c.isEmpty(); - } - - /** - * Always returns <tt>false</tt>. - * A <tt>SynchronousQueue</tt> has no internal capacity. - * - * @param c the collection - * @return <tt>false</tt> - */ - public boolean removeAll(Collection c) { - return false; - } - - /** - * Always returns <tt>false</tt>. - * A <tt>SynchronousQueue</tt> has no internal capacity. - * - * @param c the collection - * @return <tt>false</tt> - */ - public boolean retainAll(Collection c) { - return false; - } - - /** - * Always returns <tt>null</tt>. - * A <tt>SynchronousQueue</tt> does not return elements - * unless actively waited on. - * - * @return <tt>null</tt> - */ - public Object peek() { - return null; - } - - - static class EmptyIterator implements Iterator { - public boolean hasNext() { - return false; - } - public Object next() { - throw new NoSuchElementException(); - } - public void remove() { - throw new IllegalStateException(); - } - } - - /** - * Returns an empty iterator in which <tt>hasNext</tt> always returns - * <tt>false</tt>. - * - * @return an empty iterator - */ - public Iterator iterator() { - return new EmptyIterator(); - } - - - /** - * Returns a zero-length array. - * @return a zero-length array - */ - public Object[] toArray() { - return new Object[0]; - } - - /** - * Sets the zeroeth element of the specified array to <tt>null</tt> - * (if the array has non-zero length) and returns it. - * - * @param a the array - * @return the specified array - * @throws NullPointerException if the specified array is null - */ - public Object[] toArray(Object[] a) { - if (a.length > 0) - a[0] = null; - return a; - } - - /** - * @throws UnsupportedOperationException {@inheritDoc} - * @throws ClassCastException {@inheritDoc} - * @throws NullPointerException {@inheritDoc} - * @throws IllegalArgumentException {@inheritDoc} - */ - public int drainTo(Collection c) { - if (c == null) - throw new NullPointerException(); - if (c == this) - throw new IllegalArgumentException(); - int n = 0; - Object e; - while ( (e = poll()) != null) { - c.add(e); - ++n; - } - return n; - } - - /** - * @throws UnsupportedOperationException {@inheritDoc} - * @throws ClassCastException {@inheritDoc} - * @throws NullPointerException {@inheritDoc} - * @throws IllegalArgumentException {@inheritDoc} - */ - public int drainTo(Collection c, int maxElements) { - if (c == null) - throw new NullPointerException(); - if (c == this) - throw new IllegalArgumentException(); - int n = 0; - Object e; - while (n < maxElements && (e = poll()) != null) { - c.add(e); - ++n; - } - return n; - } -} diff --git a/src/actors/scala/actors/threadpool/ThreadFactory.java b/src/actors/scala/actors/threadpool/ThreadFactory.java deleted file mode 100644 index ed6e90ccaa..0000000000 --- a/src/actors/scala/actors/threadpool/ThreadFactory.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Written by Doug Lea with assistance from members of JCP JSR-166 - * Expert Group and released to the public domain, as explained at - * http://creativecommons.org/licenses/publicdomain - */ - -package scala.actors.threadpool; - -/** - * An object that creates new threads on demand. Using thread factories - * removes hardwiring of calls to {@link Thread#Thread(Runnable) new Thread}, - * enabling applications to use special thread subclasses, priorities, etc. - * - * <p> - * The simplest implementation of this interface is just: - * <pre> - * class SimpleThreadFactory implements ThreadFactory { - * public Thread newThread(Runnable r) { - * return new Thread(r); - * } - * } - * </pre> - * - * The {@link Executors#defaultThreadFactory} method provides a more - * useful simple implementation, that sets the created thread context - * to known values before returning it. - * @since 1.5 - * @author Doug Lea - */ -public interface ThreadFactory { - - /** - * Constructs a new {@code Thread}. Implementations may also initialize - * priority, name, daemon status, {@code ThreadGroup}, etc. - * - * @param r a runnable to be executed by new thread instance - * @return constructed thread, or {@code null} if the request to - * create a thread is rejected - */ - Thread newThread(Runnable r); -} diff --git a/src/actors/scala/actors/threadpool/ThreadPoolExecutor.java b/src/actors/scala/actors/threadpool/ThreadPoolExecutor.java deleted file mode 100644 index 11e35b034c..0000000000 --- a/src/actors/scala/actors/threadpool/ThreadPoolExecutor.java +++ /dev/null @@ -1,1968 +0,0 @@ -/* - * Written by Doug Lea with assistance from members of JCP JSR-166 - * Expert Group and released to the public domain, as explained at - * http://creativecommons.org/licenses/publicdomain - */ - -package scala.actors.threadpool; -import scala.actors.threadpool.locks.*; -import scala.actors.threadpool.helpers.Utils; -import java.util.HashSet; -import java.util.List; -import java.util.Iterator; -import java.util.ArrayList; -import java.util.ConcurrentModificationException; - -/** - * An {@link ExecutorService} that executes each submitted task using - * one of possibly several pooled threads, normally configured - * using {@link Executors} factory methods. - * - * <p>Thread pools address two different problems: they usually - * provide improved performance when executing large numbers of - * asynchronous tasks, due to reduced per-task invocation overhead, - * and they provide a means of bounding and managing the resources, - * including threads, consumed when executing a collection of tasks. - * Each {@code ThreadPoolExecutor} also maintains some basic - * statistics, such as the number of completed tasks. - * - * <p>To be useful across a wide range of contexts, this class - * provides many adjustable parameters and extensibility - * hooks. However, programmers are urged to use the more convenient - * {@link Executors} factory methods {@link - * Executors#newCachedThreadPool} (unbounded thread pool, with - * automatic thread reclamation), {@link Executors#newFixedThreadPool} - * (fixed size thread pool) and {@link - * Executors#newSingleThreadExecutor} (single background thread), that - * preconfigure settings for the most common usage - * scenarios. Otherwise, use the following guide when manually - * configuring and tuning this class: - * - * <dl> - * - * <dt>Core and maximum pool sizes</dt> - * - * <dd>A {@code ThreadPoolExecutor} will automatically adjust the - * pool size (see {@link #getPoolSize}) - * according to the bounds set by - * corePoolSize (see {@link #getCorePoolSize}) and - * maximumPoolSize (see {@link #getMaximumPoolSize}). - * - * When a new task is submitted in method {@link #execute}, and fewer - * than corePoolSize threads are running, a new thread is created to - * handle the request, even if other worker threads are idle. If - * there are more than corePoolSize but less than maximumPoolSize - * threads running, a new thread will be created only if the queue is - * full. By setting corePoolSize and maximumPoolSize the same, you - * create a fixed-size thread pool. By setting maximumPoolSize to an - * essentially unbounded value such as {@code Integer.MAX_VALUE}, you - * allow the pool to accommodate an arbitrary number of concurrent - * tasks. Most typically, core and maximum pool sizes are set only - * upon construction, but they may also be changed dynamically using - * {@link #setCorePoolSize} and {@link #setMaximumPoolSize}. </dd> - * - * <dt>On-demand construction</dt> - * - * <dd> By default, even core threads are initially created and - * started only when new tasks arrive, but this can be overridden - * dynamically using method {@link #prestartCoreThread} or {@link - * #prestartAllCoreThreads}. You probably want to prestart threads if - * you construct the pool with a non-empty queue. </dd> - * - * <dt>Creating new threads</dt> - * - * <dd>New threads are created using a {@link ThreadFactory}. If not - * otherwise specified, a {@link Executors#defaultThreadFactory} is - * used, that creates threads to all be in the same {@link - * ThreadGroup} and with the same {@code NORM_PRIORITY} priority and - * non-daemon status. By supplying a different ThreadFactory, you can - * alter the thread's name, thread group, priority, daemon status, - * etc. If a {@code ThreadFactory} fails to create a thread when asked - * by returning null from {@code newThread}, the executor will - * continue, but might not be able to execute any tasks. Threads - * should possess the "modifyThread" {@code RuntimePermission}. If - * worker threads or other threads using the pool do not possess this - * permission, service may be degraded: configuration changes may not - * take effect in a timely manner, and a shutdown pool may remain in a - * state in which termination is possible but not completed.</dd> - * - * <dt>Keep-alive times</dt> - * - * <dd>If the pool currently has more than corePoolSize threads, - * excess threads will be terminated if they have been idle for more - * than the keepAliveTime (see {@link #getKeepAliveTime}). This - * provides a means of reducing resource consumption when the pool is - * not being actively used. If the pool becomes more active later, new - * threads will be constructed. This parameter can also be changed - * dynamically using method {@link #setKeepAliveTime}. Using a value - * of {@code Long.MAX_VALUE} {@link TimeUnit#NANOSECONDS} effectively - * disables idle threads from ever terminating prior to shut down. By - * default, the keep-alive policy applies only when there are more - * than corePoolSizeThreads. But method {@link - * #allowCoreThreadTimeOut(boolean)} can be used to apply this - * time-out policy to core threads as well, so long as the - * keepAliveTime value is non-zero. </dd> - * - * <dt>Queuing</dt> - * - * <dd>Any {@link BlockingQueue} may be used to transfer and hold - * submitted tasks. The use of this queue interacts with pool sizing: - * - * <ul> - * - * <li> If fewer than corePoolSize threads are running, the Executor - * always prefers adding a new thread - * rather than queuing.</li> - * - * <li> If corePoolSize or more threads are running, the Executor - * always prefers queuing a request rather than adding a new - * thread.</li> - * - * <li> If a request cannot be queued, a new thread is created unless - * this would exceed maximumPoolSize, in which case, the task will be - * rejected.</li> - * - * </ul> - * - * There are three general strategies for queuing: - * <ol> - * - * <li> <em> Direct handoffs.</em> A good default choice for a work - * queue is a {@link SynchronousQueue} that hands off tasks to threads - * without otherwise holding them. Here, an attempt to queue a task - * will fail if no threads are immediately available to run it, so a - * new thread will be constructed. This policy avoids lockups when - * handling sets of requests that might have internal dependencies. - * Direct handoffs generally require unbounded maximumPoolSizes to - * avoid rejection of new submitted tasks. This in turn admits the - * possibility of unbounded thread growth when commands continue to - * arrive on average faster than they can be processed. </li> - * - * <li><em> Unbounded queues.</em> Using an unbounded queue (for - * example a {@link LinkedBlockingQueue} without a predefined - * capacity) will cause new tasks to wait in the queue when all - * corePoolSize threads are busy. Thus, no more than corePoolSize - * threads will ever be created. (And the value of the maximumPoolSize - * therefore doesn't have any effect.) This may be appropriate when - * each task is completely independent of others, so tasks cannot - * affect each others execution; for example, in a web page server. - * While this style of queuing can be useful in smoothing out - * transient bursts of requests, it admits the possibility of - * unbounded work queue growth when commands continue to arrive on - * average faster than they can be processed. </li> - * - * <li><em>Bounded queues.</em> A bounded queue (for example, an - * {@link ArrayBlockingQueue}) helps prevent resource exhaustion when - * used with finite maximumPoolSizes, but can be more difficult to - * tune and control. Queue sizes and maximum pool sizes may be traded - * off for each other: Using large queues and small pools minimizes - * CPU usage, OS resources, and context-switching overhead, but can - * lead to artificially low throughput. If tasks frequently block (for - * example if they are I/O bound), a system may be able to schedule - * time for more threads than you otherwise allow. Use of small queues - * generally requires larger pool sizes, which keeps CPUs busier but - * may encounter unacceptable scheduling overhead, which also - * decreases throughput. </li> - * - * </ol> - * - * </dd> - * - * <dt>Rejected tasks</dt> - * - * <dd> New tasks submitted in method {@link #execute} will be - * <em>rejected</em> when the Executor has been shut down, and also - * when the Executor uses finite bounds for both maximum threads and - * work queue capacity, and is saturated. In either case, the {@code - * execute} method invokes the {@link - * RejectedExecutionHandler#rejectedExecution} method of its {@link - * RejectedExecutionHandler}. Four predefined handler policies are - * provided: - * - * <ol> - * - * <li> In the default {@link ThreadPoolExecutor.AbortPolicy}, the - * handler throws a runtime {@link RejectedExecutionException} upon - * rejection. </li> - * - * <li> In {@link ThreadPoolExecutor.CallerRunsPolicy}, the thread - * that invokes {@code execute} itself runs the task. This provides a - * simple feedback control mechanism that will slow down the rate that - * new tasks are submitted. </li> - * - * <li> In {@link ThreadPoolExecutor.DiscardPolicy}, a task that - * cannot be executed is simply dropped. </li> - * - * <li>In {@link ThreadPoolExecutor.DiscardOldestPolicy}, if the - * executor is not shut down, the task at the head of the work queue - * is dropped, and then execution is retried (which can fail again, - * causing this to be repeated.) </li> - * - * </ol> - * - * It is possible to define and use other kinds of {@link - * RejectedExecutionHandler} classes. Doing so requires some care - * especially when policies are designed to work only under particular - * capacity or queuing policies. </dd> - * - * <dt>Hook methods</dt> - * - * <dd>This class provides {@code protected} overridable {@link - * #beforeExecute} and {@link #afterExecute} methods that are called - * before and after execution of each task. These can be used to - * manipulate the execution environment; for example, reinitializing - * ThreadLocals, gathering statistics, or adding log - * entries. Additionally, method {@link #terminated} can be overridden - * to perform any special processing that needs to be done once the - * Executor has fully terminated. - * - * <p>If hook or callback methods throw exceptions, internal worker - * threads may in turn fail and abruptly terminate.</dd> - * - * <dt>Queue maintenance</dt> - * - * <dd> Method {@link #getQueue} allows access to the work queue for - * purposes of monitoring and debugging. Use of this method for any - * other purpose is strongly discouraged. Two supplied methods, - * {@link #remove} and {@link #purge} are available to assist in - * storage reclamation when large numbers of queued tasks become - * cancelled.</dd> - * - * <dt>Finalization</dt> - * - * <dd> A pool that is no longer referenced in a program <em>AND</em> - * has no remaining threads will be {@code shutdown} automatically. If - * you would like to ensure that unreferenced pools are reclaimed even - * if users forget to call {@link #shutdown}, then you must arrange - * that unused threads eventually die, by setting appropriate - * keep-alive times, using a lower bound of zero core threads and/or - * setting {@link #allowCoreThreadTimeOut(boolean)}. </dd> - * - * </dl> - * - * <p> <b>Extension example</b>. Most extensions of this class - * override one or more of the protected hook methods. For example, - * here is a subclass that adds a simple pause/resume feature: - * - * <pre> {@code - * class PausableThreadPoolExecutor extends ThreadPoolExecutor { - * private boolean isPaused; - * private ReentrantLock pauseLock = new ReentrantLock(); - * private Condition unpaused = pauseLock.newCondition(); - * - * public PausableThreadPoolExecutor(...) { super(...); } - * - * protected void beforeExecute(Thread t, Runnable r) { - * super.beforeExecute(t, r); - * pauseLock.lock(); - * try { - * while (isPaused) unpaused.await(); - * } catch (InterruptedException ie) { - * t.interrupt(); - * } finally { - * pauseLock.unlock(); - * } - * } - * - * public void pause() { - * pauseLock.lock(); - * try { - * isPaused = true; - * } finally { - * pauseLock.unlock(); - * } - * } - * - * public void resume() { - * pauseLock.lock(); - * try { - * isPaused = false; - * unpaused.signalAll(); - * } finally { - * pauseLock.unlock(); - * } - * } - * }}</pre> - * - * @since 1.5 - * @author Doug Lea - */ -public class ThreadPoolExecutor extends AbstractExecutorService { - /** - * The main pool control state, ctl, is an atomic integer packing - * two conceptual fields - * workerCount, indicating the effective number of threads - * runState, indicating whether running, shutting down etc - * - * In order to pack them into one int, we limit workerCount to - * (2^29)-1 (about 500 million) threads rather than (2^31)-1 (2 - * billion) otherwise representable. If this is ever an issue in - * the future, the variable can be changed to be an AtomicLong, - * and the shift/mask constants below adjusted. But until the need - * arises, this code is a bit faster and simpler using an int. - * - * The workerCount is the number of workers that have been - * permitted to start and not permitted to stop. The value may be - * transiently different from the actual number of live threads, - * for example when a ThreadFactory fails to create a thread when - * asked, and when exiting threads are still performing - * bookkeeping before terminating. The user-visible pool size is - * reported as the current size of the workers set. - * - * The runState provides the main lifecyle control, taking on values: - * - * RUNNING: Accept new tasks and process queued tasks - * SHUTDOWN: Don't accept new tasks, but process queued tasks - * STOP: Don't accept new tasks, don't process queued tasks, - * and interrupt in-progress tasks - * TIDYING: All tasks have terminated, workerCount is zero, - * the thread transitioning to state TIDYING - * will run the terminated() hook method - * TERMINATED: terminated() has completed - * - * The numerical order among these values matters, to allow - * ordered comparisons. The runState monotonically increases over - * time, but need not hit each state. The transitions are: - * - * RUNNING -> SHUTDOWN - * On invocation of shutdown(), perhaps implicitly in finalize() - * (RUNNING or SHUTDOWN) -> STOP - * On invocation of shutdownNow() - * SHUTDOWN -> TIDYING - * When both queue and pool are empty - * STOP -> TIDYING - * When pool is empty - * TIDYING -> TERMINATED - * When the terminated() hook method has completed - * - * Threads waiting in awaitTermination() will return when the - * state reaches TERMINATED. - * - * Detecting the transition from SHUTDOWN to TIDYING is less - * straightforward than you'd like because the queue may become - * empty after non-empty and vice versa during SHUTDOWN state, but - * we can only terminate if, after seeing that it is empty, we see - * that workerCount is 0 (which sometimes entails a recheck -- see - * below). - */ - private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0)); - private static final int COUNT_BITS = 29; // Integer.SIZE - 3; - private static final int CAPACITY = (1 << COUNT_BITS) - 1; - - // runState is stored in the high-order bits - private static final int RUNNING = -1 << COUNT_BITS; - private static final int SHUTDOWN = 0 << COUNT_BITS; - private static final int STOP = 1 << COUNT_BITS; - private static final int TIDYING = 2 << COUNT_BITS; - private static final int TERMINATED = 3 << COUNT_BITS; - - // Packing and unpacking ctl - private static int runStateOf(int c) { return c & ~CAPACITY; } - private static int workerCountOf(int c) { return c & CAPACITY; } - private static int ctlOf(int rs, int wc) { return rs | wc; } - - /* - * Bit field accessors that don't require unpacking ctl. - * These depend on the bit layout and on workerCount being never negative. - */ - - private static boolean runStateLessThan(int c, int s) { - return c < s; - } - - private static boolean runStateAtLeast(int c, int s) { - return c >= s; - } - - private static boolean isRunning(int c) { - return c < SHUTDOWN; - } - - /** - * Attempt to CAS-increment the workerCount field of ctl. - */ - private boolean compareAndIncrementWorkerCount(int expect) { - return ctl.compareAndSet(expect, expect + 1); - } - - /** - * Attempt to CAS-decrement the workerCount field of ctl. - */ - private boolean compareAndDecrementWorkerCount(int expect) { - return ctl.compareAndSet(expect, expect - 1); - } - - /** - * Decrements the workerCount field of ctl. This is called only on - * abrupt termination of a thread (see processWorkerExit). Other - * decrements are performed within getTask. - */ - private void decrementWorkerCount() { - do {} while (! compareAndDecrementWorkerCount(ctl.get())); - } - - /** - * The queue used for holding tasks and handing off to worker - * threads. We do not require that workQueue.poll() returning - * null necessarily means that workQueue.isEmpty(), so rely - * solely on isEmpty to see if the queue is empty (which we must - * do for example when deciding whether to transition from - * SHUTDOWN to TIDYING). This accommodates special-purpose - * queues such as DelayQueues for which poll() is allowed to - * return null even if it may later return non-null when delays - * expire. - */ - private final BlockingQueue workQueue; - - // TODO: DK: mainLock is used in lock(); try { ... } finally { unlock(); } - // Consider replacing with synchronized {} if performance reasons exist - /** - * Lock held on access to workers set and related bookkeeping. - * While we could use a concurrent set of some sort, it turns out - * to be generally preferable to use a lock. Among the reasons is - * that this serializes interruptIdleWorkers, which avoids - * unnecessary interrupt storms, especially during shutdown. - * Otherwise exiting threads would concurrently interrupt those - * that have not yet interrupted. It also simplifies some of the - * associated statistics bookkeeping of largestPoolSize etc. We - * also hold mainLock on shutdown and shutdownNow, for the sake of - * ensuring workers set is stable while separately checking - * permission to interrupt and actually interrupting. - */ - public final ReentrantLock mainLock = new ReentrantLock(); - - /** - * Set containing all worker threads in pool. Accessed only when - * holding mainLock. - */ - public final HashSet workers = new HashSet(); - - /** - * Wait condition to support awaitTermination - */ - private final Condition termination = mainLock.newCondition(); - - /** - * Tracks largest attained pool size. Accessed only under - * mainLock. - */ - private int largestPoolSize; - - /** - * Counter for completed tasks. Updated only on termination of - * worker threads. Accessed only under mainLock. - */ - private long completedTaskCount; - - /* - * All user control parameters are declared as volatiles so that - * ongoing actions are based on freshest values, but without need - * for locking, since no internal invariants depend on them - * changing synchronously with respect to other actions. - */ - - /** - * Factory for new threads. All threads are created using this - * factory (via method addWorker). All callers must be prepared - * for addWorker to fail, which may reflect a system or user's - * policy limiting the number of threads. Even though it is not - * treated as an error, failure to create threads may result in - * new tasks being rejected or existing ones remaining stuck in - * the queue. On the other hand, no special precautions exist to - * handle OutOfMemoryErrors that might be thrown while trying to - * create threads, since there is generally no recourse from - * within this class. - */ - private volatile ThreadFactory threadFactory; - - /** - * Handler called when saturated or shutdown in execute. - */ - private volatile RejectedExecutionHandler handler; - - /** - * Timeout in nanoseconds for idle threads waiting for work. - * Threads use this timeout when there are more than corePoolSize - * present or if allowCoreThreadTimeOut. Otherwise they wait - * forever for new work. - */ - private volatile long keepAliveTime; - - /** - * If false (default), core threads stay alive even when idle. - * If true, core threads use keepAliveTime to time out waiting - * for work. - */ - private volatile boolean allowCoreThreadTimeOut; - - /** - * Core pool size is the minimum number of workers to keep alive - * (and not allow to time out etc) unless allowCoreThreadTimeOut - * is set, in which case the minimum is zero. - */ - private volatile int corePoolSize; - - /** - * Maximum pool size. Note that the actual maximum is internally - * bounded by CAPACITY. - */ - private volatile int maximumPoolSize; - - /** - * The default rejected execution handler - */ - private static final RejectedExecutionHandler defaultHandler = - new AbortPolicy(); - - /** - * Permission required for callers of shutdown and shutdownNow. - * We additionally require (see checkShutdownAccess) that callers - * have permission to actually interrupt threads in the worker set - * (as governed by Thread.interrupt, which relies on - * ThreadGroup.checkAccess, which in turn relies on - * SecurityManager.checkAccess). Shutdowns are attempted only if - * these checks pass. - * - * All actual invocations of Thread.interrupt (see - * interruptIdleWorkers and interruptWorkers) ignore - * SecurityExceptions, meaning that the attempted interrupts - * silently fail. In the case of shutdown, they should not fail - * unless the SecurityManager has inconsistent policies, sometimes - * allowing access to a thread and sometimes not. In such cases, - * failure to actually interrupt threads may disable or delay full - * termination. Other uses of interruptIdleWorkers are advisory, - * and failure to actually interrupt will merely delay response to - * configuration changes so is not handled exceptionally. - */ - private static final RuntimePermission shutdownPerm = - new RuntimePermission("modifyThread"); - - /** - * Class Worker mainly maintains interrupt control state for - * threads running tasks, along with other minor bookkeeping. This - * class opportunistically extends ReentrantLock to simplify - * acquiring and releasing a lock surrounding each task execution. - * This protects against interrupts that are intended to wake up a - * worker thread waiting for a task from instead interrupting a - * task being run. - */ - public final class Worker extends ReentrantLock implements Runnable { - /** - * This class will never be serialized, but we provide a - * serialVersionUID to suppress a javac warning. - */ - private static final long serialVersionUID = 6138294804551838833L; - - /** Thread this worker is running in. Null if factory fails. */ - public final Thread thread; - /** Initial task to run. Possibly null. */ - Runnable firstTask; - /** Per-thread task counter */ - volatile long completedTasks; - - /** - * Creates with given first task and thread from ThreadFactory. - * @param firstTask the first task (null if none) - */ - Worker(Runnable firstTask) { - this.firstTask = firstTask; - this.thread = getThreadFactory().newThread(this); - } - - /** Delegates main run loop to outer runWorker */ - public void run() { - runWorker(this); - } - } - - /* - * Methods for setting control state - */ - - /** - * Transitions runState to given target, or leaves it alone if - * already at least the given target. - * - * @param targetState the desired state, either SHUTDOWN or STOP - * (but not TIDYING or TERMINATED -- use tryTerminate for that) - */ - private void advanceRunState(int targetState) { - for (;;) { - int c = ctl.get(); - if (runStateAtLeast(c, targetState) || - ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c)))) - break; - } - } - - /** - * Transitions to TERMINATED state if either (SHUTDOWN and pool - * and queue empty) or (STOP and pool empty). If otherwise - * eligible to terminate but workerCount is nonzero, interrupts an - * idle worker to ensure that shutdown signals propagate. This - * method must be called following any action that might make - * termination possible -- reducing worker count or removing tasks - * from the queue during shutdown. The method is non-private to - * allow access from ScheduledThreadPoolExecutor. - */ - final void tryTerminate() { - for (;;) { - int c = ctl.get(); - if (isRunning(c) || - runStateAtLeast(c, TIDYING) || - (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty())) - return; - if (workerCountOf(c) != 0) { // Eligible to terminate - interruptIdleWorkers(ONLY_ONE); - return; - } - - final ReentrantLock mainLock = this.mainLock; - mainLock.lock(); - try { - if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) { - try { - terminated(); - } finally { - ctl.set(ctlOf(TERMINATED, 0)); - termination.signalAll(); - } - return; - } - } finally { - mainLock.unlock(); - } - // else retry on failed CAS - } - } - - /* - * Methods for controlling interrupts to worker threads. - */ - - /** - * If there is a security manager, makes sure caller has - * permission to shut down threads in general (see shutdownPerm). - * If this passes, additionally makes sure the caller is allowed - * to interrupt each worker thread. This might not be true even if - * first check passed, if the SecurityManager treats some threads - * specially. - */ - private void checkShutdownAccess() { - SecurityManager security = System.getSecurityManager(); - if (security != null) { - security.checkPermission(shutdownPerm); - final ReentrantLock mainLock = this.mainLock; - mainLock.lock(); - try { - for (Iterator itr = workers.iterator(); itr.hasNext();) { - Worker w = (Worker)itr.next(); - security.checkAccess(w.thread); - } - } finally { - mainLock.unlock(); - } - } - } - - /** - * Interrupts all threads, even if active. Ignores SecurityExceptions - * (in which case some threads may remain uninterrupted). - */ - private void interruptWorkers() { - final ReentrantLock mainLock = this.mainLock; - mainLock.lock(); - try { - for (Iterator itr = workers.iterator(); itr.hasNext();) { - Worker w = (Worker)itr.next(); - try { - w.thread.interrupt(); - } catch (SecurityException ignore) { - } - } - } finally { - mainLock.unlock(); - } - } - - /** - * Interrupts threads that might be waiting for tasks (as - * indicated by not being locked) so they can check for - * termination or configuration changes. Ignores - * SecurityExceptions (in which case some threads may remain - * uninterrupted). - * - * @param onlyOne If true, interrupt at most one worker. This is - * called only from tryTerminate when termination is otherwise - * enabled but there are still other workers. In this case, at - * most one waiting worker is interrupted to propagate shutdown - * signals in case all threads are currently waiting. - * Interrupting any arbitrary thread ensures that newly arriving - * workers since shutdown began will also eventually exit. - * To guarantee eventual termination, it suffices to always - * interrupt only one idle worker, but shutdown() interrupts all - * idle workers so that redundant workers exit promptly, not - * waiting for a straggler task to finish. - */ - private void interruptIdleWorkers(boolean onlyOne) { - final ReentrantLock mainLock = this.mainLock; - mainLock.lock(); - try { - Iterator it = workers.iterator(); - while (it.hasNext()) { - Worker w = (Worker)it.next(); - Thread t = w.thread; - if (!t.isInterrupted() && w.tryLock()) { - try { - t.interrupt(); - } catch (SecurityException ignore) { - } finally { - w.unlock(); - } - } - if (onlyOne) - break; - } - } finally { - mainLock.unlock(); - } - } - - /** - * Common form of interruptIdleWorkers, to avoid having to - * remember what the boolean argument means. - */ - private void interruptIdleWorkers() { - interruptIdleWorkers(false); - } - - private static final boolean ONLY_ONE = true; - - /** - * Ensures that unless the pool is stopping, the current thread - * does not have its interrupt set. This requires a double-check - * of state in case the interrupt was cleared concurrently with a - * shutdownNow -- if so, the interrupt is re-enabled. - */ - private void clearInterruptsForTaskRun() { - if (runStateLessThan(ctl.get(), STOP) && - Thread.interrupted() && - runStateAtLeast(ctl.get(), STOP)) - Thread.currentThread().interrupt(); - } - - /* - * Misc utilities, most of which are also exported to - * ScheduledThreadPoolExecutor - */ - - /** - * Invokes the rejected execution handler for the given command. - * Package-protected for use by ScheduledThreadPoolExecutor. - */ - final void reject(Runnable command) { - handler.rejectedExecution(command, this); - } - - /** - * Performs any further cleanup following run state transition on - * invocation of shutdown. A no-op here, but used by - * ScheduledThreadPoolExecutor to cancel delayed tasks. - */ - void onShutdown() { - } - - /** - * State check needed by ScheduledThreadPoolExecutor to - * enable running tasks during shutdown. - * - * @param shutdownOK true if should return true if SHUTDOWN - */ - final boolean isRunningOrShutdown(boolean shutdownOK) { - int rs = runStateOf(ctl.get()); - return rs == RUNNING || (rs == SHUTDOWN && shutdownOK); - } - - /** - * Drains the task queue into a new list, normally using - * drainTo. But if the queue is a DelayQueue or any other kind of - * queue for which poll or drainTo may fail to remove some - * elements, it deletes them one by one. - */ - private List drainQueue() { - BlockingQueue q = workQueue; - List<Runnable> taskList = new ArrayList<Runnable>(); - q.drainTo(taskList); - if (!q.isEmpty()) { - Runnable[] arr = (Runnable[])q.toArray(new Runnable[0]); - for (int i=0; i<arr.length; i++) { - Runnable r = arr[i]; - if (q.remove(r)) - taskList.add(r); - } - } - return taskList; - } - - /* - * Methods for creating, running and cleaning up after workers - */ - - /** - * Checks if a new worker can be added with respect to current - * pool state and the given bound (either core or maximum). If so, - * the worker count is adjusted accordingly, and, if possible, a - * new worker is created and started running firstTask as its - * first task. This method returns false if the pool is stopped or - * eligible to shut down. It also returns false if the thread - * factory fails to create a thread when asked, which requires a - * backout of workerCount, and a recheck for termination, in case - * the existence of this worker was holding up termination. - * - * @param firstTask the task the new thread should run first (or - * null if none). Workers are created with an initial first task - * (in method execute()) to bypass queuing when there are fewer - * than corePoolSize threads (in which case we always start one), - * or when the queue is full (in which case we must bypass queue). - * Initially idle threads are usually created via - * prestartCoreThread or to replace other dying workers. - * - * @param core if true use corePoolSize as bound, else - * maximumPoolSize. (A boolean indicator is used here rather than a - * value to ensure reads of fresh values after checking other pool - * state). - * @return true if successful - */ - private boolean addWorker(Runnable firstTask, boolean core) { - retry: - for (;;) { - int c = ctl.get(); - int rs = runStateOf(c); - - // Check if queue empty only if necessary. - if (rs >= SHUTDOWN && - ! (rs == SHUTDOWN && - firstTask == null && - ! workQueue.isEmpty())) - return false; - - for (;;) { - int wc = workerCountOf(c); - if (wc >= CAPACITY || - wc >= (core ? corePoolSize : maximumPoolSize)) - return false; - if (compareAndIncrementWorkerCount(c)) - break retry; - c = ctl.get(); // Re-read ctl - if (runStateOf(c) != rs) - continue retry; - // else CAS failed due to workerCount change; retry inner loop - } - } - - Worker w = new Worker(firstTask); - Thread t = w.thread; - - final ReentrantLock mainLock = this.mainLock; - mainLock.lock(); - try { - // Recheck while holding lock. - // Back out on ThreadFactory failure or if - // shut down before lock acquired. - int c = ctl.get(); - int rs = runStateOf(c); - - if (t == null || - (rs >= SHUTDOWN && - ! (rs == SHUTDOWN && - firstTask == null))) { - decrementWorkerCount(); - tryTerminate(); - return false; - } - - workers.add(w); - - int s = workers.size(); - if (s > largestPoolSize) - largestPoolSize = s; - } finally { - mainLock.unlock(); - } - - t.start(); - // It is possible (but unlikely) for a thread to have been - // added to workers, but not yet started, during transition to - // STOP, which could result in a rare missed interrupt, - // because Thread.interrupt is not guaranteed to have any effect - // on a non-yet-started Thread (see Thread#interrupt). - if (runStateOf(ctl.get()) == STOP && ! t.isInterrupted()) - t.interrupt(); - - return true; - } - - /** - * Performs cleanup and bookkeeping for a dying worker. Called - * only from worker threads. Unless completedAbruptly is set, - * assumes that workerCount has already been adjusted to account - * for exit. This method removes thread from worker set, and - * possibly terminates the pool or replaces the worker if either - * it exited due to user task exception or if fewer than - * corePoolSize workers are running or queue is non-empty but - * there are no workers. - * - * @param w the worker - * @param completedAbruptly if the worker died due to user exception - */ - private void processWorkerExit(Worker w, boolean completedAbruptly) { - if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted - decrementWorkerCount(); - - final ReentrantLock mainLock = this.mainLock; - mainLock.lock(); - try { - completedTaskCount += w.completedTasks; - workers.remove(w); - } finally { - mainLock.unlock(); - } - - tryTerminate(); - - int c = ctl.get(); - if (runStateLessThan(c, STOP)) { - if (!completedAbruptly) { - int min = allowCoreThreadTimeOut ? 0 : corePoolSize; - if (min == 0 && ! workQueue.isEmpty()) - min = 1; - if (workerCountOf(c) >= min) - return; // replacement not needed - } - addWorker(null, false); - } - } - - /** - * Performs blocking or timed wait for a task, depending on - * current configuration settings, or returns null if this worker - * must exit because of any of: - * 1. There are more than maximumPoolSize workers (due to - * a call to setMaximumPoolSize). - * 2. The pool is stopped. - * 3. The pool is shutdown and the queue is empty. - * 4. This worker timed out waiting for a task, and timed-out - * workers are subject to termination (that is, - * {@code allowCoreThreadTimeOut || workerCount > corePoolSize}) - * both before and after the timed wait. - * - * @return task, or null if the worker must exit, in which case - * workerCount is decremented - */ - private Runnable getTask() { - boolean timedOut = false; // Did the last poll() time out? - - retry: - for (;;) { - int c = ctl.get(); - int rs = runStateOf(c); - - // Check if queue empty only if necessary. - if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) { - decrementWorkerCount(); - return null; - } - - boolean timed; // Are workers subject to culling? - - for (;;) { - int wc = workerCountOf(c); - timed = allowCoreThreadTimeOut || wc > corePoolSize; - - if (wc <= maximumPoolSize && ! (timedOut && timed)) - break; - if (compareAndDecrementWorkerCount(c)) - return null; - c = ctl.get(); // Re-read ctl - if (runStateOf(c) != rs) - continue retry; - // else CAS failed due to workerCount change; retry inner loop - } - - try { - Runnable r = timed ? - (Runnable)workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) : - (Runnable)workQueue.take(); - if (r != null) - return r; - timedOut = true; - } catch (InterruptedException retry) { - timedOut = false; - } - } - } - - /** - * Main worker run loop. Repeatedly gets tasks from queue and - * executes them, while coping with a number of issues: - * - * 1. We may start out with an initial task, in which case we - * don't need to get the first one. Otherwise, as long as pool is - * running, we get tasks from getTask. If it returns null then the - * worker exits due to changed pool state or configuration - * parameters. Other exits result from exception throws in - * external code, in which case completedAbruptly holds, which - * usually leads processWorkerExit to replace this thread. - * - * 2. Before running any task, the lock is acquired to prevent - * other pool interrupts while the task is executing, and - * clearInterruptsForTaskRun called to ensure that unless pool is - * stopping, this thread does not have its interrupt set. - * - * 3. Each task run is preceded by a call to beforeExecute, which - * might throw an exception, in which case we cause thread to die - * (breaking loop with completedAbruptly true) without processing - * the task. - * - * 4. Assuming beforeExecute completes normally, we run the task, - * gathering any of its thrown exceptions to send to - * afterExecute. We separately handle RuntimeException, Error - * (both of which the specs guarantee that we trap) and arbitrary - * Throwables. Because we cannot rethrow Throwables within - * Runnable.run, we wrap them within Errors on the way out (to the - * thread's UncaughtExceptionHandler). Any thrown exception also - * conservatively causes thread to die. - * - * 5. After task.run completes, we call afterExecute, which may - * also throw an exception, which will also cause thread to - * die. According to JLS Sec 14.20, this exception is the one that - * will be in effect even if task.run throws. - * - * The net effect of the exception mechanics is that afterExecute - * and the thread's UncaughtExceptionHandler have as accurate - * information as we can provide about any problems encountered by - * user code. - * - * @param w the worker - */ - final void runWorker(Worker w) { - Runnable task = w.firstTask; - w.firstTask = null; - boolean completedAbruptly = true; - try { - while (task != null || (task = getTask()) != null) { - w.lock(); - clearInterruptsForTaskRun(); - try { - beforeExecute(w.thread, task); - Throwable thrown = null; - try { - task.run(); - } catch (RuntimeException x) { - thrown = x; throw x; - } catch (Error x) { - thrown = x; throw x; - } catch (Throwable x) { - thrown = x; throw new Error(x); - } finally { - afterExecute(task, thrown); - } - } finally { - task = null; - w.completedTasks++; - w.unlock(); - } - } - completedAbruptly = false; - } finally { - processWorkerExit(w, completedAbruptly); - } - } - - // Public constructors and methods - - /** - * Creates a new {@code ThreadPoolExecutor} with the given initial - * parameters and default thread factory and rejected execution handler. - * It may be more convenient to use one of the {@link Executors} factory - * methods instead of this general purpose constructor. - * - * @param corePoolSize the number of threads to keep in the pool, even - * if they are idle, unless {@code allowCoreThreadTimeOut} is set - * @param maximumPoolSize the maximum number of threads to allow in the - * pool - * @param keepAliveTime when the number of threads is greater than - * the core, this is the maximum time that excess idle threads - * will wait for new tasks before terminating. - * @param unit the time unit for the {@code keepAliveTime} argument - * @param workQueue the queue to use for holding tasks before they are - * executed. This queue will hold only the {@code Runnable} - * tasks submitted by the {@code execute} method. - * @throws IllegalArgumentException if one of the following holds:<br> - * {@code corePoolSize < 0}<br> - * {@code keepAliveTime < 0}<br> - * {@code maximumPoolSize <= 0}<br> - * {@code maximumPoolSize < corePoolSize} - * @throws NullPointerException if {@code workQueue} is null - */ - public ThreadPoolExecutor(int corePoolSize, - int maximumPoolSize, - long keepAliveTime, - TimeUnit unit, - BlockingQueue workQueue) { - this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, - Executors.defaultThreadFactory(), defaultHandler); - } - - /** - * Creates a new {@code ThreadPoolExecutor} with the given initial - * parameters and default rejected execution handler. - * - * @param corePoolSize the number of threads to keep in the pool, even - * if they are idle, unless {@code allowCoreThreadTimeOut} is set - * @param maximumPoolSize the maximum number of threads to allow in the - * pool - * @param keepAliveTime when the number of threads is greater than - * the core, this is the maximum time that excess idle threads - * will wait for new tasks before terminating. - * @param unit the time unit for the {@code keepAliveTime} argument - * @param workQueue the queue to use for holding tasks before they are - * executed. This queue will hold only the {@code Runnable} - * tasks submitted by the {@code execute} method. - * @param threadFactory the factory to use when the executor - * creates a new thread - * @throws IllegalArgumentException if one of the following holds:<br> - * {@code corePoolSize < 0}<br> - * {@code keepAliveTime < 0}<br> - * {@code maximumPoolSize <= 0}<br> - * {@code maximumPoolSize < corePoolSize} - * @throws NullPointerException if {@code workQueue} - * or {@code threadFactory} is null - */ - public ThreadPoolExecutor(int corePoolSize, - int maximumPoolSize, - long keepAliveTime, - TimeUnit unit, - BlockingQueue workQueue, - ThreadFactory threadFactory) { - this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, - threadFactory, defaultHandler); - } - - /** - * Creates a new {@code ThreadPoolExecutor} with the given initial - * parameters and default thread factory. - * - * @param corePoolSize the number of threads to keep in the pool, even - * if they are idle, unless {@code allowCoreThreadTimeOut} is set - * @param maximumPoolSize the maximum number of threads to allow in the - * pool - * @param keepAliveTime when the number of threads is greater than - * the core, this is the maximum time that excess idle threads - * will wait for new tasks before terminating. - * @param unit the time unit for the {@code keepAliveTime} argument - * @param workQueue the queue to use for holding tasks before they are - * executed. This queue will hold only the {@code Runnable} - * tasks submitted by the {@code execute} method. - * @param handler the handler to use when execution is blocked - * because the thread bounds and queue capacities are reached - * @throws IllegalArgumentException if one of the following holds:<br> - * {@code corePoolSize < 0}<br> - * {@code keepAliveTime < 0}<br> - * {@code maximumPoolSize <= 0}<br> - * {@code maximumPoolSize < corePoolSize} - * @throws NullPointerException if {@code workQueue} - * or {@code handler} is null - */ - public ThreadPoolExecutor(int corePoolSize, - int maximumPoolSize, - long keepAliveTime, - TimeUnit unit, - BlockingQueue workQueue, - RejectedExecutionHandler handler) { - this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, - Executors.defaultThreadFactory(), handler); - } - - /** - * Creates a new {@code ThreadPoolExecutor} with the given initial - * parameters. - * - * @param corePoolSize the number of threads to keep in the pool, even - * if they are idle, unless {@code allowCoreThreadTimeOut} is set - * @param maximumPoolSize the maximum number of threads to allow in the - * pool - * @param keepAliveTime when the number of threads is greater than - * the core, this is the maximum time that excess idle threads - * will wait for new tasks before terminating. - * @param unit the time unit for the {@code keepAliveTime} argument - * @param workQueue the queue to use for holding tasks before they are - * executed. This queue will hold only the {@code Runnable} - * tasks submitted by the {@code execute} method. - * @param threadFactory the factory to use when the executor - * creates a new thread - * @param handler the handler to use when execution is blocked - * because the thread bounds and queue capacities are reached - * @throws IllegalArgumentException if one of the following holds:<br> - * {@code corePoolSize < 0}<br> - * {@code keepAliveTime < 0}<br> - * {@code maximumPoolSize <= 0}<br> - * {@code maximumPoolSize < corePoolSize} - * @throws NullPointerException if {@code workQueue} - * or {@code threadFactory} or {@code handler} is null - */ - public ThreadPoolExecutor(int corePoolSize, - int maximumPoolSize, - long keepAliveTime, - TimeUnit unit, - BlockingQueue workQueue, - ThreadFactory threadFactory, - RejectedExecutionHandler handler) { - if (corePoolSize < 0 || - maximumPoolSize <= 0 || - maximumPoolSize < corePoolSize || - keepAliveTime < 0) - throw new IllegalArgumentException(); - if (workQueue == null || threadFactory == null || handler == null) - throw new NullPointerException(); - this.corePoolSize = corePoolSize; - this.maximumPoolSize = maximumPoolSize; - this.workQueue = workQueue; - this.keepAliveTime = unit.toNanos(keepAliveTime); - this.threadFactory = threadFactory; - this.handler = handler; - } - - /** - * Executes the given task sometime in the future. The task - * may execute in a new thread or in an existing pooled thread. - * - * If the task cannot be submitted for execution, either because this - * executor has been shutdown or because its capacity has been reached, - * the task is handled by the current {@code RejectedExecutionHandler}. - * - * @param command the task to execute - * @throws RejectedExecutionException at discretion of - * {@code RejectedExecutionHandler}, if the task - * cannot be accepted for execution - * @throws NullPointerException if {@code command} is null - */ - public void execute(Runnable command) { - if (command == null) - throw new NullPointerException(); - /* - * Proceed in 3 steps: - * - * 1. If fewer than corePoolSize threads are running, try to - * start a new thread with the given command as its first - * task. The call to addWorker atomically checks runState and - * workerCount, and so prevents false alarms that would add - * threads when it shouldn't, by returning false. - * - * 2. If a task can be successfully queued, then we still need - * to double-check whether we should have added a thread - * (because existing ones died since last checking) or that - * the pool shut down since entry into this method. So we - * recheck state and if necessary roll back the enqueuing if - * stopped, or start a new thread if there are none. - * - * 3. If we cannot queue task, then we try to add a new - * thread. If it fails, we know we are shut down or saturated - * and so reject the task. - */ - int c = ctl.get(); - if (workerCountOf(c) < corePoolSize) { - if (addWorker(command, true)) - return; - c = ctl.get(); - } - if (isRunning(c) && workQueue.offer(command)) { - int recheck = ctl.get(); - if (! isRunning(recheck) && remove(command)) - reject(command); - else if (workerCountOf(recheck) == 0) - addWorker(null, false); - } - else if (!addWorker(command, false)) - reject(command); - } - - /** - * Initiates an orderly shutdown in which previously submitted - * tasks are executed, but no new tasks will be accepted. - * Invocation has no additional effect if already shut down. - * - * @throws SecurityException {@inheritDoc} - */ - public void shutdown() { - final ReentrantLock mainLock = this.mainLock; - mainLock.lock(); - try { - checkShutdownAccess(); - advanceRunState(SHUTDOWN); - interruptIdleWorkers(); - onShutdown(); // hook for ScheduledThreadPoolExecutor - } finally { - mainLock.unlock(); - } - tryTerminate(); - } - - /** - * Attempts to stop all actively executing tasks, halts the - * processing of waiting tasks, and returns a list of the tasks - * that were awaiting execution. These tasks are drained (removed) - * from the task queue upon return from this method. - * - * <p>There are no guarantees beyond best-effort attempts to stop - * processing actively executing tasks. This implementation - * cancels tasks via {@link Thread#interrupt}, so any task that - * fails to respond to interrupts may never terminate. - * - * @throws SecurityException {@inheritDoc} - */ - public List shutdownNow() { - List tasks; - final ReentrantLock mainLock = this.mainLock; - mainLock.lock(); - try { - checkShutdownAccess(); - advanceRunState(STOP); - interruptWorkers(); - tasks = drainQueue(); - } finally { - mainLock.unlock(); - } - tryTerminate(); - return tasks; - } - - public boolean isShutdown() { - return ! isRunning(ctl.get()); - } - - /** - * Returns true if this executor is in the process of terminating - * after {@link #shutdown} or {@link #shutdownNow} but has not - * completely terminated. This method may be useful for - * debugging. A return of {@code true} reported a sufficient - * period after shutdown may indicate that submitted tasks have - * ignored or suppressed interruption, causing this executor not - * to properly terminate. - * - * @return true if terminating but not yet terminated - */ - public boolean isTerminating() { - int c = ctl.get(); - return ! isRunning(c) && runStateLessThan(c, TERMINATED); - } - - public boolean isTerminated() { - return runStateAtLeast(ctl.get(), TERMINATED); - } - - public boolean awaitTermination(long timeout, TimeUnit unit) - throws InterruptedException { - long nanos = unit.toNanos(timeout); - long deadline = Utils.nanoTime() + nanos; - final ReentrantLock mainLock = this.mainLock; - mainLock.lock(); - try { - if (runStateAtLeast(ctl.get(), TERMINATED)) - return true; - while (nanos > 0) { - termination.await(nanos, TimeUnit.NANOSECONDS); - if (runStateAtLeast(ctl.get(), TERMINATED)) - return true; - nanos = deadline - Utils.nanoTime(); - } - return false; - } finally { - mainLock.unlock(); - } - } - - /** - * Invokes {@code shutdown} when this executor is no longer - * referenced and it has no threads. - */ - protected void finalize() { - shutdown(); - } - - /** - * Sets the thread factory used to create new threads. - * - * @param threadFactory the new thread factory - * @throws NullPointerException if threadFactory is null - * @see #getThreadFactory - */ - public void setThreadFactory(ThreadFactory threadFactory) { - if (threadFactory == null) - throw new NullPointerException(); - this.threadFactory = threadFactory; - } - - /** - * Returns the thread factory used to create new threads. - * - * @return the current thread factory - * @see #setThreadFactory - */ - public ThreadFactory getThreadFactory() { - return threadFactory; - } - - /** - * Sets a new handler for unexecutable tasks. - * - * @param handler the new handler - * @throws NullPointerException if handler is null - * @see #getRejectedExecutionHandler - */ - public void setRejectedExecutionHandler(RejectedExecutionHandler handler) { - if (handler == null) - throw new NullPointerException(); - this.handler = handler; - } - - /** - * Returns the current handler for unexecutable tasks. - * - * @return the current handler - * @see #setRejectedExecutionHandler - */ - public RejectedExecutionHandler getRejectedExecutionHandler() { - return handler; - } - - /** - * Sets the core number of threads. This overrides any value set - * in the constructor. If the new value is smaller than the - * current value, excess existing threads will be terminated when - * they next become idle. If larger, new threads will, if needed, - * be started to execute any queued tasks. - * - * @param corePoolSize the new core size - * @throws IllegalArgumentException if {@code corePoolSize < 0} - * @see #getCorePoolSize - */ - public void setCorePoolSize(int corePoolSize) { - if (corePoolSize < 0) - throw new IllegalArgumentException(); - int delta = corePoolSize - this.corePoolSize; - this.corePoolSize = corePoolSize; - if (workerCountOf(ctl.get()) > corePoolSize) - interruptIdleWorkers(); - else if (delta > 0) { - // We don't really know how many new threads are "needed". - // As a heuristic, prestart enough new workers (up to new - // core size) to handle the current number of tasks in - // queue, but stop if queue becomes empty while doing so. - int k = Math.min(delta, workQueue.size()); - while (k-- > 0 && addWorker(null, true)) { - if (workQueue.isEmpty()) - break; - } - } - } - - /** - * Returns the core number of threads. - * - * @return the core number of threads - * @see #setCorePoolSize - */ - public int getCorePoolSize() { - return corePoolSize; - } - - /** - * Starts a core thread, causing it to idly wait for work. This - * overrides the default policy of starting core threads only when - * new tasks are executed. This method will return {@code false} - * if all core threads have already been started. - * - * @return {@code true} if a thread was started - */ - public boolean prestartCoreThread() { - return workerCountOf(ctl.get()) < corePoolSize && - addWorker(null, true); - } - - /** - * Starts all core threads, causing them to idly wait for work. This - * overrides the default policy of starting core threads only when - * new tasks are executed. - * - * @return the number of threads started - */ - public int prestartAllCoreThreads() { - int n = 0; - while (addWorker(null, true)) - ++n; - return n; - } - - /** - * Returns true if this pool allows core threads to time out and - * terminate if no tasks arrive within the keepAlive time, being - * replaced if needed when new tasks arrive. When true, the same - * keep-alive policy applying to non-core threads applies also to - * core threads. When false (the default), core threads are never - * terminated due to lack of incoming tasks. - * - * @return {@code true} if core threads are allowed to time out, - * else {@code false} - * - * @since 1.6 - */ - public boolean allowsCoreThreadTimeOut() { - return allowCoreThreadTimeOut; - } - - /** - * Sets the policy governing whether core threads may time out and - * terminate if no tasks arrive within the keep-alive time, being - * replaced if needed when new tasks arrive. When false, core - * threads are never terminated due to lack of incoming - * tasks. When true, the same keep-alive policy applying to - * non-core threads applies also to core threads. To avoid - * continual thread replacement, the keep-alive time must be - * greater than zero when setting {@code true}. This method - * should in general be called before the pool is actively used. - * - * @param value {@code true} if should time out, else {@code false} - * @throws IllegalArgumentException if value is {@code true} - * and the current keep-alive time is not greater than zero - * - * @since 1.6 - */ - public void allowCoreThreadTimeOut(boolean value) { - if (value && keepAliveTime <= 0) - throw new IllegalArgumentException("Core threads must have nonzero keep alive times"); - if (value != allowCoreThreadTimeOut) { - allowCoreThreadTimeOut = value; - if (value) - interruptIdleWorkers(); - } - } - - /** - * Sets the maximum allowed number of threads. This overrides any - * value set in the constructor. If the new value is smaller than - * the current value, excess existing threads will be - * terminated when they next become idle. - * - * @param maximumPoolSize the new maximum - * @throws IllegalArgumentException if the new maximum is - * less than or equal to zero, or - * less than the {@linkplain #getCorePoolSize core pool size} - * @see #getMaximumPoolSize - */ - public void setMaximumPoolSize(int maximumPoolSize) { - if (maximumPoolSize <= 0 || maximumPoolSize < corePoolSize) - throw new IllegalArgumentException(); - this.maximumPoolSize = maximumPoolSize; - if (workerCountOf(ctl.get()) > maximumPoolSize) - interruptIdleWorkers(); - } - - /** - * Returns the maximum allowed number of threads. - * - * @return the maximum allowed number of threads - * @see #setMaximumPoolSize - */ - public int getMaximumPoolSize() { - return maximumPoolSize; - } - - /** - * Sets the time limit for which threads may remain idle before - * being terminated. If there are more than the core number of - * threads currently in the pool, after waiting this amount of - * time without processing a task, excess threads will be - * terminated. This overrides any value set in the constructor. - * - * @param time the time to wait. A time value of zero will cause - * excess threads to terminate immediately after executing tasks. - * @param unit the time unit of the {@code time} argument - * @throws IllegalArgumentException if {@code time} less than zero or - * if {@code time} is zero and {@code allowsCoreThreadTimeOut} - * @see #getKeepAliveTime - */ - public void setKeepAliveTime(long time, TimeUnit unit) { - if (time < 0) - throw new IllegalArgumentException(); - if (time == 0 && allowsCoreThreadTimeOut()) - throw new IllegalArgumentException("Core threads must have nonzero keep alive times"); - long keepAliveTime = unit.toNanos(time); - long delta = keepAliveTime - this.keepAliveTime; - this.keepAliveTime = keepAliveTime; - if (delta < 0) - interruptIdleWorkers(); - } - - /** - * Returns the thread keep-alive time, which is the amount of time - * that threads in excess of the core pool size may remain - * idle before being terminated. - * - * @param unit the desired time unit of the result - * @return the time limit - * @see #setKeepAliveTime - */ - public long getKeepAliveTime(TimeUnit unit) { - return unit.convert(keepAliveTime, TimeUnit.NANOSECONDS); - } - - /* User-level queue utilities */ - - /** - * Returns the task queue used by this executor. Access to the - * task queue is intended primarily for debugging and monitoring. - * This queue may be in active use. Retrieving the task queue - * does not prevent queued tasks from executing. - * - * @return the task queue - */ - public BlockingQueue getQueue() { - return workQueue; - } - - /** - * Removes this task from the executor's internal queue if it is - * present, thus causing it not to be run if it has not already - * started. - * - * <p> This method may be useful as one part of a cancellation - * scheme. It may fail to remove tasks that have been converted - * into other forms before being placed on the internal queue. For - * example, a task entered using {@code submit} might be - * converted into a form that maintains {@code Future} status. - * However, in such cases, method {@link #purge} may be used to - * remove those Futures that have been cancelled. - * - * @param task the task to remove - * @return true if the task was removed - */ - public boolean remove(Runnable task) { - boolean removed = workQueue.remove(task); - tryTerminate(); // In case SHUTDOWN and now empty - return removed; - } - - /** - * Tries to remove from the work queue all {@link Future} - * tasks that have been cancelled. This method can be useful as a - * storage reclamation operation, that has no other impact on - * functionality. Cancelled tasks are never executed, but may - * accumulate in work queues until worker threads can actively - * remove them. Invoking this method instead tries to remove them now. - * However, this method may fail to remove tasks in - * the presence of interference by other threads. - */ - public void purge() { - final BlockingQueue q = workQueue; - try { - Iterator it = q.iterator(); - while (it.hasNext()) { - Runnable r = (Runnable)it.next(); - if (r instanceof Future && ((Future)r).isCancelled()) - it.remove(); - } - } catch (ConcurrentModificationException fallThrough) { - // Take slow path if we encounter interference during traversal. - // Make copy for traversal and call remove for cancelled entries. - // The slow path is more likely to be O(N*N). - Object[] arr = q.toArray(); - for (int i=0; i<arr.length; i++) { - Object r = arr[i]; - if (r instanceof Future && ((Future)r).isCancelled()) - q.remove(r); - } - } - - tryTerminate(); // In case SHUTDOWN and now empty - } - - /* Statistics */ - - /** - * Returns the current number of threads in the pool. - * - * @return the number of threads - */ - public int getPoolSize() { - final ReentrantLock mainLock = this.mainLock; - mainLock.lock(); - try { - // Remove rare and surprising possibility of - // isTerminated() && getPoolSize() > 0 - return runStateAtLeast(ctl.get(), TIDYING) ? 0 - : workers.size(); - } finally { - mainLock.unlock(); - } - } - - /** - * Returns the approximate number of threads that are actively - * executing tasks. - * - * @return the number of threads - */ - public int getActiveCount() { - final ReentrantLock mainLock = this.mainLock; - mainLock.lock(); - try { - int n = 0; - for (Iterator itr = workers.iterator(); itr.hasNext();) { - Worker w = (Worker)itr.next(); - if (w.isLocked()) - ++n; - } - return n; - } finally { - mainLock.unlock(); - } - } - - /** - * Returns the largest number of threads that have ever - * simultaneously been in the pool. - * - * @return the number of threads - */ - public int getLargestPoolSize() { - final ReentrantLock mainLock = this.mainLock; - mainLock.lock(); - try { - return largestPoolSize; - } finally { - mainLock.unlock(); - } - } - - /** - * Returns the approximate total number of tasks that have ever been - * scheduled for execution. Because the states of tasks and - * threads may change dynamically during computation, the returned - * value is only an approximation. - * - * @return the number of tasks - */ - public long getTaskCount() { - final ReentrantLock mainLock = this.mainLock; - mainLock.lock(); - try { - long n = completedTaskCount; - for (Iterator itr = workers.iterator(); itr.hasNext();) { - Worker w = (Worker)itr.next(); - n += w.completedTasks; - if (w.isLocked()) - ++n; - } - return n + workQueue.size(); - } finally { - mainLock.unlock(); - } - } - - /** - * Returns the approximate total number of tasks that have - * completed execution. Because the states of tasks and threads - * may change dynamically during computation, the returned value - * is only an approximation, but one that does not ever decrease - * across successive calls. - * - * @return the number of tasks - */ - public long getCompletedTaskCount() { - final ReentrantLock mainLock = this.mainLock; - mainLock.lock(); - try { - long n = completedTaskCount; - for (Iterator itr = workers.iterator(); itr.hasNext();) { - Worker w = (Worker)itr.next(); - n += w.completedTasks; - } - return n; - } finally { - mainLock.unlock(); - } - } - - /* Extension hooks */ - - /** - * Method invoked prior to executing the given Runnable in the - * given thread. This method is invoked by thread {@code t} that - * will execute task {@code r}, and may be used to re-initialize - * ThreadLocals, or to perform logging. - * - * <p>This implementation does nothing, but may be customized in - * subclasses. Note: To properly nest multiple overridings, subclasses - * should generally invoke {@code super.beforeExecute} at the end of - * this method. - * - * @param t the thread that will run task {@code r} - * @param r the task that will be executed - */ - protected void beforeExecute(Thread t, Runnable r) { } - - /** - * Method invoked upon completion of execution of the given Runnable. - * This method is invoked by the thread that executed the task. If - * non-null, the Throwable is the uncaught {@code RuntimeException} - * or {@code Error} that caused execution to terminate abruptly. - * - * <p>This implementation does nothing, but may be customized in - * subclasses. Note: To properly nest multiple overridings, subclasses - * should generally invoke {@code super.afterExecute} at the - * beginning of this method. - * - * <p><b>Note:</b> When actions are enclosed in tasks (such as - * {@link FutureTask}) either explicitly or via methods such as - * {@code submit}, these task objects catch and maintain - * computational exceptions, and so they do not cause abrupt - * termination, and the internal exceptions are <em>not</em> - * passed to this method. If you would like to trap both kinds of - * failures in this method, you can further probe for such cases, - * as in this sample subclass that prints either the direct cause - * or the underlying exception if a task has been aborted: - * - * <pre> {@code - * class ExtendedExecutor extends ThreadPoolExecutor { - * // ... - * protected void afterExecute(Runnable r, Throwable t) { - * super.afterExecute(r, t); - * if (t == null && r instanceof Future<?>) { - * try { - * Object result = ((Future<?>) r).get(); - * } catch (CancellationException ce) { - * t = ce; - * } catch (ExecutionException ee) { - * t = ee.getCause(); - * } catch (InterruptedException ie) { - * Thread.currentThread().interrupt(); // ignore/reset - * } - * } - * if (t != null) - * System.out.println(t); - * } - * }}</pre> - * - * @param r the runnable that has completed - * @param t the exception that caused termination, or null if - * execution completed normally - */ - protected void afterExecute(Runnable r, Throwable t) { } - - /** - * Method invoked when the Executor has terminated. Default - * implementation does nothing. Note: To properly nest multiple - * overridings, subclasses should generally invoke - * {@code super.terminated} within this method. - */ - protected void terminated() { } - - /* Predefined RejectedExecutionHandlers */ - - /** - * A handler for rejected tasks that runs the rejected task - * directly in the calling thread of the {@code execute} method, - * unless the executor has been shut down, in which case the task - * is discarded. - */ - public static class CallerRunsPolicy implements RejectedExecutionHandler { - /** - * Creates a {@code CallerRunsPolicy}. - */ - public CallerRunsPolicy() { } - - /** - * Executes task r in the caller's thread, unless the executor - * has been shut down, in which case the task is discarded. - * - * @param r the runnable task requested to be executed - * @param e the executor attempting to execute this task - */ - public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { - if (!e.isShutdown()) { - r.run(); - } - } - } - - /** - * A handler for rejected tasks that throws a - * {@code RejectedExecutionException}. - */ - public static class AbortPolicy implements RejectedExecutionHandler { - /** - * Creates an {@code AbortPolicy}. - */ - public AbortPolicy() { } - - /** - * Always throws RejectedExecutionException. - * - * @param r the runnable task requested to be executed - * @param e the executor attempting to execute this task - * @throws RejectedExecutionException always. - */ - public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { - throw new RejectedExecutionException(); - } - } - - /** - * A handler for rejected tasks that silently discards the - * rejected task. - */ - public static class DiscardPolicy implements RejectedExecutionHandler { - /** - * Creates a {@code DiscardPolicy}. - */ - public DiscardPolicy() { } - - /** - * Does nothing, which has the effect of discarding task r. - * - * @param r the runnable task requested to be executed - * @param e the executor attempting to execute this task - */ - public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { - } - } - - /** - * A handler for rejected tasks that discards the oldest unhandled - * request and then retries {@code execute}, unless the executor - * is shut down, in which case the task is discarded. - */ - public static class DiscardOldestPolicy implements RejectedExecutionHandler { - /** - * Creates a {@code DiscardOldestPolicy} for the given executor. - */ - public DiscardOldestPolicy() { } - - /** - * Obtains and ignores the next task that the executor - * would otherwise execute, if one is immediately available, - * and then retries execution of task r, unless the executor - * is shut down, in which case task r is instead discarded. - * - * @param r the runnable task requested to be executed - * @param e the executor attempting to execute this task - */ - public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { - if (!e.isShutdown()) { - e.getQueue().poll(); - e.execute(r); - } - } - } -} diff --git a/src/actors/scala/actors/threadpool/TimeUnit.java b/src/actors/scala/actors/threadpool/TimeUnit.java deleted file mode 100644 index c443750e33..0000000000 --- a/src/actors/scala/actors/threadpool/TimeUnit.java +++ /dev/null @@ -1,407 +0,0 @@ -/* - * Written by Doug Lea with assistance from members of JCP JSR-166 - * Expert Group and released to the public domain, as explained at - * http://creativecommons.org/licenses/publicdomain - */ - -package scala.actors.threadpool; - -import java.io.InvalidObjectException; -import java.io.ObjectStreamException; - -/** - * A <tt>TimeUnit</tt> represents time durations at a given unit of - * granularity and provides utility methods to convert across units, - * and to perform timing and delay operations in these units. A - * <tt>TimeUnit</tt> does not maintain time information, but only - * helps organize and use time representations that may be maintained - * separately across various contexts. A nanosecond is defined as one - * thousandth of a microsecond, a microsecond as one thousandth of a - * millisecond, a millisecond as one thousandth of a second, a minute - * as sixty seconds, an hour as sixty minutes, and a day as twenty four - * hours. - * - * <p>A <tt>TimeUnit</tt> is mainly used to inform time-based methods - * how a given timing parameter should be interpreted. For example, - * the following code will timeout in 50 milliseconds if the {@link - * edu.emory.mathcs.backport.java.util.concurrent.locks.Lock lock} is not available: - * - * <pre> Lock lock = ...; - * if ( lock.tryLock(50L, TimeUnit.MILLISECONDS) ) ... - * </pre> - * while this code will timeout in 50 seconds: - * <pre> - * Lock lock = ...; - * if ( lock.tryLock(50L, TimeUnit.SECONDS) ) ... - * </pre> - * - * Note however, that there is no guarantee that a particular timeout - * implementation will be able to notice the passage of time at the - * same granularity as the given <tt>TimeUnit</tt>. - * - * @since 1.5 - * @author Doug Lea - */ -public abstract class TimeUnit implements java.io.Serializable { - - public static final TimeUnit NANOSECONDS = new TimeUnit(0, "NANOSECONDS") { - private final static long serialVersionUID = 535148490883208361L; - public long toNanos(long d) { return d; } - public long toMicros(long d) { return d/(C1/C0); } - public long toMillis(long d) { return d/(C2/C0); } - public long toSeconds(long d) { return d/(C3/C0); } - public long toMinutes(long d) { return d/(C4/C0); } - public long toHours(long d) { return d/(C5/C0); } - public long toDays(long d) { return d/(C6/C0); } - public long convert(long d, TimeUnit u) { return u.toNanos(d); } - int excessNanos(long d, long m) { return (int)(d - (m*C2)); } - }; - public static final TimeUnit MICROSECONDS = new TimeUnit(1, "MICROSECONDS") { - private final static long serialVersionUID = 2185906575929579108L; - public long toNanos(long d) { return x(d, C1/C0, MAX/(C1/C0)); } - public long toMicros(long d) { return d; } - public long toMillis(long d) { return d/(C2/C1); } - public long toSeconds(long d) { return d/(C3/C1); } - public long toMinutes(long d) { return d/(C4/C1); } - public long toHours(long d) { return d/(C5/C1); } - public long toDays(long d) { return d/(C6/C1); } - public long convert(long d, TimeUnit u) { return u.toMicros(d); } - int excessNanos(long d, long m) { return (int)((d*C1) - (m*C2)); } - }; - public static final TimeUnit MILLISECONDS = new TimeUnit(2, "MILLISECONDS") { - private final static long serialVersionUID = 9032047794123325184L; - public long toNanos(long d) { return x(d, C2/C0, MAX/(C2/C0)); } - public long toMicros(long d) { return x(d, C2/C1, MAX/(C2/C1)); } - public long toMillis(long d) { return d; } - public long toSeconds(long d) { return d/(C3/C2); } - public long toMinutes(long d) { return d/(C4/C2); } - public long toHours(long d) { return d/(C5/C2); } - public long toDays(long d) { return d/(C6/C2); } - public long convert(long d, TimeUnit u) { return u.toMillis(d); } - int excessNanos(long d, long m) { return 0; } - }; - public static final TimeUnit SECONDS = new TimeUnit(3, "SECONDS") { - private final static long serialVersionUID = 227755028449378390L; - public long toNanos(long d) { return x(d, C3/C0, MAX/(C3/C0)); } - public long toMicros(long d) { return x(d, C3/C1, MAX/(C3/C1)); } - public long toMillis(long d) { return x(d, C3/C2, MAX/(C3/C2)); } - public long toSeconds(long d) { return d; } - public long toMinutes(long d) { return d/(C4/C3); } - public long toHours(long d) { return d/(C5/C3); } - public long toDays(long d) { return d/(C6/C3); } - public long convert(long d, TimeUnit u) { return u.toSeconds(d); } - int excessNanos(long d, long m) { return 0; } - }; - public static final TimeUnit MINUTES = new TimeUnit(4, "MINUTES") { - private final static long serialVersionUID = 1827351566402609187L; - public long toNanos(long d) { return x(d, C4/C0, MAX/(C4/C0)); } - public long toMicros(long d) { return x(d, C4/C1, MAX/(C4/C1)); } - public long toMillis(long d) { return x(d, C4/C2, MAX/(C4/C2)); } - public long toSeconds(long d) { return x(d, C4/C3, MAX/(C4/C3)); } - public long toMinutes(long d) { return d; } - public long toHours(long d) { return d/(C5/C4); } - public long toDays(long d) { return d/(C6/C4); } - public long convert(long d, TimeUnit u) { return u.toMinutes(d); } - int excessNanos(long d, long m) { return 0; } - }; - public static final TimeUnit HOURS = new TimeUnit(5, "HOURS") { - private final static long serialVersionUID = -6438436134732089810L; - public long toNanos(long d) { return x(d, C5/C0, MAX/(C5/C0)); } - public long toMicros(long d) { return x(d, C5/C1, MAX/(C5/C1)); } - public long toMillis(long d) { return x(d, C5/C2, MAX/(C5/C2)); } - public long toSeconds(long d) { return x(d, C5/C3, MAX/(C5/C3)); } - public long toMinutes(long d) { return x(d, C5/C4, MAX/(C5/C4)); } - public long toHours(long d) { return d; } - public long toDays(long d) { return d/(C6/C5); } - public long convert(long d, TimeUnit u) { return u.toHours(d); } - int excessNanos(long d, long m) { return 0; } - }; - public static final TimeUnit DAYS = new TimeUnit(6, "DAYS") { - private final static long serialVersionUID = 567463171959674600L; - public long toNanos(long d) { return x(d, C6/C0, MAX/(C6/C0)); } - public long toMicros(long d) { return x(d, C6/C1, MAX/(C6/C1)); } - public long toMillis(long d) { return x(d, C6/C2, MAX/(C6/C2)); } - public long toSeconds(long d) { return x(d, C6/C3, MAX/(C6/C3)); } - public long toMinutes(long d) { return x(d, C6/C4, MAX/(C6/C4)); } - public long toHours(long d) { return x(d, C6/C5, MAX/(C6/C5)); } - public long toDays(long d) { return d; } - public long convert(long d, TimeUnit u) { return u.toDays(d); } - int excessNanos(long d, long m) { return 0; } - }; - - private static final TimeUnit[] values = new TimeUnit[] - { NANOSECONDS, MICROSECONDS, MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS }; - - public static TimeUnit[] values() { - return (TimeUnit[])values.clone(); - } - - /** - * Returns the enum constant of this type with the specified name. The - * string must match <em>exactly</em> an identifier used to declare an - * enum constant in this type. (Extraneous whitespace characters are not - * permitted.) - * - * @param name the name of the enum constant to be returned - * @return the enum constant with the specified name - * @throws IllegalArgumentException - * if this enum type has no constant with the specified name - */ - public static TimeUnit valueOf(String name) { - for (int i = 0; i < values.length; i++) { - if (values[i].name.equals(name)) { - return values[i]; - } - } - throw new IllegalArgumentException("No enum const TimeUnit." + name); - } - - /** - * The ordinal of this unit. This is useful both for {@link #ordinal()} - * and to maintain serialization consistence with earlier versions. - */ - private final int index; - - /** name of this unit */ - private final String name; - - /** Internal constructor */ - TimeUnit(int index, String name) { - this.index = index; - this.name = name; - } - - // Handy constants for conversion methods - static final long C0 = 1; - static final long C1 = C0 * 1000; - static final long C2 = C1 * 1000; - static final long C3 = C2 * 1000; - static final long C4 = C3 * 60; - static final long C5 = C4 * 60; - static final long C6 = C5 * 24; - - static final long MAX = Long.MAX_VALUE; - - /** - * Scale d by m, checking for overflow. - * This has a short name to make above code more readable. - */ - static long x(long d, long m, long over) { - if (d > over) return Long.MAX_VALUE; - if (d < -over) return Long.MIN_VALUE; - return d * m; - } - - /** - * Convert the given time duration in the given unit to this - * unit. Conversions from finer to coarser granularities - * truncate, so lose precision. For example converting - * <tt>999</tt> milliseconds to seconds results in - * <tt>0</tt>. Conversions from coarser to finer granularities - * with arguments that would numerically overflow saturate to - * <tt>Long.MIN_VALUE</tt> if negative or <tt>Long.MAX_VALUE</tt> - * if positive. - * - * <p>For example, to convert 10 minutes to milliseconds, use: - * <tt>TimeUnit.MILLISECONDS.convert(10L, TimeUnit.MINUTES)</tt> - * - * @param sourceDuration the time duration in the given <tt>sourceUnit</tt> - * @param sourceUnit the unit of the <tt>sourceDuration</tt> argument - * @return the converted duration in this unit, - * or <tt>Long.MIN_VALUE</tt> if conversion would negatively - * overflow, or <tt>Long.MAX_VALUE</tt> if it would positively overflow. - */ - public abstract long convert(long sourceDuration, TimeUnit sourceUnit); - - /** - * Equivalent to <tt>NANOSECONDS.convert(duration, this)</tt>. - * @param duration the duration - * @return the converted duration, - * or <tt>Long.MIN_VALUE</tt> if conversion would negatively - * overflow, or <tt>Long.MAX_VALUE</tt> if it would positively overflow. - * @see #convert - */ - public abstract long toNanos(long duration); - - /** - * Equivalent to <tt>MICROSECONDS.convert(duration, this)</tt>. - * @param duration the duration - * @return the converted duration, - * or <tt>Long.MIN_VALUE</tt> if conversion would negatively - * overflow, or <tt>Long.MAX_VALUE</tt> if it would positively overflow. - * @see #convert - */ - public abstract long toMicros(long duration); - - /** - * Equivalent to <tt>MILLISECONDS.convert(duration, this)</tt>. - * @param duration the duration - * @return the converted duration, - * or <tt>Long.MIN_VALUE</tt> if conversion would negatively - * overflow, or <tt>Long.MAX_VALUE</tt> if it would positively overflow. - * @see #convert - */ - public abstract long toMillis(long duration); - - /** - * Equivalent to <tt>SECONDS.convert(duration, this)</tt>. - * @param duration the duration - * @return the converted duration, - * or <tt>Long.MIN_VALUE</tt> if conversion would negatively - * overflow, or <tt>Long.MAX_VALUE</tt> if it would positively overflow. - * @see #convert - */ - public abstract long toSeconds(long duration); - - /** - * Equivalent to <tt>MINUTES.convert(duration, this)</tt>. - * @param duration the duration - * @return the converted duration, - * or <tt>Long.MIN_VALUE</tt> if conversion would negatively - * overflow, or <tt>Long.MAX_VALUE</tt> if it would positively overflow. - * @see #convert - * @since 1.6 - */ - public abstract long toMinutes(long duration); - - /** - * Equivalent to <tt>HOURS.convert(duration, this)</tt>. - * @param duration the duration - * @return the converted duration, - * or <tt>Long.MIN_VALUE</tt> if conversion would negatively - * overflow, or <tt>Long.MAX_VALUE</tt> if it would positively overflow. - * @see #convert - * @since 1.6 - */ - public abstract long toHours(long duration); - - /** - * Equivalent to <tt>DAYS.convert(duration, this)</tt>. - * @param duration the duration - * @return the converted duration - * @see #convert - * @since 1.6 - */ - public abstract long toDays(long duration); - - /** - * Utility to compute the excess-nanosecond argument to wait, - * sleep, join. - * @param d the duration - * @param m the number of milliseconds - * @return the number of nanoseconds - */ - abstract int excessNanos(long d, long m); - - /** - * Returns the name of this enum constant, exactly as declared in its enum - * declaration. <strong>Most programmers should use the - * {@link #toString()} method in preference to this one, as the toString - * method may return a more user-friendly name.</strong> This method is - * designed primarily for use in specialized situations where correctness - * depends on getting the exact name, which will not vary from release to - * release. - * - * @return the name of this enum constant - */ - public String name() { - return name; - } - - /** - * Returns the ordinal of this enumeration constant (its position in its - * enum declaration, where the initial constant is assigned an ordinal of - * zero). Most programmers will have no use for this method. It is - * designed for use by sophisticated enum-based data structures, such as - * <code>EnumSet</code> and <code>EnumMap</code>. - * - * @return the ordinal of this enumeration constant - */ - public int ordinal() { - return index; - } - - /* - * Guarantees that deserialized objects will be referentially equal to the - * standard enumeration objects. - */ - protected Object readResolve() throws ObjectStreamException { - try { - return valueOf(name); - } catch (IllegalArgumentException e) { - throw new InvalidObjectException(name - + " is not a valid enum for TimeUnit"); - } - } - - /** - * Performs a timed <tt>Object.wait</tt> using this time unit. - * This is a convenience method that converts timeout arguments - * into the form required by the <tt>Object.wait</tt> method. - * - * <p>For example, you could implement a blocking <tt>poll</tt> - * method (see {@link BlockingQueue#poll BlockingQueue.poll}) - * using: - * - * <pre> public synchronized Object poll(long timeout, TimeUnit unit) throws InterruptedException { - * while (empty) { - * unit.timedWait(this, timeout); - * ... - * } - * }</pre> - * - * @param obj the object to wait on - * @param timeout the maximum time to wait. If less than - * or equal to zero, do not wait at all. - * @throws InterruptedException if interrupted while waiting. - * @see java.lang.Object#wait(long, int) - */ - public void timedWait(Object obj, long timeout) - throws InterruptedException { - if (timeout > 0) { - long ms = toMillis(timeout); - int ns = excessNanos(timeout, ms); - obj.wait(ms, ns); - } - } - - /** - * Performs a timed <tt>Thread.join</tt> using this time unit. - * This is a convenience method that converts time arguments into the - * form required by the <tt>Thread.join</tt> method. - * @param thread the thread to wait for - * @param timeout the maximum time to wait. If less than - * or equal to zero, do not wait at all. - * @throws InterruptedException if interrupted while waiting. - * @see java.lang.Thread#join(long, int) - */ - public void timedJoin(Thread thread, long timeout) - throws InterruptedException { - if (timeout > 0) { - long ms = toMillis(timeout); - int ns = excessNanos(timeout, ms); - thread.join(ms, ns); - } - } - - /** - * Performs a <tt>Thread.sleep</tt> using this unit. - * This is a convenience method that converts time arguments into the - * form required by the <tt>Thread.sleep</tt> method. - * @param timeout the maximum time to sleep. If less than - * or equal to zero, do not sleep at all. - * @throws InterruptedException if interrupted while sleeping. - * @see java.lang.Thread#sleep - */ - public void sleep(long timeout) throws InterruptedException { - if (timeout > 0) { - long ms = toMillis(timeout); - int ns = excessNanos(timeout, ms); - Thread.sleep(ms, ns); - } - } - - public String toString() { - return name; - } -} diff --git a/src/actors/scala/actors/threadpool/TimeoutException.java b/src/actors/scala/actors/threadpool/TimeoutException.java deleted file mode 100644 index c6fdbe5dc4..0000000000 --- a/src/actors/scala/actors/threadpool/TimeoutException.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Written by Doug Lea with assistance from members of JCP JSR-166 - * Expert Group and released to the public domain, as explained at - * http://creativecommons.org/licenses/publicdomain - */ - -package scala.actors.threadpool; - -/** - * Exception thrown when a blocking operation times out. Blocking - * operations for which a timeout is specified need a means to - * indicate that the timeout has occurred. For many such operations it - * is possible to return a value that indicates timeout; when that is - * not possible or desirable then <tt>TimeoutException</tt> should be - * declared and thrown. - * - * @since 1.5 - * @author Doug Lea - */ -public class TimeoutException extends Exception { - private static final long serialVersionUID = 1900926677490660714L; - - /** - * Constructs a <tt>TimeoutException</tt> with no specified detail - * message. - */ - public TimeoutException() {} - - /** - * Constructs a <tt>TimeoutException</tt> with the specified detail - * message. - * - * @param message the detail message - */ - public TimeoutException(String message) { - super(message); - } -} diff --git a/src/actors/scala/actors/threadpool/helpers/FIFOWaitQueue.java b/src/actors/scala/actors/threadpool/helpers/FIFOWaitQueue.java deleted file mode 100644 index 432b851f3e..0000000000 --- a/src/actors/scala/actors/threadpool/helpers/FIFOWaitQueue.java +++ /dev/null @@ -1,85 +0,0 @@ -package scala.actors.threadpool.helpers; - -import java.util.Collection; -import java.util.ArrayList; -import java.util.List; - -/** - * Simple linked list queue used in FIFOSemaphore. - * Methods are not synchronized; they depend on synch of callers. - * Must be public, since it is used by Semaphore (outside this package). - * NOTE: this class is NOT present in java.util.concurrent. - **/ - -public class FIFOWaitQueue extends WaitQueue implements java.io.Serializable { - - private final static long serialVersionUID = 2416444691925378811L; - - protected transient WaitNode head_ = null; - protected transient WaitNode tail_ = null; - - public FIFOWaitQueue() {} - - public void insert(WaitNode w) { - if (tail_ == null) - head_ = tail_ = w; - else { - tail_.next = w; - tail_ = w; - } - } - - public WaitNode extract() { - if (head_ == null) - return null; - else { - WaitNode w = head_; - head_ = w.next; - if (head_ == null) - tail_ = null; - w.next = null; - return w; - } - } - - public void putBack(WaitNode w) { - w.next = head_; - head_ = w; - if (tail_ == null) - tail_ = w; - } - - public boolean hasNodes() { - return head_ != null; - } - - public int getLength() { - int count = 0; - WaitNode node = head_; - while (node != null) { - if (node.waiting) count++; - node = node.next; - } - return count; - } - - public Collection getWaitingThreads() { - List<Thread> list = new ArrayList<Thread>(); - int count = 0; - WaitNode node = head_; - while (node != null) { - if (node.waiting) list.add(node.owner); - node = node.next; - } - return list; - } - - public boolean isWaiting(Thread thread) { - if (thread == null) throw new NullPointerException(); - for (WaitNode node = head_; node != null; node = node.next) { - if (node.waiting && node.owner == thread) return true; - } - return false; - } - -} diff --git a/src/actors/scala/actors/threadpool/helpers/NanoTimer.java b/src/actors/scala/actors/threadpool/helpers/NanoTimer.java deleted file mode 100644 index f3edf13565..0000000000 --- a/src/actors/scala/actors/threadpool/helpers/NanoTimer.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Written by Dawid Kurzyniec and released to the public domain, as explained - * at http://creativecommons.org/licenses/publicdomain - */ -package scala.actors.threadpool.helpers; - -/** - * Interface to specify custom implementation of precise timer. - * - * @author Dawid Kurzyniec - * @version 1.0 - */ -public interface NanoTimer { - /** - * Returns the current value of the most precise available system timer, - * in nanoseconds. This method can only be used to measure elapsed time and - * is not related to any other notion of system or wall-clock time. The - * value returned represents nanoseconds since some fixed but arbitrary - * time (perhaps in the future, so values may be negative). This method - * provides nanosecond precision, but not necessarily nanosecond accuracy. - * No guarantees are made about how frequently values change. Differences - * in successive calls that span greater than approximately 292 years - * (263 nanoseconds) will not accurately compute elapsed time due to - * numerical overflow. - * - * @return The current value of the system timer, in nanoseconds. - */ - long nanoTime(); -} diff --git a/src/actors/scala/actors/threadpool/helpers/ThreadHelpers.java b/src/actors/scala/actors/threadpool/helpers/ThreadHelpers.java deleted file mode 100644 index 13da20c4d6..0000000000 --- a/src/actors/scala/actors/threadpool/helpers/ThreadHelpers.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Written by Dawid Kurzyniec and released to the public domain, as explained - * at http://creativecommons.org/licenses/publicdomain - */ -package scala.actors.threadpool.helpers; - -/** - * Emulation of some new functionality present in java.lang.Thread in J2SE 5.0. - * - * @author Dawid Kurzyniec - * @version 1.0 - */ -public class ThreadHelpers { - - private ThreadHelpers() {} - - /** - * Returns wrapped runnable that ensures that if an exception occurs - * during the execution, the specified exception handler is invoked. - * @param runnable runnable for which exceptions are to be intercepted - * @param handler the exception handler to call when exception occurs - * during execution of the given runnable - * @return wrapped runnable - */ - public static Runnable assignExceptionHandler(final Runnable runnable, - final UncaughtExceptionHandler handler) - { - if (runnable == null || handler == null) { - throw new NullPointerException(); - } - return new Runnable() { - public void run() { - try { - runnable.run(); - } - catch (Throwable error) { - try { - handler.uncaughtException(Thread.currentThread(), error); - } - catch (Throwable ignore) {} - } - } - }; - } - - /** - * Abstraction of the exception handler which receives notifications of - * exceptions occurred possibly in various parts of the system. Exception - * handlers present attractive approach to exception handling in multi-threaded - * systems, as they can handle exceptions that occurred in different threads. - * <p> - * This class is analogous to Thread.UncaughtExceptionHandler in J2SE 5.0. - * Obviously you cannot use it the same way, e.g. you cannot assign the - * handler to the thread so that it is invoked when thread terminates. - * However, it can be {@link ThreadHelpers#assignExceptionHandler emulated}. - */ - public static interface UncaughtExceptionHandler { - /** - * Notification of the uncaught exception that occurred within specified - * thread. - * @param thread the thread where the exception occurred - * @param error the exception - */ - void uncaughtException(Thread thread, Throwable error); - } -} diff --git a/src/actors/scala/actors/threadpool/helpers/Utils.java b/src/actors/scala/actors/threadpool/helpers/Utils.java deleted file mode 100644 index d12389215d..0000000000 --- a/src/actors/scala/actors/threadpool/helpers/Utils.java +++ /dev/null @@ -1,343 +0,0 @@ -/* - * Written by Dawid Kurzyniec, based on code written by Doug Lea with assistance - * from members of JCP JSR-166 Expert Group. Released to the public domain, - * as explained at http://creativecommons.org/licenses/publicdomain. - * - * Thanks to Craig Mattocks for suggesting to use <code>sun.misc.Perf</code>. - */ - -package scala.actors.threadpool.helpers; - -//import edu.emory.mathcs.backport.java.util.*; -import scala.actors.threadpool.*; -import scala.actors.threadpool.locks.*; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.lang.reflect.Array; -import java.util.Iterator; -import java.util.Collection; - -/** - * <p> - * This class groups together the functionality of java.util.concurrent that - * cannot be fully and reliably implemented in backport, but for which some - * form of emulation is possible. - * <p> - * Currently, this class contains methods related to nanosecond-precision - * timing, particularly via the {@link #nanoTime} method. To measure time - * accurately, this method by default uses <code>java.sun.Perf</code> on - * JDK1.4.2 and it falls back to <code>System.currentTimeMillis</code> - * on earlier JDKs. - * - * @author Dawid Kurzyniec - * @version 1.0 - */ -public final class Utils { - - private final static NanoTimer nanoTimer; - private final static String providerProp = - "edu.emory.mathcs.backport.java.util.concurrent.NanoTimerProvider"; - - static { - NanoTimer timer = null; - try { - String nanoTimerClassName = - AccessController.doPrivileged(new PrivilegedAction<String>() { - public String run() { - return System.getProperty(providerProp); - } - }); - if (nanoTimerClassName != null) { - Class cls = Class.forName(nanoTimerClassName); - timer = (NanoTimer) cls.newInstance(); - } - } - catch (Exception e) { - System.err.println("WARNING: unable to load the system-property-defined " + - "nanotime provider; switching to the default"); - e.printStackTrace(); - } - - if (timer == null) { - try { - timer = new SunPerfProvider(); - } - catch (Throwable e) {} - } - - if (timer == null) { - timer = new MillisProvider(); - } - - nanoTimer = timer; - } - - private Utils() {} - - /** - * Returns the current value of the most precise available system timer, - * in nanoseconds. This method can only be used to measure elapsed time and - * is not related to any other notion of system or wall-clock time. The - * value returned represents nanoseconds since some fixed but arbitrary - * time (perhaps in the future, so values may be negative). This method - * provides nanosecond precision, but not necessarily nanosecond accuracy. - * No guarantees are made about how frequently values change. Differences - * in successive calls that span greater than approximately 292 years - * (2^63 nanoseconds) will not accurately compute elapsed time due to - * numerical overflow. - * <p> - * <em>Implementation note:</em>By default, this method uses - * <code>sun.misc.Perf</code> on Java 1.4.2, and falls back to - * System.currentTimeMillis() emulation on earlier JDKs. Custom - * timer can be provided via the system property - * <code>edu.emory.mathcs.backport.java.util.concurrent.NanoTimerProvider</code>. - * The value of the property should name a class implementing - * {@link NanoTimer} interface. - * <p> - * Note: on JDK 1.4.2, <code>sun.misc.Perf</code> timer seems to have - * resolution of the order of 1 microsecond, measured on Linux. - * - * @return The current value of the system timer, in nanoseconds. - */ - public static long nanoTime() { - return nanoTimer.nanoTime(); - } - - /** - * Causes the current thread to wait until it is signalled or interrupted, - * or the specified waiting time elapses. This method originally appears - * in the {@link Condition} interface, but it was moved to here since it - * can only be emulated, with very little accuracy guarantees: the - * efficient implementation requires accurate nanosecond timer and native - * support for nanosecond-precision wait queues, which are not usually - * present in JVMs prior to 1.5. Loss of precision may cause total waiting - * times to be systematically shorter than specified when re-waits occur. - * - * <p>The lock associated with this condition is atomically - * released and the current thread becomes disabled for thread scheduling - * purposes and lies dormant until <em>one</em> of five things happens: - * <ul> - * <li>Some other thread invokes the {@link - * edu.emory.mathcs.backport.java.util.concurrent.locks.Condition#signal} - * method for this - * <tt>Condition</tt> and the current thread happens to be chosen as the - * thread to be awakened; or - * <li>Some other thread invokes the {@link - * edu.emory.mathcs.backport.java.util.concurrent.locks.Condition#signalAll} - * method for this - * <tt>Condition</tt>; or - * <li>Some other thread {@link Thread#interrupt interrupts} the current - * thread, and interruption of thread suspension is supported; or - * <li>The specified waiting time elapses; or - * <li>A "<em>spurious wakeup</em>" occurs. - * </ul> - * - * <p>In all cases, before this method can return the current thread must - * re-acquire the lock associated with this condition. When the - * thread returns it is <em>guaranteed</em> to hold this lock. - * - * <p>If the current thread: - * <ul> - * <li>has its interrupted status set on entry to this method; or - * <li>is {@link Thread#interrupt interrupted} while waiting - * and interruption of thread suspension is supported, - * </ul> - * then {@link InterruptedException} is thrown and the current thread's - * interrupted status is cleared. It is not specified, in the first - * case, whether or not the test for interruption occurs before the lock - * is released. - * - * <p>The method returns an estimate of the number of nanoseconds - * remaining to wait given the supplied <tt>nanosTimeout</tt> - * value upon return, or a value less than or equal to zero if it - * timed out. Accuracy of this estimate is directly dependent on the - * accuracy of {@link #nanoTime}. This value can be used to determine - * whether and how long to re-wait in cases where the wait returns but an - * awaited condition still does not hold. Typical uses of this method take - * the following form: - * - * <pre> - * synchronized boolean aMethod(long timeout, TimeUnit unit) { - * long nanosTimeout = unit.toNanos(timeout); - * while (!conditionBeingWaitedFor) { - * if (nanosTimeout > 0) - * nanosTimeout = theCondition.awaitNanos(nanosTimeout); - * else - * return false; - * } - * // ... - * } - * </pre> - * - * <p><b>Implementation Considerations</b> - * <p>The current thread is assumed to hold the lock associated with this - * <tt>Condition</tt> when this method is called. - * It is up to the implementation to determine if this is - * the case and if not, how to respond. Typically, an exception will be - * thrown (such as {@link IllegalMonitorStateException}) and the - * implementation must document that fact. - * - * <p>A condition implementation can favor responding to an interrupt over - * normal method return in response to a signal, or over indicating the - * elapse of the specified waiting time. In either case the implementation - * must ensure that the signal is redirected to another waiting thread, if - * there is one. - * - * @param cond the condition to wait for - * @param nanosTimeout the maximum time to wait, in nanoseconds - * @return A value less than or equal to zero if the wait has - * timed out; otherwise an estimate, that - * is strictly less than the <tt>nanosTimeout</tt> argument, - * of the time still remaining when this method returned. - * - * @throws InterruptedException if the current thread is interrupted (and - * interruption of thread suspension is supported). - */ - public static long awaitNanos(Condition cond, long nanosTimeout) - throws InterruptedException - { - if (nanosTimeout <= 0) return nanosTimeout; - long now = nanoTime(); - cond.await(nanosTimeout, TimeUnit.NANOSECONDS); - return nanosTimeout - (nanoTime() - now); - } - - private static final class SunPerfProvider implements NanoTimer { - final Perf perf; - final long multiplier, divisor; - SunPerfProvider() { - perf = - AccessController.doPrivileged(new PrivilegedAction<Perf>() { - public Perf run() { - return Perf.getPerf(); - } - }); - // trying to avoid BOTH overflow and rounding errors - long numerator = 1000000000; - long denominator = perf.highResFrequency(); - long gcd = gcd(numerator, denominator); - this.multiplier = numerator / gcd; - this.divisor = denominator / gcd; - } - public long nanoTime() { - long ctr = perf.highResCounter(); - - // anything less sophisticated suffers either from rounding errors - // (FP arithmetics, backport v1.0) or overflow, when gcd is small - // (a bug in backport v1.0_01 reported by Ramesh Nethi) - - return ((ctr / divisor) * multiplier) + - (ctr % divisor) * multiplier / divisor; - - // even the above can theoretically cause problems if your JVM is - // running for sufficiently long time, but "sufficiently" means 292 - // years (worst case), or 30,000 years (common case). - - // Details: when the ticks ctr overflows, there is no way to avoid - // discontinuity in computed nanos, even in infinite arithmetics, - // unless we count number of overflows that the ctr went through - // since the JVM started. This follows from the fact that - // (2^64*multiplier/divisor) mod (2^64) > 0 in general case. - // Theoretically we could find out the number of overflows by - // checking System.currentTimeMillis(), but this is unreliable - // since the system time can unpredictably change during the JVM - // lifetime. - // The time to overflow is 2^63 / ticks frequency. With current - // ticks frequencies of several MHz, it gives about 30,000 years - // before the problem happens. If ticks frequency reaches 1 GHz, the - // time to overflow is 292 years. It is unlikely that the frequency - // ever exceeds 1 GHz. We could double the time to overflow - // (to 2^64 / frequency) by using unsigned arithmetics, e.g. by - // adding the following correction whenever the ticks is negative: - // -2*((Long.MIN_VALUE / divisor) * multiplier + - // (Long.MIN_VALUE % divisor) * multiplier / divisor) - // But, with the worst case of as much as 292 years, it does not - // seem justified. - } - } - - private static final class MillisProvider implements NanoTimer { - MillisProvider() {} - public long nanoTime() { - return System.currentTimeMillis() * 1000000; - } - } - - private static long gcd(long a, long b) { - long r; - while (b>0) { r = a % b; a = b; b = r; } - return a; - } - - - public static Object[] collectionToArray(Collection c) { - // guess the array size; expect to possibly be different - int len = c.size(); - Object[] arr = new Object[len]; - Iterator itr = c.iterator(); - int idx = 0; - while (true) { - while (idx < len && itr.hasNext()) { - arr[idx++] = itr.next(); - } - if (!itr.hasNext()) { - if (idx == len) return arr; - // otherwise have to trim - return Arrays.copyOf(arr, idx, Object[].class); - } - // otherwise, have to grow - int newcap = ((arr.length/2)+1)*3; - if (newcap < arr.length) { - // overflow - if (arr.length < Integer.MAX_VALUE) { - newcap = Integer.MAX_VALUE; - } - else { - throw new OutOfMemoryError("required array size too large"); - } - } - arr = Arrays.copyOf(arr, newcap, Object[].class); - len = newcap; - } - } - - public static Object[] collectionToArray(Collection c, Object[] a) { - Class aType = a.getClass(); - // guess the array size; expect to possibly be different - int len = c.size(); - Object[] arr = (a.length >= len ? a : - (Object[])Array.newInstance(aType.getComponentType(), len)); - Iterator itr = c.iterator(); - int idx = 0; - while (true) { - while (idx < len && itr.hasNext()) { - arr[idx++] = itr.next(); - } - if (!itr.hasNext()) { - if (idx == len) return arr; - if (arr == a) { - // orig array -> null terminate - a[idx] = null; - return a; - } - else { - // have to trim - return Arrays.copyOf(arr, idx, aType); - } - } - // otherwise, have to grow - int newcap = ((arr.length/2)+1)*3; - if (newcap < arr.length) { - // overflow - if (arr.length < Integer.MAX_VALUE) { - newcap = Integer.MAX_VALUE; - } - else { - throw new OutOfMemoryError("required array size too large"); - } - } - arr = Arrays.copyOf(arr, newcap, aType); - len = newcap; - } - } -} diff --git a/src/actors/scala/actors/threadpool/helpers/WaitQueue.java b/src/actors/scala/actors/threadpool/helpers/WaitQueue.java deleted file mode 100644 index bcbf29e5c2..0000000000 --- a/src/actors/scala/actors/threadpool/helpers/WaitQueue.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - based on file: QueuedSemaphore.java - Originally written by Doug Lea and released into the public domain. - This may be used for any purposes whatsoever without acknowledgment. - Thanks for the assistance and support of Sun Microsystems Labs, - and everyone contributing, testing, and using this code. - History: - Date Who What - 11Jun1998 dl Create public version - 5Aug1998 dl replaced int counters with longs - 24Aug1999 dl release(n): screen arguments - */ - -package scala.actors.threadpool.helpers; - -import java.util.Collection; -import scala.actors.threadpool.*; - -/** - * Base class for internal queue classes for semaphores, etc. - * Relies on subclasses to actually implement queue mechanics. - * NOTE: this class is NOT present in java.util.concurrent. - **/ - -public abstract class WaitQueue { - - public abstract void insert(WaitNode w); // assumed not to block - public abstract WaitNode extract(); // should return null if empty - public abstract void putBack(WaitNode w); - - public abstract boolean hasNodes(); - public abstract int getLength(); - public abstract Collection getWaitingThreads(); - public abstract boolean isWaiting(Thread thread); - - public static interface QueuedSync { - // invoked with sync on wait node, (atomically) just before enqueuing - boolean recheck(WaitNode node); - // invoked with sync on wait node, (atomically) just before signalling - void takeOver(WaitNode node); - } - - public static class WaitNode { - boolean waiting = true; - WaitNode next = null; - final Thread owner; - - public WaitNode() { - this.owner = Thread.currentThread(); - } - - public Thread getOwner() { - return owner; - } - - public synchronized boolean signal(QueuedSync sync) { - boolean signalled = waiting; - if (signalled) { - waiting = false; - notify(); - sync.takeOver(this); - } - return signalled; - } - - public synchronized boolean doTimedWait(QueuedSync sync, long nanos) - throws InterruptedException - { - if (sync.recheck(this) || !waiting) - return true; - else if (nanos <= 0) { - waiting = false; - return false; - } - else { - long deadline = Utils.nanoTime() + nanos; - try { - for (; ; ) { - TimeUnit.NANOSECONDS.timedWait(this, nanos); - if (!waiting) // definitely signalled - return true; - else { - nanos = deadline - Utils.nanoTime(); - if (nanos <= 0) { // timed out - waiting = false; - return false; - } - } - } - } - catch (InterruptedException ex) { - if (waiting) { // no notification - waiting = false; // invalidate for the signaller - throw ex; - } - else { // thread was interrupted after it was notified - Thread.currentThread().interrupt(); - return true; - } - } - } - } - - public synchronized void doWait(QueuedSync sync) - throws InterruptedException - { - if (!sync.recheck(this)) { - try { - while (waiting) wait(); - } - catch (InterruptedException ex) { - if (waiting) { // no notification - waiting = false; // invalidate for the signaller - throw ex; - } - else { // thread was interrupted after it was notified - Thread.currentThread().interrupt(); - return; - } - } - } - } - - public synchronized void doWaitUninterruptibly(QueuedSync sync) { - if (!sync.recheck(this)) { - boolean wasInterrupted = Thread.interrupted(); - try { - while (waiting) { - try { - wait(); - } - catch (InterruptedException ex) { - wasInterrupted = true; - // no need to notify; if we were signalled, we - // must be not waiting, and we'll act like signalled - } - } - } - finally { - if (wasInterrupted) Thread.currentThread().interrupt(); - } - } - } - } -} - diff --git a/src/actors/scala/actors/threadpool/locks/CondVar.java b/src/actors/scala/actors/threadpool/locks/CondVar.java deleted file mode 100644 index 44df1c0b97..0000000000 --- a/src/actors/scala/actors/threadpool/locks/CondVar.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - File: ConditionVariable.java - Originally written by Doug Lea and released into the public domain. - This may be used for any purposes whatsoever without acknowledgment. - Thanks for the assistance and support of Sun Microsystems Labs, - and everyone contributing, testing, and using this code. - History: - Date Who What - 11Jun1998 dl Create public version - */ - -package scala.actors.threadpool.locks; - -import java.util.Collection; -import java.util.Date; -import scala.actors.threadpool.*; -import scala.actors.threadpool.helpers.*; - -class CondVar implements Condition, java.io.Serializable { - private static final long serialVersionUID = -5009898475638427940L; - - /** The lock **/ - protected final ExclusiveLock lock; - - /** - * Create a new CondVar that relies on the given mutual - * exclusion lock. - * @param lock A non-reentrant mutual exclusion lock. - **/ - - CondVar(ExclusiveLock lock) { - this.lock = lock; - } - - public void awaitUninterruptibly() { - int holdCount = lock.getHoldCount(); - if (holdCount == 0) { - throw new IllegalMonitorStateException(); - } - // avoid instant spurious wakeup if thread already interrupted - boolean wasInterrupted = Thread.interrupted(); - try { - synchronized (this) { - for (int i=holdCount; i>0; i--) lock.unlock(); - try { - wait(); - } - catch (InterruptedException ex) { - wasInterrupted = true; - // may have masked the signal and there is no way - // to tell; we must wake up spuriously - } - } - } - finally { - for (int i=holdCount; i>0; i--) lock.lock(); - if (wasInterrupted) { - Thread.currentThread().interrupt(); - } - } - } - - public void await() throws InterruptedException { - int holdCount = lock.getHoldCount(); - if (holdCount == 0) { - throw new IllegalMonitorStateException(); - } - if (Thread.interrupted()) throw new InterruptedException(); - try { - synchronized (this) { - for (int i=holdCount; i>0; i--) lock.unlock(); - try { - wait(); - } - catch (InterruptedException ex) { - notify(); - throw ex; - } - } - } - finally { - for (int i=holdCount; i>0; i--) lock.lock(); - } - } - - public boolean await(long timeout, TimeUnit unit) throws InterruptedException { - int holdCount = lock.getHoldCount(); - if (holdCount == 0) { - throw new IllegalMonitorStateException(); - } - if (Thread.interrupted()) throw new InterruptedException(); - long nanos = unit.toNanos(timeout); - boolean success = false; - try { - synchronized (this) { - for (int i=holdCount; i>0; i--) lock.unlock(); - try { - if (nanos > 0) { - long start = Utils.nanoTime(); - TimeUnit.NANOSECONDS.timedWait(this, nanos); - // DK: due to coarse-grained (millis) clock, it seems - // preferable to acknowledge timeout (success == false) - // when the equality holds (timing is exact) - success = Utils.nanoTime() - start < nanos; - } - } - catch (InterruptedException ex) { - notify(); - throw ex; - } - } - } - finally { - for (int i=holdCount; i>0; i--) lock.lock(); - } - return success; - } - -// public long awaitNanos(long timeout) throws InterruptedException { -// throw new UnsupportedOperationException(); -// } -// - public boolean awaitUntil(Date deadline) throws InterruptedException { - if (deadline == null) throw new NullPointerException(); - int holdCount = lock.getHoldCount(); - if (holdCount == 0) { - throw new IllegalMonitorStateException(); - } - long abstime = deadline.getTime(); - if (Thread.interrupted()) throw new InterruptedException(); - - boolean success = false; - try { - synchronized (this) { - for (int i=holdCount; i>0; i--) lock.unlock(); - try { - long start = System.currentTimeMillis(); - long msecs = abstime - start; - if (msecs > 0) { - wait(msecs); - // DK: due to coarse-grained (millis) clock, it seems - // preferable to acknowledge timeout (success == false) - // when the equality holds (timing is exact) - success = System.currentTimeMillis() - start < msecs; - } - } - catch (InterruptedException ex) { - notify(); - throw ex; - } - } - } - finally { - for (int i=holdCount; i>0; i--) lock.lock(); - } - return success; - } - - public synchronized void signal() { - if (!lock.isHeldByCurrentThread()) { - throw new IllegalMonitorStateException(); - } - notify(); - } - - public synchronized void signalAll() { - if (!lock.isHeldByCurrentThread()) { - throw new IllegalMonitorStateException(); - } - notifyAll(); - } - - protected ExclusiveLock getLock() { return lock; } - - protected boolean hasWaiters() { - throw new UnsupportedOperationException("Use FAIR version"); - } - - protected int getWaitQueueLength() { - throw new UnsupportedOperationException("Use FAIR version"); - } - - protected Collection getWaitingThreads() { - throw new UnsupportedOperationException("Use FAIR version"); - } - - static interface ExclusiveLock extends Lock { - boolean isHeldByCurrentThread(); - int getHoldCount(); - } -} diff --git a/src/actors/scala/actors/threadpool/locks/Condition.java b/src/actors/scala/actors/threadpool/locks/Condition.java deleted file mode 100644 index 0553684321..0000000000 --- a/src/actors/scala/actors/threadpool/locks/Condition.java +++ /dev/null @@ -1,434 +0,0 @@ -/* - * Written by Doug Lea with assistance from members of JCP JSR-166 - * Expert Group and released to the public domain, as explained at - * http://creativecommons.org/licenses/publicdomain - */ - -package scala.actors.threadpool.locks; - -import scala.actors.threadpool.*; -import java.util.Date; - -/** - * {@code Condition} factors out the {@code Object} monitor - * methods ({@link Object#wait() wait}, {@link Object#notify notify} - * and {@link Object#notifyAll notifyAll}) into distinct objects to - * give the effect of having multiple wait-sets per object, by - * combining them with the use of arbitrary {@link Lock} implementations. - * Where a {@code Lock} replaces the use of {@code synchronized} methods - * and statements, a {@code Condition} replaces the use of the Object - * monitor methods. - * - * <p>Conditions (also known as <em>condition queues</em> or - * <em>condition variables</em>) provide a means for one thread to - * suspend execution (to "wait") until notified by another - * thread that some state condition may now be true. Because access - * to this shared state information occurs in different threads, it - * must be protected, so a lock of some form is associated with the - * condition. The key property that waiting for a condition provides - * is that it <em>atomically</em> releases the associated lock and - * suspends the current thread, just like {@code Object.wait}. - * - * <p>A {@code Condition} instance is intrinsically bound to a lock. - * To obtain a {@code Condition} instance for a particular {@link Lock} - * instance use its {@link Lock#newCondition newCondition()} method. - * - * <p>As an example, suppose we have a bounded buffer which supports - * {@code put} and {@code take} methods. If a - * {@code take} is attempted on an empty buffer, then the thread will block - * until an item becomes available; if a {@code put} is attempted on a - * full buffer, then the thread will block until a space becomes available. - * We would like to keep waiting {@code put} threads and {@code take} - * threads in separate wait-sets so that we can use the optimization of - * only notifying a single thread at a time when items or spaces become - * available in the buffer. This can be achieved using two - * {@link Condition} instances. - * <pre> - * class BoundedBuffer { - * <b>final Lock lock = new ReentrantLock();</b> - * final Condition notFull = <b>lock.newCondition(); </b> - * final Condition notEmpty = <b>lock.newCondition(); </b> - * - * final Object[] items = new Object[100]; - * int putptr, takeptr, count; - * - * public void put(Object x) throws InterruptedException { - * <b>lock.lock(); - * try {</b> - * while (count == items.length) - * <b>notFull.await();</b> - * items[putptr] = x; - * if (++putptr == items.length) putptr = 0; - * ++count; - * <b>notEmpty.signal();</b> - * <b>} finally { - * lock.unlock(); - * }</b> - * } - * - * public Object take() throws InterruptedException { - * <b>lock.lock(); - * try {</b> - * while (count == 0) - * <b>notEmpty.await();</b> - * Object x = items[takeptr]; - * if (++takeptr == items.length) takeptr = 0; - * --count; - * <b>notFull.signal();</b> - * return x; - * <b>} finally { - * lock.unlock(); - * }</b> - * } - * } - * </pre> - * - * (The {@link edu.emory.mathcs.backport.java.util.concurrent.ArrayBlockingQueue} class provides - * this functionality, so there is no reason to implement this - * sample usage class.) - * - * <p>A {@code Condition} implementation can provide behavior and semantics - * that is - * different from that of the {@code Object} monitor methods, such as - * guaranteed ordering for notifications, or not requiring a lock to be held - * when performing notifications. - * If an implementation provides such specialized semantics then the - * implementation must document those semantics. - * - * <p>Note that {@code Condition} instances are just normal objects and can - * themselves be used as the target in a {@code synchronized} statement, - * and can have their own monitor {@link Object#wait wait} and - * {@link Object#notify notification} methods invoked. - * Acquiring the monitor lock of a {@code Condition} instance, or using its - * monitor methods, has no specified relationship with acquiring the - * {@link Lock} associated with that {@code Condition} or the use of its - * {@linkplain #await waiting} and {@linkplain #signal signalling} methods. - * It is recommended that to avoid confusion you never use {@code Condition} - * instances in this way, except perhaps within their own implementation. - * - * <p>Except where noted, passing a {@code null} value for any parameter - * will result in a {@link NullPointerException} being thrown. - * - * <h3>Implementation Considerations</h3> - * - * <p>When waiting upon a {@code Condition}, a "<em>spurious - * wakeup</em>" is permitted to occur, in - * general, as a concession to the underlying platform semantics. - * This has little practical impact on most application programs as a - * {@code Condition} should always be waited upon in a loop, testing - * the state predicate that is being waited for. An implementation is - * free to remove the possibility of spurious wakeups but it is - * recommended that applications programmers always assume that they can - * occur and so always wait in a loop. - * - * <p>The three forms of condition waiting - * (interruptible, non-interruptible, and timed) may differ in their ease of - * implementation on some platforms and in their performance characteristics. - * In particular, it may be difficult to provide these features and maintain - * specific semantics such as ordering guarantees. - * Further, the ability to interrupt the actual suspension of the thread may - * not always be feasible to implement on all platforms. - * - * <p>Consequently, an implementation is not required to define exactly the - * same guarantees or semantics for all three forms of waiting, nor is it - * required to support interruption of the actual suspension of the thread. - * - * <p>An implementation is required to - * clearly document the semantics and guarantees provided by each of the - * waiting methods, and when an implementation does support interruption of - * thread suspension then it must obey the interruption semantics as defined - * in this interface. - * - * <p>As interruption generally implies cancellation, and checks for - * interruption are often infrequent, an implementation can favor responding - * to an interrupt over normal method return. This is true even if it can be - * shown that the interrupt occurred after another action may have unblocked - * the thread. An implementation should document this behavior. - * - * @since 1.5 - * @author Doug Lea - */ -public interface Condition { - - /** - * Causes the current thread to wait until it is signalled or - * {@linkplain Thread#interrupt interrupted}. - * - * <p>The lock associated with this {@code Condition} is atomically - * released and the current thread becomes disabled for thread scheduling - * purposes and lies dormant until <em>one</em> of four things happens: - * <ul> - * <li>Some other thread invokes the {@link #signal} method for this - * {@code Condition} and the current thread happens to be chosen as the - * thread to be awakened; or - * <li>Some other thread invokes the {@link #signalAll} method for this - * {@code Condition}; or - * <li>Some other thread {@linkplain Thread#interrupt interrupts} the - * current thread, and interruption of thread suspension is supported; or - * <li>A "<em>spurious wakeup</em>" occurs. - * </ul> - * - * <p>In all cases, before this method can return the current thread must - * re-acquire the lock associated with this condition. When the - * thread returns it is <em>guaranteed</em> to hold this lock. - * - * <p>If the current thread: - * <ul> - * <li>has its interrupted status set on entry to this method; or - * <li>is {@linkplain Thread#interrupt interrupted} while waiting - * and interruption of thread suspension is supported, - * </ul> - * then {@link InterruptedException} is thrown and the current thread's - * interrupted status is cleared. It is not specified, in the first - * case, whether or not the test for interruption occurs before the lock - * is released. - * - * <p><b>Implementation Considerations</b> - * - * <p>The current thread is assumed to hold the lock associated with this - * {@code Condition} when this method is called. - * It is up to the implementation to determine if this is - * the case and if not, how to respond. Typically, an exception will be - * thrown (such as {@link IllegalMonitorStateException}) and the - * implementation must document that fact. - * - * <p>An implementation can favor responding to an interrupt over normal - * method return in response to a signal. In that case the implementation - * must ensure that the signal is redirected to another waiting thread, if - * there is one. - * - * @throws InterruptedException if the current thread is interrupted - * (and interruption of thread suspension is supported) - */ - void await() throws InterruptedException; - - /** - * Causes the current thread to wait until it is signalled. - * - * <p>The lock associated with this condition is atomically - * released and the current thread becomes disabled for thread scheduling - * purposes and lies dormant until <em>one</em> of three things happens: - * <ul> - * <li>Some other thread invokes the {@link #signal} method for this - * {@code Condition} and the current thread happens to be chosen as the - * thread to be awakened; or - * <li>Some other thread invokes the {@link #signalAll} method for this - * {@code Condition}; or - * <li>A "<em>spurious wakeup</em>" occurs. - * </ul> - * - * <p>In all cases, before this method can return the current thread must - * re-acquire the lock associated with this condition. When the - * thread returns it is <em>guaranteed</em> to hold this lock. - * - * <p>If the current thread's interrupted status is set when it enters - * this method, or it is {@linkplain Thread#interrupt interrupted} - * while waiting, it will continue to wait until signalled. When it finally - * returns from this method its interrupted status will still - * be set. - * - * <p><b>Implementation Considerations</b> - * - * <p>The current thread is assumed to hold the lock associated with this - * {@code Condition} when this method is called. - * It is up to the implementation to determine if this is - * the case and if not, how to respond. Typically, an exception will be - * thrown (such as {@link IllegalMonitorStateException}) and the - * implementation must document that fact. - */ - void awaitUninterruptibly(); - -// /** -// * Causes the current thread to wait until it is signalled or interrupted, -// * or the specified waiting time elapses. -// * -// * <p>The lock associated with this condition is atomically -// * released and the current thread becomes disabled for thread scheduling -// * purposes and lies dormant until <em>one</em> of five things happens: -// * <ul> -// * <li>Some other thread invokes the {@link #signal} method for this -// * <tt>Condition</tt> and the current thread happens to be chosen as the -// * thread to be awakened; or -// * <li>Some other thread invokes the {@link #signalAll} method for this -// * <tt>Condition</tt>; or -// * <li>Some other thread {@link Thread#interrupt interrupts} the current -// * thread, and interruption of thread suspension is supported; or -// * <li>The specified waiting time elapses; or -// * <li>A "<em>spurious wakeup</em>" occurs. -// * </ul> -// * -// * <p>In all cases, before this method can return the current thread must -// * re-acquire the lock associated with this condition. When the -// * thread returns it is <em>guaranteed</em> to hold this lock. -// * -// * <p>If the current thread: -// * <ul> -// * <li>has its interrupted status set on entry to this method; or -// * <li>is {@link Thread#interrupt interrupted} while waiting -// * and interruption of thread suspension is supported, -// * </ul> -// * then {@link InterruptedException} is thrown and the current thread's -// * interrupted status is cleared. It is not specified, in the first -// * case, whether or not the test for interruption occurs before the lock -// * is released. -// * -// * <p>The method returns an estimate of the number of nanoseconds -// * remaining to wait given the supplied <tt>nanosTimeout</tt> -// * value upon return, or a value less than or equal to zero if it -// * timed out. This value can be used to determine whether and how -// * long to re-wait in cases where the wait returns but an awaited -// * condition still does not hold. Typical uses of this method take -// * the following form: -// * -// * <pre> -// * synchronized boolean aMethod(long timeout, TimeUnit unit) { -// * long nanosTimeout = unit.toNanos(timeout); -// * while (!conditionBeingWaitedFor) { -// * if (nanosTimeout > 0) -// * nanosTimeout = theCondition.awaitNanos(nanosTimeout); -// * else -// * return false; -// * } -// * // ... -// * } -// * </pre> -// * -// * <p> Design note: This method requires a nanosecond argument so -// * as to avoid truncation errors in reporting remaining times. -// * Such precision loss would make it difficult for programmers to -// * ensure that total waiting times are not systematically shorter -// * than specified when re-waits occur. -// * -// * <p><b>Implementation Considerations</b> -// * <p>The current thread is assumed to hold the lock associated with this -// * <tt>Condition</tt> when this method is called. -// * It is up to the implementation to determine if this is -// * the case and if not, how to respond. Typically, an exception will be -// * thrown (such as {@link IllegalMonitorStateException}) and the -// * implementation must document that fact. -// * -// * <p>An implementation can favor responding to an interrupt over normal -// * method return in response to a signal, or over indicating the elapse -// * of the specified waiting time. In either case the implementation -// * must ensure that the signal is redirected to another waiting thread, if -// * there is one. -// * -// * @param nanosTimeout the maximum time to wait, in nanoseconds -// * @return A value less than or equal to zero if the wait has -// * timed out; otherwise an estimate, that -// * is strictly less than the <tt>nanosTimeout</tt> argument, -// * of the time still remaining when this method returned. -// * -// * @throws InterruptedException if the current thread is interrupted (and -// * interruption of thread suspension is supported). -// */ -// long awaitNanos(long nanosTimeout) throws InterruptedException; - - /** - * Causes the current thread to wait until it is signalled or interrupted, - * or the specified waiting time elapses. This method is behaviorally - * equivalent to:<br> - * <pre> - * awaitNanos(unit.toNanos(time)) > 0 - * </pre> - * @param time the maximum time to wait - * @param unit the time unit of the {@code time} argument - * @return {@code false} if the waiting time detectably elapsed - * before return from the method, else {@code true} - * @throws InterruptedException if the current thread is interrupted - * (and interruption of thread suspension is supported) - */ - boolean await(long time, TimeUnit unit) throws InterruptedException; - - /** - * Causes the current thread to wait until it is signalled or interrupted, - * or the specified deadline elapses. - * - * <p>The lock associated with this condition is atomically - * released and the current thread becomes disabled for thread scheduling - * purposes and lies dormant until <em>one</em> of five things happens: - * <ul> - * <li>Some other thread invokes the {@link #signal} method for this - * {@code Condition} and the current thread happens to be chosen as the - * thread to be awakened; or - * <li>Some other thread invokes the {@link #signalAll} method for this - * {@code Condition}; or - * <li>Some other thread {@linkplain Thread#interrupt interrupts} the - * current thread, and interruption of thread suspension is supported; or - * <li>The specified deadline elapses; or - * <li>A "<em>spurious wakeup</em>" occurs. - * </ul> - * - * <p>In all cases, before this method can return the current thread must - * re-acquire the lock associated with this condition. When the - * thread returns it is <em>guaranteed</em> to hold this lock. - * - * - * <p>If the current thread: - * <ul> - * <li>has its interrupted status set on entry to this method; or - * <li>is {@linkplain Thread#interrupt interrupted} while waiting - * and interruption of thread suspension is supported, - * </ul> - * then {@link InterruptedException} is thrown and the current thread's - * interrupted status is cleared. It is not specified, in the first - * case, whether or not the test for interruption occurs before the lock - * is released. - * - * - * <p>The return value indicates whether the deadline has elapsed, - * which can be used as follows: - * <pre> - * synchronized boolean aMethod(Date deadline) { - * boolean stillWaiting = true; - * while (!conditionBeingWaitedFor) { - * if (stillWaiting) - * stillWaiting = theCondition.awaitUntil(deadline); - * else - * return false; - * } - * // ... - * } - * </pre> - * - * <p><b>Implementation Considerations</b> - * - * <p>The current thread is assumed to hold the lock associated with this - * {@code Condition} when this method is called. - * It is up to the implementation to determine if this is - * the case and if not, how to respond. Typically, an exception will be - * thrown (such as {@link IllegalMonitorStateException}) and the - * implementation must document that fact. - * - * <p>An implementation can favor responding to an interrupt over normal - * method return in response to a signal, or over indicating the passing - * of the specified deadline. In either case the implementation - * must ensure that the signal is redirected to another waiting thread, if - * there is one. - * - * @param deadline the absolute time to wait until - * @return {@code false} if the deadline has elapsed upon return, else - * {@code true} - * @throws InterruptedException if the current thread is interrupted - * (and interruption of thread suspension is supported) - */ - boolean awaitUntil(Date deadline) throws InterruptedException; - - /** - * Wakes up one waiting thread. - * - * <p>If any threads are waiting on this condition then one - * is selected for waking up. That thread must then re-acquire the - * lock before returning from {@code await}. - */ - void signal(); - - /** - * Wakes up all waiting threads. - * - * <p>If any threads are waiting on this condition then they are - * all woken up. Each thread must re-acquire the lock before it can - * return from {@code await}. - */ - void signalAll(); -} diff --git a/src/actors/scala/actors/threadpool/locks/FIFOCondVar.java b/src/actors/scala/actors/threadpool/locks/FIFOCondVar.java deleted file mode 100644 index 144ac54d37..0000000000 --- a/src/actors/scala/actors/threadpool/locks/FIFOCondVar.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - File: ConditionVariable.java - Originally written by Doug Lea and released into the public domain. - This may be used for any purposes whatsoever without acknowledgment. - Thanks for the assistance and support of Sun Microsystems Labs, - and everyone contributing, testing, and using this code. - History: - Date Who What - 11Jun1998 dl Create public version - */ - -package scala.actors.threadpool.locks; - -import java.util.Collection; -import java.util.Date; -import scala.actors.threadpool.*; -import scala.actors.threadpool.helpers.*; - -class FIFOCondVar extends CondVar implements Condition, java.io.Serializable { - private static final long serialVersionUID = -497497271881010475L; - - private static final WaitQueue.QueuedSync sync = new WaitQueue.QueuedSync() { - public boolean recheck(WaitQueue.WaitNode node) { return false; } - public void takeOver(WaitQueue.WaitNode node) {} - }; - - // wait queue; only accessed when holding the lock - private final WaitQueue wq = new FIFOWaitQueue(); - - /** - * Create a new CondVar that relies on the given mutual exclusion lock. - * @param lock A non-reentrant mutual exclusion lock. - */ - FIFOCondVar(ExclusiveLock lock) { - super(lock); - } - - public void awaitUninterruptibly() { - int holdCount = lock.getHoldCount(); - if (holdCount == 0) { - throw new IllegalMonitorStateException(); - } - WaitQueue.WaitNode n = new WaitQueue.WaitNode(); - wq.insert(n); - for (int i=holdCount; i>0; i--) lock.unlock(); - try { - n.doWaitUninterruptibly(sync); - } - finally { - for (int i=holdCount; i>0; i--) lock.lock(); - } - } - - public void await() throws InterruptedException { - int holdCount = lock.getHoldCount(); - if (holdCount == 0) { - throw new IllegalMonitorStateException(); - } - if (Thread.interrupted()) throw new InterruptedException(); - WaitQueue.WaitNode n = new WaitQueue.WaitNode(); - wq.insert(n); - for (int i=holdCount; i>0; i--) lock.unlock(); - try { - n.doWait(sync); - } - finally { - for (int i=holdCount; i>0; i--) lock.lock(); - } - } - - public boolean await(long timeout, TimeUnit unit) throws InterruptedException { - int holdCount = lock.getHoldCount(); - if (holdCount == 0) { - throw new IllegalMonitorStateException(); - } - if (Thread.interrupted()) throw new InterruptedException(); - long nanos = unit.toNanos(timeout); - WaitQueue.WaitNode n = new WaitQueue.WaitNode(); - wq.insert(n); - boolean success = false; - for (int i=holdCount; i>0; i--) lock.unlock(); - try { - success = n.doTimedWait(sync, nanos); - } - finally { - for (int i=holdCount; i>0; i--) lock.lock(); - } - return success; - } - -// public long awaitNanos(long timeout) throws InterruptedException { -// throw new UnsupportedOperationException(); -// } -// - public boolean awaitUntil(Date deadline) throws InterruptedException { - if (deadline == null) throw new NullPointerException(); - long abstime = deadline.getTime(); - long start = System.currentTimeMillis(); - long msecs = abstime - start; - return await(msecs, TimeUnit.MILLISECONDS); - } - - public void signal() { - if (!lock.isHeldByCurrentThread()) { - throw new IllegalMonitorStateException(); - } - for (;;) { - WaitQueue.WaitNode w = wq.extract(); - if (w == null) return; // no one to signal - if (w.signal(sync)) return; // notify if still waiting, else skip - } - } - - public void signalAll() { - if (!lock.isHeldByCurrentThread()) { - throw new IllegalMonitorStateException(); - } - for (;;) { - WaitQueue.WaitNode w = wq.extract(); - if (w == null) return; // no more to signal - w.signal(sync); - } - } - - protected boolean hasWaiters() { - if (!lock.isHeldByCurrentThread()) { - throw new IllegalMonitorStateException(); - } - return wq.hasNodes(); - } - - protected int getWaitQueueLength() { - if (!lock.isHeldByCurrentThread()) { - throw new IllegalMonitorStateException(); - } - return wq.getLength(); - } - - protected Collection getWaitingThreads() { - if (!lock.isHeldByCurrentThread()) { - throw new IllegalMonitorStateException(); - } - return wq.getWaitingThreads(); - } - - -} diff --git a/src/actors/scala/actors/threadpool/locks/Lock.java b/src/actors/scala/actors/threadpool/locks/Lock.java deleted file mode 100644 index 47a4e8e777..0000000000 --- a/src/actors/scala/actors/threadpool/locks/Lock.java +++ /dev/null @@ -1,328 +0,0 @@ -/* - * Written by Doug Lea with assistance from members of JCP JSR-166 - * Expert Group and released to the public domain, as explained at - * http://creativecommons.org/licenses/publicdomain - */ - -package scala.actors.threadpool.locks; - -import scala.actors.threadpool.TimeUnit; - -/** - * {@code Lock} implementations provide more extensive locking - * operations than can be obtained using {@code synchronized} methods - * and statements. They allow more flexible structuring, may have - * quite different properties, and may support multiple associated - * {@link Condition} objects. - * - * <p>A lock is a tool for controlling access to a shared resource by - * multiple threads. Commonly, a lock provides exclusive access to a - * shared resource: only one thread at a time can acquire the lock and - * all access to the shared resource requires that the lock be - * acquired first. However, some locks may allow concurrent access to - * a shared resource, such as the read lock of a {@link ReadWriteLock}. - * - * <p>The use of {@code synchronized} methods or statements provides - * access to the implicit monitor lock associated with every object, but - * forces all lock acquisition and release to occur in a block-structured way: - * when multiple locks are acquired they must be released in the opposite - * order, and all locks must be released in the same lexical scope in which - * they were acquired. - * - * <p>While the scoping mechanism for {@code synchronized} methods - * and statements makes it much easier to program with monitor locks, - * and helps avoid many common programming errors involving locks, - * there are occasions where you need to work with locks in a more - * flexible way. For example, some algorithms for traversing - * concurrently accessed data structures require the use of - * "hand-over-hand" or "chain locking": you - * acquire the lock of node A, then node B, then release A and acquire - * C, then release B and acquire D and so on. Implementations of the - * {@code Lock} interface enable the use of such techniques by - * allowing a lock to be acquired and released in different scopes, - * and allowing multiple locks to be acquired and released in any - * order. - * - * <p>With this increased flexibility comes additional - * responsibility. The absence of block-structured locking removes the - * automatic release of locks that occurs with {@code synchronized} - * methods and statements. In most cases, the following idiom - * should be used: - * - * <pre><tt> Lock l = ...; - * l.lock(); - * try { - * // access the resource protected by this lock - * } finally { - * l.unlock(); - * } - * </tt></pre> - * - * When locking and unlocking occur in different scopes, care must be - * taken to ensure that all code that is executed while the lock is - * held is protected by try-finally or try-catch to ensure that the - * lock is released when necessary. - * - * <p>{@code Lock} implementations provide additional functionality - * over the use of {@code synchronized} methods and statements by - * providing a non-blocking attempt to acquire a lock ({@link - * #tryLock()}), an attempt to acquire the lock that can be - * interrupted ({@link #lockInterruptibly}, and an attempt to acquire - * the lock that can timeout ({@link #tryLock(long, TimeUnit)}). - * - * <p>A {@code Lock} class can also provide behavior and semantics - * that is quite different from that of the implicit monitor lock, - * such as guaranteed ordering, non-reentrant usage, or deadlock - * detection. If an implementation provides such specialized semantics - * then the implementation must document those semantics. - * - * <p>Note that {@code Lock} instances are just normal objects and can - * themselves be used as the target in a {@code synchronized} statement. - * Acquiring the - * monitor lock of a {@code Lock} instance has no specified relationship - * with invoking any of the {@link #lock} methods of that instance. - * It is recommended that to avoid confusion you never use {@code Lock} - * instances in this way, except within their own implementation. - * - * <p>Except where noted, passing a {@code null} value for any - * parameter will result in a {@link NullPointerException} being - * thrown. - * - * <h3>Memory Synchronization</h3> - * - * <p>All {@code Lock} implementations <em>must</em> enforce the same - * memory synchronization semantics as provided by the built-in monitor - * lock, as described in <a href="http://java.sun.com/docs/books/jls/"> - * The Java Language Specification, Third Edition (17.4 Memory Model)</a>: - * <ul> - * <li>A successful {@code lock} operation has the same memory - * synchronization effects as a successful <em>Lock</em> action. - * <li>A successful {@code unlock} operation has the same - * memory synchronization effects as a successful <em>Unlock</em> action. - * </ul> - * - * Unsuccessful locking and unlocking operations, and reentrant - * locking/unlocking operations, do not require any memory - * synchronization effects. - * - * <h3>Implementation Considerations</h3> - * - * <p> The three forms of lock acquisition (interruptible, - * non-interruptible, and timed) may differ in their performance - * characteristics, ordering guarantees, or other implementation - * qualities. Further, the ability to interrupt the <em>ongoing</em> - * acquisition of a lock may not be available in a given {@code Lock} - * class. Consequently, an implementation is not required to define - * exactly the same guarantees or semantics for all three forms of - * lock acquisition, nor is it required to support interruption of an - * ongoing lock acquisition. An implementation is required to clearly - * document the semantics and guarantees provided by each of the - * locking methods. It must also obey the interruption semantics as - * defined in this interface, to the extent that interruption of lock - * acquisition is supported: which is either totally, or only on - * method entry. - * - * <p>As interruption generally implies cancellation, and checks for - * interruption are often infrequent, an implementation can favor responding - * to an interrupt over normal method return. This is true even if it can be - * shown that the interrupt occurred after another action may have unblocked - * the thread. An implementation should document this behavior. - * - * @see ReentrantLock - * @see Condition - * @see ReadWriteLock - * - * @since 1.5 - * @author Doug Lea - */ -public interface Lock { - - /** - * Acquires the lock. - * - * <p>If the lock is not available then the current thread becomes - * disabled for thread scheduling purposes and lies dormant until the - * lock has been acquired. - * - * <p><b>Implementation Considerations</b> - * - * <p>A {@code Lock} implementation may be able to detect erroneous use - * of the lock, such as an invocation that would cause deadlock, and - * may throw an (unchecked) exception in such circumstances. The - * circumstances and the exception type must be documented by that - * {@code Lock} implementation. - */ - void lock(); - - /** - * Acquires the lock unless the current thread is - * {@linkplain Thread#interrupt interrupted}. - * - * <p>Acquires the lock if it is available and returns immediately. - * - * <p>If the lock is not available then the current thread becomes - * disabled for thread scheduling purposes and lies dormant until - * one of two things happens: - * - * <ul> - * <li>The lock is acquired by the current thread; or - * <li>Some other thread {@linkplain Thread#interrupt interrupts} the - * current thread, and interruption of lock acquisition is supported. - * </ul> - * - * <p>If the current thread: - * <ul> - * <li>has its interrupted status set on entry to this method; or - * <li>is {@linkplain Thread#interrupt interrupted} while acquiring the - * lock, and interruption of lock acquisition is supported, - * </ul> - * then {@link InterruptedException} is thrown and the current thread's - * interrupted status is cleared. - * - * <p><b>Implementation Considerations</b> - * - * <p>The ability to interrupt a lock acquisition in some - * implementations may not be possible, and if possible may be an - * expensive operation. The programmer should be aware that this - * may be the case. An implementation should document when this is - * the case. - * - * <p>An implementation can favor responding to an interrupt over - * normal method return. - * - * <p>A {@code Lock} implementation may be able to detect - * erroneous use of the lock, such as an invocation that would - * cause deadlock, and may throw an (unchecked) exception in such - * circumstances. The circumstances and the exception type must - * be documented by that {@code Lock} implementation. - * - * @throws InterruptedException if the current thread is - * interrupted while acquiring the lock (and interruption - * of lock acquisition is supported). - */ - void lockInterruptibly() throws InterruptedException; - - /** - * Acquires the lock only if it is free at the time of invocation. - * - * <p>Acquires the lock if it is available and returns immediately - * with the value {@code true}. - * If the lock is not available then this method will return - * immediately with the value {@code false}. - * - * <p>A typical usage idiom for this method would be: - * <pre> - * Lock lock = ...; - * if (lock.tryLock()) { - * try { - * // manipulate protected state - * } finally { - * lock.unlock(); - * } - * } else { - * // perform alternative actions - * } - * </pre> - * This usage ensures that the lock is unlocked if it was acquired, and - * doesn't try to unlock if the lock was not acquired. - * - * @return {@code true} if the lock was acquired and - * {@code false} otherwise - */ - boolean tryLock(); - - /** - * Acquires the lock if it is free within the given waiting time and the - * current thread has not been {@linkplain Thread#interrupt interrupted}. - * - * <p>If the lock is available this method returns immediately - * with the value {@code true}. - * If the lock is not available then - * the current thread becomes disabled for thread scheduling - * purposes and lies dormant until one of three things happens: - * <ul> - * <li>The lock is acquired by the current thread; or - * <li>Some other thread {@linkplain Thread#interrupt interrupts} the - * current thread, and interruption of lock acquisition is supported; or - * <li>The specified waiting time elapses - * </ul> - * - * <p>If the lock is acquired then the value {@code true} is returned. - * - * <p>If the current thread: - * <ul> - * <li>has its interrupted status set on entry to this method; or - * <li>is {@linkplain Thread#interrupt interrupted} while acquiring - * the lock, and interruption of lock acquisition is supported, - * </ul> - * then {@link InterruptedException} is thrown and the current thread's - * interrupted status is cleared. - * - * <p>If the specified waiting time elapses then the value {@code false} - * is returned. - * If the time is - * less than or equal to zero, the method will not wait at all. - * - * <p><b>Implementation Considerations</b> - * - * <p>The ability to interrupt a lock acquisition in some implementations - * may not be possible, and if possible may - * be an expensive operation. - * The programmer should be aware that this may be the case. An - * implementation should document when this is the case. - * - * <p>An implementation can favor responding to an interrupt over normal - * method return, or reporting a timeout. - * - * <p>A {@code Lock} implementation may be able to detect - * erroneous use of the lock, such as an invocation that would cause - * deadlock, and may throw an (unchecked) exception in such circumstances. - * The circumstances and the exception type must be documented by that - * {@code Lock} implementation. - * - * @param time the maximum time to wait for the lock - * @param unit the time unit of the {@code time} argument - * @return {@code true} if the lock was acquired and {@code false} - * if the waiting time elapsed before the lock was acquired - * - * @throws InterruptedException if the current thread is interrupted - * while acquiring the lock (and interruption of lock - * acquisition is supported) - */ - boolean tryLock(long time, TimeUnit unit) throws InterruptedException; - - /** - * Releases the lock. - * - * <p><b>Implementation Considerations</b> - * - * <p>A {@code Lock} implementation will usually impose - * restrictions on which thread can release a lock (typically only the - * holder of the lock can release it) and may throw - * an (unchecked) exception if the restriction is violated. - * Any restrictions and the exception - * type must be documented by that {@code Lock} implementation. - */ - void unlock(); - - /** - * Returns a new {@link Condition} instance that is bound to this - * {@code Lock} instance. - * - * <p>Before waiting on the condition the lock must be held by the - * current thread. - * A call to {@link Condition#await()} will atomically release the lock - * before waiting and re-acquire the lock before the wait returns. - * - * <p><b>Implementation Considerations</b> - * - * <p>The exact operation of the {@link Condition} instance depends on - * the {@code Lock} implementation and must be documented by that - * implementation. - * - * @return A new {@link Condition} instance for this {@code Lock} instance - * @throws UnsupportedOperationException if this {@code Lock} - * implementation does not support conditions - */ - Condition newCondition(); -} diff --git a/src/actors/scala/actors/threadpool/locks/ReadWriteLock.java b/src/actors/scala/actors/threadpool/locks/ReadWriteLock.java deleted file mode 100644 index 02983f9bd4..0000000000 --- a/src/actors/scala/actors/threadpool/locks/ReadWriteLock.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Written by Doug Lea with assistance from members of JCP JSR-166 - * Expert Group and released to the public domain, as explained at - * http://creativecommons.org/licenses/publicdomain - */ - -package scala.actors.threadpool.locks; - -/** - * A <tt>ReadWriteLock</tt> maintains a pair of associated {@link - * Lock locks}, one for read-only operations and one for writing. - * The {@link #readLock read lock} may be held simultaneously by - * multiple reader threads, so long as there are no writers. The - * {@link #writeLock write lock} is exclusive. - * - * <p>All <tt>ReadWriteLock</tt> implementations must guarantee that - * the memory synchronization effects of <tt>writeLock</tt> operations - * (as specified in the {@link Lock} interface) also hold with respect - * to the associated <tt>readLock</tt>. That is, a thread successfully - * acquiring the read lock will see all updates made upon previous - * release of the write lock. - * - * <p>A read-write lock allows for a greater level of concurrency in - * accessing shared data than that permitted by a mutual exclusion lock. - * It exploits the fact that while only a single thread at a time (a - * <em>writer</em> thread) can modify the shared data, in many cases any - * number of threads can concurrently read the data (hence <em>reader</em> - * threads). - * In theory, the increase in concurrency permitted by the use of a read-write - * lock will lead to performance improvements over the use of a mutual - * exclusion lock. In practice this increase in concurrency will only be fully - * realized on a multi-processor, and then only if the access patterns for - * the shared data are suitable. - * - * <p>Whether or not a read-write lock will improve performance over the use - * of a mutual exclusion lock depends on the frequency that the data is - * read compared to being modified, the duration of the read and write - * operations, and the contention for the data - that is, the number of - * threads that will try to read or write the data at the same time. - * For example, a collection that is initially populated with data and - * thereafter infrequently modified, while being frequently searched - * (such as a directory of some kind) is an ideal candidate for the use of - * a read-write lock. However, if updates become frequent then the data - * spends most of its time being exclusively locked and there is little, if any - * increase in concurrency. Further, if the read operations are too short - * the overhead of the read-write lock implementation (which is inherently - * more complex than a mutual exclusion lock) can dominate the execution - * cost, particularly as many read-write lock implementations still serialize - * all threads through a small section of code. Ultimately, only profiling - * and measurement will establish whether the use of a read-write lock is - * suitable for your application. - * - * - * <p>Although the basic operation of a read-write lock is straight-forward, - * there are many policy decisions that an implementation must make, which - * may affect the effectiveness of the read-write lock in a given application. - * Examples of these policies include: - * <ul> - * <li>Determining whether to grant the read lock or the write lock, when - * both readers and writers are waiting, at the time that a writer releases - * the write lock. Writer preference is common, as writes are expected to be - * short and infrequent. Reader preference is less common as it can lead to - * lengthy delays for a write if the readers are frequent and long-lived as - * expected. Fair, or "in-order" implementations are also possible. - * - * <li>Determining whether readers that request the read lock while a - * reader is active and a writer is waiting, are granted the read lock. - * Preference to the reader can delay the writer indefinitely, while - * preference to the writer can reduce the potential for concurrency. - * - * <li>Determining whether the locks are reentrant: can a thread with the - * write lock reacquire it? Can it acquire a read lock while holding the - * write lock? Is the read lock itself reentrant? - * - * <li>Can the write lock be downgraded to a read lock without allowing - * an intervening writer? Can a read lock be upgraded to a write lock, - * in preference to other waiting readers or writers? - * - * </ul> - * You should consider all of these things when evaluating the suitability - * of a given implementation for your application. - * - * @see ReentrantReadWriteLock - * @see Lock - * @see ReentrantLock - * - * @since 1.5 - * @author Doug Lea - */ -public interface ReadWriteLock { - /** - * Returns the lock used for reading. - * - * @return the lock used for reading. - */ - Lock readLock(); - - /** - * Returns the lock used for writing. - * - * @return the lock used for writing. - */ - Lock writeLock(); -} diff --git a/src/actors/scala/actors/threadpool/locks/ReentrantLock.java b/src/actors/scala/actors/threadpool/locks/ReentrantLock.java deleted file mode 100644 index b42ddd611b..0000000000 --- a/src/actors/scala/actors/threadpool/locks/ReentrantLock.java +++ /dev/null @@ -1,959 +0,0 @@ -/* - * Written by Doug Lea with assistance from members of JCP JSR-166 - * Expert Group and released to the public domain, as explained at - * http://creativecommons.org/licenses/publicdomain - */ - -package scala.actors.threadpool.locks; - -import java.util.Collection; -import scala.actors.threadpool.*; -import scala.actors.threadpool.helpers.*; - -/** - * A reentrant mutual exclusion {@link Lock} with the same basic - * behavior and semantics as the implicit monitor lock accessed using - * {@code synchronized} methods and statements, but with extended - * capabilities. - * - * <p>A {@code ReentrantLock} is <em>owned</em> by the thread last - * successfully locking, but not yet unlocking it. A thread invoking - * {@code lock} will return, successfully acquiring the lock, when - * the lock is not owned by another thread. The method will return - * immediately if the current thread already owns the lock. This can - * be checked using methods {@link #isHeldByCurrentThread}, and {@link - * #getHoldCount}. - * - * <p>The constructor for this class accepts an optional - * <em>fairness</em> parameter. When set {@code true}, under - * contention, locks favor granting access to the longest-waiting - * thread. Otherwise this lock does not guarantee any particular - * access order. Programs using fair locks accessed by many threads - * may display lower overall throughput (i.e., are slower; often much - * slower) than those using the default setting, but have smaller - * variances in times to obtain locks and guarantee lack of - * starvation. Note however, that fairness of locks does not guarantee - * fairness of thread scheduling. Thus, one of many threads using a - * fair lock may obtain it multiple times in succession while other - * active threads are not progressing and not currently holding the - * lock. - * Also note that the untimed {@link #tryLock() tryLock} method does not - * honor the fairness setting. It will succeed if the lock - * is available even if other threads are waiting. - * - * <p>It is recommended practice to <em>always</em> immediately - * follow a call to {@code lock} with a {@code try} block, most - * typically in a before/after construction such as: - * - * <pre> - * class X { - * private final ReentrantLock lock = new ReentrantLock(); - * // ... - * - * public void m() { - * lock.lock(); // block until condition holds - * try { - * // ... method body - * } finally { - * lock.unlock() - * } - * } - * } - * </pre> - * - * <p>In addition to implementing the {@link Lock} interface, this - * class defines methods {@code isLocked} and - * {@code getLockQueueLength}, as well as some associated - * {@code protected} access methods that may be useful for - * instrumentation and monitoring. - * - * <p>Serialization of this class behaves in the same way as built-in - * locks: a deserialized lock is in the unlocked state, regardless of - * its state when serialized. - * - * <p>This lock supports a maximum of 2147483647 recursive locks by - * the same thread. Attempts to exceed this limit result in - * {@link Error} throws from locking methods. - * - * @since 1.5 - * @author Doug Lea - * @author Dawid Kurzyniec - */ -public class ReentrantLock implements Lock, java.io.Serializable, - CondVar.ExclusiveLock { - private static final long serialVersionUID = 7373984872572414699L; - - private final Sync sync; - - /** - * Base of synchronization control for this lock. Subclassed - * into fair and nonfair versions below. - */ - static abstract class Sync implements java.io.Serializable { - private static final long serialVersionUID = -5179523762034025860L; - - protected transient Thread owner_ = null; - protected transient int holds_ = 0; - - protected Sync() {} - - /** - * Performs {@link Lock#lock}. The main reason for subclassing - * is to allow fast path for nonfair version. - */ - public abstract void lock(); - - public abstract void lockInterruptibly() throws InterruptedException; - - final void incHolds() { - int nextHolds = ++holds_; - if (nextHolds < 0) - throw new Error("Maximum lock count exceeded"); - holds_ = nextHolds; - } - - public boolean tryLock() { - Thread caller = Thread.currentThread(); - synchronized (this) { - if (owner_ == null) { - owner_ = caller; - holds_ = 1; - return true; - } - else if (caller == owner_) { - incHolds(); - return true; - } - } - return false; - } - - public abstract boolean tryLock(long nanos) throws InterruptedException; - - public abstract void unlock(); - - public synchronized int getHoldCount() { - return isHeldByCurrentThread() ? holds_ : 0; - } - - public synchronized boolean isHeldByCurrentThread() { - return holds_ > 0 && Thread.currentThread() == owner_; - } - - public synchronized boolean isLocked() { - return owner_ != null; - } - - public abstract boolean isFair(); - - protected synchronized Thread getOwner() { - return owner_; - } - - public boolean hasQueuedThreads() { - throw new UnsupportedOperationException("Use FAIR version"); - } - - public int getQueueLength() { - throw new UnsupportedOperationException("Use FAIR version"); - } - - public Collection getQueuedThreads() { - throw new UnsupportedOperationException("Use FAIR version"); - } - - public boolean isQueued(Thread thread) { - throw new UnsupportedOperationException("Use FAIR version"); - } - } - - /** - * Sync object for non-fair locks - */ - final static class NonfairSync extends Sync { - private static final long serialVersionUID = 7316153563782823691L; - - NonfairSync() {} - - /** - * Performs lock. Try immediate barge, backing up to normal - * acquire on failure. - */ - public void lock() { - Thread caller = Thread.currentThread(); - synchronized (this) { - if (owner_ == null) { - owner_ = caller; - holds_ = 1; - return; - } - else if (caller == owner_) { - incHolds(); - return; - } - else { - boolean wasInterrupted = Thread.interrupted(); - try { - while (true) { - try { - wait(); - } - catch (InterruptedException e) { - wasInterrupted = true; - // no need to notify; if we were signalled, we - // will act as signalled, ignoring the - // interruption - } - if (owner_ == null) { - owner_ = caller; - holds_ = 1; - return; - } - } - } - finally { - if (wasInterrupted) Thread.currentThread().interrupt(); - } - } - } - } - - public void lockInterruptibly() throws InterruptedException { - if (Thread.interrupted()) throw new InterruptedException(); - Thread caller = Thread.currentThread(); - synchronized (this) { - if (owner_ == null) { - owner_ = caller; - holds_ = 1; - return; - } - else if (caller == owner_) { - incHolds(); - return; - } - else { - try { - do { wait(); } while (owner_ != null); - owner_ = caller; - holds_ = 1; - return; - } - catch (InterruptedException ex) { - if (owner_ == null) notify(); - throw ex; - } - } - } - } - - public boolean tryLock(long nanos) throws InterruptedException { - if (Thread.interrupted()) throw new InterruptedException(); - Thread caller = Thread.currentThread(); - - synchronized (this) { - if (owner_ == null) { - owner_ = caller; - holds_ = 1; - return true; - } - else if (caller == owner_) { - incHolds(); - return true; - } - else if (nanos <= 0) - return false; - else { - long deadline = Utils.nanoTime() + nanos; - try { - for (; ; ) { - TimeUnit.NANOSECONDS.timedWait(this, nanos); - if (caller == owner_) { - incHolds(); - return true; - } - else if (owner_ == null) { - owner_ = caller; - holds_ = 1; - return true; - } - else { - nanos = deadline - Utils.nanoTime(); - if (nanos <= 0) - return false; - } - } - } - catch (InterruptedException ex) { - if (owner_ == null) notify(); - throw ex; - } - } - } - } - - public synchronized void unlock() { - if (Thread.currentThread() != owner_) - throw new IllegalMonitorStateException("Not owner"); - - if (--holds_ == 0) { - owner_ = null; - notify(); - } - } - - public final boolean isFair() { - return false; - } - } - - /** - * Sync object for fair locks - */ - final static class FairSync extends Sync implements WaitQueue.QueuedSync { - private static final long serialVersionUID = -3000897897090466540L; - - private transient WaitQueue wq_ = new FIFOWaitQueue(); - - FairSync() {} - - public synchronized boolean recheck(WaitQueue.WaitNode node) { - Thread caller = Thread.currentThread(); - if (owner_ == null) { - owner_ = caller; - holds_ = 1; - return true; - } - else if (caller == owner_) { - incHolds(); - return true; - } - wq_.insert(node); - return false; - } - - public synchronized void takeOver(WaitQueue.WaitNode node) { - // assert (holds_ == 1 && owner_ == Thread.currentThread() - owner_ = node.getOwner(); - } - - public void lock() { - Thread caller = Thread.currentThread(); - synchronized (this) { - if (owner_ == null) { - owner_ = caller; - holds_ = 1; - return; - } - else if (caller == owner_) { - incHolds(); - return; - } - } - WaitQueue.WaitNode n = new WaitQueue.WaitNode(); - n.doWaitUninterruptibly(this); - } - - public void lockInterruptibly() throws InterruptedException { - if (Thread.interrupted()) throw new InterruptedException(); - Thread caller = Thread.currentThread(); - synchronized (this) { - if (owner_ == null) { - owner_ = caller; - holds_ = 1; - return; - } - else if (caller == owner_) { - incHolds(); - return; - } - } - WaitQueue.WaitNode n = new WaitQueue.WaitNode(); - n.doWait(this); - } - - public boolean tryLock(long nanos) throws InterruptedException { - if (Thread.interrupted()) throw new InterruptedException(); - Thread caller = Thread.currentThread(); - synchronized (this) { - if (owner_ == null) { - owner_ = caller; - holds_ = 1; - return true; - } - else if (caller == owner_) { - incHolds(); - return true; - } - } - WaitQueue.WaitNode n = new WaitQueue.WaitNode(); - return n.doTimedWait(this, nanos); - } - - protected synchronized WaitQueue.WaitNode getSignallee(Thread caller) { - if (caller != owner_) - throw new IllegalMonitorStateException("Not owner"); - // assert (holds_ > 0) - if (holds_ >= 2) { // current thread will keep the lock - --holds_; - return null; - } - // assert (holds_ == 1) - WaitQueue.WaitNode w = wq_.extract(); - if (w == null) { // if none, clear for new arrivals - owner_ = null; - holds_ = 0; - } - return w; - } - - public void unlock() { - Thread caller = Thread.currentThread(); - for (;;) { - WaitQueue.WaitNode w = getSignallee(caller); - if (w == null) return; // no one to signal - if (w.signal(this)) return; // notify if still waiting, else skip - } - } - - public final boolean isFair() { - return true; - } - - public synchronized boolean hasQueuedThreads() { - return wq_.hasNodes(); - } - - public synchronized int getQueueLength() { - return wq_.getLength(); - } - - public synchronized Collection getQueuedThreads() { - return wq_.getWaitingThreads(); - } - - public synchronized boolean isQueued(Thread thread) { - return wq_.isWaiting(thread); - } - - private void readObject(java.io.ObjectInputStream in) - throws java.io.IOException, ClassNotFoundException { - in.defaultReadObject(); - synchronized (this) { - wq_ = new FIFOWaitQueue(); - } - } - } - - /** - * Creates an instance of {@code ReentrantLock}. - * This is equivalent to using {@code ReentrantLock(false)}. - */ - public ReentrantLock() { - sync = new NonfairSync(); - } - - /** - * Creates an instance of {@code ReentrantLock} with the - * given fairness policy. - * - * @param fair {@code true} if this lock should use a fair ordering policy - */ - public ReentrantLock(boolean fair) { - sync = (fair)? (Sync)new FairSync() : new NonfairSync(); - } - - - /** - * Acquires the lock. - * - * <p>Acquires the lock if it is not held by another thread and returns - * immediately, setting the lock hold count to one. - * - * <p>If the current thread already holds the lock then the hold - * count is incremented by one and the method returns immediately. - * - * <p>If the lock is held by another thread then the - * current thread becomes disabled for thread scheduling - * purposes and lies dormant until the lock has been acquired, - * at which time the lock hold count is set to one. - */ - public void lock() { - sync.lock(); - } - - /** - * Acquires the lock unless the current thread is - * {@linkplain Thread#interrupt interrupted}. - * - * <p>Acquires the lock if it is not held by another thread and returns - * immediately, setting the lock hold count to one. - * - * <p>If the current thread already holds this lock then the hold count - * is incremented by one and the method returns immediately. - * - * <p>If the lock is held by another thread then the - * current thread becomes disabled for thread scheduling - * purposes and lies dormant until one of two things happens: - * - * <ul> - * - * <li>The lock is acquired by the current thread; or - * - * <li>Some other thread {@linkplain Thread#interrupt interrupts} the - * current thread. - * - * </ul> - * - * <p>If the lock is acquired by the current thread then the lock hold - * count is set to one. - * - * <p>If the current thread: - * - * <ul> - * - * <li>has its interrupted status set on entry to this method; or - * - * <li>is {@linkplain Thread#interrupt interrupted} while acquiring - * the lock, - * - * </ul> - * - * then {@link InterruptedException} is thrown and the current thread's - * interrupted status is cleared. - * - * <p>In this implementation, as this method is an explicit - * interruption point, preference is given to responding to the - * interrupt over normal or reentrant acquisition of the lock. - * - * @throws InterruptedException if the current thread is interrupted - */ - public void lockInterruptibly() throws InterruptedException { - sync.lockInterruptibly(); - } - - /** - * Acquires the lock only if it is not held by another thread at the time - * of invocation. - * - * <p>Acquires the lock if it is not held by another thread and - * returns immediately with the value {@code true}, setting the - * lock hold count to one. Even when this lock has been set to use a - * fair ordering policy, a call to {@code tryLock()} <em>will</em> - * immediately acquire the lock if it is available, whether or not - * other threads are currently waiting for the lock. - * This "barging" behavior can be useful in certain - * circumstances, even though it breaks fairness. If you want to honor - * the fairness setting for this lock, then use - * {@link #tryLock(long, TimeUnit) tryLock(0, TimeUnit.SECONDS) } - * which is almost equivalent (it also detects interruption). - * - * <p> If the current thread already holds this lock then the hold - * count is incremented by one and the method returns {@code true}. - * - * <p>If the lock is held by another thread then this method will return - * immediately with the value {@code false}. - * - * @return {@code true} if the lock was free and was acquired by the - * current thread, or the lock was already held by the current - * thread; and {@code false} otherwise - */ - public boolean tryLock() { - return sync.tryLock(); - } - - /** - * Acquires the lock if it is not held by another thread within the given - * waiting time and the current thread has not been - * {@linkplain Thread#interrupt interrupted}. - * - * <p>Acquires the lock if it is not held by another thread and returns - * immediately with the value {@code true}, setting the lock hold count - * to one. If this lock has been set to use a fair ordering policy then - * an available lock <em>will not</em> be acquired if any other threads - * are waiting for the lock. This is in contrast to the {@link #tryLock()} - * method. If you want a timed {@code tryLock} that does permit barging on - * a fair lock then combine the timed and un-timed forms together: - * - * <pre>if (lock.tryLock() || lock.tryLock(timeout, unit) ) { ... } - * </pre> - * - * <p>If the current thread - * already holds this lock then the hold count is incremented by one and - * the method returns {@code true}. - * - * <p>If the lock is held by another thread then the - * current thread becomes disabled for thread scheduling - * purposes and lies dormant until one of three things happens: - * - * <ul> - * - * <li>The lock is acquired by the current thread; or - * - * <li>Some other thread {@linkplain Thread#interrupt interrupts} - * the current thread; or - * - * <li>The specified waiting time elapses - * - * </ul> - * - * <p>If the lock is acquired then the value {@code true} is returned and - * the lock hold count is set to one. - * - * <p>If the current thread: - * - * <ul> - * - * <li>has its interrupted status set on entry to this method; or - * - * <li>is {@linkplain Thread#interrupt interrupted} while - * acquiring the lock, - * - * </ul> - * then {@link InterruptedException} is thrown and the current thread's - * interrupted status is cleared. - * - * <p>If the specified waiting time elapses then the value {@code false} - * is returned. If the time is less than or equal to zero, the method - * will not wait at all. - * - * <p>In this implementation, as this method is an explicit - * interruption point, preference is given to responding to the - * interrupt over normal or reentrant acquisition of the lock, and - * over reporting the elapse of the waiting time. - * - * @param timeout the time to wait for the lock - * @param unit the time unit of the timeout argument - * @return {@code true} if the lock was free and was acquired by the - * current thread, or the lock was already held by the current - * thread; and {@code false} if the waiting time elapsed before - * the lock could be acquired - * @throws InterruptedException if the current thread is interrupted - * @throws NullPointerException if the time unit is null - * - */ - public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { - return sync.tryLock(unit.toNanos(timeout)); - } - - /** - * Attempts to release this lock. - * - * <p>If the current thread is the holder of this lock then the hold - * count is decremented. If the hold count is now zero then the lock - * is released. If the current thread is not the holder of this - * lock then {@link IllegalMonitorStateException} is thrown. - * - * @throws IllegalMonitorStateException if the current thread does not - * hold this lock - */ - public void unlock() { - sync.unlock(); - } - - /** - * Returns a {@link Condition} instance for use with this - * {@link Lock} instance. - * - * <p>The returned {@link Condition} instance supports the same - * usages as do the {@link Object} monitor methods ({@link - * Object#wait() wait}, {@link Object#notify notify}, and {@link - * Object#notifyAll notifyAll}) when used with the built-in - * monitor lock. - * - * <ul> - * - * <li>If this lock is not held when any of the {@link Condition} - * {@linkplain Condition#await() waiting} or {@linkplain - * Condition#signal signalling} methods are called, then an {@link - * IllegalMonitorStateException} is thrown. - * - * <li>When the condition {@linkplain Condition#await() waiting} - * methods are called the lock is released and, before they - * return, the lock is reacquired and the lock hold count restored - * to what it was when the method was called. - * - * <li>If a thread is {@linkplain Thread#interrupt interrupted} - * while waiting then the wait will terminate, an {@link - * InterruptedException} will be thrown, and the thread's - * interrupted status will be cleared. - * - * <li> Waiting threads are signalled in FIFO order. - * - * <li>The ordering of lock reacquisition for threads returning - * from waiting methods is the same as for threads initially - * acquiring the lock, which is in the default case not specified, - * but for <em>fair</em> locks favors those threads that have been - * waiting the longest. - * - * </ul> - * - * @return the Condition object - */ - public Condition newCondition() { - return isFair() ? (Condition)new FIFOCondVar(this) : new CondVar(this); - } - - /** - * Queries the number of holds on this lock by the current thread. - * - * <p>A thread has a hold on a lock for each lock action that is not - * matched by an unlock action. - * - * <p>The hold count information is typically only used for testing and - * debugging purposes. For example, if a certain section of code should - * not be entered with the lock already held then we can assert that - * fact: - * - * <pre> - * class X { - * ReentrantLock lock = new ReentrantLock(); - * // ... - * public void m() { - * assert lock.getHoldCount() == 0; - * lock.lock(); - * try { - * // ... method body - * } finally { - * lock.unlock(); - * } - * } - * } - * </pre> - * - * @return the number of holds on this lock by the current thread, - * or zero if this lock is not held by the current thread - */ - public int getHoldCount() { - return sync.getHoldCount(); - } - - /** - * Queries if this lock is held by the current thread. - * - * <p>Analogous to the {@link Thread#holdsLock} method for built-in - * monitor locks, this method is typically used for debugging and - * testing. For example, a method that should only be called while - * a lock is held can assert that this is the case: - * - * <pre> - * class X { - * ReentrantLock lock = new ReentrantLock(); - * // ... - * - * public void m() { - * assert lock.isHeldByCurrentThread(); - * // ... method body - * } - * } - * </pre> - * - * <p>It can also be used to ensure that a reentrant lock is used - * in a non-reentrant manner, for example: - * - * <pre> - * class X { - * ReentrantLock lock = new ReentrantLock(); - * // ... - * - * public void m() { - * assert !lock.isHeldByCurrentThread(); - * lock.lock(); - * try { - * // ... method body - * } finally { - * lock.unlock(); - * } - * } - * } - * </pre> - * - * @return {@code true} if current thread holds this lock and - * {@code false} otherwise - */ - public boolean isHeldByCurrentThread() { - return sync.isHeldByCurrentThread(); - } - - /** - * Queries if this lock is held by any thread. This method is - * designed for use in monitoring of the system state, - * not for synchronization control. - * - * @return {@code true} if any thread holds this lock and - * {@code false} otherwise - */ - public boolean isLocked() { - return sync.isLocked(); - } - - /** - * Returns {@code true} if this lock has fairness set true. - * - * @return {@code true} if this lock has fairness set true - */ - public final boolean isFair() { - return sync.isFair(); - } - - /** - * Returns the thread that currently owns this lock, or - * {@code null} if not owned. When this method is called by a - * thread that is not the owner, the return value reflects a - * best-effort approximation of current lock status. For example, - * the owner may be momentarily {@code null} even if there are - * threads trying to acquire the lock but have not yet done so. - * This method is designed to facilitate construction of - * subclasses that provide more extensive lock monitoring - * facilities. - * - * @return the owner, or {@code null} if not owned - */ - protected Thread getOwner() { - return sync.getOwner(); - } - - /** - * Queries whether any threads are waiting to acquire this lock. Note that - * because cancellations may occur at any time, a {@code true} - * return does not guarantee that any other thread will ever - * acquire this lock. This method is designed primarily for use in - * monitoring of the system state. - * - * @return {@code true} if there may be other threads waiting to - * acquire the lock - */ - public final boolean hasQueuedThreads() { - return sync.hasQueuedThreads(); - } - - - /** - * Queries whether the given thread is waiting to acquire this - * lock. Note that because cancellations may occur at any time, a - * {@code true} return does not guarantee that this thread - * will ever acquire this lock. This method is designed primarily for use - * in monitoring of the system state. - * - * @param thread the thread - * @return {@code true} if the given thread is queued waiting for this lock - * @throws NullPointerException if the thread is null - */ - public final boolean hasQueuedThread(Thread thread) { - return sync.isQueued(thread); - } - - - /** - * Returns an estimate of the number of threads waiting to - * acquire this lock. The value is only an estimate because the number of - * threads may change dynamically while this method traverses - * internal data structures. This method is designed for use in - * monitoring of the system state, not for synchronization - * control. - * - * @return the estimated number of threads waiting for this lock - */ - public final int getQueueLength() { - return sync.getQueueLength(); - } - - /** - * Returns a collection containing threads that may be waiting to - * acquire this lock. Because the actual set of threads may change - * dynamically while constructing this result, the returned - * collection is only a best-effort estimate. The elements of the - * returned collection are in no particular order. This method is - * designed to facilitate construction of subclasses that provide - * more extensive monitoring facilities. - * - * @return the collection of threads - */ - protected Collection getQueuedThreads() { - return sync.getQueuedThreads(); - } - - /** - * Queries whether any threads are waiting on the given condition - * associated with this lock. Note that because timeouts and - * interrupts may occur at any time, a {@code true} return does - * not guarantee that a future {@code signal} will awaken any - * threads. This method is designed primarily for use in - * monitoring of the system state. - * - * @param condition the condition - * @return {@code true} if there are any waiting threads - * @throws IllegalMonitorStateException if this lock is not held - * @throws IllegalArgumentException if the given condition is - * not associated with this lock - * @throws NullPointerException if the condition is null - */ - public boolean hasWaiters(Condition condition) { - return asCondVar(condition).hasWaiters(); - } - - /** - * Returns an estimate of the number of threads waiting on the - * given condition associated with this lock. Note that because - * timeouts and interrupts may occur at any time, the estimate - * serves only as an upper bound on the actual number of waiters. - * This method is designed for use in monitoring of the system - * state, not for synchronization control. - * - * @param condition the condition - * @return the estimated number of waiting threads - * @throws IllegalMonitorStateException if this lock is not held - * @throws IllegalArgumentException if the given condition is - * not associated with this lock - * @throws NullPointerException if the condition is null - */ - public int getWaitQueueLength(Condition condition) { - return asCondVar(condition).getWaitQueueLength(); - } - - /** - * Returns a collection containing those threads that may be - * waiting on the given condition associated with this lock. - * Because the actual set of threads may change dynamically while - * constructing this result, the returned collection is only a - * best-effort estimate. The elements of the returned collection - * are in no particular order. This method is designed to - * facilitate construction of subclasses that provide more - * extensive condition monitoring facilities. - * - * @param condition the condition - * @return the collection of threads - * @throws IllegalMonitorStateException if this lock is not held - * @throws IllegalArgumentException if the given condition is - * not associated with this lock - * @throws NullPointerException if the condition is null - */ - protected Collection getWaitingThreads(Condition condition) { - return asCondVar(condition).getWaitingThreads(); - } - - /** - * Returns a string identifying this lock, as well as its lock state. - * The state, in brackets, includes either the String {@code "Unlocked"} - * or the String {@code "Locked by"} followed by the - * {@linkplain Thread#getName name} of the owning thread. - * - * @return a string identifying this lock, as well as its lock state - */ - public String toString() { - Thread o = getOwner(); - return super.toString() + ((o == null) ? - "[Unlocked]" : - "[Locked by thread " + o.getName() + "]"); - } - - private CondVar asCondVar(Condition condition) { - if (condition == null) - throw new NullPointerException(); - if (!(condition instanceof CondVar)) - throw new IllegalArgumentException("not owner"); - CondVar condVar = (CondVar)condition; - if (condVar.lock != this) - throw new IllegalArgumentException("not owner"); - return condVar; - } -} diff --git a/src/actors/scala/actors/threadpool/locks/ReentrantReadWriteLock.java b/src/actors/scala/actors/threadpool/locks/ReentrantReadWriteLock.java deleted file mode 100644 index 914d242100..0000000000 --- a/src/actors/scala/actors/threadpool/locks/ReentrantReadWriteLock.java +++ /dev/null @@ -1,1341 +0,0 @@ -/* - * Written by Doug Lea with assistance from members of JCP JSR-166 - * Expert Group and released to the public domain, as explained at - * http://creativecommons.org/licenses/publicdomain - */ - -package scala.actors.threadpool.locks; - -import java.util.HashMap; -import scala.actors.threadpool.*; -import scala.actors.threadpool.helpers.*; - -/** - * An implementation of {@link ReadWriteLock} supporting similar - * semantics to {@link ReentrantLock}. - * <p>This class has the following properties: - * - * <ul> - * <li><b>Acquisition order</b> - * - * <p>The order of entry - * to the read and write lock is unspecified, subject to reentrancy - * constraints. A nonfair lock that is continuously contended may - * indefinitely postpone one or more reader or writer threads, but - * will normally have higher throughput than a fair lock. - * <p> - * - * DEPARTURE FROM java.util.concurrent: this implementation impose - * a writer-preference and thus its acquisition order may be different - * than in java.util.concurrent. - * - * <li><b>Reentrancy</b> - * - * <p>This lock allows both readers and writers to reacquire read or - * write locks in the style of a {@link ReentrantLock}. Non-reentrant - * readers are not allowed until all write locks held by the writing - * thread have been released. - * - * <p>Additionally, a writer can acquire the read lock, but not - * vice-versa. Among other applications, reentrancy can be useful - * when write locks are held during calls or callbacks to methods that - * perform reads under read locks. If a reader tries to acquire the - * write lock it will never succeed. - * - * <li><b>Lock downgrading</b> - * <p>Reentrancy also allows downgrading from the write lock to a read lock, - * by acquiring the write lock, then the read lock and then releasing the - * write lock. However, upgrading from a read lock to the write lock is - * <b>not</b> possible. - * - * <li><b>Interruption of lock acquisition</b> - * <p>The read lock and write lock both support interruption during lock - * acquisition. - * - * <li><b>{@link Condition} support</b> - * <p>The write lock provides a {@link Condition} implementation that - * behaves in the same way, with respect to the write lock, as the - * {@link Condition} implementation provided by - * {@link ReentrantLock#newCondition} does for {@link ReentrantLock}. - * This {@link Condition} can, of course, only be used with the write lock. - * - * <p>The read lock does not support a {@link Condition} and - * {@code readLock().newCondition()} throws - * {@code UnsupportedOperationException}. - * - * <li><b>Instrumentation</b> - * <p>This class supports methods to determine whether locks - * are held or contended. These methods are designed for monitoring - * system state, not for synchronization control. - * </ul> - * - * <p>Serialization of this class behaves in the same way as built-in - * locks: a deserialized lock is in the unlocked state, regardless of - * its state when serialized. - * - * <p><b>Sample usages</b>. Here is a code sketch showing how to exploit - * reentrancy to perform lock downgrading after updating a cache (exception - * handling is elided for simplicity): - * <pre> - * class CachedData { - * Object data; - * volatile boolean cacheValid; - * ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); - * - * void processCachedData() { - * rwl.readLock().lock(); - * if (!cacheValid) { - * // Must release read lock before acquiring write lock - * rwl.readLock().unlock(); - * rwl.writeLock().lock(); - * // Recheck state because another thread might have acquired - * // write lock and changed state before we did. - * if (!cacheValid) { - * data = ... - * cacheValid = true; - * } - * // Downgrade by acquiring read lock before releasing write lock - * rwl.readLock().lock(); - * rwl.writeLock().unlock(); // Unlock write, still hold read - * } - * - * use(data); - * rwl.readLock().unlock(); - * } - * } - * </pre> - * - * ReentrantReadWriteLocks can be used to improve concurrency in some - * uses of some kinds of Collections. This is typically worthwhile - * only when the collections are expected to be large, accessed by - * more reader threads than writer threads, and entail operations with - * overhead that outweighs synchronization overhead. For example, here - * is a class using a TreeMap that is expected to be large and - * concurrently accessed. - * - * <pre>{@code - * class RWDictionary { - * private final Map<String, Data> m = new TreeMap<String, Data>(); - * private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); - * private final Lock r = rwl.readLock(); - * private final Lock w = rwl.writeLock(); - * - * public Data get(String key) { - * r.lock(); - * try { return m.get(key); } - * finally { r.unlock(); } - * } - * public String[] allKeys() { - * r.lock(); - * try { return m.keySet().toArray(); } - * finally { r.unlock(); } - * } - * public Data put(String key, Data value) { - * w.lock(); - * try { return m.put(key, value); } - * finally { w.unlock(); } - * } - * public void clear() { - * w.lock(); - * try { m.clear(); } - * finally { w.unlock(); } - * } - * }}</pre> - * - * <h3>Implementation Notes</h3> - * - * <p>This lock supports a maximum of 65535 recursive write locks - * and 65535 read locks. Attempts to exceed these limits result in - * {@link Error} throws from locking methods. - * - * @since 1.5 - * @author Doug Lea - * - */ -public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializable { - private static final long serialVersionUID = -3463448656717690166L; - - final ReadLock readerLock_ = new ReadLock(this); - final WriteLock writerLock_ = new WriteLock(this); - - final Sync sync; - - /** - * Creates a new {@code ReentrantReadWriteLock} with - * default (nonfair) ordering properties. - */ - public ReentrantReadWriteLock() { - this.sync = new NonfairSync(); - } - - public Lock writeLock() { return writerLock_; } - public Lock readLock() { return readerLock_; } - - /** - * Synchronization implementation for ReentrantReadWriteLock. - * Subclassed into fair and nonfair versions. - */ - private abstract static class Sync implements java.io.Serializable { - - private static final int NONE = 0; - private static final int READER = 1; - private static final int WRITER = 2; - - transient int activeReaders_ = 0; - transient Thread activeWriter_ = null; - transient int waitingReaders_ = 0; - transient int waitingWriters_ = 0; - - /** Number of acquires on write lock by activeWriter_ thread **/ - transient int writeHolds_ = 0; - - /** Number of acquires on read lock by any reader thread **/ - transient HashMap<Thread, Integer> readers_ = new HashMap<Thread, Integer>(); - - /** cache/reuse the special Integer value one to speed up readlocks **/ - static final Integer IONE = new Integer(1); - - Sync() {} - - /* - Each of these variants is needed to maintain atomicity - of wait counts during wait loops. They could be - made faster by manually inlining each other. We hope that - compilers do this for us though. - */ - - synchronized boolean startReadFromNewReader() { - boolean pass = startRead(); - if (!pass) ++waitingReaders_; - return pass; - } - - synchronized boolean startWriteFromNewWriter() { - boolean pass = startWrite(); - if (!pass) ++waitingWriters_; - return pass; - } - - synchronized boolean startReadFromWaitingReader() { - boolean pass = startRead(); - if (pass) --waitingReaders_; - return pass; - } - - synchronized boolean startWriteFromWaitingWriter() { - boolean pass = startWrite(); - if (pass) --waitingWriters_; - return pass; - } - - /* - A bunch of small synchronized methods are needed - to allow communication from the Lock objects - back to this object, that serves as controller - */ - - synchronized void cancelledWaitingReader() { --waitingReaders_; } - synchronized void cancelledWaitingWriter() { --waitingWriters_; } - - boolean allowReader() { - return (activeWriter_ == null && waitingWriters_ == 0) || - activeWriter_ == Thread.currentThread(); - } - - synchronized boolean startRead() { - Thread t = Thread.currentThread(); - Object c = readers_.get(t); - if (c != null) { // already held -- just increment hold count - readers_.put(t, new Integer( ( (Integer) (c)).intValue() + 1)); - ++activeReaders_; - return true; - } - else if (allowReader()) { - readers_.put(t, IONE); - ++activeReaders_; - return true; - } - else - return false; - } - - synchronized boolean startWrite() { - if (activeWriter_ == Thread.currentThread()) { // already held; re-acquire - ++writeHolds_; - return true; - } - else if (writeHolds_ == 0) { - if (activeReaders_ == 0 || - (readers_.size() == 1 && - readers_.get(Thread.currentThread()) != null)) { - activeWriter_ = Thread.currentThread(); - writeHolds_ = 1; - return true; - } - else - return false; - } - else - return false; - } - - synchronized int endRead() { - Thread t = Thread.currentThread(); - Object c = readers_.get(t); - if (c == null) - throw new IllegalMonitorStateException(); - --activeReaders_; - if (c != IONE) { // more than one hold; decrement count - int h = ( (Integer) (c)).intValue() - 1; - Integer ih = (h == 1) ? IONE : new Integer(h); - readers_.put(t, ih); - return NONE; - } - else { - readers_.remove(t); - - if (writeHolds_ > 0) // a write lock is still held by current thread - return NONE; - else if (activeReaders_ == 0 && waitingWriters_ > 0) - return WRITER; - else - return NONE; - } - } - - synchronized int endWrite() { - if (activeWriter_ != Thread.currentThread()) { - throw new IllegalMonitorStateException(); - } - --writeHolds_; - if (writeHolds_ > 0) // still being held - return NONE; - else { - activeWriter_ = null; - if (waitingReaders_ > 0 && allowReader()) - return READER; - else if (waitingWriters_ > 0) - return WRITER; - else - return NONE; - } - } - - synchronized Thread getOwner() { - return activeWriter_; - } - - synchronized int getReadLockCount() { - return activeReaders_; - } - - synchronized boolean isWriteLocked() { - return activeWriter_ != null; - } - - synchronized boolean isWriteLockedByCurrentThread() { - return activeWriter_ == Thread.currentThread(); - } - - synchronized int getWriteHoldCount() { - return isWriteLockedByCurrentThread() ? writeHolds_ : 0; - } - - synchronized int getReadHoldCount() { - if (activeReaders_ == 0) return 0; - Thread t = Thread.currentThread(); - Integer i = readers_.get(t); - return (i == null) ? 0 : i.intValue(); - } - - final synchronized boolean hasQueuedThreads() { - return waitingWriters_ > 0 || waitingReaders_ > 0; - } - - final synchronized int getQueueLength() { - return waitingWriters_ + waitingReaders_; - } - - private void readObject(java.io.ObjectInputStream in) - throws java.io.IOException, ClassNotFoundException { - in.defaultReadObject(); - // readers_ is transient, need to reinitialize. Let's flush the memory - // and ensure visibility by synchronizing (all other accesses to - // readers_ are also synchronized on "this") - synchronized (this) { - readers_ = new HashMap<Thread, Integer>(); - } - } - } - - /** - * Nonfair version of Sync - */ - private static class NonfairSync extends Sync { - private static final long serialVersionUID = -2392241841540339773L; - - NonfairSync() {} - } - - /** - * The lock returned by method {@link ReentrantReadWriteLock#readLock}. - */ - public static class ReadLock implements Lock, java.io.Serializable { - - private static final long serialVersionUID = -5992448646407690164L; - - final ReentrantReadWriteLock lock; - - /** - * Constructor for use by subclasses - * - * @param lock the outer lock object - * @throws NullPointerException if the lock is null - */ - protected ReadLock(ReentrantReadWriteLock lock) { - if (lock == null) throw new NullPointerException(); - this.lock = lock; - } - - /** - * Acquires the read lock. - * - * <p>Acquires the read lock if the write lock is not held by - * another thread and returns immediately. - * - * <p>If the write lock is held by another thread then - * the current thread becomes disabled for thread scheduling - * purposes and lies dormant until the read lock has been acquired. - */ - public void lock() { - synchronized (this) { - if (lock.sync.startReadFromNewReader()) return; - boolean wasInterrupted = Thread.interrupted(); - try { - while (true) { - try { - ReadLock.this.wait(); - } - catch (InterruptedException ex) { - wasInterrupted = true; - // no need to propagate the potentially masked - // signal, since readers are always notified all - } - if (lock.sync.startReadFromWaitingReader()) return; - } - } - finally { - if (wasInterrupted) Thread.currentThread().interrupt(); - } - } - } - - /** - * Acquires the read lock unless the current thread is - * {@linkplain Thread#interrupt interrupted}. - * - * <p>Acquires the read lock if the write lock is not held - * by another thread and returns immediately. - * - * <p>If the write lock is held by another thread then the - * current thread becomes disabled for thread scheduling - * purposes and lies dormant until one of two things happens: - * - * <ul> - * - * <li>The read lock is acquired by the current thread; or - * - * <li>Some other thread {@linkplain Thread#interrupt interrupts} - * the current thread. - * - * </ul> - * - * <p>If the current thread: - * - * <ul> - * - * <li>has its interrupted status set on entry to this method; or - * - * <li>is {@linkplain Thread#interrupt interrupted} while - * acquiring the read lock, - * - * </ul> - * - * then {@link InterruptedException} is thrown and the current - * thread's interrupted status is cleared. - * - * <p>In this implementation, as this method is an explicit - * interruption point, preference is given to responding to - * the interrupt over normal or reentrant acquisition of the - * lock. - * - * @throws InterruptedException if the current thread is interrupted - */ - public void lockInterruptibly() throws InterruptedException { - if (Thread.interrupted()) throw new InterruptedException(); - InterruptedException ie = null; - synchronized (this) { - if (!lock.sync.startReadFromNewReader()) { - for (; ; ) { - try { - ReadLock.this.wait(); - if (lock.sync.startReadFromWaitingReader()) - return; - } - catch (InterruptedException ex) { - lock.sync.cancelledWaitingReader(); - ie = ex; - break; - } - } - } - } - if (ie != null) { - // fall through outside synch on interrupt. - // This notification is not really needed here, - // but may be in plausible subclasses - lock.writerLock_.signalWaiters(); - throw ie; - } - } - - /** - * Acquires the read lock only if the write lock is not held by - * another thread at the time of invocation. - * - * <p>Acquires the read lock if the write lock is not held by - * another thread and returns immediately with the value - * {@code true}. Even when this lock has been set to use a - * fair ordering policy, a call to {@code tryLock()} - * <em>will</em> immediately acquire the read lock if it is - * available, whether or not other threads are currently - * waiting for the read lock. This "barging" behavior - * can be useful in certain circumstances, even though it - * breaks fairness. If you want to honor the fairness setting - * for this lock, then use {@link #tryLock(long, TimeUnit) - * tryLock(0, TimeUnit.SECONDS) } which is almost equivalent - * (it also detects interruption). - * - * <p>If the write lock is held by another thread then - * this method will return immediately with the value - * {@code false}. - * - * @return {@code true} if the read lock was acquired - */ - public boolean tryLock() { - return lock.sync.startRead(); - } - - /** - * Acquires the read lock if the write lock is not held by - * another thread within the given waiting time and the - * current thread has not been {@linkplain Thread#interrupt - * interrupted}. - * - * <p>Acquires the read lock if the write lock is not held by - * another thread and returns immediately with the value - * {@code true}. If this lock has been set to use a fair - * ordering policy then an available lock <em>will not</em> be - * acquired if any other threads are waiting for the - * lock. This is in contrast to the {@link #tryLock()} - * method. If you want a timed {@code tryLock} that does - * permit barging on a fair lock then combine the timed and - * un-timed forms together: - * - * <pre>if (lock.tryLock() || lock.tryLock(timeout, unit) ) { ... } - * </pre> - * - * <p>If the write lock is held by another thread then the - * current thread becomes disabled for thread scheduling - * purposes and lies dormant until one of three things happens: - * - * <ul> - * - * <li>The read lock is acquired by the current thread; or - * - * <li>Some other thread {@linkplain Thread#interrupt interrupts} - * the current thread; or - * - * <li>The specified waiting time elapses. - * - * </ul> - * - * <p>If the read lock is acquired then the value {@code true} is - * returned. - * - * <p>If the current thread: - * - * <ul> - * - * <li>has its interrupted status set on entry to this method; or - * - * <li>is {@linkplain Thread#interrupt interrupted} while - * acquiring the read lock, - * - * </ul> then {@link InterruptedException} is thrown and the - * current thread's interrupted status is cleared. - * - * <p>If the specified waiting time elapses then the value - * {@code false} is returned. If the time is less than or - * equal to zero, the method will not wait at all. - * - * <p>In this implementation, as this method is an explicit - * interruption point, preference is given to responding to - * the interrupt over normal or reentrant acquisition of the - * lock, and over reporting the elapse of the waiting time. - * - * @param timeout the time to wait for the read lock - * @param unit the time unit of the timeout argument - * @return {@code true} if the read lock was acquired - * @throws InterruptedException if the current thread is interrupted - * @throws NullPointerException if the time unit is null - * - */ - public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { - if (Thread.interrupted()) throw new InterruptedException(); - InterruptedException ie = null; - long nanos = unit.toNanos(timeout); - synchronized (this) { - if (nanos <= 0) - return lock.sync.startRead(); - else if (lock.sync.startReadFromNewReader()) - return true; - else { - long deadline = Utils.nanoTime() + nanos; - for (; ; ) { - try { - TimeUnit.NANOSECONDS.timedWait(ReadLock.this, nanos); - } - catch (InterruptedException ex) { - lock.sync.cancelledWaitingReader(); - ie = ex; - break; - } - if (lock.sync.startReadFromWaitingReader()) - return true; - else { - nanos = deadline - Utils.nanoTime(); - if (nanos <= 0) { - lock.sync.cancelledWaitingReader(); - break; - } - } - } - } - } - // safeguard on interrupt or timeout: - lock.writerLock_.signalWaiters(); - if (ie != null) - throw ie; - else - return false; // timed out - } - - /** - * Attempts to release this lock. - * - * <p> If the number of readers is now zero then the lock - * is made available for write lock attempts. - */ - public void unlock() { - switch (lock.sync.endRead()) { - case Sync.NONE: return; - case Sync.READER: lock.readerLock_.signalWaiters(); return; - case Sync.WRITER: lock.writerLock_.signalWaiters(); return; - } - } - - /** - * Throws {@code UnsupportedOperationException} because - * {@code ReadLocks} do not support conditions. - * - * @throws UnsupportedOperationException always - */ - public Condition newCondition() { - throw new UnsupportedOperationException(); - } - - synchronized void signalWaiters() { - notifyAll(); - } - - /** - * Returns a string identifying this lock, as well as its lock state. - * The state, in brackets, includes the String {@code "Read locks ="} - * followed by the number of held read locks. - * - * @return a string identifying this lock, as well as its lock state - */ - public String toString() { - int r = lock.getReadLockCount(); - return super.toString() + - "[Read locks = " + r + "]"; - } - - } - - /** - * The lock returned by method {@link ReentrantReadWriteLock#writeLock}. - */ - public static class WriteLock implements Lock, CondVar.ExclusiveLock, - java.io.Serializable { - - private static final long serialVersionUID = -4992448646407690164L; - final ReentrantReadWriteLock lock; - - /** - * Constructor for use by subclasses - * - * @param lock the outer lock object - * @throws NullPointerException if the lock is null - */ - protected WriteLock(ReentrantReadWriteLock lock) { - if (lock == null) throw new NullPointerException(); - this.lock = lock; - } - - /** - * Acquires the write lock. - * - * <p>Acquires the write lock if neither the read nor write lock - * are held by another thread - * and returns immediately, setting the write lock hold count to - * one. - * - * <p>If the current thread already holds the write lock then the - * hold count is incremented by one and the method returns - * immediately. - * - * <p>If the lock is held by another thread then the current - * thread becomes disabled for thread scheduling purposes and - * lies dormant until the write lock has been acquired, at which - * time the write lock hold count is set to one. - */ - public void lock() { - synchronized (this) { - if (lock.sync.startWriteFromNewWriter()) return; - boolean wasInterrupted = Thread.interrupted(); - try { - while (true) { - try { - WriteLock.this.wait(); - } - catch (InterruptedException ex) { - wasInterrupted = true; - // no need to notify; if we were notified, - // we will act as notified, and succeed in - // startWrite and return - } - if (lock.sync.startWriteFromWaitingWriter()) return; - } - } - finally { - if (wasInterrupted) Thread.currentThread().interrupt(); - } - } - } - - /** - * Acquires the write lock unless the current thread is - * {@linkplain Thread#interrupt interrupted}. - * - * <p>Acquires the write lock if neither the read nor write lock - * are held by another thread - * and returns immediately, setting the write lock hold count to - * one. - * - * <p>If the current thread already holds this lock then the - * hold count is incremented by one and the method returns - * immediately. - * - * <p>If the lock is held by another thread then the current - * thread becomes disabled for thread scheduling purposes and - * lies dormant until one of two things happens: - * - * <ul> - * - * <li>The write lock is acquired by the current thread; or - * - * <li>Some other thread {@linkplain Thread#interrupt interrupts} - * the current thread. - * - * </ul> - * - * <p>If the write lock is acquired by the current thread then the - * lock hold count is set to one. - * - * <p>If the current thread: - * - * <ul> - * - * <li>has its interrupted status set on entry to this method; - * or - * - * <li>is {@linkplain Thread#interrupt interrupted} while - * acquiring the write lock, - * - * </ul> - * - * then {@link InterruptedException} is thrown and the current - * thread's interrupted status is cleared. - * - * <p>In this implementation, as this method is an explicit - * interruption point, preference is given to responding to - * the interrupt over normal or reentrant acquisition of the - * lock. - * - * @throws InterruptedException if the current thread is interrupted - */ - public void lockInterruptibly() throws InterruptedException { - if (Thread.interrupted()) throw new InterruptedException(); - InterruptedException ie = null; - synchronized (this) { - if (!lock.sync.startWriteFromNewWriter()) { - for (; ; ) { - try { - WriteLock.this.wait(); - if (lock.sync.startWriteFromWaitingWriter()) - return; - } - catch (InterruptedException ex) { - lock.sync.cancelledWaitingWriter(); - WriteLock.this.notify(); - ie = ex; - break; - } - } - } - } - if (ie != null) { - // Fall through outside synch on interrupt. - // On exception, we may need to signal readers. - // It is not worth checking here whether it is strictly necessary. - lock.readerLock_.signalWaiters(); - throw ie; - } - } - - /** - * Acquires the write lock only if it is not held by another thread - * at the time of invocation. - * - * <p>Acquires the write lock if neither the read nor write lock - * are held by another thread - * and returns immediately with the value {@code true}, - * setting the write lock hold count to one. Even when this lock has - * been set to use a fair ordering policy, a call to - * {@code tryLock()} <em>will</em> immediately acquire the - * lock if it is available, whether or not other threads are - * currently waiting for the write lock. This "barging" - * behavior can be useful in certain circumstances, even - * though it breaks fairness. If you want to honor the - * fairness setting for this lock, then use {@link - * #tryLock(long, TimeUnit) tryLock(0, TimeUnit.SECONDS) } - * which is almost equivalent (it also detects interruption). - * - * <p> If the current thread already holds this lock then the - * hold count is incremented by one and the method returns - * {@code true}. - * - * <p>If the lock is held by another thread then this method - * will return immediately with the value {@code false}. - * - * @return {@code true} if the lock was free and was acquired - * by the current thread, or the write lock was already held - * by the current thread; and {@code false} otherwise. - */ - public boolean tryLock() { - return lock.sync.startWrite(); - } - - /** - * Acquires the write lock if it is not held by another thread - * within the given waiting time and the current thread has - * not been {@linkplain Thread#interrupt interrupted}. - * - * <p>Acquires the write lock if neither the read nor write lock - * are held by another thread - * and returns immediately with the value {@code true}, - * setting the write lock hold count to one. If this lock has been - * set to use a fair ordering policy then an available lock - * <em>will not</em> be acquired if any other threads are - * waiting for the write lock. This is in contrast to the {@link - * #tryLock()} method. If you want a timed {@code tryLock} - * that does permit barging on a fair lock then combine the - * timed and un-timed forms together: - * - * <pre>if (lock.tryLock() || lock.tryLock(timeout, unit) ) { ... } - * </pre> - * - * <p>If the current thread already holds this lock then the - * hold count is incremented by one and the method returns - * {@code true}. - * - * <p>If the lock is held by another thread then the current - * thread becomes disabled for thread scheduling purposes and - * lies dormant until one of three things happens: - * - * <ul> - * - * <li>The write lock is acquired by the current thread; or - * - * <li>Some other thread {@linkplain Thread#interrupt interrupts} - * the current thread; or - * - * <li>The specified waiting time elapses - * - * </ul> - * - * <p>If the write lock is acquired then the value {@code true} is - * returned and the write lock hold count is set to one. - * - * <p>If the current thread: - * - * <ul> - * - * <li>has its interrupted status set on entry to this method; - * or - * - * <li>is {@linkplain Thread#interrupt interrupted} while - * acquiring the write lock, - * - * </ul> - * - * then {@link InterruptedException} is thrown and the current - * thread's interrupted status is cleared. - * - * <p>If the specified waiting time elapses then the value - * {@code false} is returned. If the time is less than or - * equal to zero, the method will not wait at all. - * - * <p>In this implementation, as this method is an explicit - * interruption point, preference is given to responding to - * the interrupt over normal or reentrant acquisition of the - * lock, and over reporting the elapse of the waiting time. - * - * @param timeout the time to wait for the write lock - * @param unit the time unit of the timeout argument - * - * @return {@code true} if the lock was free and was acquired - * by the current thread, or the write lock was already held by the - * current thread; and {@code false} if the waiting time - * elapsed before the lock could be acquired. - * - * @throws InterruptedException if the current thread is interrupted - * @throws NullPointerException if the time unit is null - * - */ - public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { - if (Thread.interrupted()) throw new InterruptedException(); - InterruptedException ie = null; - long nanos = unit.toNanos(timeout); - synchronized (this) { - if (nanos <= 0) - return lock.sync.startWrite(); - else if (lock.sync.startWriteFromNewWriter()) - return true; - else { - long deadline = Utils.nanoTime() + nanos; - for (; ; ) { - try { - TimeUnit.NANOSECONDS.timedWait(WriteLock.this, nanos); - } - catch (InterruptedException ex) { - lock.sync.cancelledWaitingWriter(); - WriteLock.this.notify(); - ie = ex; - break; - } - if (lock.sync.startWriteFromWaitingWriter()) - return true; - else { - nanos = deadline - Utils.nanoTime(); - if (nanos <= 0) { - lock.sync.cancelledWaitingWriter(); - WriteLock.this.notify(); - break; - } - } - } - } - } - - lock.readerLock_.signalWaiters(); - if (ie != null) - throw ie; - else - return false; // timed out - } - - /** - * Attempts to release this lock. - * - * <p>If the current thread is the holder of this lock then - * the hold count is decremented. If the hold count is now - * zero then the lock is released. If the current thread is - * not the holder of this lock then {@link - * IllegalMonitorStateException} is thrown. - * - * @throws IllegalMonitorStateException if the current thread does not - * hold this lock. - */ - public void unlock() { - switch (lock.sync.endWrite()) { - case Sync.NONE: return; - case Sync.READER: lock.readerLock_.signalWaiters(); return; - case Sync.WRITER: lock.writerLock_.signalWaiters(); return; - } - } - - /** - * Returns a {@link Condition} instance for use with this - * {@link Lock} instance. - * <p>The returned {@link Condition} instance supports the same - * usages as do the {@link Object} monitor methods ({@link - * Object#wait() wait}, {@link Object#notify notify}, and {@link - * Object#notifyAll notifyAll}) when used with the built-in - * monitor lock. - * - * <ul> - * - * <li>If this write lock is not held when any {@link - * Condition} method is called then an {@link - * IllegalMonitorStateException} is thrown. (Read locks are - * held independently of write locks, so are not checked or - * affected. However it is essentially always an error to - * invoke a condition waiting method when the current thread - * has also acquired read locks, since other threads that - * could unblock it will not be able to acquire the write - * lock.) - * - * <li>When the condition {@linkplain Condition#await() waiting} - * methods are called the write lock is released and, before - * they return, the write lock is reacquired and the lock hold - * count restored to what it was when the method was called. - * - * <li>If a thread is {@linkplain Thread#interrupt interrupted} while - * waiting then the wait will terminate, an {@link - * InterruptedException} will be thrown, and the thread's - * interrupted status will be cleared. - * - * <li> Waiting threads are signalled in FIFO order. - * - * <li>The ordering of lock reacquisition for threads returning - * from waiting methods is the same as for threads initially - * acquiring the lock, which is in the default case not specified, - * but for <em>fair</em> locks favors those threads that have been - * waiting the longest. - * - * </ul> - * - * @return the Condition object - */ - public Condition newCondition() { - return new CondVar(this); - } - - synchronized void signalWaiters() { - notify(); - } - - /** - * Returns a string identifying this lock, as well as its lock - * state. The state, in brackets includes either the String - * {@code "Unlocked"} or the String {@code "Locked by"} - * followed by the {@linkplain Thread#getName name} of the owning thread. - * - * @return a string identifying this lock, as well as its lock state - */ - public String toString() { - Thread o = lock.getOwner(); - return super.toString() + ((o == null) ? - "[Unlocked]" : - "[Locked by thread " + o.getName() + "]"); - } - - /** - * Queries if this write lock is held by the current thread. - * Identical in effect to {@link - * ReentrantReadWriteLock#isWriteLockedByCurrentThread}. - * - * @return {@code true} if the current thread holds this lock and - * {@code false} otherwise - * @since 1.6 - */ - public boolean isHeldByCurrentThread() { - return lock.sync.isWriteLockedByCurrentThread(); - } - - /** - * Queries the number of holds on this write lock by the current - * thread. A thread has a hold on a lock for each lock action - * that is not matched by an unlock action. Identical in effect - * to {@link ReentrantReadWriteLock#getWriteHoldCount}. - * - * @return the number of holds on this lock by the current thread, - * or zero if this lock is not held by the current thread - * @since 1.6 - */ - public int getHoldCount() { - return lock.sync.getWriteHoldCount(); - } - - } - - // Instrumentation and status - - /** - * Returns {@code true} if this lock has fairness set true. - * - * @return {@code true} if this lock has fairness set true - */ - public final boolean isFair() { - return false; - } - - /** - * Returns the thread that currently owns the write lock, or - * {@code null} if not owned. When this method is called by a - * thread that is not the owner, the return value reflects a - * best-effort approximation of current lock status. For example, - * the owner may be momentarily {@code null} even if there are - * threads trying to acquire the lock but have not yet done so. - * This method is designed to facilitate construction of - * subclasses that provide more extensive lock monitoring - * facilities. - * - * @return the owner, or {@code null} if not owned - */ - protected Thread getOwner() { - return sync.getOwner(); - } - - /** - * Queries the number of read locks held for this lock. This - * method is designed for use in monitoring system state, not for - * synchronization control. - * @return the number of read locks held. - */ - public int getReadLockCount() { - return sync.getReadLockCount(); - } - - /** - * Queries if the write lock is held by any thread. This method is - * designed for use in monitoring system state, not for - * synchronization control. - * - * @return {@code true} if any thread holds the write lock and - * {@code false} otherwise - */ - public boolean isWriteLocked() { - return sync.isWriteLocked(); - } - - /** - * Queries if the write lock is held by the current thread. - * - * @return {@code true} if the current thread holds the write lock and - * {@code false} otherwise - */ - public boolean isWriteLockedByCurrentThread() { - return sync.isWriteLockedByCurrentThread(); - } - - /** - * Queries the number of reentrant write holds on this lock by the - * current thread. A writer thread has a hold on a lock for - * each lock action that is not matched by an unlock action. - * - * @return the number of holds on the write lock by the current thread, - * or zero if the write lock is not held by the current thread - */ - public int getWriteHoldCount() { - return sync.getWriteHoldCount(); - } - - /** - * Queries the number of reentrant read holds on this lock by the - * current thread. A reader thread has a hold on a lock for - * each lock action that is not matched by an unlock action. - * - * @return the number of holds on the read lock by the current thread, - * or zero if the read lock is not held by the current thread - * @since 1.6 - */ - public int getReadHoldCount() { - return sync.getReadHoldCount(); - } - - -// /** -// * Returns a collection containing threads that may be waiting to -// * acquire the write lock. Because the actual set of threads may -// * change dynamically while constructing this result, the returned -// * collection is only a best-effort estimate. The elements of the -// * returned collection are in no particular order. This method is -// * designed to facilitate construction of subclasses that provide -// * more extensive lock monitoring facilities. -// * @return the collection of threads -// */ -// protected Collection getQueuedWriterThreads() { -// return sync.getExclusiveQueuedThreads(); -// } -// -// /** -// * Returns a collection containing threads that may be waiting to -// * acquire the read lock. Because the actual set of threads may -// * change dynamically while constructing this result, the returned -// * collection is only a best-effort estimate. The elements of the -// * returned collection are in no particular order. This method is -// * designed to facilitate construction of subclasses that provide -// * more extensive lock monitoring facilities. -// * @return the collection of threads -// */ -// protected Collection getQueuedReaderThreads() { -// return sync.getSharedQueuedThreads(); -// } -// - /** - * Queries whether any threads are waiting to acquire the read or - * write lock. Note that because cancellations may occur at any - * time, a {@code true} return does not guarantee that any other - * thread will ever acquire a lock. This method is designed - * primarily for use in monitoring of the system state. - * - * @return {@code true} if there may be other threads waiting to - * acquire the lock - */ - public final boolean hasQueuedThreads() { - return sync.hasQueuedThreads(); - } -// -// /** -// * Queries whether the given thread is waiting to acquire either -// * the read or write lock. Note that because cancellations may -// * occur at any time, a <tt>true</tt> return does not guarantee -// * that this thread will ever acquire a lock. This method is -// * designed primarily for use in monitoring of the system state. -// * -// * @param thread the thread -// * @return true if the given thread is queued waiting for this lock. -// * @throws NullPointerException if thread is null -// */ -// public final boolean hasQueuedThread(Thread thread) { -// return sync.isQueued(thread); -// } - - /** - * Returns an estimate of the number of threads waiting to acquire - * either the read or write lock. The value is only an estimate - * because the number of threads may change dynamically while this - * method traverses internal data structures. This method is - * designed for use in monitoring of the system state, not for - * synchronization control. - * - * @return the estimated number of threads waiting for this lock - */ - public final int getQueueLength() { - return sync.getQueueLength(); - } - -// /** -// * Returns a collection containing threads that may be waiting to -// * acquire either the read or write lock. Because the actual set -// * of threads may change dynamically while constructing this -// * result, the returned collection is only a best-effort estimate. -// * The elements of the returned collection are in no particular -// * order. This method is designed to facilitate construction of -// * subclasses that provide more extensive monitoring facilities. -// * @return the collection of threads -// */ -// protected Collection getQueuedThreads() { -// return sync.getQueuedThreads(); -// } -// -// /** -// * Queries whether any threads are waiting on the given condition -// * associated with the write lock. Note that because timeouts and -// * interrupts may occur at any time, a <tt>true</tt> return does -// * not guarantee that a future <tt>signal</tt> will awaken any -// * threads. This method is designed primarily for use in -// * monitoring of the system state. -// * @param condition the condition -// * @return <tt>true</tt> if there are any waiting threads. -// * @throws IllegalMonitorStateException if this lock -// * is not held -// * @throws IllegalArgumentException if the given condition is -// * not associated with this lock -// * @throws NullPointerException if condition null -// */ -// public boolean hasWaiters(Condition condition) { -// if (condition == null) -// throw new NullPointerException(); -// if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject)) -// throw new IllegalArgumentException("not owner"); -// return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject)condition); -// } - -// /** -// * Returns an estimate of the number of threads waiting on the -// * given condition associated with the write lock. Note that because -// * timeouts and interrupts may occur at any time, the estimate -// * serves only as an upper bound on the actual number of waiters. -// * This method is designed for use in monitoring of the system -// * state, not for synchronization control. -// * @param condition the condition -// * @return the estimated number of waiting threads. -// * @throws IllegalMonitorStateException if this lock -// * is not held -// * @throws IllegalArgumentException if the given condition is -// * not associated with this lock -// * @throws NullPointerException if condition null -// */ -// public int getWaitQueueLength(Condition condition) { -// if (condition == null) -// throw new NullPointerException(); -// if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject)) -// throw new IllegalArgumentException("not owner"); -// return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject)condition); -// } -// -// /** -// * Returns a collection containing those threads that may be -// * waiting on the given condition associated with the write lock. -// * Because the actual set of threads may change dynamically while -// * constructing this result, the returned collection is only a -// * best-effort estimate. The elements of the returned collection -// * are in no particular order. This method is designed to -// * facilitate construction of subclasses that provide more -// * extensive condition monitoring facilities. -// * @param condition the condition -// * @return the collection of threads -// * @throws IllegalMonitorStateException if this lock -// * is not held -// * @throws IllegalArgumentException if the given condition is -// * not associated with this lock -// * @throws NullPointerException if condition null -// */ -// protected Collection getWaitingThreads(Condition condition) { -// if (condition == null) -// throw new NullPointerException(); -// if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject)) -// throw new IllegalArgumentException("not owner"); -// return sync.getWaitingThreads((AbstractQueuedSynchronizer.ConditionObject)condition); -// } - - /** - * Returns a string identifying this lock, as well as its lock state. - * The state, in brackets, includes the String {@code "Write locks ="} - * followed by the number of reentrantly held write locks, and the - * String {@code "Read locks ="} followed by the number of held - * read locks. - * - * @return a string identifying this lock, as well as its lock state - */ - public String toString() { - return super.toString() + - "[Write locks = " + getWriteHoldCount() + - ", Read locks = " + getReadLockCount() + "]"; - } -} diff --git a/src/build/bnd/scala-actors.bnd b/src/build/bnd/scala-actors.bnd deleted file mode 100644 index 69885fc2bf..0000000000 --- a/src/build/bnd/scala-actors.bnd +++ /dev/null @@ -1,7 +0,0 @@ -Bundle-Name: Scala Actors -Bundle-SymbolicName: org.scala-lang.scala-actors -ver: @VERSION@ -Bundle-Version: ${ver} -Export-Package: *;version=${ver} -Import-Package: scala.*;version="${range;[==,=+);${ver}}",* -Bundle-RequiredExecutionEnvironment: JavaSE-1.6, JavaSE-1.7 diff --git a/src/build/bnd/scala-continuations-library.bnd b/src/build/bnd/scala-continuations-library.bnd deleted file mode 100644 index b36718cc5b..0000000000 --- a/src/build/bnd/scala-continuations-library.bnd +++ /dev/null @@ -1,7 +0,0 @@ -Bundle-Name: Scala Delimited Continuations Library -Bundle-SymbolicName: org.scala-lang.plugins.scala-continuations-library -ver: @CONTINUATIONS_LIBRARY_VERSION@ -Bundle-Version: ${ver} -Export-Package: *;version=${ver} -Import-Package: scala.*;version="${range;[==,=+);@VERSION@}",* -Bundle-RequiredExecutionEnvironment: JavaSE-1.6, JavaSE-1.7 diff --git a/src/build/bnd/scala-continuations-plugin.bnd b/src/build/bnd/scala-continuations-plugin.bnd deleted file mode 100644 index 2f2464b452..0000000000 --- a/src/build/bnd/scala-continuations-plugin.bnd +++ /dev/null @@ -1,7 +0,0 @@ -Bundle-Name: Scala Delimited Continuations Compiler Plugin -Bundle-SymbolicName: org.scala-lang.plugins.scala-continuations-plugin -ver: @CONTINUATIONS_PLUGIN_VERSION@ -Bundle-Version: ${ver} -Export-Package: *;version=${ver} -Import-Package: scala.*;version="${range;[==,=+);@VERSION@}",* -Bundle-RequiredExecutionEnvironment: JavaSE-1.6, JavaSE-1.7 diff --git a/src/build/dbuild-meta-json-gen.scala b/src/build/dbuild-meta-json-gen.scala index d1d4c12b3f..f967fffdd0 100644 --- a/src/build/dbuild-meta-json-gen.scala +++ b/src/build/dbuild-meta-json-gen.scala @@ -1,13 +1,19 @@ -// use this script to generate dbuild-meta.json -// make sure the version is specified correctly, -// update the dependency structure and -// check out distributed-build and run `sbt console`: -// TODO: also generate build.xml and eclipse config from a similar data-structure +// Use this script to generate dbuild-meta.json -import distributed.project.model._ +// To generate the file: +// - check out https://github.com/typesafehub/dbuild +// - run `sbt metadata/console` +// - paste the code below + +// The `version` field is required for the ProjMeta data structure. However, dbuild will +// overwrite the version specified here with the version number found in the build.number +// file, so the actual value doesn't matter, see ScalaBuildSystem: +// https://github.com/typesafehub/dbuild/blob/25b087759cc52876712c594ea4172148beea1310/support/src/main/scala/com/typesafe/dbuild/support/scala/ScalaBuildSystem.scala#L351 + +import com.typesafe.dbuild.model._ val meta = - ExtractedBuildMeta("2.11.0", Seq( + ProjMeta(version = "2.12.0", projects = Seq( Project("scala-library", "org.scala-lang", Seq(ProjectRef("scala-library", "org.scala-lang")), Seq.empty), // TODO: forkjoin @@ -19,7 +25,6 @@ val meta = Seq(ProjectRef("scala-reflect", "org.scala-lang"), ProjectRef("scala-xml", "org.scala-lang.modules"), ProjectRef("scala-parser-combinators", "org.scala-lang.modules") - // asm )), // Project("scala-repl", "org.scala-lang", @@ -30,10 +35,6 @@ val meta = // Seq(ProjectRef("scala-interactive", "org.scala-lang")), // Seq(ProjectRef("scala-compiler", "org.scala-lang"), ProjectRef("scaladoc", "org.scala-lang"))), - Project("scala-actors", "org.scala-lang", - Seq(ProjectRef("scala-actors", "org.scala-lang")), - Seq(ProjectRef("scala-library", "org.scala-lang"))), - // Project("scaladoc", "org.scala-lang", // Seq(ProjectRef("scaladoc", "org.scala-lang")), // Seq(ProjectRef("scala-compiler", "org.scala-lang"),ProjectRef("scala-partest", "org.scala-lang"), ProjectRef("scala-xml", "org.scala-lang"), ProjectRef("scala-parser-combinators", "org.scala-lang"))), @@ -44,4 +45,4 @@ val meta = )) -println(Utils.writeValue(meta)) +println(Utils.writeValueFormatted(meta)) diff --git a/src/build/maven/scala-actors-pom.xml b/src/build/maven/scala-actors-pom.xml deleted file mode 100644 index a0ebcecad1..0000000000 --- a/src/build/maven/scala-actors-pom.xml +++ /dev/null @@ -1,51 +0,0 @@ -<?xml version="1.0"?> -<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> - <modelVersion>4.0.0</modelVersion> - <groupId>org.scala-lang</groupId> - <artifactId>scala-actors</artifactId> - <packaging>jar</packaging> - <version>@VERSION@</version> - <name>Scala Actors library</name> - <description>Deprecated Actors Library for Scala</description> - <url>http://www.scala-lang.org/</url> - <inceptionYear>2006</inceptionYear> - <organization> - <name>LAMP/EPFL</name> - <url>http://lamp.epfl.ch/</url> - </organization> - <licenses> - <license> - <name>BSD 3-Clause</name> - <url>http://www.scala-lang.org/license.html</url> - <distribution>repo</distribution> - </license> - </licenses> - <scm> - <connection>scm:git:git://github.com/scala/scala.git</connection> - <url>https://github.com/scala/scala.git</url> - </scm> - <issueManagement> - <system>JIRA</system> - <url>https://issues.scala-lang.org/</url> - </issueManagement> - <properties> - <info.apiURL>http://www.scala-lang.org/api/@VERSION@/</info.apiURL> - </properties> - <dependencies> - <dependency> - <groupId>org.scala-lang</groupId> - <artifactId>scala-library</artifactId> - <version>@VERSION@</version> - </dependency> - </dependencies> - <developers> - <developer> - <id>lamp</id> - <name>EPFL LAMP</name> - </developer> - <developer> - <id>Typesafe</id> - <name>Typesafe, Inc.</name> - </developer> - </developers> -</project> diff --git a/src/build/maven/scala-dist-pom.xml b/src/build/maven/scala-dist-pom.xml index 9477e14285..1f6b6710ac 100644 --- a/src/build/maven/scala-dist-pom.xml +++ b/src/build/maven/scala-dist-pom.xml @@ -44,12 +44,6 @@ <artifactId>scalap</artifactId> <version>@VERSION@</version> </dependency> - <dependency> - <groupId>org.scala-lang.plugins</groupId> - <!-- plugins are fully cross-versioned. But, we don't publish with 2.11.0-SNAPSHOT, instead use full version of the last non-snapshot version --> - <artifactId>scala-continuations-plugin_@SCALA_FULL_VERSION@</artifactId> - <version>@CONTINUATIONS_PLUGIN_VERSION@</version> - </dependency> <!-- duplicated from scala-compiler, where it's optional, so that resolving scala-dist's transitive dependencies does not include jline, even though we need to include it in the dist, but macros depending on the compiler diff --git a/src/build/maven/scala-library-all-pom.xml b/src/build/maven/scala-library-all-pom.xml index 3fcf207559..074c067742 100644 --- a/src/build/maven/scala-library-all-pom.xml +++ b/src/build/maven/scala-library-all-pom.xml @@ -49,31 +49,11 @@ <artifactId>scala-parser-combinators_@SCALA_BINARY_VERSION@</artifactId> <version>@PARSER_COMBINATORS_VERSION@</version> </dependency> - <!-- - the continuations plugin is a dependency of scala-dist, as scala-library-all should be - a drop-in replacement for scala-library, and as such should not (indirectly) - depend on plugins/the compiler. - --> - <dependency> - <groupId>org.scala-lang.plugins</groupId> - <artifactId>scala-continuations-library_@SCALA_BINARY_VERSION@</artifactId> - <version>@CONTINUATIONS_LIBRARY_VERSION@</version> - </dependency> <dependency> <groupId>org.scala-lang.modules</groupId> <artifactId>scala-swing_@SCALA_BINARY_VERSION@</artifactId> <version>@SCALA_SWING_VERSION@</version> </dependency> - <dependency> - <groupId>com.typesafe.akka</groupId> - <artifactId>akka-actor_@SCALA_BINARY_VERSION@</artifactId> - <version>@AKKA_ACTOR_VERSION@</version> - </dependency> - <dependency> - <groupId>org.scala-lang</groupId> - <artifactId>scala-actors-migration_@SCALA_BINARY_VERSION@</artifactId> - <version>@ACTORS_MIGRATION_VERSION@</version> - </dependency> </dependencies> <developers> <developer> diff --git a/src/compiler/scala/tools/cmd/Property.scala b/src/compiler/scala/tools/cmd/Property.scala index b1d951a5c4..e6262a7e40 100644 --- a/src/compiler/scala/tools/cmd/Property.scala +++ b/src/compiler/scala/tools/cmd/Property.scala @@ -9,6 +9,7 @@ package cmd import nsc.io._ import java.util.Properties import java.io.FileInputStream +import scala.sys.SystemProperties /** Contains logic for translating a property key/value pair into * equivalent command line arguments. The default settings will @@ -58,7 +59,7 @@ trait Property extends Reference { returning(new Properties)(_ load new FileInputStream(file.path)) def systemPropertiesToOptions: List[String] = - propertiesToOptions(System.getProperties) + propertiesToOptions(new SystemProperties().toList) def propertiesToOptions(file: File): List[String] = propertiesToOptions(loadProperties(file)) diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 3469726455..778f2fed59 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -1378,8 +1378,11 @@ class Global(var currentSettings: Settings, var reporter: Reporter) settings.userSetSettings filter (_.isDeprecated) foreach { s => currentRun.reporting.deprecationWarning(NoPosition, s.name + " is deprecated: " + s.deprecationMessage.get) } - if (settings.target.value.contains("jvm-1.5")) - currentRun.reporting.deprecationWarning(NoPosition, settings.target.name + ":" + settings.target.value + " is deprecated: use target for Java 1.6 or above.") + val supportedTarget = "jvm-1.8" + if (settings.target.value != supportedTarget) { + currentRun.reporting.deprecationWarning(NoPosition, settings.target.name + ":" + settings.target.value + " is deprecated and has no effect, setting to " + supportedTarget) + settings.target.value = supportedTarget + } } /* An iterator returning all the units being compiled in this run */ diff --git a/src/compiler/scala/tools/nsc/ast/DocComments.scala b/src/compiler/scala/tools/nsc/ast/DocComments.scala index 6442ef2d54..c70690e697 100755 --- a/src/compiler/scala/tools/nsc/ast/DocComments.scala +++ b/src/compiler/scala/tools/nsc/ast/DocComments.scala @@ -129,25 +129,6 @@ trait DocComments { self: Global => getDocComment(sym) map getUseCases getOrElse List() } - private val wikiReplacements = List( - ("""(\n\s*\*?)(\s*\n)""" .r, """$1 <p>$2"""), - ("""<([^\w/])""" .r, """<$1"""), - ("""([^\w/])>""" .r, """$1>"""), - ("""\{\{\{(.*(?:\n.*)*)\}\}\}""".r, """<pre>$1</pre>"""), - ("""`([^`]*)`""" .r, """<code>$1</code>"""), - ("""__([^_]*)__""" .r, """<u>$1</u>"""), - ("""''([^']*)''""" .r, """<i>$1</i>"""), - ("""'''([^']*)'''""" .r, """<b>$1</b>"""), - ("""\^([^^]*)\^""" .r, """<sup>$1</sup>"""), - (""",,([^,]*),,""" .r, """<sub>$1</sub>""")) - - /** Returns just the wiki expansion (this would correspond to - * a comment in the input format of the JavaDoc tool, modulo differences - * in tags.) - */ - def expandWiki(str: String): String = - (str /: wikiReplacements) { (str1, regexRepl) => regexRepl._1 replaceAllIn(str1, regexRepl._2) } - private def getDocComment(sym: Symbol): Option[DocComment] = mapFind(sym :: allInheritedOverriddenSymbols(sym))(docComments get _) diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index 4f195c2985..b76fb3d823 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -665,6 +665,15 @@ self => } def isLiteral = isLiteralToken(in.token) + def isSimpleExprIntroToken(token: Token): Boolean = isLiteralToken(token) || (token match { + case IDENTIFIER | BACKQUOTED_IDENT | + THIS | SUPER | NEW | USCORE | + LPAREN | LBRACE | XMLSTART => true + case _ => false + }) + + def isSimpleExprIntro: Boolean = isExprIntroToken(in.token) + def isExprIntroToken(token: Token): Boolean = isLiteralToken(token) || (token match { case IDENTIFIER | BACKQUOTED_IDENT | THIS | SUPER | IF | FOR | NEW | USCORE | TRY | WHILE | @@ -1565,11 +1574,14 @@ self => def prefixExpr(): Tree = { if (isUnaryOp) { atPos(in.offset) { - val name = nme.toUnaryName(rawIdent().toTermName) - if (name == nme.UNARY_- && isNumericLit) - simpleExprRest(literal(isNegated = true), canApply = true) - else - Select(stripParens(simpleExpr()), name) + if (lookingAhead(isSimpleExprIntro)) { + val uname = nme.toUnaryName(rawIdent().toTermName) + if (uname == nme.UNARY_- && isNumericLit) + simpleExprRest(literal(isNegated = true), canApply = true) + else + Select(stripParens(simpleExpr()), uname) + } + else simpleExpr() } } else simpleExpr() diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala index 3e23291e92..01eff71057 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala @@ -1145,7 +1145,7 @@ abstract class GenICode extends SubComponent { // a package here, check if there's a package object. val sym = ( if (!tree.symbol.isPackageClass) tree.symbol - else tree.symbol.info.member(nme.PACKAGE) match { + else tree.symbol.info.packageObject match { case NoSymbol => abort("Cannot use package as value: " + tree) case s => devWarning(s"Found ${tree.symbol} where a package object is required. Converting to ${s.moduleClass}") @@ -1502,7 +1502,7 @@ abstract class GenICode extends SubComponent { if (!settings.optimise) { if (l.tpe <:< BoxedNumberClass.tpe) { if (r.tpe <:< BoxedNumberClass.tpe) platform.externalEqualsNumNum - else if (r.tpe <:< BoxedCharacterClass.tpe) platform.externalEqualsNumObject // will be externalEqualsNumChar in 2.12, SI-9030 + else if (r.tpe <:< BoxedCharacterClass.tpe) platform.externalEqualsNumChar else platform.externalEqualsNumObject } else platform.externalEquals } else { diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala index 40ba0c010b..c3f71969f6 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala @@ -842,7 +842,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder { * loading another throwable first). * * New (http://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.10.1) - * - Requires consistent stack map frames. GenBCode generates stack frames if -target:jvm-1.6 + * - Requires consistent stack map frames. GenBCode always generates stack frames. * or higher. * - In practice: the ASM library computes stack map frames for us (ClassWriter). Emitting * correct frames after an ATHROW is probably complex, so ASM uses the following strategy: @@ -921,7 +921,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder { def genLoadModule(tree: Tree): BType = { val module = ( if (!tree.symbol.isPackageClass) tree.symbol - else tree.symbol.info.member(nme.PACKAGE) match { + else tree.symbol.info.packageObject match { case NoSymbol => abort(s"SI-5604: Cannot use package as value: $tree") case s => abort(s"SI-5604: found package class where package object expected: $tree") } @@ -1231,7 +1231,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder { val equalsMethod: Symbol = { if (l.tpe <:< BoxedNumberClass.tpe) { if (r.tpe <:< BoxedNumberClass.tpe) platform.externalEqualsNumNum - else if (r.tpe <:< BoxedCharacterClass.tpe) platform.externalEqualsNumObject // will be externalEqualsNumChar in 2.12, SI-9030 + else if (r.tpe <:< BoxedCharacterClass.tpe) platform.externalEqualsNumChar else platform.externalEqualsNumObject } else platform.externalEquals } diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala index 6aa3a62295..23e0a4e17a 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala @@ -329,7 +329,8 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters { // If the `sym` is a java module class, we use the java class instead. This ensures that we // register the class (instead of the module class) in innerClassBufferASM. // The two symbols have the same name, so the resulting internalName is the same. - val classSym = if (sym.isJavaDefined && sym.isModuleClass) sym.linkedClassOfClass else sym + // Phase travel (exitingPickler) required for SI-6613 - linkedCoC is only reliable in early phases (nesting) + val classSym = if (sym.isJavaDefined && sym.isModuleClass) exitingPickler(sym.linkedClassOfClass) else sym getClassBTypeAndRegisterInnerClass(classSym).internalName } diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeIdiomatic.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeIdiomatic.scala index eb0da7caef..535e1a8620 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeIdiomatic.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeIdiomatic.scala @@ -28,9 +28,6 @@ abstract class BCodeIdiomatic extends SubComponent { import coreBTypes._ val classfileVersion: Int = settings.target.value match { - case "jvm-1.5" => asm.Opcodes.V1_5 - case "jvm-1.6" => asm.Opcodes.V1_6 - case "jvm-1.7" => asm.Opcodes.V1_7 case "jvm-1.8" => asm.Opcodes.V1_8 } diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala index 71686fd9d7..ccad50616c 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala @@ -441,9 +441,6 @@ abstract class GenASM extends SubComponent with BytecodeWriters { self => // ----------------------------------------------------------------------------------------- private val classfileVersion: Int = settings.target.value match { - case "jvm-1.5" => asm.Opcodes.V1_5 - case "jvm-1.6" => asm.Opcodes.V1_6 - case "jvm-1.7" => asm.Opcodes.V1_7 case "jvm-1.8" => asm.Opcodes.V1_8 } diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala index 455117d837..16e8aee1dd 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala @@ -247,6 +247,9 @@ abstract class GenBCode extends BCodeSyncAndTry { localOptimizations(item.plain) addToQ3(item) } catch { + case e: java.lang.RuntimeException if e.getMessage != null && (e.getMessage contains "too large!") => + reporter.error(NoPosition, + s"Could not write class ${item.plain.name} because it exceeds JVM code size limits. ${e.getMessage}") case ex: Throwable => ex.printStackTrace() error(s"Error while emitting ${item.plain.name}\n${ex.getMessage}") diff --git a/src/compiler/scala/tools/nsc/settings/AbsScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/AbsScalaSettings.scala index 6b339b2a6d..8386722b63 100644 --- a/src/compiler/scala/tools/nsc/settings/AbsScalaSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/AbsScalaSettings.scala @@ -31,6 +31,7 @@ trait AbsScalaSettings { def BooleanSetting(name: String, descr: String): BooleanSetting def ChoiceSetting(name: String, helpArg: String, descr: String, choices: List[String], default: String): ChoiceSetting + def ChoiceSettingForcedDefault(name: String, helpArg: String, descr: String, choices: List[String], default: String): ChoiceSetting def IntSetting(name: String, descr: String, default: Int, range: Option[(Int, Int)], parser: String => Option[Int]): IntSetting def MultiStringSetting(name: String, helpArg: String, descr: String): MultiStringSetting def MultiChoiceSetting[E <: MultiChoiceEnumeration](name: String, helpArg: String, descr: String, domain: E, default: Option[List[String]]): MultiChoiceSetting[E] diff --git a/src/compiler/scala/tools/nsc/settings/MutableSettings.scala b/src/compiler/scala/tools/nsc/settings/MutableSettings.scala index b4987e1240..9cc8faf8c2 100644 --- a/src/compiler/scala/tools/nsc/settings/MutableSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/MutableSettings.scala @@ -221,6 +221,13 @@ class MutableSettings(val errorFn: String => Unit) def BooleanSetting(name: String, descr: String) = add(new BooleanSetting(name, descr)) def ChoiceSetting(name: String, helpArg: String, descr: String, choices: List[String], default: String) = add(new ChoiceSetting(name, helpArg, descr, choices, default)) + def ChoiceSettingForcedDefault(name: String, helpArg: String, descr: String, choices: List[String], default: String) = + ChoiceSetting(name, helpArg, descr, choices, default).withPostSetHook(sett => + if (sett.value != default) { + sett.withDeprecationMessage(s"${name}:${sett.value} is deprecated, forcing use of $default") + sett.value = default + } + ) def IntSetting(name: String, descr: String, default: Int, range: Option[(Int, Int)], parser: String => Option[Int]) = add(new IntSetting(name, descr, default, range, parser)) def MultiStringSetting(name: String, arg: String, descr: String) = add(new MultiStringSetting(name, arg, descr)) diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala index 0cdece59e1..c9d97a9469 100644 --- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala @@ -222,9 +222,8 @@ trait ScalaSettings extends AbsScalaSettings val YdisableUnreachablePrevention = BooleanSetting("-Ydisable-unreachable-prevention", "Disable the prevention of unreachable blocks in code generation.") val YnoLoadImplClass = BooleanSetting ("-Yno-load-impl-class", "Do not load $class.class files.") - val exposeEmptyPackage = BooleanSetting("-Yexpose-empty-package", "Internal only: expose the empty package.").internalOnly() - // the current standard is "inline" but we are moving towards "method" - val Ydelambdafy = ChoiceSetting ("-Ydelambdafy", "strategy", "Strategy used for translating lambdas into JVM code.", List("inline", "method"), "inline") + val exposeEmptyPackage = BooleanSetting ("-Yexpose-empty-package", "Internal only: expose the empty package.").internalOnly() + val Ydelambdafy = ChoiceSetting ("-Ydelambdafy", "strategy", "Strategy used for translating lambdas into JVM code.", List("inline", "method"), "method") val YskipInlineInfoAttribute = BooleanSetting("-Yskip-inline-info-attribute", "Do not add the ScalaInlineInfo attribute to classfiles generated by -Ybackend:GenASM") @@ -357,7 +356,7 @@ trait ScalaSettings extends AbsScalaSettings */ val Ybackend = ChoiceSetting ("-Ybackend", "choice of bytecode emitter", "Choice of bytecode emitter.", List("GenASM", "GenBCode"), - "GenASM") + "GenBCode") // Feature extensions val XmacroSettings = MultiStringSetting("-Xmacro-settings", "option", "Custom settings for macros.") diff --git a/src/compiler/scala/tools/nsc/settings/ScalaVersion.scala b/src/compiler/scala/tools/nsc/settings/ScalaVersion.scala index 43bdad5882..7e67b7bec6 100644 --- a/src/compiler/scala/tools/nsc/settings/ScalaVersion.scala +++ b/src/compiler/scala/tools/nsc/settings/ScalaVersion.scala @@ -68,45 +68,39 @@ case object AnyScalaVersion extends ScalaVersion { * Factory methods for producing ScalaVersions */ object ScalaVersion { - private val dot = "\\." - private val dash = "\\-" - private def not(s:String) = s"[^${s}]" - private val R = s"((${not(dot)}*)(${dot}(${not(dot)}*)(${dot}(${not(dash)}*)(${dash}(.*))?)?)?)".r - - def apply(versionString : String, errorHandler: String => Unit): ScalaVersion = { - def errorAndValue() = { - errorHandler( - s"There was a problem parsing ${versionString}. " + - "Versions should be in the form major[.minor[.revision]] " + - "where each part is a positive number, as in 2.10.1. " + - "The minor and revision parts are optional." - ) - AnyScalaVersion - } + private val dot = """\.""" + private val dash = "-" + private val vchar = """\d""" //"[^-+.]" + private val vpat = s"(?s)($vchar+)(?:$dot($vchar+)(?:$dot($vchar+)(?:$dash(.*))?)?)?".r + private val rcpat = """(?i)rc(\d*)""".r + private val mspat = """(?i)m(\d*)""".r + + def apply(versionString: String, errorHandler: String => Unit): ScalaVersion = { + def error() = errorHandler( + s"There was a problem parsing ${versionString}. " + + "Versions should be in the form major[.minor[.revision]] " + + "where each part is a positive number, as in 2.10.1. " + + "The minor and revision parts are optional." + ) def toInt(s: String) = s match { case null | "" => 0 - case _ => s.toInt + case _ => s.toInt } - def isInt(s: String) = util.Try(toInt(s)).isSuccess - def toBuild(s: String) = s match { case null | "FINAL" => Final - case s if (s.toUpperCase.startsWith("RC") && isInt(s.substring(2))) => RC(toInt(s.substring(2))) - case s if (s.toUpperCase.startsWith("M") && isInt(s.substring(1))) => Milestone(toInt(s.substring(1))) - case _ => Development(s) + case rcpat(i) => RC(toInt(i)) + case mspat(i) => Milestone(toInt(i)) + case _ /* | "" */ => Development(s) } - try versionString match { + versionString match { case "none" => NoScalaVersion - case "any" => AnyScalaVersion - case R(_, majorS, _, minorS, _, revS, _, buildS) => + case "any" => AnyScalaVersion + case vpat(majorS, minorS, revS, buildS) => SpecificScalaVersion(toInt(majorS), toInt(minorS), toInt(revS), toBuild(buildS)) - case _ => - errorAndValue() - } catch { - case e: NumberFormatException => errorAndValue() + case _ => error() ; AnyScalaVersion } } diff --git a/src/compiler/scala/tools/nsc/settings/StandardScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/StandardScalaSettings.scala index d42c0dd730..f197a4930d 100644 --- a/src/compiler/scala/tools/nsc/settings/StandardScalaSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/StandardScalaSettings.scala @@ -38,8 +38,8 @@ trait StandardScalaSettings { val nowarn = BooleanSetting ("-nowarn", "Generate no warnings.") val optimise: BooleanSetting // depends on post hook which mutates other settings val print = BooleanSetting ("-print", "Print program with Scala-specific features removed.") - val target = ChoiceSetting ("-target", "target", "Target platform for object files. All JVM 1.5 targets are deprecated.", - List("jvm-1.5", "jvm-1.6", "jvm-1.7", "jvm-1.8"), "jvm-1.6") + val target = ChoiceSettingForcedDefault ("-target", "target", "Target platform for object files. All JVM 1.5 - 1.7 targets are deprecated.", + List("jvm-1.5", "jvm-1.6", "jvm-1.7", "jvm-1.8"), "jvm-1.8") val unchecked = BooleanSetting ("-unchecked", "Enable additional warnings where generated code depends on assumptions.") val uniqid = BooleanSetting ("-uniqid", "Uniquely tag all identifiers in debugging output.") val usejavacp = BooleanSetting ("-usejavacp", "Utilize the java.class.path in classpath resolution.") diff --git a/src/compiler/scala/tools/nsc/transform/Delambdafy.scala b/src/compiler/scala/tools/nsc/transform/Delambdafy.scala index 5a7f6c52da..ddf003bb98 100644 --- a/src/compiler/scala/tools/nsc/transform/Delambdafy.scala +++ b/src/compiler/scala/tools/nsc/transform/Delambdafy.scala @@ -18,7 +18,7 @@ import scala.collection.mutable.LinkedHashMap * * From a lambda, Delambdafy will create: * - * Under -target:jvm-1.7 and below: + * Under GenASM * * 1) a new top level class that a) has fields and a constructor taking the captured environment (including possibly the "this" @@ -27,7 +27,7 @@ import scala.collection.mutable.LinkedHashMap * c) if needed a bridge method for the apply method * 2) an instantiation of the newly created class which replaces the lambda * - * Under -target:jvm-1.8 with GenBCode: + * Under GenBCode: * * 1) An application of the captured arguments to a fictional symbol representing the lambda factory. * This will be translated by the backed into an invokedynamic using a bootstrap method in JDK8's `LambdaMetaFactory`. @@ -571,10 +571,7 @@ abstract class Delambdafy extends Transform with TypingTransformers with ast.Tre // The functional interface that can be used to adapt the lambda target method `target` to the // given function type. Returns `NoSymbol` if the compiler settings are unsuitable. private def java8CompatFunctionalInterface(target: Symbol, functionType: Type): (Symbol, Boolean) = { - val canUseLambdaMetafactory: Boolean = { - val isTarget18 = settings.target.value.contains("jvm-1.8") - settings.isBCodeActive && isTarget18 - } + val canUseLambdaMetafactory = settings.isBCodeActive val sym = functionType.typeSymbol val pack = currentRun.runDefinitions.Scala_Java8_CompatPackage diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index a04625c9c5..833f25537c 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -341,8 +341,8 @@ abstract class Erasure extends AddInterfaces buf append (if (restpe.typeSymbol == UnitClass || sym0.isConstructor) VOID_TAG.toString else jsig(restpe)) buf.toString - case RefinedType(parent :: _, decls) => - boxedSig(parent) + case RefinedType(parents, decls) => + boxedSig(intersectionDominator(parents)) case ClassInfoType(parents, _, _) => superSig(parents) case AnnotatedType(_, atp) => diff --git a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala index 540de2cfe1..f12f6c4e18 100644 --- a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala +++ b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala @@ -446,8 +446,10 @@ abstract class ExplicitOuter extends InfoTransform // // See SI-6552 for an example of why `sym.owner.enclMethod hasAnnotation ScalaInlineClass` // is not suitable; if we make a method-local class non-private, it mangles outer pointer names. - if (currentClass != sym.owner || - (closestEnclMethod(currentOwner) hasAnnotation ScalaInlineClass)) + def enclMethodIsInline = closestEnclMethod(currentOwner) hasAnnotation ScalaInlineClass + // SI-8710 The extension method condition reflects our knowledge that a call to `new Meter(12).privateMethod` + // with later be rewritten (in erasure) to `Meter.privateMethod$extension(12)`. + if ((currentClass != sym.owner || enclMethodIsInline) && !sym.isMethodWithExtension) sym.makeNotPrivate(sym.owner) val qsym = qual.tpe.widen.typeSymbol diff --git a/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala b/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala index 116047a2ad..6349fc3fb9 100644 --- a/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala +++ b/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala @@ -208,7 +208,7 @@ abstract class ExtensionMethods extends Transform with TypingTransformers { def makeExtensionMethodSymbol = { val extensionName = extensionNames(origMeth).head.toTermName val extensionMeth = ( - companion.moduleClass.newMethod(extensionName, tree.pos.focus, origMeth.flags & ~OVERRIDE & ~PROTECTED & ~LOCAL | FINAL) + companion.moduleClass.newMethod(extensionName, tree.pos.focus, origMeth.flags & ~OVERRIDE & ~PROTECTED & ~PRIVATE & ~LOCAL | FINAL) setAnnotations origMeth.annotations ) origMeth.removeAnnotation(TailrecClass) // it's on the extension method, now. diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index b310e6c3a1..65316e4f00 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -237,7 +237,7 @@ abstract class UnCurry extends InfoTransform def canUseDelamdafyMethod = ( (inConstructorFlag == 0) // Avoiding synthesizing code prone to SI-6666, SI-8363 by using old-style lambda translation - && (!isSpecialized || (settings.isBCodeActive && settings.target.value == "jvm-1.8")) // DelambdafyTransformer currently only emits generic FunctionN-s, use the old style in the meantime + && (!isSpecialized || settings.isBCodeActive) // DelambdafyTransformer currently only emits generic FunctionN-s, use the old style in the meantime ) if (inlineFunctionExpansion || !canUseDelamdafyMethod) { val parents = addSerializable(abstractFunctionForFunctionType(fun.tpe)) diff --git a/src/compiler/scala/tools/nsc/typechecker/ConstantFolder.scala b/src/compiler/scala/tools/nsc/typechecker/ConstantFolder.scala index 56ed0ee16c..2f4771e9d4 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ConstantFolder.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ConstantFolder.scala @@ -75,7 +75,7 @@ abstract class ConstantFolder { case nme.AND => Constant(x.booleanValue & y.booleanValue) case nme.EQ => Constant(x.booleanValue == y.booleanValue) case nme.NE => Constant(x.booleanValue != y.booleanValue) - case _ => null + case _ => null } private def foldSubrangeOp(op: Name, x: Constant, y: Constant): Constant = op match { case nme.OR => Constant(x.intValue | y.intValue) @@ -95,14 +95,20 @@ abstract class ConstantFolder { case nme.MUL => Constant(x.intValue * y.intValue) case nme.DIV => Constant(x.intValue / y.intValue) case nme.MOD => Constant(x.intValue % y.intValue) - case _ => null + case _ => null } private def foldLongOp(op: Name, x: Constant, y: Constant): Constant = op match { case nme.OR => Constant(x.longValue | y.longValue) case nme.XOR => Constant(x.longValue ^ y.longValue) case nme.AND => Constant(x.longValue & y.longValue) - case nme.LSL => Constant(x.longValue << y.longValue) + case nme.LSL if x.tag <= IntTag + => Constant(x.intValue << y.longValue) + case nme.LSL => Constant(x.longValue << y.longValue) + case nme.LSR if x.tag <= IntTag + => Constant(x.intValue >>> y.longValue) case nme.LSR => Constant(x.longValue >>> y.longValue) + case nme.ASR if x.tag <= IntTag + => Constant(x.intValue >> y.longValue) case nme.ASR => Constant(x.longValue >> y.longValue) case nme.EQ => Constant(x.longValue == y.longValue) case nme.NE => Constant(x.longValue != y.longValue) @@ -115,7 +121,7 @@ abstract class ConstantFolder { case nme.MUL => Constant(x.longValue * y.longValue) case nme.DIV => Constant(x.longValue / y.longValue) case nme.MOD => Constant(x.longValue % y.longValue) - case _ => null + case _ => null } private def foldFloatOp(op: Name, x: Constant, y: Constant): Constant = op match { case nme.EQ => Constant(x.floatValue == y.floatValue) @@ -129,7 +135,7 @@ abstract class ConstantFolder { case nme.MUL => Constant(x.floatValue * y.floatValue) case nme.DIV => Constant(x.floatValue / y.floatValue) case nme.MOD => Constant(x.floatValue % y.floatValue) - case _ => null + case _ => null } private def foldDoubleOp(op: Name, x: Constant, y: Constant): Constant = op match { case nme.EQ => Constant(x.doubleValue == y.doubleValue) @@ -143,7 +149,7 @@ abstract class ConstantFolder { case nme.MUL => Constant(x.doubleValue * y.doubleValue) case nme.DIV => Constant(x.doubleValue / y.doubleValue) case nme.MOD => Constant(x.doubleValue % y.doubleValue) - case _ => null + case _ => null } private def foldBinop(op: Name, x: Constant, y: Constant): Constant = { @@ -162,7 +168,7 @@ abstract class ConstantFolder { case _ => null } catch { - case ex: ArithmeticException => null + case _: ArithmeticException => null } } } diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index 542f58795a..7c931600e5 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -809,12 +809,8 @@ trait Contexts { self: Analyzer => private def collectImplicitImports(imp: ImportInfo): List[ImplicitInfo] = { val qual = imp.qual - val pre = - if (qual.tpe.typeSymbol.isPackageClass) - // SI-6225 important if the imported symbol is inherited by the the package object. - singleType(qual.tpe, qual.tpe member nme.PACKAGE) - else - qual.tpe + val qualSym = qual.tpe.typeSymbol + val pre = qual.tpe def collect(sels: List[ImportSelector]): List[ImplicitInfo] = sels match { case List() => List() @@ -885,7 +881,8 @@ trait Contexts { self: Analyzer => Some(collectImplicitImports(imports.head)) } else if (owner.isPackageClass) { // the corresponding package object may contain implicit members. - Some(collectImplicits(owner.tpe.implicitMembers, owner.tpe)) + val pre = owner.packageObject.typeOfThis + Some(collectImplicits(pre.implicitMembers, pre)) } else Some(Nil) } @@ -955,52 +952,18 @@ trait Contexts { self: Analyzer => private def importedAccessibleSymbol(imp: ImportInfo, name: Name, requireExplicit: Boolean): Symbol = imp.importedSymbol(name, requireExplicit) filter (s => isAccessible(s, imp.qual.tpe, superAccess = false)) - /** Is `sym` defined in package object of package `pkg`? - * Since sym may be defined in some parent of the package object, - * we cannot inspect its owner only; we have to go through the - * info of the package object. However to avoid cycles we'll check - * what other ways we can before pushing that way. - */ - def isInPackageObject(sym: Symbol, pkg: Symbol): Boolean = { - def uninitialized(what: String) = { - log(s"Cannot look for $sym in package object of $pkg; $what is not initialized.") - false - } - def pkgClass = if (pkg.isTerm) pkg.moduleClass else pkg - def matchesInfo = ( - // need to be careful here to not get a cyclic reference during bootstrap - if (pkg.isInitialized) { - val module = pkg.info member nme.PACKAGEkw - if (module.isInitialized) - module.info.member(sym.name).alternatives contains sym - else - uninitialized("" + module) - } - else uninitialized("" + pkg) - ) - def inPackageObject(sym: Symbol) = ( - // To be in the package object, one of these must be true: - // 1) sym.owner is a package object class, and sym.owner.owner is the package class for `pkg` - // 2) sym.owner is inherited by the correct package object class - // We try to establish 1) by inspecting the owners directly, and then we try - // to rule out 2), and only if both those fail do we resort to looking in the info. - !sym.hasPackageFlag && sym.owner.exists && ( - if (sym.owner.isPackageObjectClass) - sym.owner.owner == pkgClass - else - !sym.owner.isPackageClass && matchesInfo - ) - ) + private def requiresQualifier(s: Symbol) = ( + s.owner.isClass + && !s.owner.isPackageClass + && !s.isTypeParameterOrSkolem + && !s.isExistentiallyBound + ) - // An overloaded symbol might not have the expected owner! - // The alternatives must be inspected directly. - pkgClass.isPackageClass && ( - if (sym.isOverloaded) - sym.alternatives forall (isInPackageObject(_, pkg)) - else - inPackageObject(sym) - ) - } + /** Must `sym` defined in package object of package `pkg`, if + * it selected from a prefix with `pkg` as its type symbol? + */ + def isInPackageObject(sym: Symbol, pkg: Symbol): Boolean = + pkg.isPackage && sym.owner != pkg && requiresQualifier(sym) def isNameInScope(name: Name) = lookupSymbol(name, _ => true).isSuccess @@ -1036,11 +999,6 @@ trait Contexts { self: Analyzer => || unit.exists && s.sourceFile != unit.source.file ) ) - def requiresQualifier(s: Symbol) = ( - s.owner.isClass - && !s.owner.isPackageClass - && !s.isTypeParameterOrSkolem - ) def lookupInPrefix(name: Name) = pre member name filter qualifies def accessibleInPrefix(s: Symbol) = isAccessible(s, pre, superAccess = false) diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala index 80e06eb8fa..3274c86072 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala @@ -1012,15 +1012,12 @@ trait Implicits { } case None => if (pre.isStable && !pre.typeSymbol.isExistentiallyBound) { - val companion = companionSymbolOf(sym, context) - companion.moduleClass match { - case mc: ModuleClassSymbol => - val infos = - for (im <- mc.implicitMembers.toList) yield new ImplicitInfo(im.name, singleType(pre, companion), im) - if (infos.nonEmpty) - infoMap += (sym -> infos) - case _ => - } + val pre1 = + if (sym.isPackageClass) sym.packageObject.typeOfThis + else singleType(pre, companionSymbolOf(sym, context)) + val infos = pre1.implicitMembers.iterator.map(mem => new ImplicitInfo(mem.name, pre1, mem)).toList + if (infos.nonEmpty) + infoMap += (sym -> infos) } val bts = tp.baseTypeSeq var i = 1 diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index ea0a9bb243..a4c794e8cf 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -1446,7 +1446,7 @@ trait Infer extends Checkable { log(s"Attaching AntiPolyType-carrying overloaded type to $sym") // Multiple alternatives which are within bounds; spin up an // overloaded type which carries an "AntiPolyType" as a prefix. - val tparams = newAsSeenFromMap(pre, hd.owner) mapOver hd.typeParams + val tparams = new AsSeenFromMap(pre, hd.owner) mapOver hd.typeParams val bounds = tparams map (_.tpeHK) // see e.g., #1236 val tpe = PolyType(tparams, OverloadedType(AntiPolyType(pre, bounds), alts)) finish(sym setInfo tpe, tpe) diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala index 39cd610b1c..1bc5daac65 100644 --- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala +++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala @@ -9,6 +9,7 @@ package typechecker import symtab.Flags._ import scala.collection.mutable import scala.reflect.ClassTag +import PartialFunction.{ cond => when } /** * @author Lukas Rytz @@ -551,64 +552,73 @@ trait NamesDefaults { self: Analyzer => } } - /** - * Removes name assignments from args. Additionally, returns an array mapping - * argument indices from call-site-order to definition-site-order. + /** Removes name assignments from args. Additionally, returns an array mapping + * argument indices from call-site-order to definition-site-order. * - * Verifies that names are not specified twice, positional args don't appear - * after named ones. + * Verifies that names are not specified twice, and positional args don't appear after named ones. */ def removeNames(typer: Typer)(args: List[Tree], params: List[Symbol]): (List[Tree], Array[Int]) = { implicit val context0 = typer.context - // maps indices from (order written by user) to (order of definition) - val argPos = Array.fill(args.length)(-1) - var positionalAllowed = true - val namelessArgs = mapWithIndex(args) { (arg, argIndex) => - arg match { - case arg @ AssignOrNamedArg(Ident(name), rhs) => - def matchesName(param: Symbol) = !param.isSynthetic && ( - (param.name == name) || (param.deprecatedParamName match { - case Some(`name`) => - context0.deprecationWarning(arg.pos, param, - s"the parameter name $name has been deprecated. Use ${param.name} instead.") - true - case _ => false - }) - ) - val paramPos = params indexWhere matchesName - if (paramPos == -1) { - if (positionalAllowed) { - argPos(argIndex) = argIndex - // prevent isNamed from being true when calling doTypedApply recursively, - // treat the arg as an assignment of type Unit - Assign(arg.lhs, rhs) setPos arg.pos - } - else UnknownParameterNameNamesDefaultError(arg, name) - } - else if (argPos contains paramPos) { + def matchesName(param: Symbol, name: Name, argIndex: Int) = { + def warn(w: String) = context0.deprecationWarning(args(argIndex).pos, param, w) + def checkDeprecation(anonOK: Boolean) = + when (param.deprecatedParamName) { + case Some(`name`) => true + case Some(nme.NO_NAME) => anonOK + } + def checkName = { + val res = param.name == name + if (res && checkDeprecation(true)) warn(s"naming parameter $name has been deprecated.") + res + } + def checkAltName = { + val res = checkDeprecation(false) + if (res) warn(s"the parameter name $name has been deprecated. Use ${param.name} instead.") + res + } + !param.isSynthetic && (checkName || checkAltName) + } + // argPos maps indices from (order written by user) to (order of definition) + val argPos = Array.fill(args.length)(-1) + val namelessArgs = { + var positionalAllowed = true + def stripNamedArg(arg: AssignOrNamedArg, argIndex: Int): Tree = { + val AssignOrNamedArg(Ident(name), rhs) = arg + params indexWhere (p => matchesName(p, name, argIndex)) match { + case -1 if positionalAllowed => + // prevent isNamed from being true when calling doTypedApply recursively, + // treat the arg as an assignment of type Unit + Assign(arg.lhs, rhs) setPos arg.pos + case -1 => + UnknownParameterNameNamesDefaultError(arg, name) + case paramPos if argPos contains paramPos => val existingArgIndex = argPos.indexWhere(_ == paramPos) - val otherName = args(paramPos) match { - case AssignOrNamedArg(Ident(oName), rhs) if oName != name => Some(oName) - case _ => None + val otherName = Some(args(paramPos)) collect { + case AssignOrNamedArg(Ident(oName), _) if oName != name => oName } DoubleParamNamesDefaultError(arg, name, existingArgIndex+1, otherName) - } else if (isAmbiguousAssignment(typer, params(paramPos), arg)) + case paramPos if isAmbiguousAssignment(typer, params(paramPos), arg) => AmbiguousReferenceInNamesDefaultError(arg, name) - else { - // if the named argument is on the original parameter - // position, positional after named is allowed. - if (argIndex != paramPos) - positionalAllowed = false - argPos(argIndex) = paramPos + case paramPos if paramPos != argIndex => + positionalAllowed = false // named arg is not in original parameter order: require names after this + argPos(argIndex) = paramPos // fix up the arg position rhs - } - case _ => - argPos(argIndex) = argIndex - if (positionalAllowed) arg - else PositionalAfterNamedNamesDefaultError(arg) + case _ => rhs + } + } + mapWithIndex(args) { + case (arg: AssignOrNamedArg, argIndex) => + val t = stripNamedArg(arg, argIndex) + if (!t.isErroneous && argPos(argIndex) < 0) argPos(argIndex) = argIndex + t + case (arg, argIndex) => + if (positionalAllowed) { + argPos(argIndex) = argIndex + arg + } else + PositionalAfterNamedNamesDefaultError(arg) } } - (namelessArgs, argPos) } } diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala index 966e8f1abe..d65d2092ad 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala @@ -87,24 +87,6 @@ trait SyntheticMethods extends ast.TreeDSL { def accessors = clazz.caseFieldAccessors val arity = accessors.size - // If this is ProductN[T1, T2, ...], accessorLub is the lub of T1, T2, ..., . - // !!! Hidden behind -Xexperimental due to bummer type inference bugs. - // Refining from Iterator[Any] leads to types like - // - // Option[Int] { def productIterator: Iterator[String] } - // - // appearing legitimately, but this breaks invariant places - // like Tags and Arrays which are not robust and infer things - // which they shouldn't. - val accessorLub = ( - if (settings.Xexperimental) { - global.lub(accessors map (_.tpe.finalResultType)) match { - case RefinedType(parents, decls) if !decls.isEmpty => intersectionType(parents) - case tp => tp - } - } - else AnyTpe - ) def forwardToRuntime(method: Symbol): Tree = forwardMethod(method, getMember(ScalaRunTimeModule, (method.name prepend "_")))(mkThis :: _) @@ -125,8 +107,8 @@ trait SyntheticMethods extends ast.TreeDSL { } } def productIteratorMethod = { - createMethod(nme.productIterator, iteratorOfType(accessorLub))(_ => - gen.mkMethodCall(ScalaRunTimeModule, nme.typedProductIterator, List(accessorLub), List(mkThis)) + createMethod(nme.productIterator, iteratorOfType(AnyTpe))(_ => + gen.mkMethodCall(ScalaRunTimeModule, nme.typedProductIterator, List(AnyTpe), List(mkThis)) ) } @@ -246,7 +228,7 @@ trait SyntheticMethods extends ast.TreeDSL { List( Product_productPrefix -> (() => constantNullary(nme.productPrefix, clazz.name.decode)), Product_productArity -> (() => constantNullary(nme.productArity, arity)), - Product_productElement -> (() => perElementMethod(nme.productElement, accessorLub)(mkThisSelect)), + Product_productElement -> (() => perElementMethod(nme.productElement, AnyTpe)(mkThisSelect)), Product_iterator -> (() => productIteratorMethod), Product_canEqual -> (() => canEqualMethod) // This is disabled pending a reimplementation which doesn't add any @@ -380,7 +362,14 @@ trait SyntheticMethods extends ast.TreeDSL { for (ddef @ DefDef(_, _, _, _, _, _) <- templ.body ; if isRewrite(ddef.symbol)) { val original = ddef.symbol - val newAcc = deriveMethod(ddef.symbol, name => context.unit.freshTermName(name + "$")) { newAcc => + val i = original.owner.caseFieldAccessors.indexOf(original) + def freshAccessorName = { + devWarning(s"Unable to find $original among case accessors of ${original.owner}: ${original.owner.caseFieldAccessors}") + context.unit.freshTermName(original.name + "$") + } + def nameSuffixedByParamIndex = original.name.append(nme.CASE_ACCESSOR + "$" + i).toTermName + val newName = if (i < 0) freshAccessorName else nameSuffixedByParamIndex + val newAcc = deriveMethod(ddef.symbol, name => newName) { newAcc => newAcc.makePublic newAcc resetFlag (ACCESSOR | PARAMACCESSOR | OVERRIDE) ddef.rhs.duplicate diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index b5129af9ec..2dfecbaea1 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -542,7 +542,11 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper } val qual = typedQualifier { atPos(tree.pos.makeTransparent) { tree match { - case Ident(_) => Ident(rootMirror.getPackageObjectWithMember(pre, sym)) + case Ident(_) => + val packageObject = + if (sym.owner.isModuleClass) sym.owner.sourceModule // historical optimization, perhaps no longer needed + else pre.typeSymbol.packageObject + Ident(packageObject) case Select(qual, _) => Select(qual, nme.PACKAGEkw) case SelectFromTypeTree(qual, _) => Select(qual, nme.PACKAGEkw) } @@ -928,24 +932,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper def insertApply(): Tree = { assert(!context.inTypeConstructorAllowed, mode) //@M val adapted = adaptToName(tree, nme.apply) - def stabilize0(pre: Type): Tree = stabilize(adapted, pre, MonoQualifierModes, WildcardType) - - // TODO reconcile the overlap between Typers#stablize and TreeGen.stabilize - val qual = adapted match { - case This(_) => - gen.stabilize(adapted) - case Ident(_) => - val owner = adapted.symbol.owner - val pre = - if (owner.isPackageClass) owner.thisType - else if (owner.isClass) context.enclosingSubClassContext(owner).prefix - else NoPrefix - stabilize0(pre) - case Select(qualqual, _) => - stabilize0(qualqual.tpe) - case other => - other - } + val qual = gen.stabilize(adapted) typedPos(tree.pos, mode, pt) { Select(qual setPos tree.pos.makeTransparent, nme.apply) } @@ -2228,7 +2215,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper val allParams = meth.paramss.flatten for (p <- allParams) { for (n <- p.deprecatedParamName) { - if (allParams.exists(p1 => p1.name == n || (p != p1 && p1.deprecatedParamName.exists(_ == n)))) + if (allParams.exists(p1 => p != p1 && (p1.name == n || p1.deprecatedParamName.exists(_ == n)))) DeprecatedParamNameError(p, n) } } @@ -5228,7 +5215,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper if (refTyped.isErrorTyped) { setError(tree) } else { - tree setType refTyped.tpe.resultType + tree setType refTyped.tpe.resultType.deconst if (refTyped.isErrorTyped || treeInfo.admitsTypeSelection(refTyped)) tree else UnstableTreeError(tree) } diff --git a/src/compiler/scala/tools/reflect/WrappedProperties.scala b/src/compiler/scala/tools/reflect/WrappedProperties.scala index 523287fc66..348d000d15 100644 --- a/src/compiler/scala/tools/reflect/WrappedProperties.scala +++ b/src/compiler/scala/tools/reflect/WrappedProperties.scala @@ -30,9 +30,10 @@ trait WrappedProperties extends PropertiesTrait { def systemProperties: List[(String, String)] = { import scala.collection.JavaConverters._ wrap { + // SI-7269,7775 Avoid `ConcurrentModificationException` and nulls if another thread modifies properties val props = System.getProperties - // SI-7269 Be careful to avoid `ConcurrentModificationException` if another thread modifies the properties map - props.stringPropertyNames().asScala.toList.map(k => (k, props.get(k).asInstanceOf[String])) + val it = props.stringPropertyNames().asScala.iterator map (k => (k, props getProperty k)) filter (_._2 ne null) + it.toList } getOrElse Nil } } diff --git a/src/compiler/scala/tools/util/PathResolver.scala b/src/compiler/scala/tools/util/PathResolver.scala index 8e5b1e0a5c..f122437b63 100644 --- a/src/compiler/scala/tools/util/PathResolver.scala +++ b/src/compiler/scala/tools/util/PathResolver.scala @@ -52,7 +52,7 @@ object PathResolver { */ object Environment { private def searchForBootClasspath = - systemProperties find (_._1 endsWith ".boot.class.path") map (_._2) getOrElse "" + systemProperties collectFirst { case (k, v) if k endsWith ".boot.class.path" => v } getOrElse "" /** Environment variables which java pays attention to so it * seems we do as well. diff --git a/src/eclipse/partest/.classpath b/src/eclipse/partest/.classpath index 7f28868d95..7e2f119193 100644 --- a/src/eclipse/partest/.classpath +++ b/src/eclipse/partest/.classpath @@ -5,7 +5,7 @@ <classpathentry combineaccessrules="false" kind="src" path="/repl"/> <classpathentry kind="var" path="M2_REPO/com/googlecode/java-diff-utils/diffutils/1.3.0/diffutils-1.3.0.jar"/> <classpathentry kind="var" path="M2_REPO/org/scala-sbt/test-interface/1.0/test-interface-1.0.jar"/> - <classpathentry kind="var" path="M2_REPO/org/scala-lang/modules/scala-partest_2.11.0-M7/1.0.0-RC8/scala-partest_2.11.0-M7-1.0.0-RC8.jar"/> + <classpathentry kind="var" path="M2_REPO/org/scala-lang/modules/scala-partest_2.11/1.0.0/scala-partest_2.11-1.0.0.jar"/> <classpathentry kind="var" path="SCALA_BASEDIR/lib/ant/ant.jar"/> <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> <classpathentry combineaccessrules="false" kind="src" path="/scala-compiler"/> diff --git a/src/eclipse/repl/.classpath b/src/eclipse/repl/.classpath index 8ff9aabfbf..cbaabb9af1 100644 --- a/src/eclipse/repl/.classpath +++ b/src/eclipse/repl/.classpath @@ -3,7 +3,6 @@ <classpathentry kind="src" path="repl"/> <classpathentry combineaccessrules="false" kind="src" path="/asm"/> <classpathentry kind="var" path="M2_REPO/jline/jline/2.12/jline-2.12.jar"/> - <!-- <classpathentry kind="var" path="SCALA_BASEDIR/build/deps/repl/jline-2.12.jar"/> --> <classpathentry combineaccessrules="false" kind="src" path="/scala-compiler"/> <classpathentry combineaccessrules="false" kind="src" path="/scala-library"/> <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> diff --git a/src/eclipse/scaladoc/.classpath b/src/eclipse/scaladoc/.classpath index c8f0e89b8a..ee6427176a 100644 --- a/src/eclipse/scaladoc/.classpath +++ b/src/eclipse/scaladoc/.classpath @@ -6,8 +6,8 @@ <classpathentry combineaccessrules="false" kind="src" path="/scala-compiler"/> <classpathentry combineaccessrules="false" kind="src" path="/scala-library"/> <classpathentry combineaccessrules="false" kind="src" path="/partest-extras"/> - <classpathentry kind="var" path="M2_REPO/org/scala-lang/modules/scala-xml_2.11.0-M7/1.0.0-RC7/scala-xml_2.11.0-M7-1.0.0-RC7.jar"/> - <classpathentry kind="var" path="M2_REPO/org/scala-lang/modules/scala-parser-combinators_2.11.0-M7/1.0.0-RC5/scala-parser-combinators_2.11.0-M7-1.0.0-RC5.jar"/> - <classpathentry kind="var" path="M2_REPO/org/scala-lang/modules/scala-partest_2.11.0-M7/1.0.0-RC8/scala-partest_2.11.0-M7-1.0.0-RC8.jar"/> + <classpathentry kind="var" path="M2_REPO/org/scala-lang/modules/scala-xml_2.11/1.0.2/scala-xml_2.11-1.0.2.jar"/> + <classpathentry kind="var" path="M2_REPO/org/scala-lang/modules/scala-parser-combinators_2.11/1.0.1/scala-parser-combinators_2.11-1.0.1.jar"/> + <classpathentry kind="var" path="M2_REPO/org/scala-lang/modules/scala-partest_2.11/1.0.0/scala-partest_2.11-1.0.0.jar"/> <classpathentry kind="output" path="build-quick-scaladoc"/> </classpath> diff --git a/src/forkjoin/scala/concurrent/forkjoin/ForkJoinPool.java b/src/forkjoin/scala/concurrent/forkjoin/ForkJoinPool.java index 6578504155..9bd378c61c 100644 --- a/src/forkjoin/scala/concurrent/forkjoin/ForkJoinPool.java +++ b/src/forkjoin/scala/concurrent/forkjoin/ForkJoinPool.java @@ -23,6 +23,7 @@ import java.util.concurrent.TimeUnit; * @since 1.8 * @author Doug Lea */ +@Deprecated /*public*/ abstract class CountedCompleter<T> extends ForkJoinTask<T> { private static final long serialVersionUID = 5232453752276485070L; @@ -471,6 +472,7 @@ import java.util.concurrent.TimeUnit; * @since 1.7 * @author Doug Lea */ +@Deprecated public class ForkJoinPool extends AbstractExecutorService { /* @@ -3578,6 +3580,7 @@ public class ForkJoinPool extends AbstractExecutorService { * } * }}</pre> */ + @Deprecated public static interface ManagedBlocker { /** * Possibly blocks the current thread, for example waiting for diff --git a/src/forkjoin/scala/concurrent/forkjoin/ForkJoinTask.java b/src/forkjoin/scala/concurrent/forkjoin/ForkJoinTask.java index fd1e132b07..b4f5c24ca9 100644 --- a/src/forkjoin/scala/concurrent/forkjoin/ForkJoinTask.java +++ b/src/forkjoin/scala/concurrent/forkjoin/ForkJoinTask.java @@ -180,6 +180,7 @@ import java.lang.reflect.Constructor; * @since 1.7 * @author Doug Lea */ +@Deprecated public abstract class ForkJoinTask<V> implements Future<V>, Serializable { /* @@ -391,6 +392,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable { * any ForkJoinPool will call helpExpungeStaleExceptions when its * pool becomes isQuiescent. */ + @Deprecated static final class ExceptionNode extends WeakReference<ForkJoinTask<?>> { final Throwable ex; ExceptionNode next; @@ -1330,6 +1332,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable { * to be compliant with AbstractExecutorService constraints * when used in ForkJoinPool. */ + @Deprecated static final class AdaptedRunnable<T> extends ForkJoinTask<T> implements RunnableFuture<T> { final Runnable runnable; @@ -1349,6 +1352,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable { /** * Adaptor for Runnables without results */ + @Deprecated static final class AdaptedRunnableAction extends ForkJoinTask<Void> implements RunnableFuture<Void> { final Runnable runnable; @@ -1366,6 +1370,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable { /** * Adaptor for Callables */ + @Deprecated static final class AdaptedCallable<T> extends ForkJoinTask<T> implements RunnableFuture<T> { final Callable<? extends T> callable; diff --git a/src/forkjoin/scala/concurrent/forkjoin/ForkJoinWorkerThread.java b/src/forkjoin/scala/concurrent/forkjoin/ForkJoinWorkerThread.java index e62fc6eb71..e00fb5cc43 100644 --- a/src/forkjoin/scala/concurrent/forkjoin/ForkJoinWorkerThread.java +++ b/src/forkjoin/scala/concurrent/forkjoin/ForkJoinWorkerThread.java @@ -20,6 +20,7 @@ package scala.concurrent.forkjoin; * @since 1.7 * @author Doug Lea */ +@Deprecated public class ForkJoinWorkerThread extends Thread { /* * ForkJoinWorkerThreads are managed by ForkJoinPools and perform diff --git a/src/forkjoin/scala/concurrent/forkjoin/LinkedTransferQueue.java b/src/forkjoin/scala/concurrent/forkjoin/LinkedTransferQueue.java index 07e81b395d..47d52af895 100644 --- a/src/forkjoin/scala/concurrent/forkjoin/LinkedTransferQueue.java +++ b/src/forkjoin/scala/concurrent/forkjoin/LinkedTransferQueue.java @@ -53,6 +53,7 @@ import java.util.concurrent.locks.LockSupport; * @author Doug Lea * @param <E> the type of elements held in this collection */ +@Deprecated public class LinkedTransferQueue<E> extends AbstractQueue<E> implements TransferQueue<E>, java.io.Serializable { private static final long serialVersionUID = -3223113410248163686L; @@ -416,6 +417,7 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E> * unnecessary ordering constraints: Writes that are intrinsically * ordered wrt other accesses or CASes use simple relaxed forms. */ + @Deprecated static final class Node { final boolean isData; // false if this is a request node volatile Object item; // initially non-null if isData; CASed to match @@ -789,6 +791,7 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E> return count; } + @Deprecated final class Itr implements Iterator<E> { private Node nextNode; // next node to return item for private E nextItem; // the corresponding item diff --git a/src/forkjoin/scala/concurrent/forkjoin/RecursiveAction.java b/src/forkjoin/scala/concurrent/forkjoin/RecursiveAction.java index 1e7cdd952d..f4a77f0f61 100644 --- a/src/forkjoin/scala/concurrent/forkjoin/RecursiveAction.java +++ b/src/forkjoin/scala/concurrent/forkjoin/RecursiveAction.java @@ -133,6 +133,7 @@ package scala.concurrent.forkjoin; * @since 1.7 * @author Doug Lea */ +@Deprecated public abstract class RecursiveAction extends ForkJoinTask<Void> { private static final long serialVersionUID = 5232453952276485070L; diff --git a/src/forkjoin/scala/concurrent/forkjoin/RecursiveTask.java b/src/forkjoin/scala/concurrent/forkjoin/RecursiveTask.java index d1e1547143..097b7cda1f 100644 --- a/src/forkjoin/scala/concurrent/forkjoin/RecursiveTask.java +++ b/src/forkjoin/scala/concurrent/forkjoin/RecursiveTask.java @@ -36,6 +36,7 @@ package scala.concurrent.forkjoin; * @since 1.7 * @author Doug Lea */ +@Deprecated public abstract class RecursiveTask<V> extends ForkJoinTask<V> { private static final long serialVersionUID = 5232453952276485270L; diff --git a/src/forkjoin/scala/concurrent/forkjoin/ThreadLocalRandom.java b/src/forkjoin/scala/concurrent/forkjoin/ThreadLocalRandom.java index 19237c9092..3ea1af66bc 100644 --- a/src/forkjoin/scala/concurrent/forkjoin/ThreadLocalRandom.java +++ b/src/forkjoin/scala/concurrent/forkjoin/ThreadLocalRandom.java @@ -32,6 +32,7 @@ import java.util.Random; * @since 1.7 * @author Doug Lea */ +@Deprecated public class ThreadLocalRandom extends Random { // same constants as Random, but must be redeclared because private private static final long multiplier = 0x5DEECE66DL; @@ -80,6 +81,7 @@ public class ThreadLocalRandom extends Random { * * @return the current thread's {@code ThreadLocalRandom} */ + @Deprecated public static ThreadLocalRandom current() { return localRandom.get(); } diff --git a/src/forkjoin/scala/concurrent/forkjoin/TransferQueue.java b/src/forkjoin/scala/concurrent/forkjoin/TransferQueue.java index 7d149c7ae5..4fcd8ea601 100644 --- a/src/forkjoin/scala/concurrent/forkjoin/TransferQueue.java +++ b/src/forkjoin/scala/concurrent/forkjoin/TransferQueue.java @@ -37,6 +37,7 @@ import java.util.concurrent.*; * @author Doug Lea * @param <E> the type of elements held in this collection */ +@Deprecated public interface TransferQueue<E> extends BlockingQueue<E> { /** * Transfers the element to a waiting consumer immediately, if possible. diff --git a/src/forkjoin/scala/concurrent/util/Unsafe.java b/src/forkjoin/scala/concurrent/util/Unsafe.java index ef893c94d9..d82e4bbdd5 100644 --- a/src/forkjoin/scala/concurrent/util/Unsafe.java +++ b/src/forkjoin/scala/concurrent/util/Unsafe.java @@ -7,14 +7,12 @@ \* */ package scala.concurrent.util; - - - import java.lang.reflect.Field; - +@Deprecated public final class Unsafe { + @Deprecated public final static sun.misc.Unsafe instance; static { try { diff --git a/src/intellij/actors.iml.SAMPLE b/src/intellij/actors.iml.SAMPLE deleted file mode 100644 index dfdf396c46..0000000000 --- a/src/intellij/actors.iml.SAMPLE +++ /dev/null @@ -1,14 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<module type="JAVA_MODULE" version="4"> - <component name="NewModuleRootManager" inherit-compiler-output="true"> - <exclude-output /> - <content url="file://$MODULE_DIR$/../actors"> - <sourceFolder url="file://$MODULE_DIR$/../actors" isTestSource="false" /> - </content> - <orderEntry type="inheritedJdk" /> - <orderEntry type="sourceFolder" forTests="false" /> - <orderEntry type="module" module-name="library" /> - <orderEntry type="module" module-name="forkjoin" /> - <orderEntry type="library" name="starr" level="project" /> - </component> -</module>
\ No newline at end of file diff --git a/src/intellij/scala.ipr.SAMPLE b/src/intellij/scala.ipr.SAMPLE index 47ac2be188..290d53aa5d 100644 --- a/src/intellij/scala.ipr.SAMPLE +++ b/src/intellij/scala.ipr.SAMPLE @@ -35,7 +35,6 @@ </component> <component name="ProjectModuleManager"> <modules> - <module fileurl="file://$PROJECT_DIR$/actors.iml" filepath="$PROJECT_DIR$/actors.iml" /> <module fileurl="file://$PROJECT_DIR$/compiler.iml" filepath="$PROJECT_DIR$/compiler.iml" /> <module fileurl="file://$PROJECT_DIR$/forkjoin.iml" filepath="$PROJECT_DIR$/forkjoin.iml" /> <module fileurl="file://$PROJECT_DIR$/interactive.iml" filepath="$PROJECT_DIR$/interactive.iml" /> diff --git a/src/intellij/test-junit.iml.SAMPLE b/src/intellij/test-junit.iml.SAMPLE index 86dc39c175..8252ef6d98 100644 --- a/src/intellij/test-junit.iml.SAMPLE +++ b/src/intellij/test-junit.iml.SAMPLE @@ -7,7 +7,6 @@ </content> <orderEntry type="inheritedJdk" /> <orderEntry type="sourceFolder" forTests="false" /> - <orderEntry type="module" module-name="actors" /> <orderEntry type="module" module-name="compiler" /> <orderEntry type="module" module-name="forkjoin" /> <orderEntry type="module" module-name="library" /> diff --git a/src/intellij/test.iml.SAMPLE b/src/intellij/test.iml.SAMPLE index 5047967721..e7eb7576c3 100644 --- a/src/intellij/test.iml.SAMPLE +++ b/src/intellij/test.iml.SAMPLE @@ -7,7 +7,6 @@ </content> <orderEntry type="inheritedJdk" /> <orderEntry type="sourceFolder" forTests="false" /> - <orderEntry type="module" module-name="actors" /> <orderEntry type="module" module-name="compiler" /> <orderEntry type="module" module-name="forkjoin" /> <orderEntry type="module" module-name="interactive" /> diff --git a/src/interactive/scala/tools/nsc/interactive/Global.scala b/src/interactive/scala/tools/nsc/interactive/Global.scala index 727bfdd510..e79c1a01ab 100644 --- a/src/interactive/scala/tools/nsc/interactive/Global.scala +++ b/src/interactive/scala/tools/nsc/interactive/Global.scala @@ -19,6 +19,8 @@ import scala.annotation.{ elidable, tailrec } import scala.language.implicitConversions import scala.tools.nsc.typechecker.Typers import scala.util.control.Breaks._ +import java.util.concurrent.ConcurrentHashMap +import scala.collection.JavaConverters.mapAsScalaMapConverter /** * This trait allows the IDE to have an instance of the PC that @@ -157,33 +159,20 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") override def forInteractive = true override protected def synchronizeNames = true - override def newAsSeenFromMap(pre: Type, clazz: Symbol): AsSeenFromMap = - new InteractiveAsSeenFromMap(pre, clazz) - - class InteractiveAsSeenFromMap(pre: Type, clazz: Symbol) extends AsSeenFromMap(pre, clazz) { - /** The method formerly known as 'instParamsRelaxed' goes here if it's still necessary, - * which it is currently supposed it is not. - * - * If it is, change AsSeenFromMap method correspondingTypeArgument to call an overridable - * method rather than aborting in the failure case. - */ - } - /** A map of all loaded files to the rich compilation units that correspond to them. */ - val unitOfFile = new LinkedHashMap[AbstractFile, RichCompilationUnit] with - SynchronizedMap[AbstractFile, RichCompilationUnit] { + val unitOfFile = mapAsScalaMapConverter(new ConcurrentHashMap[AbstractFile, RichCompilationUnit] { override def put(key: AbstractFile, value: RichCompilationUnit) = { val r = super.put(key, value) - if (r.isEmpty) debugLog("added unit for "+key) + if (r == null) debugLog("added unit for "+key) r } - override def remove(key: AbstractFile) = { + override def remove(key: Any) = { val r = super.remove(key) - if (r.nonEmpty) debugLog("removed unit for "+key) + if (r != null) debugLog("removed unit for "+key) r } - } + }).asScala /** A set containing all those files that need to be removed * Units are removed by getUnit, typically once a unit is finished compiled. @@ -1101,7 +1090,7 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") val implicitlyAdded = viaView != NoSymbol members.add(sym, pre, implicitlyAdded) { (s, st) => new TypeMember(s, st, - context.isAccessible(if (s.hasGetter) s.getter(s.owner) else s, pre, superAccess && !implicitlyAdded), + context.isAccessible(if (s.hasGetter) s.getterIn(s.owner) else s, pre, superAccess && !implicitlyAdded), inherited, viaView) } diff --git a/src/library/rootdoc.txt b/src/library/rootdoc.txt index e84942b8c4..95f9836cc9 100644 --- a/src/library/rootdoc.txt +++ b/src/library/rootdoc.txt @@ -44,12 +44,8 @@ Additional parts of the standard library are shipped as separate libraries. Thes - [[scala.reflect `scala.reflect`]] - Scala's reflection API (scala-reflect.jar) - [[scala.xml `scala.xml`]] - XML parsing, manipulation, and serialization (scala-xml.jar) - [[scala.swing `scala.swing`]] - A convenient wrapper around Java's GUI framework called Swing (scala-swing.jar) - - [[scala.util.continuations `scala.util.continuations`]] - Delimited continuations using continuation-passing-style - (scala-continuations-library.jar, scala-continuations-plugin.jar) - [[scala.util.parsing `scala.util.parsing`]] - [[scala.util.parsing.combinator Parser combinators]], including an example implementation of a [[scala.util.parsing.json JSON parser]] (scala-parser-combinators.jar) - - [[scala.actors `scala.actors`]] - Actor-based concurrency (deprecated and replaced by Akka actors, - scala-actors.jar) == Automatic imports == diff --git a/src/library/scala/PartialFunction.scala b/src/library/scala/PartialFunction.scala index fba759eb32..98dd35d306 100644 --- a/src/library/scala/PartialFunction.scala +++ b/src/library/scala/PartialFunction.scala @@ -161,10 +161,10 @@ trait PartialFunction[-A, +B] extends (A => B) { self => object PartialFunction { /** Composite function produced by `PartialFunction#orElse` method */ - private class OrElse[-A, +B] (f1: PartialFunction[A, B], f2: PartialFunction[A, B]) extends PartialFunction[A, B] { + private class OrElse[-A, +B] (f1: PartialFunction[A, B], f2: PartialFunction[A, B]) extends scala.runtime.AbstractPartialFunction[A, B] { def isDefinedAt(x: A) = f1.isDefinedAt(x) || f2.isDefinedAt(x) - def apply(x: A): B = f1.applyOrElse(x, f2) + override def apply(x: A): B = f1.applyOrElse(x, f2) override def applyOrElse[A1 <: A, B1 >: B](x: A1, default: A1 => B1): B1 = { val z = f1.applyOrElse(x, checkFallback[B]) diff --git a/src/library/scala/Predef.scala b/src/library/scala/Predef.scala index 0f300412b7..012e7afd74 100644 --- a/src/library/scala/Predef.scala +++ b/src/library/scala/Predef.scala @@ -126,7 +126,7 @@ object Predef extends LowPriorityImplicits with DeprecatedPredef { def optManifest[T](implicit m: OptManifest[T]) = m // Minor variations on identity functions - def identity[A](x: A): A = x // @see `conforms` for the implicit version + @inline def identity[A](x: A): A = x // @see `conforms` for the implicit version @inline def implicitly[T](implicit e: T) = e // for summoning implicit values from the nether world -- TODO: when dependent method types are on by default, give this result type `e.type`, so that inliner has better chance of knowing which method to inline in calls like `implicitly[MatchingStrategy[Option]].zero` @inline def locally[T](x: T): T = x // to communicate intent and avoid unmoored statements @@ -329,16 +329,28 @@ object Predef extends LowPriorityImplicits with DeprecatedPredef { case null => null }).asInstanceOf[ArrayOps[T]] - implicit def booleanArrayOps(xs: Array[Boolean]): ArrayOps[Boolean] = new ArrayOps.ofBoolean(xs) - implicit def byteArrayOps(xs: Array[Byte]): ArrayOps[Byte] = new ArrayOps.ofByte(xs) - implicit def charArrayOps(xs: Array[Char]): ArrayOps[Char] = new ArrayOps.ofChar(xs) - implicit def doubleArrayOps(xs: Array[Double]): ArrayOps[Double] = new ArrayOps.ofDouble(xs) - implicit def floatArrayOps(xs: Array[Float]): ArrayOps[Float] = new ArrayOps.ofFloat(xs) - implicit def intArrayOps(xs: Array[Int]): ArrayOps[Int] = new ArrayOps.ofInt(xs) - implicit def longArrayOps(xs: Array[Long]): ArrayOps[Long] = new ArrayOps.ofLong(xs) - implicit def refArrayOps[T <: AnyRef](xs: Array[T]): ArrayOps[T] = new ArrayOps.ofRef[T](xs) - implicit def shortArrayOps(xs: Array[Short]): ArrayOps[Short] = new ArrayOps.ofShort(xs) - implicit def unitArrayOps(xs: Array[Unit]): ArrayOps[Unit] = new ArrayOps.ofUnit(xs) + // TODO: when we remove, these should we drop the underscores from the new generation below? (For source compatibility in case someone was shadowing these.) + @deprecated("For binary compatibility only. Release new partest and remove in M3.", "2.12.0-M2") def booleanArrayOps(xs: Array[Boolean]): ArrayOps[Boolean] = new ArrayOps.ofBoolean(xs) + @deprecated("For binary compatibility only. Release new partest and remove in M3.", "2.12.0-M2") def byteArrayOps(xs: Array[Byte]): ArrayOps[Byte] = new ArrayOps.ofByte(xs) + @deprecated("For binary compatibility only. Release new partest and remove in M3.", "2.12.0-M2") def charArrayOps(xs: Array[Char]): ArrayOps[Char] = new ArrayOps.ofChar(xs) + @deprecated("For binary compatibility only. Release new partest and remove in M3.", "2.12.0-M2") def doubleArrayOps(xs: Array[Double]): ArrayOps[Double] = new ArrayOps.ofDouble(xs) + @deprecated("For binary compatibility only. Release new partest and remove in M3.", "2.12.0-M2") def floatArrayOps(xs: Array[Float]): ArrayOps[Float] = new ArrayOps.ofFloat(xs) + @deprecated("For binary compatibility only. Release new partest and remove in M3.", "2.12.0-M2") def intArrayOps(xs: Array[Int]): ArrayOps[Int] = new ArrayOps.ofInt(xs) + @deprecated("For binary compatibility only. Release new partest and remove in M3.", "2.12.0-M2") def longArrayOps(xs: Array[Long]): ArrayOps[Long] = new ArrayOps.ofLong(xs) + @deprecated("For binary compatibility only. Release new partest and remove in M3.", "2.12.0-M2") def refArrayOps[T <: AnyRef](xs: Array[T]): ArrayOps[T] = new ArrayOps.ofRef[T](xs) + @deprecated("For binary compatibility only. Release new partest and remove in M3.", "2.12.0-M2") def shortArrayOps(xs: Array[Short]): ArrayOps[Short] = new ArrayOps.ofShort(xs) + @deprecated("For binary compatibility only. Release new partest and remove in M3.", "2.12.0-M2") def unitArrayOps(xs: Array[Unit]): ArrayOps[Unit] = new ArrayOps.ofUnit(xs) + + implicit def _booleanArrayOps(xs: Array[Boolean]): ArrayOps.ofBoolean = new ArrayOps.ofBoolean(xs) + implicit def _byteArrayOps(xs: Array[Byte]): ArrayOps.ofByte = new ArrayOps.ofByte(xs) + implicit def _charArrayOps(xs: Array[Char]): ArrayOps.ofChar = new ArrayOps.ofChar(xs) + implicit def _doubleArrayOps(xs: Array[Double]): ArrayOps.ofDouble = new ArrayOps.ofDouble(xs) + implicit def _floatArrayOps(xs: Array[Float]): ArrayOps.ofFloat = new ArrayOps.ofFloat(xs) + implicit def _intArrayOps(xs: Array[Int]): ArrayOps.ofInt = new ArrayOps.ofInt(xs) + implicit def _longArrayOps(xs: Array[Long]): ArrayOps.ofLong = new ArrayOps.ofLong(xs) + implicit def _refArrayOps[T <: AnyRef](xs: Array[T]): ArrayOps.ofRef[T] = new ArrayOps.ofRef[T](xs) + implicit def _shortArrayOps(xs: Array[Short]): ArrayOps.ofShort = new ArrayOps.ofShort(xs) + implicit def _unitArrayOps(xs: Array[Unit]): ArrayOps.ofUnit = new ArrayOps.ofUnit(xs) // "Autoboxing" and "Autounboxing" --------------------------------------------------- diff --git a/src/library/scala/beans/BeanInfo.scala b/src/library/scala/beans/BeanInfo.scala index 799e93e71a..d7f0a1618b 100644 --- a/src/library/scala/beans/BeanInfo.scala +++ b/src/library/scala/beans/BeanInfo.scala @@ -17,4 +17,5 @@ package scala.beans * * @author Ross Judson (rjudson@managedobjects.com) */ +@deprecated(message = "the generation of BeanInfo classes is no longer supported", since = "2.12.0") class BeanInfo extends scala.annotation.Annotation diff --git a/src/library/scala/collection/IterableViewLike.scala b/src/library/scala/collection/IterableViewLike.scala index b84d90c51b..c254ed7480 100644 --- a/src/library/scala/collection/IterableViewLike.scala +++ b/src/library/scala/collection/IterableViewLike.scala @@ -69,6 +69,10 @@ trait IterableViewLike[+A, trait Appended[B >: A] extends super.Appended[B] with Transformed[B] { def iterator = self.iterator ++ rest } + + trait Prepended[B >: A] extends super.Prepended[B] with Transformed[B] { + def iterator = fst.toIterator ++ self + } trait Filtered extends super.Filtered with Transformed[A] { def iterator = self.iterator filter pred @@ -110,6 +114,7 @@ trait IterableViewLike[+A, } with AbstractTransformed[(A1, B)] with ZippedAll[A1, B] protected override def newForced[B](xs: => GenSeq[B]): Transformed[B] = new { val forced = xs } with AbstractTransformed[B] with Forced[B] protected override def newAppended[B >: A](that: GenTraversable[B]): Transformed[B] = new { val rest = that } with AbstractTransformed[B] with Appended[B] + protected override def newPrepended[B >: A](that: GenTraversable[B]): Transformed[B] = new { val fst = that } with AbstractTransformed[B] with Prepended[B] protected override def newMapped[B](f: A => B): Transformed[B] = new { val mapping = f } with AbstractTransformed[B] with Mapped[B] protected override def newFlatMapped[B](f: A => GenTraversableOnce[B]): Transformed[B] = new { val mapping = f } with AbstractTransformed[B] with FlatMapped[B] protected override def newFiltered(p: A => Boolean): Transformed[A] = new { val pred = p } with AbstractTransformed[A] with Filtered diff --git a/src/library/scala/collection/Iterator.scala b/src/library/scala/collection/Iterator.scala index c9037eb3e3..e2c271145d 100644 --- a/src/library/scala/collection/Iterator.scala +++ b/src/library/scala/collection/Iterator.scala @@ -182,7 +182,7 @@ object Iterator { } } def hasNext = (current ne null) && (current.hasNext || advance()) - def next() = if (hasNext) current.next else Iterator.empty.next + def next() = if (hasNext) current.next() else Iterator.empty.next() override def ++[B >: A](that: => GenTraversableOnce[B]): Iterator[B] = new ConcatIterator(current, queue :+ (() => that.toIterator)) @@ -191,11 +191,55 @@ object Iterator { private[scala] final class JoinIterator[+A](lhs: Iterator[A], that: => GenTraversableOnce[A]) extends Iterator[A] { private[this] lazy val rhs: Iterator[A] = that.toIterator def hasNext = lhs.hasNext || rhs.hasNext - def next = if (lhs.hasNext) lhs.next else rhs.next + def next() = if (lhs.hasNext) lhs.next() else rhs.next() override def ++[B >: A](that: => GenTraversableOnce[B]) = new ConcatIterator(this, Vector(() => that.toIterator)) } + + /** Creates a delegating iterator capped by a limit count. Negative limit means unbounded. + * Lazily skip to start on first evaluation. Avoids daisy-chained iterators due to slicing. + */ + private[scala] final class SliceIterator[A](val underlying: Iterator[A], start: Int, limit: Int) extends AbstractIterator[A] { + private var remaining = limit + private var dropping = start + @inline private def unbounded = remaining < 0 + private def skip(): Unit = + while (dropping > 0) { + if (underlying.hasNext) { + underlying.next() + dropping -= 1 + } else + dropping = 0 + } + def hasNext = { skip(); remaining != 0 && underlying.hasNext } + def next() = { + skip() + if (remaining > 0) { + remaining -= 1 + underlying.next() + } + else if (unbounded) underlying.next() + else empty.next() + } + override protected def sliceIterator(from: Int, until: Int): Iterator[A] = { + val lo = from max 0 + def adjustedBound = + if (unbounded) -1 + else 0 max (remaining - lo) + val rest = + if (until < 0) adjustedBound // respect current bound, if any + else if (until <= lo) 0 // empty + else if (unbounded) until - lo // now finite + else adjustedBound min (until - lo) // keep lesser bound + if (rest == 0) empty + else { + dropping += lo + remaining = rest + this + } + } + } } import Iterator.empty @@ -307,11 +351,11 @@ trait Iterator[+A] extends TraversableOnce[A] { /** Selects first ''n'' values of this iterator. * * @param n the number of values to take - * @return an iterator producing only of the first `n` values of this iterator, or else the + * @return an iterator producing only the first `n` values of this iterator, or else the * whole iterator, if it produces fewer than `n` values. * @note Reuse: $consumesAndProducesIterator */ - def take(n: Int): Iterator[A] = slice(0, n) + def take(n: Int): Iterator[A] = sliceIterator(0, n max 0) /** Advances this iterator past the first ''n'' elements, or the length of the iterator, whichever is smaller. * @@ -332,29 +376,24 @@ trait Iterator[+A] extends TraversableOnce[A] { /** Creates an iterator returning an interval of the values produced by this iterator. * * @param from the index of the first element in this iterator which forms part of the slice. - * @param until the index of the first element following the slice. + * If negative, the slice starts at zero. + * @param until the index of the first element following the slice. If negative, the slice is empty. * @return an iterator which advances this iterator past the first `from` elements using `drop`, * and then takes `until - from` elements, using `take`. * @note Reuse: $consumesAndProducesIterator */ - def slice(from: Int, until: Int): Iterator[A] = { + def slice(from: Int, until: Int): Iterator[A] = sliceIterator(from, until max 0) + + /** Creates an optionally bounded slice, unbounded if `until` is negative. */ + protected def sliceIterator(from: Int, until: Int): Iterator[A] = { val lo = from max 0 - var toDrop = lo - while (toDrop > 0 && self.hasNext) { - self.next() - toDrop -= 1 - } + val rest = + if (until < 0) -1 // unbounded + else if (until <= lo) 0 // empty + else until - lo // finite - new AbstractIterator[A] { - private var remaining = until - lo - def hasNext = remaining > 0 && self.hasNext - def next(): A = - if (remaining > 0) { - remaining -= 1 - self.next() - } - else empty.next() - } + if (rest == 0) empty + else new Iterator.SliceIterator(this, lo, rest) } /** Creates a new iterator that maps all produced values of this iterator @@ -805,8 +844,25 @@ trait Iterator[+A] extends TraversableOnce[A] { * or -1 if such an element does not exist until the end of the iterator is reached. * @note Reuse: $consumesIterator */ - def indexWhere(p: A => Boolean): Int = { + def indexWhere(p: A => Boolean): Int = indexWhere(p, 0) + + /** Returns the index of the first produced value satisfying a predicate, or -1, after or at + * some start index. + * $mayNotTerminateInf + * + * @param p the predicate to test values + * @param from the start index + * @return the index `>= from` of the first produced value satisfying `p`, + * or -1 if such an element does not exist until the end of the iterator is reached. + * @note Reuse: $consumesIterator + */ + def indexWhere(p: A => Boolean, from: Int): Int = { var i = 0 + while (i < from && hasNext) { + next() + i += 1 + } + var found = false while (!found && hasNext) { if (p(next())) { @@ -827,8 +883,26 @@ trait Iterator[+A] extends TraversableOnce[A] { * or -1 if such an element does not exist until the end of the iterator is reached. * @note Reuse: $consumesIterator */ - def indexOf[B >: A](elem: B): Int = { + def indexOf[B >: A](elem: B): Int = indexOf(elem, 0) + + /** Returns the index of the first occurrence of the specified object in this iterable object + * after or at some start index. + * $mayNotTerminateInf + * + * @param elem element to search for. + * @param from the start index + * @return the index `>= from` of the first occurrence of `elem` in the values produced by this + * iterator, or -1 if such an element does not exist until the end of the iterator is + * reached. + * @note Reuse: $consumesIterator + */ + def indexOf[B >: A](elem: B, from: Int): Int = { var i = 0 + while (i < from && hasNext) { + next() + i += 1 + } + var found = false while (!found && hasNext) { if (next() == elem) { @@ -1147,9 +1221,8 @@ trait Iterator[+A] extends TraversableOnce[A] { * $willNotTerminateInf */ def copyToArray[B >: A](xs: Array[B], start: Int, len: Int): Unit = { - require(start >= 0 && (start < xs.length || xs.length == 0), s"start $start out of range ${xs.length}") var i = start - val end = start + math.min(len, xs.length - start) + val end = start + math.min(len, xs.length - start) while (i < end && hasNext) { xs(i) = next() i += 1 diff --git a/src/library/scala/collection/MapLike.scala b/src/library/scala/collection/MapLike.scala index d133400570..b474abc12a 100644 --- a/src/library/scala/collection/MapLike.scala +++ b/src/library/scala/collection/MapLike.scala @@ -230,11 +230,15 @@ self => protected class FilteredKeys(p: A => Boolean) extends AbstractMap[A, B] with DefaultMap[A, B] { override def foreach[C](f: ((A, B)) => C): Unit = for (kv <- self) if (p(kv._1)) f(kv) def iterator = self.iterator.filter(kv => p(kv._1)) - override def contains(key: A) = self.contains(key) && p(key) + override def contains(key: A) = p(key) && self.contains(key) def get(key: A) = if (!p(key)) None else self.get(key) } /** Filters this map by retaining only keys satisfying a predicate. + * + * '''Note''': the predicate must accept any key of type `A`, not just those already + * present in the map, as the predicate is tested before the underlying map is queried. + * * @param p the predicate used to test keys * @return an immutable map consisting only of those key value pairs of this map where the key satisfies * the predicate `p`. The resulting map wraps the original map without copying any elements. @@ -319,11 +323,20 @@ self => res } - /* Overridden for efficiency. */ - override def toSeq: Seq[(A, B)] = toBuffer[(A, B)] + override def toSeq: Seq[(A, B)] = { + if (isEmpty) Vector.empty[(A, B)] + else { + // Default appropriate for immutable collections; mutable collections override this + val vb = Vector.newBuilder[(A, B)] + foreach(vb += _) + vb.result + } + } + override def toBuffer[C >: (A, B)]: mutable.Buffer[C] = { val result = new mutable.ArrayBuffer[C](size) - copyToBuffer(result) + // Faster to let the map iterate itself than to defer through copyToBuffer + foreach(result += _) result } diff --git a/src/library/scala/collection/SeqViewLike.scala b/src/library/scala/collection/SeqViewLike.scala index 3473c8aff1..1fbcb6531e 100644 --- a/src/library/scala/collection/SeqViewLike.scala +++ b/src/library/scala/collection/SeqViewLike.scala @@ -96,6 +96,14 @@ trait SeqViewLike[+A, if (idx < self.length) self(idx) else restSeq(idx - self.length) } + trait Prepended[B >: A] extends super.Prepended[B] with Transformed[B] { + protected[this] lazy val fstSeq = fst.toSeq + def length: Int = fstSeq.length + self.length + def apply(idx: Int): B = + if (idx < fstSeq.length) fstSeq(idx) + else self.apply(idx - fstSeq.length) + } + trait Filtered extends super.Filtered with Transformed[A] { protected[this] lazy val index = { var len = 0 @@ -179,21 +187,12 @@ trait SeqViewLike[+A, final override protected[this] def viewIdentifier = "P" } - trait Prepended[B >: A] extends Transformed[B] { - protected[this] val fst: B - override def iterator: Iterator[B] = Iterator.single(fst) ++ self.iterator - def length: Int = 1 + self.length - def apply(idx: Int): B = - if (idx == 0) fst - else self.apply(idx - 1) - final override protected[this] def viewIdentifier = "A" - } - /** Boilerplate method, to override in each subclass * This method could be eliminated if Scala had virtual classes */ protected override def newForced[B](xs: => GenSeq[B]): Transformed[B] = new { val forced = xs } with AbstractTransformed[B] with Forced[B] protected override def newAppended[B >: A](that: GenTraversable[B]): Transformed[B] = new { val rest = that } with AbstractTransformed[B] with Appended[B] + protected override def newPrepended[B >: A](that: GenTraversable[B]): Transformed[B] = new { protected[this] val fst = that } with AbstractTransformed[B] with Prepended[B] protected override def newMapped[B](f: A => B): Transformed[B] = new { val mapping = f } with AbstractTransformed[B] with Mapped[B] protected override def newFlatMapped[B](f: A => GenTraversableOnce[B]): Transformed[B] = new { val mapping = f } with AbstractTransformed[B] with FlatMapped[B] protected override def newFiltered(p: A => Boolean): Transformed[A] = new { val pred = p } with AbstractTransformed[A] with Filtered @@ -212,7 +211,6 @@ trait SeqViewLike[+A, val patch = _patch val replaced = _replaced } with AbstractTransformed[B] with Patched[B] - protected def newPrepended[B >: A](elem: B): Transformed[B] = new { protected[this] val fst = elem } with AbstractTransformed[B] with Prepended[B] // see comment in IterableViewLike. protected override def newTaken(n: Int): Transformed[A] = newSliced(SliceInterval(0, n)) @@ -242,7 +240,7 @@ trait SeqViewLike[+A, } override def +:[B >: A, That](elem: B)(implicit bf: CanBuildFrom[This, B, That]): That = - newPrepended(elem).asInstanceOf[That] + newPrepended(elem :: Nil).asInstanceOf[That] override def :+[B >: A, That](elem: B)(implicit bf: CanBuildFrom[This, B, That]): That = ++(Iterator.single(elem))(bf) diff --git a/src/library/scala/collection/SetLike.scala b/src/library/scala/collection/SetLike.scala index f8ac1d754d..d03c808c2c 100644 --- a/src/library/scala/collection/SetLike.scala +++ b/src/library/scala/collection/SetLike.scala @@ -77,11 +77,20 @@ self => protected[this] override def parCombiner = ParSet.newCombiner[A] - /* Overridden for efficiency. */ - override def toSeq: Seq[A] = toBuffer[A] + // Default collection type appropriate for immutable collections; mutable collections override this + override def toSeq: Seq[A] = { + if (isEmpty) Vector.empty[A] + else { + val vb = Vector.newBuilder[A] + foreach(vb += _) + vb.result + } + } + override def toBuffer[A1 >: A]: mutable.Buffer[A1] = { val result = new mutable.ArrayBuffer[A1](size) - copyToBuffer(result) + // Faster to let the map iterate itself than to defer through copyToBuffer + foreach(result += _) result } diff --git a/src/library/scala/collection/TraversableLike.scala b/src/library/scala/collection/TraversableLike.scala index 96374ef653..f187a7a655 100644 --- a/src/library/scala/collection/TraversableLike.scala +++ b/src/library/scala/collection/TraversableLike.scala @@ -253,7 +253,7 @@ trait TraversableLike[+A, +Repr] extends Any b.result } - private def filterImpl(p: A => Boolean, isFlipped: Boolean): Repr = { + private[scala] def filterImpl(p: A => Boolean, isFlipped: Boolean): Repr = { val b = newBuilder for (x <- this) if (p(x) != isFlipped) b += x diff --git a/src/library/scala/collection/TraversableViewLike.scala b/src/library/scala/collection/TraversableViewLike.scala index 5926c69ebf..0901d749c3 100644 --- a/src/library/scala/collection/TraversableViewLike.scala +++ b/src/library/scala/collection/TraversableViewLike.scala @@ -189,6 +189,15 @@ trait TraversableViewLike[+A, } final override protected[this] def viewIdentifier = "A" } + + trait Prepended[B >: A] extends Transformed[B] { + protected[this] val fst: GenTraversable[B] + def foreach[U](f: B => U) { + fst foreach f + self foreach f + } + final override protected[this] def viewIdentifier = "A" + } trait Filtered extends Transformed[A] { protected[this] val pred: A => Boolean @@ -222,11 +231,15 @@ trait TraversableViewLike[+A, final override protected[this] def viewIdentifier = "D" } - override def ++[B >: A, That](xs: GenTraversableOnce[B])(implicit bf: CanBuildFrom[This, B, That]): That = { + override def ++[B >: A, That](xs: GenTraversableOnce[B])(implicit bf: CanBuildFrom[This, B, That]): That = newAppended(xs.seq.toTraversable).asInstanceOf[That] -// was: if (bf.isInstanceOf[ByPassCanBuildFrom]) newAppended(that).asInstanceOf[That] -// else super.++[B, That](that)(bf) - } + + override def ++:[B >: A, That](xs: TraversableOnce[B])(implicit bf: CanBuildFrom[This, B, That]): That = + newPrepended(xs.seq.toTraversable).asInstanceOf[That] + + // Need second one because of optimization in TraversableLike + override def ++:[B >: A, That](xs: Traversable[B])(implicit bf: CanBuildFrom[This, B, That]): That = + newPrepended(xs).asInstanceOf[That] override def map[B, That](f: A => B)(implicit bf: CanBuildFrom[This, B, That]): That = { newMapped(f).asInstanceOf[That] @@ -253,6 +266,7 @@ trait TraversableViewLike[+A, */ protected def newForced[B](xs: => GenSeq[B]): Transformed[B] = new { val forced = xs } with AbstractTransformed[B] with Forced[B] protected def newAppended[B >: A](that: GenTraversable[B]): Transformed[B] = new { val rest = that } with AbstractTransformed[B] with Appended[B] + protected def newPrepended[B >: A](that: GenTraversable[B]): Transformed[B] = new { val fst = that } with AbstractTransformed[B] with Prepended[B] protected def newMapped[B](f: A => B): Transformed[B] = new { val mapping = f } with AbstractTransformed[B] with Mapped[B] protected def newFlatMapped[B](f: A => GenTraversableOnce[B]): Transformed[B] = new { val mapping = f } with AbstractTransformed[B] with FlatMapped[B] protected def newFiltered(p: A => Boolean): Transformed[A] = new { val pred = p } with AbstractTransformed[A] with Filtered diff --git a/src/library/scala/collection/concurrent/Map.scala b/src/library/scala/collection/concurrent/Map.scala index cfb567abe9..f27dfd57fc 100644 --- a/src/library/scala/collection/concurrent/Map.scala +++ b/src/library/scala/collection/concurrent/Map.scala @@ -86,4 +86,15 @@ trait Map[A, B] extends scala.collection.mutable.Map[A, B] { * @return `Some(v)` if the given key was previously mapped to some value `v`, or `None` otherwise */ def replace(k: A, v: B): Option[B] + + override def getOrElseUpdate(key: A, op: =>B): B = get(key) match { + case Some(v) => v + case None => + val v = op + putIfAbsent(key, v) match { + case Some(nv) => nv + case None => v + } + } + } diff --git a/src/library/scala/collection/convert/WrapAsJava.scala b/src/library/scala/collection/convert/WrapAsJava.scala index 9916fe9843..e97a2ff1fc 100644 --- a/src/library/scala/collection/convert/WrapAsJava.scala +++ b/src/library/scala/collection/convert/WrapAsJava.scala @@ -30,8 +30,9 @@ trait WrapAsJava { * @return A Java Iterator view of the argument. */ implicit def asJavaIterator[A](it: Iterator[A]): ju.Iterator[A] = it match { - case JIteratorWrapper(wrapped) => wrapped.asInstanceOf[ju.Iterator[A]] - case _ => IteratorWrapper(it) + case null => null + case JIteratorWrapper(wrapped) => wrapped.asInstanceOf[ju.Iterator[A]] + case _ => IteratorWrapper(it) } /** @@ -48,8 +49,9 @@ trait WrapAsJava { * @return A Java Enumeration view of the argument. */ implicit def asJavaEnumeration[A](it: Iterator[A]): ju.Enumeration[A] = it match { + case null => null case JEnumerationWrapper(wrapped) => wrapped.asInstanceOf[ju.Enumeration[A]] - case _ => IteratorWrapper(it) + case _ => IteratorWrapper(it) } /** @@ -66,8 +68,9 @@ trait WrapAsJava { * @return A Java Iterable view of the argument. */ implicit def asJavaIterable[A](i: Iterable[A]): jl.Iterable[A] = i match { - case JIterableWrapper(wrapped) => wrapped.asInstanceOf[jl.Iterable[A]] - case _ => IterableWrapper(i) + case null => null + case JIterableWrapper(wrapped) => wrapped.asInstanceOf[jl.Iterable[A]] + case _ => IterableWrapper(i) } /** @@ -82,8 +85,9 @@ trait WrapAsJava { * @return A Java Collection view of the argument. */ implicit def asJavaCollection[A](it: Iterable[A]): ju.Collection[A] = it match { - case JCollectionWrapper(wrapped) => wrapped.asInstanceOf[ju.Collection[A]] - case _ => new IterableWrapper(it) + case null => null + case JCollectionWrapper(wrapped) => wrapped.asInstanceOf[ju.Collection[A]] + case _ => new IterableWrapper(it) } /** @@ -100,8 +104,9 @@ trait WrapAsJava { * @return A Java List view of the argument. */ implicit def bufferAsJavaList[A](b: mutable.Buffer[A]): ju.List[A] = b match { - case JListWrapper(wrapped) => wrapped - case _ => new MutableBufferWrapper(b) + case null => null + case JListWrapper(wrapped) => wrapped + case _ => new MutableBufferWrapper(b) } /** @@ -118,8 +123,9 @@ trait WrapAsJava { * @return A Java List view of the argument. */ implicit def mutableSeqAsJavaList[A](seq: mutable.Seq[A]): ju.List[A] = seq match { - case JListWrapper(wrapped) => wrapped - case _ => new MutableSeqWrapper(seq) + case null => null + case JListWrapper(wrapped) => wrapped + case _ => new MutableSeqWrapper(seq) } /** @@ -136,8 +142,9 @@ trait WrapAsJava { * @return A Java List view of the argument. */ implicit def seqAsJavaList[A](seq: Seq[A]): ju.List[A] = seq match { - case JListWrapper(wrapped) => wrapped.asInstanceOf[ju.List[A]] - case _ => new SeqWrapper(seq) + case null => null + case JListWrapper(wrapped) => wrapped.asInstanceOf[ju.List[A]] + case _ => new SeqWrapper(seq) } /** @@ -154,8 +161,9 @@ trait WrapAsJava { * @return A Java Set view of the argument. */ implicit def mutableSetAsJavaSet[A](s: mutable.Set[A]): ju.Set[A] = s match { + case null => null case JSetWrapper(wrapped) => wrapped - case _ => new MutableSetWrapper(s) + case _ => new MutableSetWrapper(s) } /** @@ -172,8 +180,9 @@ trait WrapAsJava { * @return A Java Set view of the argument. */ implicit def setAsJavaSet[A](s: Set[A]): ju.Set[A] = s match { + case null => null case JSetWrapper(wrapped) => wrapped - case _ => new SetWrapper(s) + case _ => new SetWrapper(s) } /** @@ -190,9 +199,9 @@ trait WrapAsJava { * @return A Java Map view of the argument. */ implicit def mutableMapAsJavaMap[A, B](m: mutable.Map[A, B]): ju.Map[A, B] = m match { - //case JConcurrentMapWrapper(wrapped) => wrapped + case null => null case JMapWrapper(wrapped) => wrapped - case _ => new MutableMapWrapper(m) + case _ => new MutableMapWrapper(m) } /** @@ -210,9 +219,9 @@ trait WrapAsJava { * @return A Java `Dictionary` view of the argument. */ implicit def asJavaDictionary[A, B](m: mutable.Map[A, B]): ju.Dictionary[A, B] = m match { - //case JConcurrentMapWrapper(wrapped) => wrapped - case JDictionaryWrapper(wrapped) => wrapped - case _ => new DictionaryWrapper(m) + case null => null + case JDictionaryWrapper(wrapped) => wrapped + case _ => new DictionaryWrapper(m) } /** @@ -230,9 +239,9 @@ trait WrapAsJava { * @return A Java `Map` view of the argument. */ implicit def mapAsJavaMap[A, B](m: Map[A, B]): ju.Map[A, B] = m match { - //case JConcurrentMapWrapper(wrapped) => wrapped + case null => null case JMapWrapper(wrapped) => wrapped.asInstanceOf[ju.Map[A, B]] - case _ => new MapWrapper(m) + case _ => new MapWrapper(m) } /** @@ -251,8 +260,9 @@ trait WrapAsJava { * @return A Java `ConcurrentMap` view of the argument. */ implicit def mapAsJavaConcurrentMap[A, B](m: concurrent.Map[A, B]): juc.ConcurrentMap[A, B] = m match { + case null => null case JConcurrentMapWrapper(wrapped) => wrapped - case _ => new ConcurrentMapWrapper(m) + case _ => new ConcurrentMapWrapper(m) } } diff --git a/src/library/scala/collection/convert/WrapAsScala.scala b/src/library/scala/collection/convert/WrapAsScala.scala index ab151a6778..7332b71af1 100644 --- a/src/library/scala/collection/convert/WrapAsScala.scala +++ b/src/library/scala/collection/convert/WrapAsScala.scala @@ -30,8 +30,9 @@ trait WrapAsScala { * @return A Scala `Iterator` view of the argument. */ implicit def asScalaIterator[A](it: ju.Iterator[A]): Iterator[A] = it match { + case null => null case IteratorWrapper(wrapped) => wrapped - case _ => JIteratorWrapper(it) + case _ => JIteratorWrapper(it) } /** @@ -48,8 +49,9 @@ trait WrapAsScala { * @return A Scala Iterator view of the argument. */ implicit def enumerationAsScalaIterator[A](i: ju.Enumeration[A]): Iterator[A] = i match { + case null => null case IteratorWrapper(wrapped) => wrapped - case _ => JEnumerationWrapper(i) + case _ => JEnumerationWrapper(i) } /** @@ -67,8 +69,9 @@ trait WrapAsScala { * @return A Scala Iterable view of the argument. */ implicit def iterableAsScalaIterable[A](i: jl.Iterable[A]): Iterable[A] = i match { + case null => null case IterableWrapper(wrapped) => wrapped - case _ => JIterableWrapper(i) + case _ => JIterableWrapper(i) } /** @@ -82,8 +85,9 @@ trait WrapAsScala { * @return A Scala Iterable view of the argument. */ implicit def collectionAsScalaIterable[A](i: ju.Collection[A]): Iterable[A] = i match { + case null => null case IterableWrapper(wrapped) => wrapped - case _ => JCollectionWrapper(i) + case _ => JCollectionWrapper(i) } /** @@ -101,8 +105,9 @@ trait WrapAsScala { * @return A Scala mutable `Buffer` view of the argument. */ implicit def asScalaBuffer[A](l: ju.List[A]): mutable.Buffer[A] = l match { - case MutableBufferWrapper(wrapped) => wrapped - case _ =>new JListWrapper(l) + case null => null + case MutableBufferWrapper(wrapped) => wrapped + case _ => new JListWrapper(l) } /** @@ -119,8 +124,9 @@ trait WrapAsScala { * @return A Scala mutable Set view of the argument. */ implicit def asScalaSet[A](s: ju.Set[A]): mutable.Set[A] = s match { + case null => null case MutableSetWrapper(wrapped) => wrapped - case _ =>new JSetWrapper(s) + case _ => new JSetWrapper(s) } /** @@ -144,9 +150,9 @@ trait WrapAsScala { * @return A Scala mutable Map view of the argument. */ implicit def mapAsScalaMap[A, B](m: ju.Map[A, B]): mutable.Map[A, B] = m match { - //case ConcurrentMapWrapper(wrapped) => wrapped + case null => null case MutableMapWrapper(wrapped) => wrapped - case _ => new JMapWrapper(m) + case _ => new JMapWrapper(m) } /** @@ -163,8 +169,9 @@ trait WrapAsScala { * @return A Scala mutable ConcurrentMap view of the argument. */ implicit def mapAsScalaConcurrentMap[A, B](m: juc.ConcurrentMap[A, B]): concurrent.Map[A, B] = m match { - case cmw: ConcurrentMapWrapper[a, b] => cmw.underlying - case _ => new JConcurrentMapWrapper(m) + case null => null + case cmw: ConcurrentMapWrapper[A, B] => cmw.underlying + case _ => new JConcurrentMapWrapper(m) } /** @@ -179,8 +186,9 @@ trait WrapAsScala { * @return A Scala mutable Map[String, String] view of the argument. */ implicit def dictionaryAsScalaMap[A, B](p: ju.Dictionary[A, B]): mutable.Map[A, B] = p match { + case null => null case DictionaryWrapper(wrapped) => wrapped - case _ => new JDictionaryWrapper(p) + case _ => new JDictionaryWrapper(p) } /** @@ -194,7 +202,8 @@ trait WrapAsScala { * @return A Scala mutable Map[String, String] view of the argument. */ implicit def propertiesAsScalaMap(p: ju.Properties): mutable.Map[String, String] = p match { - case _ => new JPropertiesWrapper(p) + case null => null + case _ => new JPropertiesWrapper(p) } } diff --git a/src/library/scala/collection/generic/MutableSortedMapFactory.scala b/src/library/scala/collection/generic/MutableSortedMapFactory.scala new file mode 100644 index 0000000000..b6fa933ca8 --- /dev/null +++ b/src/library/scala/collection/generic/MutableSortedMapFactory.scala @@ -0,0 +1,24 @@ +package scala +package collection +package generic + +import scala.language.higherKinds + +/** + * A template for companion objects of `SortedMap` and subclasses thereof. + * + * @tparam CC the type of the collection. + * + * @author Rui Gonçalves + * @since 2.12 + * @version 2.12 + * + * @define Coll `mutable.SortedMap` + * @define coll mutable sorted map + * @define factoryInfo + * This object provides a set of operations needed to create sorted maps of type `$Coll`. + * @define sortedMapCanBuildFromInfo + * The standard `CanBuildFrom` instance for sorted maps + */ +abstract class MutableSortedMapFactory[CC[A, B] <: mutable.SortedMap[A, B] with SortedMapLike[A, B, CC[A, B]]] + extends SortedMapFactory[CC] diff --git a/src/library/scala/collection/immutable/HashSet.scala b/src/library/scala/collection/immutable/HashSet.scala index f548eac88d..49b4397cf2 100644 --- a/src/library/scala/collection/immutable/HashSet.scala +++ b/src/library/scala/collection/immutable/HashSet.scala @@ -194,7 +194,7 @@ class HashSet[A] extends AbstractSet[A] protected def get0(key: A, hash: Int, level: Int): Boolean = false - def updated0(key: A, hash: Int, level: Int): HashSet[A] = + private[collection] def updated0(key: A, hash: Int, level: Int): HashSet[A] = new HashSet.HashSet1(key, hash) protected def removed0(key: A, hash: Int, level: Int): HashSet[A] = this @@ -256,10 +256,10 @@ object HashSet extends ImmutableSetFactory[HashSet] { class HashSet1[A](private[HashSet] val key: A, private[HashSet] val hash: Int) extends LeafHashSet[A] { override def size = 1 - override def get0(key: A, hash: Int, level: Int): Boolean = + override protected def get0(key: A, hash: Int, level: Int): Boolean = (hash == this.hash && key == this.key) - override def subsetOf0(that: HashSet[A], level: Int) = { + override protected def subsetOf0(that: HashSet[A], level: Int) = { // check if that contains this.key // we use get0 with our key and hash at the correct level instead of calling contains, // which would not work since that might not be a top-level HashSet @@ -267,7 +267,7 @@ object HashSet extends ImmutableSetFactory[HashSet] { that.get0(key, hash, level) } - override def updated0(key: A, hash: Int, level: Int): HashSet[A] = + override private[collection] def updated0(key: A, hash: Int, level: Int): HashSet[A] = if (hash == this.hash && key == this.key) this else { if (hash != this.hash) { @@ -312,7 +312,7 @@ object HashSet extends ImmutableSetFactory[HashSet] { override private[immutable] def diff0(that: HashSet[A], level: Int, buffer: Array[HashSet[A]], offset0: Int): HashSet[A] = if (that.get0(key, hash, level)) null else this - override def removed0(key: A, hash: Int, level: Int): HashSet[A] = + override protected def removed0(key: A, hash: Int, level: Int): HashSet[A] = if (hash == this.hash && key == this.key) null else this override protected def filter0(p: A => Boolean, negate: Boolean, level: Int, buffer: Array[HashSet[A]], offset0: Int): HashSet[A] = @@ -326,10 +326,10 @@ object HashSet extends ImmutableSetFactory[HashSet] { override def size = ks.size - override def get0(key: A, hash: Int, level: Int): Boolean = + override protected def get0(key: A, hash: Int, level: Int): Boolean = if (hash == this.hash) ks.contains(key) else false - override def subsetOf0(that: HashSet[A], level: Int) = { + override protected def subsetOf0(that: HashSet[A], level: Int) = { // we have to check each element // we use get0 with our hash at the correct level instead of calling contains, // which would not work since that might not be a top-level HashSet @@ -337,11 +337,11 @@ object HashSet extends ImmutableSetFactory[HashSet] { ks.forall(key => that.get0(key, hash, level)) } - override def updated0(key: A, hash: Int, level: Int): HashSet[A] = + override private[collection] def updated0(key: A, hash: Int, level: Int): HashSet[A] = if (hash == this.hash) new HashSetCollision1(hash, ks + key) else makeHashTrieSet(this.hash, this, hash, new HashSet1(key, hash), level) - override def union0(that: LeafHashSet[A], level: Int): HashSet[A] = that match { + override private[immutable] def union0(that: LeafHashSet[A], level: Int): HashSet[A] = that match { case that if that.hash != this.hash => // different hash code, so there is no need to investigate further. // Just create a branch node containing the two. @@ -374,7 +374,7 @@ object HashSet extends ImmutableSetFactory[HashSet] { } } - override def union0(that: HashSet[A], level: Int, buffer: Array[HashSet[A]], offset0: Int): HashSet[A] = that match { + override private[immutable] def union0(that: HashSet[A], level: Int, buffer: Array[HashSet[A]], offset0: Int): HashSet[A] = that match { case that: LeafHashSet[A] => // switch to the simpler Tree/Leaf implementation this.union0(that, level) @@ -431,7 +431,7 @@ object HashSet extends ImmutableSetFactory[HashSet] { } } - override def removed0(key: A, hash: Int, level: Int): HashSet[A] = + override protected def removed0(key: A, hash: Int, level: Int): HashSet[A] = if (hash == this.hash) { val ks1 = ks - key ks1.size match { @@ -528,7 +528,7 @@ object HashSet extends ImmutableSetFactory[HashSet] { override def size = size0 - override def get0(key: A, hash: Int, level: Int): Boolean = { + override protected def get0(key: A, hash: Int, level: Int): Boolean = { val index = (hash >>> level) & 0x1f val mask = (1 << index) if (bitmap == - 1) { @@ -540,7 +540,7 @@ object HashSet extends ImmutableSetFactory[HashSet] { false } - override def updated0(key: A, hash: Int, level: Int): HashSet[A] = { + override private[collection] def updated0(key: A, hash: Int, level: Int): HashSet[A] = { val index = (hash >>> level) & 0x1f val mask = (1 << index) val offset = Integer.bitCount(bitmap & (mask-1)) @@ -842,7 +842,7 @@ object HashSet extends ImmutableSetFactory[HashSet] { case _ => this } - override def removed0(key: A, hash: Int, level: Int): HashSet[A] = { + override protected def removed0(key: A, hash: Int, level: Int): HashSet[A] = { val index = (hash >>> level) & 0x1f val mask = (1 << index) val offset = Integer.bitCount(bitmap & (mask-1)) @@ -879,7 +879,7 @@ object HashSet extends ImmutableSetFactory[HashSet] { } } - override def subsetOf0(that: HashSet[A], level: Int): Boolean = if (that eq this) true else that match { + override protected def subsetOf0(that: HashSet[A], level: Int): Boolean = if (that eq this) true else that match { case that: HashTrieSet[A] if this.size0 <= that.size0 => // create local mutable copies of members var abm = this.bitmap diff --git a/src/library/scala/collection/immutable/List.scala b/src/library/scala/collection/immutable/List.scala index 82e38d3549..7b1997252d 100644 --- a/src/library/scala/collection/immutable/List.scala +++ b/src/library/scala/collection/immutable/List.scala @@ -13,7 +13,7 @@ package immutable import generic._ import mutable.{Builder, ListBuffer} import scala.annotation.tailrec -import java.io._ +import java.io.{ObjectOutputStream, ObjectInputStream} /** A class for immutable linked lists representing ordered collections * of elements of type. @@ -86,7 +86,7 @@ sealed abstract class List[+A] extends AbstractSeq[A] with Product with GenericTraversableTemplate[A, List] with LinearSeqOptimized[A, List[A]] - with Serializable { + with scala.Serializable { override def companion: GenericCompanion[List] = List import scala.collection.{Iterable, Traversable, Seq, IndexedSeq} diff --git a/src/library/scala/collection/immutable/ListMap.scala b/src/library/scala/collection/immutable/ListMap.scala index 7c40e84280..c5773338f5 100644 --- a/src/library/scala/collection/immutable/ListMap.scala +++ b/src/library/scala/collection/immutable/ListMap.scala @@ -29,7 +29,11 @@ object ListMap extends ImmutableMapFactory[ListMap] { new MapCanBuildFrom[A, B] def empty[A, B]: ListMap[A, B] = EmptyListMap.asInstanceOf[ListMap[A, B]] - private object EmptyListMap extends ListMap[Any, Nothing] { } + @SerialVersionUID(-8256686706655863282L) + private object EmptyListMap extends ListMap[Any, Nothing] { + override def apply(key: Any) = throw new NoSuchElementException("key not found: " + key) + override def contains(key: Any) = false + } } /** This class implements immutable maps using a list-based data structure. @@ -159,7 +163,6 @@ extends AbstractMap[A, B] */ override def apply(k: A): B1 = apply0(this, k) - @tailrec private def apply0(cur: ListMap[A, B1], k: A): B1 = if (cur.isEmpty) throw new NoSuchElementException("key not found: "+k) else if (k == cur.key) cur.value @@ -176,7 +179,16 @@ extends AbstractMap[A, B] @tailrec private def get0(cur: ListMap[A, B1], k: A): Option[B1] = if (k == cur.key) Some(cur.value) else if (cur.next.nonEmpty) get0(cur.next, k) else None - + + + override def contains(key: A): Boolean = contains0(this, key) + + @tailrec private def contains0(cur: ListMap[A, B1], k: A): Boolean = + if (k == cur.key) true + else if (cur.next.nonEmpty) contains0(cur.next, k) + else false + + /** This method allows one to create a new map with an additional mapping * from `key` to `value`. If the map contains already a mapping for `key`, * it will be overridden by this function. @@ -186,6 +198,7 @@ extends AbstractMap[A, B] new m.Node[B2](k, v) } + /** Creates a new mapping without the given `key`. * If the map does not contain a mapping for the given key, the * method returns the same map. diff --git a/src/library/scala/collection/immutable/Map.scala b/src/library/scala/collection/immutable/Map.scala index 5178d5a862..63ddcb18cf 100644 --- a/src/library/scala/collection/immutable/Map.scala +++ b/src/library/scala/collection/immutable/Map.scala @@ -94,6 +94,8 @@ object Map extends ImmutableMapFactory[Map] { private object EmptyMap extends AbstractMap[Any, Nothing] with Map[Any, Nothing] with Serializable { override def size: Int = 0 + override def apply(key: Any) = throw new NoSuchElementException("key not found: " + key) + override def contains(key: Any) = false def get(key: Any): Option[Nothing] = None def iterator: Iterator[(Any, Nothing)] = Iterator.empty override def updated [B1] (key: Any, value: B1): Map[Any, B1] = new Map1(key, value) @@ -103,6 +105,8 @@ object Map extends ImmutableMapFactory[Map] { class Map1[A, +B](key1: A, value1: B) extends AbstractMap[A, B] with Map[A, B] with Serializable { override def size = 1 + override def apply(key: A) = if (key == key1) value1 else throw new NoSuchElementException("key not found: " + key) + override def contains(key: A) = key == key1 def get(key: A): Option[B] = if (key == key1) Some(value1) else None def iterator = Iterator((key1, value1)) @@ -119,6 +123,11 @@ object Map extends ImmutableMapFactory[Map] { class Map2[A, +B](key1: A, value1: B, key2: A, value2: B) extends AbstractMap[A, B] with Map[A, B] with Serializable { override def size = 2 + override def apply(key: A) = + if (key == key1) value1 + else if (key == key2) value2 + else throw new NoSuchElementException("key not found: " + key) + override def contains(key: A) = (key == key1) || (key == key2) def get(key: A): Option[B] = if (key == key1) Some(value1) else if (key == key2) Some(value2) @@ -140,6 +149,12 @@ object Map extends ImmutableMapFactory[Map] { class Map3[A, +B](key1: A, value1: B, key2: A, value2: B, key3: A, value3: B) extends AbstractMap[A, B] with Map[A, B] with Serializable { override def size = 3 + override def apply(key: A) = + if (key == key1) value1 + else if (key == key2) value2 + else if (key == key3) value3 + else throw new NoSuchElementException("key not found: " + key) + override def contains(key: A) = (key == key1) || (key == key2) || (key == key3) def get(key: A): Option[B] = if (key == key1) Some(value1) else if (key == key2) Some(value2) @@ -164,6 +179,13 @@ object Map extends ImmutableMapFactory[Map] { class Map4[A, +B](key1: A, value1: B, key2: A, value2: B, key3: A, value3: B, key4: A, value4: B) extends AbstractMap[A, B] with Map[A, B] with Serializable { override def size = 4 + override def apply(key: A) = + if (key == key1) value1 + else if (key == key2) value2 + else if (key == key3) value3 + else if (key == key4) value4 + else throw new NoSuchElementException("key not found: " + key) + override def contains(key: A) = (key == key1) || (key == key2) || (key == key3) || (key == key4) def get(key: A): Option[B] = if (key == key1) Some(value1) else if (key == key2) Some(value2) diff --git a/src/library/scala/collection/immutable/PagedSeq.scala b/src/library/scala/collection/immutable/PagedSeq.scala index f11217d26a..8910ee16b9 100644 --- a/src/library/scala/collection/immutable/PagedSeq.scala +++ b/src/library/scala/collection/immutable/PagedSeq.scala @@ -12,7 +12,7 @@ package scala package collection package immutable -import java.io._ +import java.io.{File, FileReader, Reader} import scala.util.matching.Regex import scala.reflect.ClassTag diff --git a/src/library/scala/collection/immutable/Range.scala b/src/library/scala/collection/immutable/Range.scala index 3ae8a2c342..0b380517f8 100644 --- a/src/library/scala/collection/immutable/Range.scala +++ b/src/library/scala/collection/immutable/Range.scala @@ -202,7 +202,24 @@ extends scala.collection.AbstractSeq[Int] copy(locationAfterN(n), end, step) } ) - + + /** Creates a new range containing the elements starting at `from` up to but not including `until`. + * + * $doesNotUseBuilders + * + * @param from the element at which to start + * @param until the element at which to end (not included in the range) + * @return a new range consisting of a contiguous interval of values in the old range + */ + override def slice(from: Int, until: Int): Range = + if (from <= 0) take(until) + else if (until >= numRangeElements && numRangeElements >= 0) drop(from) + else { + val fromValue = locationAfterN(from) + if (from >= until) newEmptyRange(fromValue) + else new Range.Inclusive(fromValue, locationAfterN(until-1), step) + } + /** Creates a new range containing all the elements of this range except the last one. * * $doesNotUseBuilders diff --git a/src/library/scala/collection/immutable/Stream.scala b/src/library/scala/collection/immutable/Stream.scala index 17cf02cce6..6c5b10e73b 100644 --- a/src/library/scala/collection/immutable/Stream.scala +++ b/src/library/scala/collection/immutable/Stream.scala @@ -499,6 +499,16 @@ self => ) else super.flatMap(f)(bf) + override private[scala] def filterImpl(p: A => Boolean, isFlipped: Boolean): Stream[A] = { + // optimization: drop leading prefix of elems for which f returns false + // var rest = this dropWhile (!p(_)) - forget DRY principle - GC can't collect otherwise + var rest = this + while (!rest.isEmpty && p(rest.head) == isFlipped) rest = rest.tail + // private utility func to avoid `this` on stack (would be needed for the lazy arg) + if (rest.nonEmpty) Stream.filteredTail(rest, p, isFlipped) + else Stream.Empty + } + /** Returns all the elements of this `Stream` that satisfy the predicate `p` * in a new `Stream` - i.e., it is still a lazy data structure. The order of * the elements is preserved @@ -512,67 +522,11 @@ self => * // produces * }}} */ - override def filter(p: A => Boolean): Stream[A] = { - // optimization: drop leading prefix of elems for which f returns false - // var rest = this dropWhile (!p(_)) - forget DRY principle - GC can't collect otherwise - var rest = this - while (!rest.isEmpty && !p(rest.head)) rest = rest.tail - // private utility func to avoid `this` on stack (would be needed for the lazy arg) - if (rest.nonEmpty) Stream.filteredTail(rest, p) - else Stream.Empty - } - - override final def withFilter(p: A => Boolean): StreamWithFilter = new StreamWithFilter(p) - - /** A lazier implementation of WithFilter than TraversableLike's. - */ - final class StreamWithFilter(p: A => Boolean) extends WithFilter(p) { - - override def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Stream[A], B, That]): That = { - def tailMap(coll: Stream[A]): Stream[B] = { - var head: A = null.asInstanceOf[A] - var tail: Stream[A] = coll - while (true) { - if (tail.isEmpty) - return Stream.Empty - head = tail.head - tail = tail.tail - if (p(head)) - return cons(f(head), tailMap(tail)) - } - throw new RuntimeException() - } - - if (isStreamBuilder(bf)) asThat(tailMap(Stream.this)) - else super.map(f)(bf) - } + override def filter(p: A => Boolean): Stream[A] = filterImpl(p, isFlipped = false) // This override is only left in 2.11 because of binary compatibility, see PR #3925 - override def flatMap[B, That](f: A => GenTraversableOnce[B])(implicit bf: CanBuildFrom[Stream[A], B, That]): That = { - def tailFlatMap(coll: Stream[A]): Stream[B] = { - var head: A = null.asInstanceOf[A] - var tail: Stream[A] = coll - while (true) { - if (tail.isEmpty) - return Stream.Empty - head = tail.head - tail = tail.tail - if (p(head)) - return f(head).toStream append tailFlatMap(tail) - } - throw new RuntimeException() - } - - if (isStreamBuilder(bf)) asThat(tailFlatMap(Stream.this)) - else super.flatMap(f)(bf) - } - - override def foreach[B](f: A => B) = - for (x <- self) - if (p(x)) f(x) - - override def withFilter(q: A => Boolean): StreamWithFilter = - new StreamWithFilter(x => p(x) && q(x)) - } + /** A FilterMonadic which allows GC of the head of stream during processing */ + @noinline // Workaround SI-9137, see https://github.com/scala/scala/pull/4284#issuecomment-73180791 + override final def withFilter(p: A => Boolean): FilterMonadic[A, Stream[A]] = new Stream.StreamWithFilter(this, p) /** A lazier Iterator than LinearSeqLike's. */ override def iterator: Iterator[A] = new StreamIterator(self) @@ -1295,13 +1249,36 @@ object Stream extends SeqFactory[Stream] { else cons(start, range(start + step, end, step)) } - private[immutable] def filteredTail[A](stream: Stream[A], p: A => Boolean) = { - cons(stream.head, stream.tail filter p) + private[immutable] def filteredTail[A](stream: Stream[A], p: A => Boolean, isFlipped: Boolean) = { + cons(stream.head, stream.tail.filterImpl(p, isFlipped)) } private[immutable] def collectedTail[A, B, That](head: B, stream: Stream[A], pf: PartialFunction[A, B], bf: CanBuildFrom[Stream[A], B, That]) = { cons(head, stream.tail.collect(pf)(bf).asInstanceOf[Stream[B]]) } -} + /** An implementation of `FilterMonadic` allowing GC of the filtered-out elements of + * the `Stream` as it is processed. + * + * Because this is not an inner class of `Stream` with a reference to the original + * head, it is now possible for GC to collect any leading and filtered-out elements + * which do not satisfy the filter, while the tail is still processing (see SI-8990). + */ + private[immutable] final class StreamWithFilter[A](sl: => Stream[A], p: A => Boolean) extends FilterMonadic[A, Stream[A]] { + private var s = sl // set to null to allow GC after filtered + private lazy val filtered = { val f = s filter p; s = null; f } // don't set to null if throw during filter + + def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Stream[A], B, That]): That = + filtered map f + + def flatMap[B, That](f: A => scala.collection.GenTraversableOnce[B])(implicit bf: CanBuildFrom[Stream[A], B, That]): That = + filtered flatMap f + def foreach[U](f: A => U): Unit = + filtered foreach f + + def withFilter(q: A => Boolean): FilterMonadic[A, Stream[A]] = + new StreamWithFilter[A](filtered, q) + } + +} diff --git a/src/library/scala/collection/immutable/StreamViewLike.scala b/src/library/scala/collection/immutable/StreamViewLike.scala index c2eb85815d..4d7eaeff2a 100644 --- a/src/library/scala/collection/immutable/StreamViewLike.scala +++ b/src/library/scala/collection/immutable/StreamViewLike.scala @@ -53,6 +53,7 @@ extends SeqView[A, Coll] /** boilerplate */ protected override def newForced[B](xs: => scala.collection.GenSeq[B]): Transformed[B] = new { val forced = xs } with AbstractTransformed[B] with Forced[B] protected override def newAppended[B >: A](that: scala.collection.GenTraversable[B]): Transformed[B] = new { val rest = that } with AbstractTransformed[B] with Appended[B] + protected override def newPrepended[B >: A](that: scala.collection.GenTraversable[B]): Transformed[B] = new { protected[this] val fst = that } with AbstractTransformed[B] with Prepended[B] protected override def newMapped[B](f: A => B): Transformed[B] = new { val mapping = f } with AbstractTransformed[B] with Mapped[B] protected override def newFlatMapped[B](f: A => scala.collection.GenTraversableOnce[B]): Transformed[B] = new { val mapping = f } with AbstractTransformed[B] with FlatMapped[B] protected override def newFiltered(p: A => Boolean): Transformed[A] = new { val pred = p } with AbstractTransformed[A] with Filtered @@ -67,7 +68,6 @@ extends SeqView[A, Coll] protected override def newPatched[B >: A](_from: Int, _patch: scala.collection.GenSeq[B], _replaced: Int): Transformed[B] = { new { val from = _from; val patch = _patch; val replaced = _replaced } with AbstractTransformed[B] with Patched[B] } - protected override def newPrepended[B >: A](elem: B): Transformed[B] = new { protected[this] val fst = elem } with AbstractTransformed[B] with Prepended[B] override def stringPrefix = "StreamView" } diff --git a/src/library/scala/collection/immutable/StringLike.scala b/src/library/scala/collection/immutable/StringLike.scala index 1ead894faf..7b3da1e2ea 100644 --- a/src/library/scala/collection/immutable/StringLike.scala +++ b/src/library/scala/collection/immutable/StringLike.scala @@ -201,35 +201,64 @@ self => */ def stripMargin: String = stripMargin('|') - private def escape(ch: Char): String = "\\Q" + ch + "\\E" - - def split(separator: Char): Array[String] = { - val thisString = toString - var pos = thisString.indexOf(separator) - - if (pos != -1) { - val res = new ArrayBuilder.ofRef[String] - - var prev = 0 - do { - res += thisString.substring(prev, pos) - prev = pos + 1 - pos = thisString.indexOf(separator, prev) - } while (pos != -1) - - if (prev != thisString.size) - res += thisString.substring(prev, thisString.size) - - val initialResult = res.result() - pos = initialResult.length - while (pos > 0 && initialResult(pos - 1).isEmpty) pos = pos - 1 - if (pos != initialResult.length) { - val trimmed = new Array[String](pos) - Array.copy(initialResult, 0, trimmed, 0, pos) - trimmed - } else initialResult - } else Array[String](thisString) - } + private def escape(ch: Char): String = if ( + (ch >= 'a') && (ch <= 'z') || + (ch >= 'A') && (ch <= 'Z') || + (ch >= '0' && ch <= '9')) ch.toString + else "\\" + ch + + /** Split this string around the separator character + * + * If this string is the empty string, returns an array of strings + * that contains a single empty string. + * + * If this string is not the empty string, returns an array containing + * the substrings terminated by the start of the string, the end of the + * string or the separator character, excluding empty trailing substrings + * + * If the separator character is a surrogate character, only split on + * matching surrogate characters if they are not part of a surrogate pair + * + * The behaviour follows, and is implemented in terms of <a href="http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#split%28java.lang.String%29">String.split(re: String)</a> + * + * + * @example {{{ + * "a.b".split('.') //returns Array("a", "b") + * + * //splitting the empty string always returns the array with a single + * //empty string + * "".split('.') //returns Array("") + * + * //only trailing empty substrings are removed + * "a.".split('.') //returns Array("a") + * ".a.".split('.') //returns Array("", "a") + * "..a..".split('.') //returns Array("", "", "a") + * + * //all parts are empty and trailing + * ".".split('.') //returns Array() + * "..".split('.') //returns Array() + * + * //surrogate pairs + * val high = 0xD852.toChar + * val low = 0xDF62.toChar + * val highstring = high.toString + * val lowstring = low.toString + * + * //well-formed surrogate pairs are not split + * val highlow = highstring + lowstring + * highlow.split(high) //returns Array(highlow) + * + * //bare surrogate characters are split + * val bare = "_" + highstring + "_" + * bare.split(high) //returns Array("_", "_") + * + * }}} + * + * @param separator the character used as a delimiter + */ + def split(separator: Char): Array[String] = + toString.split(escape(separator)) + @throws(classOf[java.util.regex.PatternSyntaxException]) def split(separators: Array[Char]): Array[String] = { diff --git a/src/library/scala/collection/mutable/AnyRefMap.scala b/src/library/scala/collection/mutable/AnyRefMap.scala index fccc9d83e6..ed6ca1939d 100644 --- a/src/library/scala/collection/mutable/AnyRefMap.scala +++ b/src/library/scala/collection/mutable/AnyRefMap.scala @@ -335,6 +335,24 @@ extends AbstractMap[K, V] arm } + override def +[V1 >: V](kv: (K, V1)): AnyRefMap[K, V1] = { + val arm = clone().asInstanceOf[AnyRefMap[K, V1]] + arm += kv + arm + } + + override def ++[V1 >: V](xs: GenTraversableOnce[(K, V1)]): AnyRefMap[K, V1] = { + val arm = clone().asInstanceOf[AnyRefMap[K, V1]] + xs.foreach(kv => arm += kv) + arm + } + + override def updated[V1 >: V](key: K, value: V1): AnyRefMap[K, V1] = { + val arm = clone().asInstanceOf[AnyRefMap[K, V1]] + arm += (key, value) + arm + } + private[this] def foreachElement[A,B](elems: Array[AnyRef], f: A => B) { var i,j = 0 while (i < _hashes.length & j < _size) { diff --git a/src/library/scala/collection/mutable/ArrayOps.scala b/src/library/scala/collection/mutable/ArrayOps.scala index 00491ef20e..2bc41b5802 100644 --- a/src/library/scala/collection/mutable/ArrayOps.scala +++ b/src/library/scala/collection/mutable/ArrayOps.scala @@ -40,9 +40,8 @@ trait ArrayOps[T] extends Any with ArrayLike[T, Array[T]] with CustomParalleliza arrayElementClass(repr.getClass) override def copyToArray[U >: T](xs: Array[U], start: Int, len: Int) { - var l = math.min(len, repr.length) - if (xs.length - start < l) l = xs.length - start max 0 - Array.copy(repr, 0, xs, start, l) + val l = len min repr.length min (xs.length - start) + if (l > 0) Array.copy(repr, 0, xs, start, l) } override def toArray[U >: T : ClassTag]: Array[U] = { diff --git a/src/library/scala/collection/mutable/ArraySeq.scala b/src/library/scala/collection/mutable/ArraySeq.scala index 577a838315..5a50f4fb27 100644 --- a/src/library/scala/collection/mutable/ArraySeq.scala +++ b/src/library/scala/collection/mutable/ArraySeq.scala @@ -87,7 +87,7 @@ extends AbstractSeq[A] */ override def copyToArray[B >: A](xs: Array[B], start: Int, len: Int) { val len1 = len min (xs.length - start) min length - Array.copy(array, 0, xs, start, len1) + if (len1 > 0) Array.copy(array, 0, xs, start, len1) } override def clone(): ArraySeq[A] = { diff --git a/src/library/scala/collection/mutable/BufferLike.scala b/src/library/scala/collection/mutable/BufferLike.scala index 3c57387c03..8d24538620 100644 --- a/src/library/scala/collection/mutable/BufferLike.scala +++ b/src/library/scala/collection/mutable/BufferLike.scala @@ -211,13 +211,6 @@ trait BufferLike[A, +This <: BufferLike[A, This] with Buffer[A]] */ override def stringPrefix: String = "Buffer" - /** Returns the current evolving(!) state of this buffer as a read-only sequence. - * - * @return A sequence that forwards to this buffer for all its operations. - */ - @deprecated("The returned sequence changes as this buffer is mutated. For an immutable copy, use, e.g., toList.", "2.11.0") - def readOnly: scala.collection.Seq[A] = toSeq - /** Creates a new collection containing both the elements of this collection and the provided * traversable object. * diff --git a/src/library/scala/collection/mutable/BufferProxy.scala b/src/library/scala/collection/mutable/BufferProxy.scala index d9632cce91..2d52831d37 100644 --- a/src/library/scala/collection/mutable/BufferProxy.scala +++ b/src/library/scala/collection/mutable/BufferProxy.scala @@ -43,8 +43,6 @@ trait BufferProxy[A] extends Buffer[A] with Proxy { */ def +=(elem: A): this.type = { self.+=(elem); this } - override def readOnly = self.readOnly - /** Appends a number of elements provided by a traversable object. * * @param xs the traversable object. diff --git a/src/library/scala/collection/mutable/ListBuffer.scala b/src/library/scala/collection/mutable/ListBuffer.scala index f9bab40a1e..2bc6738e53 100644 --- a/src/library/scala/collection/mutable/ListBuffer.scala +++ b/src/library/scala/collection/mutable/ListBuffer.scala @@ -12,7 +12,7 @@ package mutable import generic._ import immutable.{List, Nil, ::} -import java.io._ +import java.io.{ObjectOutputStream, ObjectInputStream} import scala.annotation.migration /** A `Buffer` implementation backed by a list. It provides constant time @@ -408,9 +408,6 @@ final class ListBuffer[A] } } - @deprecated("The result of this method will change along with this buffer, which is often not what's expected.", "2.11.0") - override def readOnly: List[A] = start - // Private methods /** Copy contents of this buffer */ @@ -426,7 +423,7 @@ final class ListBuffer[A] } override def equals(that: Any): Boolean = that match { - case that: ListBuffer[_] => this.readOnly equals that.readOnly + case that: ListBuffer[_] => this.start equals that.start case _ => super.equals(that) } diff --git a/src/library/scala/collection/mutable/LongMap.scala b/src/library/scala/collection/mutable/LongMap.scala index c124f35cd7..1eb12d817c 100644 --- a/src/library/scala/collection/mutable/LongMap.scala +++ b/src/library/scala/collection/mutable/LongMap.scala @@ -415,6 +415,24 @@ extends AbstractMap[Long, V] lm } + override def +[V1 >: V](kv: (Long, V1)): LongMap[V1] = { + val lm = clone().asInstanceOf[LongMap[V1]] + lm += kv + lm + } + + override def ++[V1 >: V](xs: GenTraversableOnce[(Long, V1)]): LongMap[V1] = { + val lm = clone().asInstanceOf[LongMap[V1]] + xs.foreach(kv => lm += kv) + lm + } + + override def updated[V1 >: V](key: Long, value: V1): LongMap[V1] = { + val lm = clone().asInstanceOf[LongMap[V1]] + lm += (key, value) + lm + } + /** Applies a function to all keys of this map. */ def foreachKey[A](f: Long => A) { if ((extraKeys & 1) == 1) f(0L) @@ -541,7 +559,7 @@ object LongMap { /** Creates a new `LongMap` from keys and values. * Equivalent to but more efficient than `LongMap((keys zip values): _*)`. */ - def fromZip[V](keys: Iterable[Long], values: Iterable[V]): LongMap[V] = { + def fromZip[V](keys: collection.Iterable[Long], values: collection.Iterable[V]): LongMap[V] = { val sz = math.min(keys.size, values.size) val lm = new LongMap[V](sz * 2) val ki = keys.iterator diff --git a/src/library/scala/collection/mutable/MapLike.scala b/src/library/scala/collection/mutable/MapLike.scala index 44af886cf5..949e5e3536 100644 --- a/src/library/scala/collection/mutable/MapLike.scala +++ b/src/library/scala/collection/mutable/MapLike.scala @@ -61,6 +61,18 @@ trait MapLike[A, B, +This <: MapLike[A, B, This] with Map[A, B]] override protected[this] def newBuilder: Builder[(A, B), This] = empty protected[this] override def parCombiner = ParMap.newCombiner[A, B] + + /** Converts this $coll to a sequence. + * + * ```Note```: assumes a fast `size` method. Subclasses should override if this is not true. + */ + override def toSeq: collection.Seq[(A, B)] = { + // ArrayBuffer for efficiency, preallocated to the right size. + val result = new ArrayBuffer[(A, B)](size) + foreach(result += _) + result + } + /** Adds a new key/value pair to this map and optionally returns previously bound value. * If the map already contains a diff --git a/src/library/scala/collection/mutable/PriorityQueue.scala b/src/library/scala/collection/mutable/PriorityQueue.scala index d3c4161e3b..619beeb1d6 100644 --- a/src/library/scala/collection/mutable/PriorityQueue.scala +++ b/src/library/scala/collection/mutable/PriorityQueue.scala @@ -16,7 +16,7 @@ import generic._ * To prioritize elements of type A there must be an implicit * Ordering[A] available at creation. * - * Only the `dequeue` and `dequeueAll` methods will return methods in priority + * Only the `dequeue` and `dequeueAll` methods will return elements in priority * order (while removing elements from the heap). Standard collection methods * including `drop` and `iterator` will remove or traverse the heap in whichever * order seems most convenient. diff --git a/src/library/scala/collection/mutable/RedBlackTree.scala b/src/library/scala/collection/mutable/RedBlackTree.scala new file mode 100644 index 0000000000..7f12264d45 --- /dev/null +++ b/src/library/scala/collection/mutable/RedBlackTree.scala @@ -0,0 +1,545 @@ +package scala.collection.mutable + +import scala.annotation.tailrec +import scala.collection.Iterator + +/** + * An object containing the red-black tree implementation used by mutable `TreeMaps`. + * + * The trees implemented in this object are *not* thread safe. + * + * @author Rui Gonçalves + * @version 2.12 + * @since 2.12 + */ +private[collection] object RedBlackTree { + + // ---- class structure ---- + + // For performance reasons, this implementation uses `null` references to represent leaves instead of a sentinel node. + // Currently, the internal nodes do not store their subtree size - only the tree object keeps track of their size. + // Therefore, while obtaining the size of the whole tree is O(1), knowing the number of entries inside a range is O(n) + // on the size of the range. + + @SerialVersionUID(21575944040195605L) + final class Tree[A, B](var root: Node[A, B], var size: Int) extends Serializable + + @SerialVersionUID(1950599696441054720L) + final class Node[A, B](var key: A, var value: B, var red: Boolean, + var left: Node[A, B], var right: Node[A, B], var parent: Node[A, B]) extends Serializable { + + override def toString: String = "Node(" + key + ", " + value + ", " + red + ", " + left + ", " + right + ")" + } + + object Tree { + def empty[A, B]: Tree[A, B] = new Tree(null, 0) + } + + object Node { + + @inline def apply[A, B](key: A, value: B, red: Boolean, + left: Node[A, B], right: Node[A, B], parent: Node[A, B]): Node[A, B] = + new Node(key, value, red, left, right, parent) + + @inline def leaf[A, B](key: A, value: B, red: Boolean, parent: Node[A, B]): Node[A, B] = + new Node(key, value, red, null, null, parent) + + def unapply[A, B](t: Node[A, B]) = Some((t.key, t.value, t.left, t.right, t.parent)) + } + + // ---- getters ---- + + def isRed(node: Node[_, _]) = (node ne null) && node.red + def isBlack(node: Node[_, _]) = (node eq null) || !node.red + + // ---- size ---- + + def size(node: Node[_, _]): Int = if (node eq null) 0 else 1 + size(node.left) + size(node.right) + def isEmpty(tree: Tree[_, _]) = tree.root eq null + + // ---- search ---- + + def get[A: Ordering, B](tree: Tree[A, B], key: A): Option[B] = getNode(tree.root, key) match { + case null => None + case node => Some(node.value) + } + + @tailrec private[this] def getNode[A, B](node: Node[A, B], key: A)(implicit ord: Ordering[A]): Node[A, B] = + if (node eq null) null + else { + val cmp = ord.compare(key, node.key) + if (cmp < 0) getNode(node.left, key) + else if (cmp > 0) getNode(node.right, key) + else node + } + + def contains[A: Ordering](tree: Tree[A, _], key: A) = getNode(tree.root, key) ne null + + def min[A, B](tree: Tree[A, B]): Option[(A, B)] = minNode(tree.root) match { + case null => None + case node => Some((node.key, node.value)) + } + + private def minNode[A, B](node: Node[A, B]): Node[A, B] = + if (node eq null) null else minNodeNonNull(node) + + @tailrec def minNodeNonNull[A, B](node: Node[A, B]): Node[A, B] = + if (node.left eq null) node else minNodeNonNull(node.left) + + def max[A, B](tree: Tree[A, B]): Option[(A, B)] = maxNode(tree.root) match { + case null => None + case node => Some((node.key, node.value)) + } + + private def maxNode[A, B](node: Node[A, B]): Node[A, B] = + if (node eq null) null else maxNodeNonNull(node) + + @tailrec def maxNodeNonNull[A, B](node: Node[A, B]): Node[A, B] = + if (node.right eq null) node else maxNodeNonNull(node.right) + + /** + * Returns the first (lowest) map entry with a key equal or greater than `key`. Returns `None` if there is no such + * node. + */ + def minAfter[A, B](tree: Tree[A, B], key: A)(implicit ord: Ordering[A]): Option[(A, B)] = + minNodeAfter(tree.root, key) match { + case null => None + case node => Some((node.key, node.value)) + } + + private[this] def minNodeAfter[A, B](node: Node[A, B], key: A)(implicit ord: Ordering[A]): Node[A, B] = { + if (node eq null) null + else { + var y: Node[A, B] = null + var x = node + var cmp = 1 + while ((x ne null) && cmp != 0) { + y = x + cmp = ord.compare(key, x.key) + x = if (cmp < 0) x.left else x.right + } + if (cmp <= 0) y else successor(y) + } + } + + /** + * Returns the last (highest) map entry with a key smaller than `key`. Returns `None` if there is no such node. + */ + def maxBefore[A, B](tree: Tree[A, B], key: A)(implicit ord: Ordering[A]): Option[(A, B)] = + maxNodeBefore(tree.root, key) match { + case null => None + case node => Some((node.key, node.value)) + } + + private[this] def maxNodeBefore[A, B](node: Node[A, B], key: A)(implicit ord: Ordering[A]): Node[A, B] = { + if (node eq null) null + else { + var y: Node[A, B] = null + var x = node + var cmp = 1 + while ((x ne null) && cmp != 0) { + y = x + cmp = ord.compare(key, x.key) + x = if (cmp < 0) x.left else x.right + } + if (cmp > 0) y else predecessor(y) + } + } + + // ---- insertion ---- + + def insert[A, B](tree: Tree[A, B], key: A, value: B)(implicit ord: Ordering[A]): Unit = { + var y: Node[A, B] = null + var x = tree.root + var cmp = 1 + while ((x ne null) && cmp != 0) { + y = x + cmp = ord.compare(key, x.key) + x = if (cmp < 0) x.left else x.right + } + + if (cmp == 0) y.value = value + else { + val z = Node.leaf(key, value, red = true, y) + + if (y eq null) tree.root = z + else if (cmp < 0) y.left = z + else y.right = z + + fixAfterInsert(tree, z) + tree.size += 1 + } + } + + private[this] def fixAfterInsert[A, B](tree: Tree[A, B], node: Node[A, B]): Unit = { + var z = node + while (isRed(z.parent)) { + if (z.parent eq z.parent.parent.left) { + val y = z.parent.parent.right + if (isRed(y)) { + z.parent.red = false + y.red = false + z.parent.parent.red = true + z = z.parent.parent + } else { + if (z eq z.parent.right) { + z = z.parent + rotateLeft(tree, z) + } + z.parent.red = false + z.parent.parent.red = true + rotateRight(tree, z.parent.parent) + } + } else { // symmetric cases + val y = z.parent.parent.left + if (isRed(y)) { + z.parent.red = false + y.red = false + z.parent.parent.red = true + z = z.parent.parent + } else { + if (z eq z.parent.left) { + z = z.parent + rotateRight(tree, z) + } + z.parent.red = false + z.parent.parent.red = true + rotateLeft(tree, z.parent.parent) + } + } + } + tree.root.red = false + } + + // ---- deletion ---- + + def delete[A, B](tree: Tree[A, B], key: A)(implicit ord: Ordering[A]): Unit = { + val z = getNode(tree.root, key) + if (z ne null) { + var y = z + var yIsRed = y.red + var x: Node[A, B] = null + var xParent: Node[A, B] = null + + if (z.left eq null) { + x = z.right + transplant(tree, z, z.right) + xParent = z.parent + } + else if (z.right eq null) { + x = z.left + transplant(tree, z, z.left) + xParent = z.parent + } + else { + y = minNodeNonNull(z.right) + yIsRed = y.red + x = y.right + + if (y.parent eq z) xParent = y + else { + xParent = y.parent + transplant(tree, y, y.right) + y.right = z.right + y.right.parent = y + } + transplant(tree, z, y) + y.left = z.left + y.left.parent = y + y.red = z.red + } + + if (!yIsRed) fixAfterDelete(tree, x, xParent) + tree.size -= 1 + } + } + + private[this] def fixAfterDelete[A, B](tree: Tree[A, B], node: Node[A, B], parent: Node[A, B]): Unit = { + var x = node + var xParent = parent + while ((x ne tree.root) && isBlack(x)) { + if (x eq xParent.left) { + var w = xParent.right + // assert(w ne null) + + if (w.red) { + w.red = false + xParent.red = true + rotateLeft(tree, xParent) + w = xParent.right + } + if (isBlack(w.left) && isBlack(w.right)) { + w.red = true + x = xParent + } else { + if (isBlack(w.right)) { + w.left.red = false + w.red = true + rotateRight(tree, w) + w = xParent.right + } + w.red = xParent.red + xParent.red = false + w.right.red = false + rotateLeft(tree, xParent) + x = tree.root + } + } else { // symmetric cases + var w = xParent.left + // assert(w ne null) + + if (w.red) { + w.red = false + xParent.red = true + rotateRight(tree, xParent) + w = xParent.left + } + if (isBlack(w.right) && isBlack(w.left)) { + w.red = true + x = xParent + } else { + if (isBlack(w.left)) { + w.right.red = false + w.red = true + rotateLeft(tree, w) + w = xParent.left + } + w.red = xParent.red + xParent.red = false + w.left.red = false + rotateRight(tree, xParent) + x = tree.root + } + } + xParent = x.parent + } + if (x ne null) x.red = false + } + + // ---- helpers ---- + + /** + * Returns the node that follows `node` in an in-order tree traversal. If `node` has the maximum key (and is, + * therefore, the last node), this method returns `null`. + */ + private[this] def successor[A, B](node: Node[A, B]): Node[A, B] = { + if (node.right ne null) minNodeNonNull(node.right) + else { + var x = node + var y = x.parent + while ((y ne null) && (x eq y.right)) { + x = y + y = y.parent + } + y + } + } + + /** + * Returns the node that precedes `node` in an in-order tree traversal. If `node` has the minimum key (and is, + * therefore, the first node), this method returns `null`. + */ + private[this] def predecessor[A, B](node: Node[A, B]): Node[A, B] = { + if (node.left ne null) maxNodeNonNull(node.left) + else { + var x = node + var y = x.parent + while ((y ne null) && (x eq y.left)) { + x = y + y = y.parent + } + y + } + } + + private[this] def rotateLeft[A, B](tree: Tree[A, B], x: Node[A, B]): Unit = if (x ne null) { + // assert(x.right ne null) + val y = x.right + x.right = y.left + + if (y.left ne null) y.left.parent = x + y.parent = x.parent + + if (x.parent eq null) tree.root = y + else if (x eq x.parent.left) x.parent.left = y + else x.parent.right = y + + y.left = x + x.parent = y + } + + private[this] def rotateRight[A, B](tree: Tree[A, B], x: Node[A, B]): Unit = if (x ne null) { + // assert(x.left ne null) + val y = x.left + x.left = y.right + + if (y.right ne null) y.right.parent = x + y.parent = x.parent + + if (x.parent eq null) tree.root = y + else if (x eq x.parent.right) x.parent.right = y + else x.parent.left = y + + y.right = x + x.parent = y + } + + /** + * Transplant the node `from` to the place of node `to`. This is done by setting `from` as a child of `to`'s previous + * parent and setting `from`'s parent to the `to`'s previous parent. The children of `from` are left unchanged. + */ + private[this] def transplant[A, B](tree: Tree[A, B], to: Node[A, B], from: Node[A, B]): Unit = { + if (to.parent eq null) tree.root = from + else if (to eq to.parent.left) to.parent.left = from + else to.parent.right = from + + if (from ne null) from.parent = to.parent + } + + // ---- tree traversal ---- + + def foreach[A, B, U](tree: Tree[A, B], f: ((A, B)) => U): Unit = foreachNode(tree.root, f) + + private[this] def foreachNode[A, B, U](node: Node[A, B], f: ((A, B)) => U): Unit = + if (node ne null) foreachNodeNonNull(node, f) + + private[this] def foreachNodeNonNull[A, B, U](node: Node[A, B], f: ((A, B)) => U): Unit = { + if (node.left ne null) foreachNodeNonNull(node.left, f) + f((node.key, node.value)) + if (node.right ne null) foreachNodeNonNull(node.right, f) + } + + def transform[A, B](tree: Tree[A, B], f: (A, B) => B): Unit = transformNode(tree.root, f) + + private[this] def transformNode[A, B, U](node: Node[A, B], f: (A, B) => B): Unit = + if (node ne null) transformNodeNonNull(node, f) + + private[this] def transformNodeNonNull[A, B, U](node: Node[A, B], f: (A, B) => B): Unit = { + if (node.left ne null) transformNodeNonNull(node.left, f) + node.value = f(node.key, node.value) + if (node.right ne null) transformNodeNonNull(node.right, f) + } + + def iterator[A: Ordering, B](tree: Tree[A, B], start: Option[A] = None, end: Option[A] = None): Iterator[(A, B)] = + new EntriesIterator(tree, start, end) + + def keysIterator[A: Ordering](tree: Tree[A, _], start: Option[A] = None, end: Option[A] = None): Iterator[A] = + new KeysIterator(tree, start, end) + + def valuesIterator[A: Ordering, B](tree: Tree[A, B], start: Option[A] = None, end: Option[A] = None): Iterator[B] = + new ValuesIterator(tree, start, end) + + private[this] abstract class TreeIterator[A, B, R](tree: Tree[A, B], start: Option[A], end: Option[A]) + (implicit ord: Ordering[A]) extends Iterator[R] { + + protected[this] def nextResult(node: Node[A, B]): R + + def hasNext: Boolean = nextNode ne null + + def next(): R = nextNode match { + case null => throw new NoSuchElementException("next on empty iterator") + case node => + nextNode = successor(node) + setNullIfAfterEnd() + nextResult(node) + } + + private[this] var nextNode: Node[A, B] = start match { + case None => minNode(tree.root) + case Some(from) => minNodeAfter(tree.root, from) + } + + private[this] def setNullIfAfterEnd(): Unit = + if (end.isDefined && (nextNode ne null) && ord.compare(nextNode.key, end.get) >= 0) + nextNode = null + + setNullIfAfterEnd() + } + + private[this] final class EntriesIterator[A: Ordering, B](tree: Tree[A, B], start: Option[A], end: Option[A]) + extends TreeIterator[A, B, (A, B)](tree, start, end) { + + def nextResult(node: Node[A, B]) = (node.key, node.value) + } + + private[this] final class KeysIterator[A: Ordering, B](tree: Tree[A, B], start: Option[A], end: Option[A]) + extends TreeIterator[A, B, A](tree, start, end) { + + def nextResult(node: Node[A, B]) = node.key + } + + private[this] final class ValuesIterator[A: Ordering, B](tree: Tree[A, B], start: Option[A], end: Option[A]) + extends TreeIterator[A, B, B](tree, start, end) { + + def nextResult(node: Node[A, B]) = node.value + } + + // ---- debugging ---- + + /** + * Checks if the tree is in a valid state. That happens if: + * - It is a valid binary search tree; + * - All red-black properties are satisfied; + * - All non-null nodes have their `parent` reference correct; + * - The size variable in `tree` corresponds to the actual size of the tree. + */ + def isValid[A: Ordering, B](tree: Tree[A, B]): Boolean = + isValidBST(tree.root) && hasProperParentRefs(tree) && isValidRedBlackTree(tree) && size(tree.root) == tree.size + + /** + * Returns true if all non-null nodes have their `parent` reference correct. + */ + private[this] def hasProperParentRefs[A, B](tree: Tree[A, B]): Boolean = { + + def hasProperParentRefs(node: Node[A, B]): Boolean = { + if (node eq null) true + else { + if ((node.left ne null) && (node.left.parent ne node) || + (node.right ne null) && (node.right.parent ne node)) false + else hasProperParentRefs(node.left) && hasProperParentRefs(node.right) + } + } + + if(tree.root eq null) true + else (tree.root.parent eq null) && hasProperParentRefs(tree.root) + } + + /** + * Returns true if this node follows the properties of a binary search tree. + */ + private[this] def isValidBST[A, B](node: Node[A, B])(implicit ord: Ordering[A]): Boolean = { + if (node eq null) true + else { + if ((node.left ne null) && (ord.compare(node.key, node.left.key) <= 0) || + (node.right ne null) && (ord.compare(node.key, node.right.key) >= 0)) false + else isValidBST(node.left) && isValidBST(node.right) + } + } + + /** + * Returns true if the tree has all the red-black tree properties: if the root node is black, if all children of red + * nodes are black and if the path from any node to any of its null children has the same number of black nodes. + */ + private[this] def isValidRedBlackTree[A, B](tree: Tree[A, B]): Boolean = { + + def noRedAfterRed(node: Node[A, B]): Boolean = { + if (node eq null) true + else if (node.red && (isRed(node.left) || isRed(node.right))) false + else noRedAfterRed(node.left) && noRedAfterRed(node.right) + } + + def blackHeight(node: Node[A, B]): Int = { + if (node eq null) 1 + else { + val lh = blackHeight(node.left) + val rh = blackHeight(node.right) + + if (lh == -1 || lh != rh) -1 + else if (isRed(node)) lh + else lh + 1 + } + } + + isBlack(tree.root) && noRedAfterRed(tree.root) && blackHeight(tree.root) >= 0 + } +} diff --git a/src/library/scala/collection/mutable/ResizableArray.scala b/src/library/scala/collection/mutable/ResizableArray.scala index c3047522e2..85a299216e 100644 --- a/src/library/scala/collection/mutable/ResizableArray.scala +++ b/src/library/scala/collection/mutable/ResizableArray.scala @@ -74,7 +74,7 @@ trait ResizableArray[A] extends IndexedSeq[A] */ override def copyToArray[B >: A](xs: Array[B], start: Int, len: Int) { val len1 = len min (xs.length - start) min length - Array.copy(array, 0, xs, start, len1) + if (len1 > 0) Array.copy(array, 0, xs, start, len1) } //########################################################################## diff --git a/src/library/scala/collection/mutable/SetLike.scala b/src/library/scala/collection/mutable/SetLike.scala index 81a71adc91..40a5c93064 100644 --- a/src/library/scala/collection/mutable/SetLike.scala +++ b/src/library/scala/collection/mutable/SetLike.scala @@ -72,6 +72,17 @@ trait SetLike[A, +This <: SetLike[A, This] with Set[A]] protected[this] override def parCombiner = ParSet.newCombiner[A] + /** Converts this $coll to a sequence. + * + * ```Note```: assumes a fast `size` method. Subclasses should override if this is not true. + */ + override def toSeq: collection.Seq[A] = { + // ArrayBuffer for efficiency, preallocated to the right size. + val result = new ArrayBuffer[A](size) + foreach(result += _) + result + } + /** Adds an element to this $coll. * * @param elem the element to be added diff --git a/src/library/scala/collection/mutable/SortedMap.scala b/src/library/scala/collection/mutable/SortedMap.scala new file mode 100644 index 0000000000..806b30e79a --- /dev/null +++ b/src/library/scala/collection/mutable/SortedMap.scala @@ -0,0 +1,57 @@ +package scala +package collection +package mutable + +import generic._ + +/** + * A mutable map whose keys are sorted. + * + * @tparam A the type of the keys contained in this sorted map. + * @tparam B the type of the values associated with the keys. + * + * @author Rui Gonçalves + * @version 2.12 + * @since 2.12 + * + * @define Coll mutable.SortedMap + * @define coll mutable sorted map + */ +trait SortedMap[A, B] + extends Map[A, B] + with collection.SortedMap[A, B] + with MapLike[A, B, SortedMap[A, B]] + with SortedMapLike[A, B, SortedMap[A, B]] { + + override protected[this] def newBuilder: Builder[(A, B), SortedMap[A, B]] = SortedMap.newBuilder[A, B] + + override def empty: SortedMap[A, B] = SortedMap.empty + + override def updated[B1 >: B](key: A, value: B1): SortedMap[A, B1] = this + ((key, value)) + + override def +[B1 >: B](kv: (A, B1)): SortedMap[A, B1] = clone().asInstanceOf[SortedMap[A, B1]] += kv + + override def +[B1 >: B](elem1: (A, B1), elem2: (A, B1), elems: (A, B1)*): SortedMap[A, B1] = + clone().asInstanceOf[SortedMap[A, B1]] += elem1 += elem2 ++= elems + + override def ++[B1 >: B](xs: GenTraversableOnce[(A, B1)]): SortedMap[A, B1] = + clone().asInstanceOf[SortedMap[A, B1]] ++= xs.seq +} + +/** + * $factoryInfo + * + * @define Coll mutable.SortedMap + * @define coll mutable sorted map + */ +object SortedMap extends MutableSortedMapFactory[SortedMap] { + + def empty[A, B](implicit ord: Ordering[A]): SortedMap[A, B] = TreeMap.empty[A, B] + + /** $sortedMapCanBuildFromInfo */ + implicit def canBuildFrom[A, B](implicit ord: Ordering[A]): CanBuildFrom[Coll, (A, B), SortedMap[A, B]] = + new SortedMapCanBuildFrom[A, B] +} + +/** Explicit instantiation of the `SortedMap` trait to reduce class file size in subclasses. */ +abstract class AbstractSortedMap[A, B] extends scala.collection.mutable.AbstractMap[A, B] with SortedMap[A, B] diff --git a/src/library/scala/collection/mutable/TreeMap.scala b/src/library/scala/collection/mutable/TreeMap.scala new file mode 100644 index 0000000000..244cc18735 --- /dev/null +++ b/src/library/scala/collection/mutable/TreeMap.scala @@ -0,0 +1,166 @@ +package scala +package collection +package mutable + +import scala.collection.generic._ +import scala.collection.mutable.{RedBlackTree => RB} + +/** + * $factoryInfo + * + * @define Coll mutable.TreeMap + * @define coll mutable tree map + */ +object TreeMap extends MutableSortedMapFactory[TreeMap] { + + def empty[A, B](implicit ord: Ordering[A]) = new TreeMap[A, B]()(ord) + + /** $sortedMapCanBuildFromInfo */ + implicit def canBuildFrom[A, B](implicit ord: Ordering[A]): CanBuildFrom[Coll, (A, B), TreeMap[A, B]] = + new SortedMapCanBuildFrom[A, B] +} + +/** + * A mutable sorted map implemented using a mutable red-black tree as underlying data structure. + * + * @param ordering the implicit ordering used to compare objects of type `A`. + * @tparam A the type of the keys contained in this tree map. + * @tparam B the type of the values associated with the keys. + * + * @author Rui Gonçalves + * @version 2.12 + * @since 2.12 + * + * @define Coll mutable.TreeMap + * @define coll mutable tree map + */ +@SerialVersionUID(-2558985573956740112L) +sealed class TreeMap[A, B] private (tree: RB.Tree[A, B])(implicit val ordering: Ordering[A]) + extends AbstractSortedMap[A, B] + with SortedMap[A, B] + with MapLike[A, B, TreeMap[A, B]] + with SortedMapLike[A, B, TreeMap[A, B]] + with Serializable { + + /** + * Creates an empty `TreeMap`. + * @param ord the implicit ordering used to compare objects of type `A`. + * @return an empty `TreeMap`. + */ + def this()(implicit ord: Ordering[A]) = this(RB.Tree.empty)(ord) + + override def empty = TreeMap.empty + override protected[this] def newBuilder = TreeMap.newBuilder[A, B] + + def rangeImpl(from: Option[A], until: Option[A]): TreeMap[A, B] = new TreeMapView(from, until) + + def -=(key: A): this.type = { RB.delete(tree, key); this } + def +=(kv: (A, B)): this.type = { RB.insert(tree, kv._1, kv._2); this } + + def get(key: A) = RB.get(tree, key) + + def iterator = RB.iterator(tree) + def iteratorFrom(start: A) = RB.iterator(tree, Some(start)) + def keysIteratorFrom(start: A) = RB.keysIterator(tree, Some(start)) + def valuesIteratorFrom(start: A) = RB.valuesIterator(tree, Some(start)) + + override def size = tree.size + override def isEmpty = RB.isEmpty(tree) + override def contains(key: A) = RB.contains(tree, key) + + override def head = RB.min(tree).get + override def headOption = RB.min(tree) + override def last = RB.max(tree).get + override def lastOption = RB.max(tree) + + override def keysIterator = RB.keysIterator(tree) + override def valuesIterator = RB.valuesIterator(tree) + + override def foreach[U](f: ((A, B)) => U): Unit = RB.foreach(tree, f) + override def transform(f: (A, B) => B) = { RB.transform(tree, f); this } + override def clear(): Unit = tree.root = null + + override def stringPrefix = "TreeMap" + + /** + * A ranged projection of a [[TreeMap]]. Mutations on this map affect the original map and vice versa. + * + * Only entries with keys between this projection's key range will ever appear as elements of this map, independently + * of whether the entries are added through the original map or through this view. That means that if one inserts a + * key-value in a view whose key is outside the view's bounds, calls to `get` or `contains` will _not_ consider the + * newly added entry. Mutations are always reflected in the original map, though. + * + * @param from the lower bound (inclusive) of this projection wrapped in a `Some`, or `None` if there is no lower + * bound. + * @param until the upper bound (exclusive) of this projection wrapped in a `Some`, or `None` if there is no upper + * bound. + */ + @SerialVersionUID(2219159283273389116L) + private[this] final class TreeMapView(from: Option[A], until: Option[A]) extends TreeMap[A, B](tree) { + + /** + * Given a possible new lower bound, chooses and returns the most constraining one (the maximum). + */ + private[this] def pickLowerBound(newFrom: Option[A]): Option[A] = (from, newFrom) match { + case (Some(fr), Some(newFr)) => Some(ordering.max(fr, newFr)) + case (None, _) => newFrom + case _ => from + } + + /** + * Given a possible new upper bound, chooses and returns the most constraining one (the minimum). + */ + private[this] def pickUpperBound(newUntil: Option[A]): Option[A] = (until, newUntil) match { + case (Some(unt), Some(newUnt)) => Some(ordering.min(unt, newUnt)) + case (None, _) => newUntil + case _ => until + } + + /** + * Returns true if the argument is inside the view bounds (between `from` and `until`). + */ + private[this] def isInsideViewBounds(key: A): Boolean = { + val afterFrom = from.isEmpty || ordering.compare(from.get, key) <= 0 + val beforeUntil = until.isEmpty || ordering.compare(key, until.get) < 0 + afterFrom && beforeUntil + } + + override def rangeImpl(from: Option[A], until: Option[A]): TreeMap[A, B] = + new TreeMapView(pickLowerBound(from), pickUpperBound(until)) + + override def get(key: A) = if (isInsideViewBounds(key)) RB.get(tree, key) else None + + override def iterator = RB.iterator(tree, from, until) + override def iteratorFrom(start: A) = RB.iterator(tree, pickLowerBound(Some(start)), until) + override def keysIteratorFrom(start: A) = RB.keysIterator(tree, pickLowerBound(Some(start)), until) + override def valuesIteratorFrom(start: A) = RB.valuesIterator(tree, pickLowerBound(Some(start)), until) + + override def size = iterator.length + override def isEmpty = !iterator.hasNext + override def contains(key: A) = isInsideViewBounds(key) && RB.contains(tree, key) + + override def head = headOption.get + override def headOption = { + val entry = if (from.isDefined) RB.minAfter(tree, from.get) else RB.min(tree) + (entry, until) match { + case (Some(e), Some(unt)) if ordering.compare(e._1, unt) >= 0 => None + case _ => entry + } + } + + override def last = lastOption.get + override def lastOption = { + val entry = if (until.isDefined) RB.maxBefore(tree, until.get) else RB.max(tree) + (entry, from) match { + case (Some(e), Some(fr)) if ordering.compare(e._1, fr) < 0 => None + case _ => entry + } + } + + override def foreach[U](f: ((A, B)) => U): Unit = iterator.foreach(f) + override def transform(f: (A, B) => B) = { + iterator.foreach { case (key, value) => update(key, f(key, value)) } + this + } + } +} diff --git a/src/library/scala/collection/parallel/RemainsIterator.scala b/src/library/scala/collection/parallel/RemainsIterator.scala index 5f2ceac0e0..7bb278b038 100644 --- a/src/library/scala/collection/parallel/RemainsIterator.scala +++ b/src/library/scala/collection/parallel/RemainsIterator.scala @@ -456,6 +456,15 @@ self => } it } + /** Drop implemented as simple eager consumption. */ + override def drop(n: Int): IterableSplitter[T] = { + var i = 0 + while (i < n && hasNext) { + next() + i += 1 + } + this + } override def take(n: Int): IterableSplitter[T] = newTaken(n) override def slice(from1: Int, until1: Int): IterableSplitter[T] = newSliceInternal(newTaken(until1), from1) diff --git a/src/library/scala/collection/parallel/immutable/ParHashSet.scala b/src/library/scala/collection/parallel/immutable/ParHashSet.scala index 65a632470e..3a1ec7fff8 100644 --- a/src/library/scala/collection/parallel/immutable/ParHashSet.scala +++ b/src/library/scala/collection/parallel/immutable/ParHashSet.scala @@ -197,7 +197,7 @@ extends scala.collection.parallel.BucketCombiner[T, ParHashSet[T], Any, HashSetC while (i < chunksz) { val v = chunkarr(i).asInstanceOf[T] val hc = trie.computeHash(v) - trie = trie.updated0(v, hc, rootbits) + trie = trie.updated0(v, hc, rootbits) // internal API, private[collection] i += 1 } i = 0 diff --git a/src/library/scala/concurrent/BlockContext.scala b/src/library/scala/concurrent/BlockContext.scala index 747cc393c3..2b8ed4c7ca 100644 --- a/src/library/scala/concurrent/BlockContext.scala +++ b/src/library/scala/concurrent/BlockContext.scala @@ -41,7 +41,7 @@ package scala.concurrent trait BlockContext { /** Used internally by the framework; - * Designates (and eventually executes) a thunk which potentially blocks the calling `Thread`. + * Designates (and eventually executes) a thunk which potentially blocks the calling `java.lang.Thread`. * * Clients must use `scala.concurrent.blocking` or `scala.concurrent.Await` instead. */ @@ -53,9 +53,16 @@ object BlockContext { override def blockOn[T](thunk: =>T)(implicit permission: CanAwait): T = thunk } + /** + * @return the `BlockContext` that will be used if no other is found. + **/ + def defaultBlockContext: BlockContext = DefaultBlockContext + private val contextLocal = new ThreadLocal[BlockContext]() - /** Obtain the current thread's current `BlockContext`. */ + /** + @return the `BlockContext` that would be used for the current `java.lang.Thread` at this point + **/ def current: BlockContext = contextLocal.get match { case null => Thread.currentThread match { case ctx: BlockContext => ctx @@ -64,7 +71,9 @@ object BlockContext { case some => some } - /** Pushes a current `BlockContext` while executing `body`. */ + /** + * Installs a current `BlockContext` around executing `body`. + **/ def withBlockContext[T](blockContext: BlockContext)(body: => T): T = { val old = contextLocal.get // can be null try { diff --git a/src/library/scala/concurrent/ExecutionContext.scala b/src/library/scala/concurrent/ExecutionContext.scala index e380c55880..df2d68c9c6 100644 --- a/src/library/scala/concurrent/ExecutionContext.scala +++ b/src/library/scala/concurrent/ExecutionContext.scala @@ -72,22 +72,24 @@ trait ExecutionContext { */ def reportFailure(@deprecatedName('t) cause: Throwable): Unit - /** Prepares for the execution of a task. Returns the prepared execution context. - * - * `prepare` should be called at the site where an `ExecutionContext` is received (for - * example, through an implicit method parameter). The returned execution context may - * then be used to execute tasks. The role of `prepare` is to save any context relevant - * to an execution's ''call site'', so that this context may be restored at the - * ''execution site''. (These are often different: for example, execution may be - * suspended through a `Promise`'s future until the `Promise` is completed, which may - * be done in another thread, on another stack.) - * - * Note: a valid implementation of `prepare` is one that simply returns `this`. - * - * @return the prepared execution context - */ + /** Prepares for the execution of a task. Returns the prepared + * execution context. The recommended implementation of + * `prepare` is to return `this`. + * + * This method should no longer be overridden or called. It was + * originally expected that `prepare` would be called by + * all libraries that consume ExecutionContexts, in order to + * capture thread local context. However, this usage has proven + * difficult to implement in practice and instead it is + * now better to avoid using `prepare` entirely. + * + * Instead, if an `ExecutionContext` needs to capture thread + * local context, it should capture that context when it is + * constructed, so that it doesn't need any additional + * preparation later. + */ + @deprecated("Preparation of ExecutionContexts will be removed.", "2.12") def prepare(): ExecutionContext = this - } /** @@ -116,7 +118,7 @@ object ExecutionContext { * * @return the global `ExecutionContext` */ - def global: ExecutionContextExecutor = Implicits.global + def global: ExecutionContextExecutor = Implicits.global.asInstanceOf[ExecutionContextExecutor] object Implicits { /** @@ -127,7 +129,7 @@ object ExecutionContext { * the thread pool uses a target number of worker threads equal to the number of * [[https://docs.oracle.com/javase/8/docs/api/java/lang/Runtime.html#availableProcessors-- available processors]]. */ - implicit lazy val global: ExecutionContextExecutor = impl.ExecutionContextImpl.fromExecutor(null: Executor) + implicit lazy val global: ExecutionContext = impl.ExecutionContextImpl.fromExecutor(null: Executor) } /** Creates an `ExecutionContext` from the given `ExecutorService`. diff --git a/src/library/scala/concurrent/Future.scala b/src/library/scala/concurrent/Future.scala index 914646320c..6304f35da9 100644 --- a/src/library/scala/concurrent/Future.scala +++ b/src/library/scala/concurrent/Future.scala @@ -10,26 +10,22 @@ package scala.concurrent import scala.language.higherKinds -import java.util.concurrent.{ ConcurrentLinkedQueue, TimeUnit, Callable } +import java.util.concurrent.{ CountDownLatch, TimeUnit, Callable } import java.util.concurrent.TimeUnit.{ NANOSECONDS => NANOS, MILLISECONDS ⇒ MILLIS } -import java.lang.{ Iterable => JIterable } -import java.util.{ LinkedList => JLinkedList } -import java.util.concurrent.atomic.{ AtomicReferenceFieldUpdater, AtomicInteger, AtomicLong, AtomicBoolean } +import java.util.concurrent.atomic.AtomicInteger import scala.util.control.NonFatal -import scala.Option import scala.util.{Try, Success, Failure} - +import scala.concurrent.duration._ import scala.annotation.tailrec import scala.collection.mutable.Builder import scala.collection.generic.CanBuildFrom import scala.reflect.ClassTag - /** The trait that represents futures. * - * Asynchronous computations that yield futures are created with the `Future` call: + * Asynchronous computations that yield futures are created with the `Future.apply` call: * * {{{ * val s = "Hello" @@ -60,6 +56,10 @@ import scala.reflect.ClassTag * If a future is failed with a `scala.runtime.NonLocalReturnControl`, * it is completed with a value from that throwable instead. * + * @define swallowsExceptions + * Since this method executes asynchronously and does not produce a return value, + * any non-fatal exceptions thrown will be reported to the `ExecutionContext`. + * * @define nonDeterministic * Note: using this method yields nondeterministic dataflow programs. * @@ -91,14 +91,7 @@ import scala.reflect.ClassTag * `execute()` either immediately or asynchronously. */ trait Future[+T] extends Awaitable[T] { - - // The executor within the lexical scope - // of the Future trait. Note that this will - // (modulo bugs) _never_ execute a callback - // other than those below in this same file. - // - // See the documentation on `InternalCallbackExecutor` for more details. - private def internalExecutor = Future.InternalCallbackExecutor + import Future.{ InternalCallbackExecutor => internalExecutor } /* Callbacks */ @@ -109,9 +102,11 @@ trait Future[+T] extends Awaitable[T] { * If the future has already been completed with a value, * this will either be applied immediately or be scheduled asynchronously. * + * $swallowsExceptions * $multipleCallbacks * $callbackInContext */ + @deprecated("use `foreach` or `onComplete` instead (keep in mind that they take total rather than partial functions)", "2.12") def onSuccess[U](pf: PartialFunction[T, U])(implicit executor: ExecutionContext): Unit = onComplete { case Success(v) => pf.applyOrElse[T, Any](v, Predef.conforms[T]) // Exploiting the cached function to avoid MatchError @@ -128,9 +123,11 @@ trait Future[+T] extends Awaitable[T] { * * Will not be called in case that the future is completed with a value. * + * $swallowsExceptions * $multipleCallbacks * $callbackInContext */ + @deprecated("use `onComplete` or `failed.foreach` instead (keep in mind that they take total rather than partial functions)", "2.12") def onFailure[U](@deprecatedName('callback) pf: PartialFunction[Throwable, U])(implicit executor: ExecutionContext): Unit = onComplete { case Failure(t) => pf.applyOrElse[Throwable, Any](t, Predef.conforms[Throwable]) // Exploiting the cached function to avoid MatchError @@ -143,8 +140,12 @@ trait Future[+T] extends Awaitable[T] { * If the future has already been completed, * this will either be applied immediately or be scheduled asynchronously. * + * $swallowsExceptions * $multipleCallbacks * $callbackInContext + * + * @tparam U only used to accept any return type of the given callback function + * @param f the function to be executed when this `Future` completes */ def onComplete[U](@deprecatedName('func) f: Try[T] => U)(implicit executor: ExecutionContext): Unit @@ -160,46 +161,47 @@ trait Future[+T] extends Awaitable[T] { */ def isCompleted: Boolean - /** The value of this `Future`. + /** The current value of this `Future`. + * + * $nonDeterministic * * If the future is not completed the returned value will be `None`. * If the future is completed the value will be `Some(Success(t))` * if it contains a valid result, or `Some(Failure(error))` if it contains * an exception. + * + * @return `None` if the `Future` wasn't completed, `Some` if it was. */ def value: Option[Try[T]] /* Projections */ - /** Returns a failed projection of this future. - * - * The failed projection is a future holding a value of type `Throwable`. + /** The returned `Future` will be successfully completed with the `Throwable` of the original `Future` + * if the original `Future` fails. * - * It is completed with a value which is the throwable of the original future - * in case the original future is failed. + * If the original `Future` is successful, the returned `Future` is failed with a `NoSuchElementException`. * - * It is failed with a `NoSuchElementException` if the original future is completed successfully. - * - * Blocking on this future returns a value if the original future is completed with an exception - * and throws a corresponding exception if the original future fails. + * @return a failed projection of this `Future`. */ - def failed: Future[Throwable] = { - implicit val ec = internalExecutor - val p = Promise[Throwable]() - onComplete { - case Failure(t) => p success t - case Success(v) => p failure (new NoSuchElementException("Future.failed not completed with a throwable.")) - } - p.future - } + def failed: Future[Throwable] = + transform({ + case Failure(t) => Success(t) + case Success(v) => Failure(new NoSuchElementException("Future.failed not completed with a throwable.")) + })(internalExecutor) /* Monadic operations */ /** Asynchronously processes the value in the future once the value becomes available. * - * Will not be called if the future fails. + * WARNING: Will not be called if this future is never completed or if it is completed with a failure. + * + * $swallowsExceptions + * + * @tparam U only used to accept any return type of the given callback function + * @param f the function which will be executed if this `Future` completes with a result, + * the return value of `f` will be discarded. */ def foreach[U](f: T => U)(implicit executor: ExecutionContext): Unit = onComplete { _ foreach f } @@ -208,33 +210,49 @@ trait Future[+T] extends Awaitable[T] { * exception thrown when 's' or 'f' is applied, that exception will be propagated * to the resulting future. * - * @param s function that transforms a successful result of the receiver into a - * successful result of the returned future - * @param f function that transforms a failure of the receiver into a failure of - * the returned future - * @return a future that will be completed with the transformed value - */ - def transform[S](s: T => S, f: Throwable => Throwable)(implicit executor: ExecutionContext): Future[S] = { - val p = Promise[S]() - // transform on Try has the wrong shape for us here - onComplete { - case Success(r) => p complete Try(s(r)) - case Failure(t) => p complete Try(throw f(t)) // will throw fatal errors! + * @tparam S the type of the returned `Future` + * @param s function that transforms a successful result of the receiver into a successful result of the returned future + * @param f function that transforms a failure of the receiver into a failure of the returned future + * @return a `Future` that will be completed with the transformed value + */ + def transform[S](s: T => S, f: Throwable => Throwable)(implicit executor: ExecutionContext): Future[S] = + transform { + case Success(r) => Try(s(r)) + case Failure(t) => Try(throw f(t)) // will throw fatal errors! } - p.future - } + + /** Creates a new Future by applying the specified function to the result + * of this Future. If there is any non-fatal exception thrown when 'f' + * is applied then that exception will be propagated to the resulting future. + * + * @tparam S the type of the returned `Future` + * @param f function that transforms the result of this future + * @return a `Future` that will be completed with the transformed value + */ + def transform[S](f: Try[T] => Try[S])(implicit executor: ExecutionContext): Future[S] + + /** Creates a new Future by applying the specified function, which produces a Future, to the result + * of this Future. If there is any non-fatal exception thrown when 'f' + * is applied then that exception will be propagated to the resulting future. + * + * @tparam S the type of the returned `Future` + * @param f function that transforms the result of this future + * @return a `Future` that will be completed with the transformed value + */ + def transformWith[S](f: Try[T] => Future[S])(implicit executor: ExecutionContext): Future[S] + /** Creates a new future by applying a function to the successful result of * this future. If this future is completed with an exception then the new * future will also contain this exception. * * $forComprehensionExamples + * + * @tparam S the type of the returned `Future` + * @param f the function which will be applied to the successful result of this `Future` + * @return a `Future` which will be completed with the result of the application of the function */ - def map[S](f: T => S)(implicit executor: ExecutionContext): Future[S] = { // transform(f, identity) - val p = Promise[S]() - onComplete { v => p complete (v map f) } - p.future - } + def map[S](f: T => S)(implicit executor: ExecutionContext): Future[S] = transform(_.map(f)) /** Creates a new future by applying a function to the successful result of * this future, and returns the result of the function as the new future. @@ -242,21 +260,23 @@ trait Future[+T] extends Awaitable[T] { * also contain this exception. * * $forComprehensionExamples + * + * @tparam S the type of the returned `Future` + * @param f the function which will be applied to the successful result of this `Future` + * @return a `Future` which will be completed with the result of the application of the function */ - def flatMap[S](f: T => Future[S])(implicit executor: ExecutionContext): Future[S] = { - import impl.Promise.DefaultPromise - val p = new DefaultPromise[S]() - onComplete { - case f: Failure[_] => p complete f.asInstanceOf[Failure[S]] - case Success(v) => try f(v) match { - // If possible, link DefaultPromises to avoid space leaks - case dp: DefaultPromise[_] => dp.asInstanceOf[DefaultPromise[S]].linkRootOf(p) - case fut => fut.onComplete(p.complete)(internalExecutor) - } catch { case NonFatal(t) => p failure t } - } - p.future + def flatMap[S](f: T => Future[S])(implicit executor: ExecutionContext): Future[S] = transformWith { + case Success(s) => f(s) + case Failure(_) => this.asInstanceOf[Future[S]] } + /** Creates a new future with one level of nesting flattened, this method is equivalent + * to `flatMap(identity)`. + * + * @tparam S the type of the returned `Future` + */ + def flatten[S](implicit ev: T <:< Future[S]): Future[S] = flatMap(ev)(internalExecutor) + /** Creates a new future by filtering the value of the current future with a predicate. * * If the current future contains a value which satisfies the predicate, the new future will also hold that value. @@ -269,14 +289,15 @@ trait Future[+T] extends Awaitable[T] { * val f = Future { 5 } * val g = f filter { _ % 2 == 1 } * val h = f filter { _ % 2 == 0 } - * Await.result(g, Duration.Zero) // evaluates to 5 + * g foreach println // Eventually prints 5 * Await.result(h, Duration.Zero) // throw a NoSuchElementException * }}} + * + * @param p the predicate to apply to the successful result of this `Future` + * @return a `Future` which will hold the successful result of this `Future` if it matches the predicate or a `NoSuchElementException` */ def filter(@deprecatedName('pred) p: T => Boolean)(implicit executor: ExecutionContext): Future[T] = - map { - r => if (p(r)) r else throw new NoSuchElementException("Future.filter predicate is not satisfied") - } + map { r => if (p(r)) r else throw new NoSuchElementException("Future.filter predicate is not satisfied") } /** Used by for-comprehensions. */ @@ -298,9 +319,13 @@ trait Future[+T] extends Awaitable[T] { * val h = f collect { * case x if x > 0 => x * 2 * } - * Await.result(g, Duration.Zero) // evaluates to 5 + * g foreach println // Eventually prints 5 * Await.result(h, Duration.Zero) // throw a NoSuchElementException * }}} + * + * @tparam S the type of the returned `Future` + *  @param pf the `PartialFunction` to apply to the successful result of this `Future` + * @return a `Future` holding the result of application of the `PartialFunction` or a `NoSuchElementException` */ def collect[S](pf: PartialFunction[T, S])(implicit executor: ExecutionContext): Future[S] = map { @@ -318,12 +343,13 @@ trait Future[+T] extends Awaitable[T] { * Future (6 / 0) recover { case e: NotFoundException => 0 } // result: exception * Future (6 / 2) recover { case e: ArithmeticException => 0 } // result: 3 * }}} + * + * @tparam U the type of the returned `Future` + * @param pf the `PartialFunction` to apply if this `Future` fails + * @return a `Future` with the successful value of this `Future` or the result of the `PartialFunction` */ - def recover[U >: T](pf: PartialFunction[Throwable, U])(implicit executor: ExecutionContext): Future[U] = { - val p = Promise[U]() - onComplete { v => p complete (v recover pf) } - p.future - } + def recover[U >: T](pf: PartialFunction[Throwable, U])(implicit executor: ExecutionContext): Future[U] = + transform { _ recover pf } /** Creates a new future that will handle any matching throwable that this * future might contain by assigning it a value of another future. @@ -337,15 +363,16 @@ trait Future[+T] extends Awaitable[T] { * val f = Future { Int.MaxValue } * Future (6 / 0) recoverWith { case e: ArithmeticException => f } // result: Int.MaxValue * }}} + * + * @tparam U the type of the returned `Future` + * @param pf the `PartialFunction` to apply if this `Future` fails + * @return a `Future` with the successful value of this `Future` or the outcome of the `Future` returned by the `PartialFunction` */ - def recoverWith[U >: T](pf: PartialFunction[Throwable, Future[U]])(implicit executor: ExecutionContext): Future[U] = { - val p = Promise[U]() - onComplete { - case Failure(t) => try pf.applyOrElse(t, (_: Throwable) => this).onComplete(p.complete)(internalExecutor) catch { case NonFatal(t) => p failure t } - case other => p complete other + def recoverWith[U >: T](pf: PartialFunction[Throwable, Future[U]])(implicit executor: ExecutionContext): Future[U] = + transformWith { + case Failure(t) => pf.applyOrElse(t, (_: Throwable) => this) + case Success(_) => this } - p.future - } /** Zips the values of `this` and `that` future, and creates * a new future holding the tuple of their results. @@ -354,17 +381,35 @@ trait Future[+T] extends Awaitable[T] { * with the throwable stored in `this`. * Otherwise, if `that` future fails, the resulting future is failed * with the throwable stored in `that`. + * + * @tparam U the type of the other `Future` + * @param that the other `Future` + * @return a `Future` with the results of both futures or the failure of the first of them that failed */ def zip[U](that: Future[U]): Future[(T, U)] = { implicit val ec = internalExecutor - val p = Promise[(T, U)]() - onComplete { - case f: Failure[_] => p complete f.asInstanceOf[Failure[(T, U)]] - case Success(s) => that onComplete { c => p.complete(c map { s2 => (s, s2) }) } - } - p.future + flatMap { r1 => that.map(r2 => (r1, r2)) } } + /** Zips the values of `this` and `that` future using a function `f`, + * and creates a new future holding the result. + * + * If `this` future fails, the resulting future is failed + * with the throwable stored in `this`. + * Otherwise, if `that` future fails, the resulting future is failed + * with the throwable stored in `that`. + * If the application of `f` throws a throwable, the resulting future + * is failed with that throwable if it is non-fatal. + * + * @tparam U the type of the other `Future` + * @tparam R the type of the resulting `Future` + * @param that the other `Future` + * @param f the function to apply to the results of `this` and `that` + * @return a `Future` with the result of the application of `f` to the results of `this` and `that` + */ + def zipWith[U, R](that: Future[U])(f: (T, U) => R)(implicit executor: ExecutionContext): Future[R] = + flatMap(r1 => that.map(r2 => f(r1, r2)))(internalExecutor) + /** Creates a new future which holds the result of this future if it was completed successfully, or, if not, * the result of the `that` future if `that` is completed successfully. * If both futures are failed, the resulting future holds the throwable object of the first future. @@ -376,24 +421,26 @@ trait Future[+T] extends Awaitable[T] { * val f = Future { sys.error("failed") } * val g = Future { 5 } * val h = f fallbackTo g - * Await.result(h, Duration.Zero) // evaluates to 5 + * h foreach println // Eventually prints 5 * }}} + * + * @tparam U the type of the other `Future` and the resulting `Future` + * @param that the `Future` whose result we want to use if this `Future` fails. + * @return a `Future` with the successful result of this or that `Future` or the failure of this `Future` if both fail */ - def fallbackTo[U >: T](that: Future[U]): Future[U] = { - implicit val ec = internalExecutor - val p = Promise[U]() - onComplete { - case s @ Success(_) => p complete s - case f @ Failure(_) => that onComplete { - case s2 @ Success(_) => p complete s2 - case _ => p complete f // Use the first failure as the failure - } + def fallbackTo[U >: T](that: Future[U]): Future[U] = + if (this eq that) this + else { + implicit val ec = internalExecutor + recoverWith { case _ => that } recoverWith { case _ => this } } - p.future - } /** Creates a new `Future[S]` which is completed with this `Future`'s result if * that conforms to `S`'s erased type or a `ClassCastException` otherwise. + * + * @tparam S the type of the returned `Future` + * @param tag the `ClassTag` which will be used to cast the result of this `Future` + * @return a `Future` holding the casted result of this `Future` or a `ClassCastException` otherwise */ def mapTo[S](implicit tag: ClassTag[S]): Future[S] = { implicit val ec = internalExecutor @@ -427,15 +474,19 @@ trait Future[+T] extends Awaitable[T] { * case Success(v) => println(v) * } * }}} + * + * @tparam U only used to accept any return type of the given `PartialFunction` + * @param pf a `PartialFunction` which will be conditionally applied to the outcome of this `Future` + * @return a `Future` which will be completed with the exact same outcome as this `Future` but after the `PartialFunction` has been executed. */ - def andThen[U](pf: PartialFunction[Try[T], U])(implicit executor: ExecutionContext): Future[T] = { - val p = Promise[T]() - onComplete { - case r => try pf.applyOrElse[Try[T], Any](r, Predef.conforms[Try[T]]) finally p complete r - } - p.future - } + def andThen[U](pf: PartialFunction[Try[T], U])(implicit executor: ExecutionContext): Future[T] = + transform { + result => + try pf.applyOrElse[Try[T], Any](result, Predef.conforms[Try[T]]) + catch { case NonFatal(t) => executor reportFailure t } + result + } } @@ -459,40 +510,102 @@ object Future { classOf[Unit] -> classOf[scala.runtime.BoxedUnit] ) + /** A Future which is never completed. + */ + final object never extends Future[Nothing] { + + @throws(classOf[TimeoutException]) + @throws(classOf[InterruptedException]) + override def ready(atMost: Duration)(implicit permit: CanAwait): this.type = { + atMost match { + case e if e eq Duration.Undefined => throw new IllegalArgumentException("cannot wait for Undefined period") + case Duration.Inf => new CountDownLatch(1).await() + case Duration.MinusInf => // Drop out + case f: FiniteDuration => + if (f > Duration.Zero) new CountDownLatch(1).await(f.toNanos, TimeUnit.NANOSECONDS) + } + throw new TimeoutException(s"Future timed out after [$atMost]") + } + + @throws(classOf[Exception]) + override def result(atMost: Duration)(implicit permit: CanAwait): Nothing = { + ready(atMost) + throw new TimeoutException(s"Future timed out after [$atMost]") + } + + override def onSuccess[U](pf: PartialFunction[Nothing, U])(implicit executor: ExecutionContext): Unit = () + override def onFailure[U](pf: PartialFunction[Throwable, U])(implicit executor: ExecutionContext): Unit = () + override def onComplete[U](f: Try[Nothing] => U)(implicit executor: ExecutionContext): Unit = () + override def isCompleted: Boolean = false + override def value: Option[Try[Nothing]] = None + override def failed: Future[Throwable] = this + override def foreach[U](f: Nothing => U)(implicit executor: ExecutionContext): Unit = () + override def transform[S](s: Nothing => S, f: Throwable => Throwable)(implicit executor: ExecutionContext): Future[S] = this + override def transform[S](f: Try[Nothing] => Try[S])(implicit executor: ExecutionContext): Future[S] = this + override def transformWith[S](f: Try[Nothing] => Future[S])(implicit executor: ExecutionContext): Future[S] = this + override def map[S](f: Nothing => S)(implicit executor: ExecutionContext): Future[S] = this + override def flatMap[S](f: Nothing => Future[S])(implicit executor: ExecutionContext): Future[S] = this + override def flatten[S](implicit ev: Nothing <:< Future[S]): Future[S] = this + override def filter(p: Nothing => Boolean)(implicit executor: ExecutionContext): Future[Nothing] = this + override def collect[S](pf: PartialFunction[Nothing, S])(implicit executor: ExecutionContext): Future[S] = this + override def recover[U >: Nothing](pf: PartialFunction[Throwable, U])(implicit executor: ExecutionContext): Future[U] = this + override def recoverWith[U >: Nothing](pf: PartialFunction[Throwable, Future[U]])(implicit executor: ExecutionContext): Future[U] = this + override def zip[U](that: Future[U]): Future[(Nothing, U)] = this + override def zipWith[U, R](that: Future[U])(f: (Nothing, U) => R)(implicit executor: ExecutionContext): Future[R] = this + override def fallbackTo[U >: Nothing](that: Future[U]): Future[U] = this + override def mapTo[S](implicit tag: ClassTag[S]): Future[S] = this + override def andThen[U](pf: PartialFunction[Try[Nothing], U])(implicit executor: ExecutionContext): Future[Nothing] = this + + override def toString: String = "Future(<never>)" + } + + /** A Future which is always completed with the Unit value. + */ + val unit: Future[Unit] = successful(()) + /** Creates an already completed Future with the specified exception. * - * @tparam T the type of the value in the future - * @return the newly created `Future` object + * @tparam T the type of the value in the future + * @param exception the non-null instance of `Throwable` + * @return the newly created `Future` instance */ def failed[T](exception: Throwable): Future[T] = Promise.failed(exception).future /** Creates an already completed Future with the specified result. * * @tparam T the type of the value in the future - * @return the newly created `Future` object + * @param result the given successful value + * @return the newly created `Future` instance */ def successful[T](result: T): Future[T] = Promise.successful(result).future /** Creates an already completed Future with the specified result or exception. * - * @tparam T the type of the value in the promise - * @return the newly created `Future` object + * @tparam T the type of the value in the `Future` + * @param result the result of the returned `Future` instance + * @return the newly created `Future` instance */ def fromTry[T](result: Try[T]): Future[T] = Promise.fromTry(result).future - /** Starts an asynchronous computation and returns a `Future` object with the result of that computation. + /** Starts an asynchronous computation and returns a `Future` instance with the result of that computation. * * The result becomes available once the asynchronous computation is completed. * - * @tparam T the type of the result - * @param body the asynchronous computation + * @tparam T the type of the result + * @param body the asynchronous computation * @param executor the execution context on which the future is run - * @return the `Future` holding the result of the computation + * @return the `Future` holding the result of the computation */ - def apply[T](body: =>T)(implicit @deprecatedName('execctx) executor: ExecutionContext): Future[T] = impl.Future(body) + def apply[T](body: =>T)(implicit @deprecatedName('execctx) executor: ExecutionContext): Future[T] = + unit.map(_ => body) - /** Simple version of `Future.traverse`. Transforms a `TraversableOnce[Future[A]]` into a `Future[TraversableOnce[A]]`. - * Useful for reducing many `Future`s into a single `Future`. + /** Simple version of `Future.traverse`. Asynchronously and non-blockingly transforms a `TraversableOnce[Future[A]]` + * into a `Future[TraversableOnce[A]]`. Useful for reducing many `Future`s into a single `Future`. + * + * @tparam A the type of the value inside the Futures + * @tparam M the type of the `TraversableOnce` of Futures + * @param in the `TraversableOnce` of Futures which will be sequenced + * @return the `Future` of the `TraversableOnce` of results */ def sequence[A, M[X] <: TraversableOnce[X]](in: M[Future[A]])(implicit cbf: CanBuildFrom[M[Future[A]], A, M[A]], executor: ExecutionContext): Future[M[A]] = { in.foldLeft(successful(cbf(in))) { @@ -500,7 +613,12 @@ object Future { } map (_.result()) } - /** Returns a new `Future` to the result of the first future in the list that is completed. + /** Asynchronously and non-blockingly returns a new `Future` to the result of the first future + * in the list that is completed. This means no matter if it is completed as a success or as a failure. + * + * @tparam T the type of the value in the future + * @param futures the `TraversableOnce` of Futures in which to find the first completed + * @return the `Future` holding the result of the future that is first to be completed */ def firstCompletedOf[T](futures: TraversableOnce[Future[T]])(implicit executor: ExecutionContext): Future[T] = { val p = Promise[T]() @@ -509,8 +627,15 @@ object Future { p.future } - /** Returns a `Future` that will hold the optional result of the first `Future` with a result that matches the predicate. + /** Asynchronously and non-blockingly returns a `Future` that will hold the optional result + * of the first `Future` with a result that matches the predicate. + * + * @tparam T the type of the value in the future + * @param futures the `TraversableOnce` of Futures to search + * @param p the predicate which indicates if it's a match + * @return the `Future` holding the optional result of the search */ + @deprecated("Use the overloaded version of this method that takes a scala.collection.immutable.Iterable instead", "2.12") def find[T](@deprecatedName('futurestravonce) futures: TraversableOnce[Future[T]])(@deprecatedName('predicate) p: T => Boolean)(implicit executor: ExecutionContext): Future[Option[T]] = { val futuresBuffer = futures.toBuffer if (futuresBuffer.isEmpty) successful[Option[T]](None) @@ -534,40 +659,127 @@ object Future { } } - /** A non-blocking fold over the specified futures, with the start value of the given zero. + + /** Asynchronously and non-blockingly returns a `Future` that will hold the optional result + * of the first `Future` with a result that matches the predicate, failed `Future`s will be ignored. + * + * @tparam T the type of the value in the future + * @param futures the `scala.collection.immutable.Iterable` of Futures to search + * @param p the predicate which indicates if it's a match + * @return the `Future` holding the optional result of the search + */ + def find[T](futures: scala.collection.immutable.Iterable[Future[T]])(p: T => Boolean)(implicit executor: ExecutionContext): Future[Option[T]] = { + def searchNext(i: Iterator[Future[T]]): Future[Option[T]] = + if (!i.hasNext) successful[Option[T]](None) + else { + i.next().transformWith { + case Success(r) if p(r) => successful(Some(r)) + case other => searchNext(i) + } + } + searchNext(futures.iterator) + } + + /** A non-blocking, asynchronous left fold over the specified futures, + * with the start value of the given zero. + * The fold is performed asynchronously in left-to-right order as the futures become completed. + * The result will be the first failure of any of the futures, or any failure in the actual fold, + * or the result of the fold. + * + * Example: + * {{{ + * val futureSum = Future.foldLeft(futures)(0)(_ + _) + * }}} + * + * @tparam T the type of the value of the input Futures + * @tparam R the type of the value of the returned `Future` + * @param futures the `scala.collection.immutable.Iterable` of Futures to be folded + * @param zero the start value of the fold + * @param op the fold operation to be applied to the zero and futures + * @return the `Future` holding the result of the fold + */ + def foldLeft[T, R](futures: scala.collection.immutable.Iterable[Future[T]])(zero: R)(op: (R, T) => R)(implicit executor: ExecutionContext): Future[R] = + foldNext(futures.iterator, zero, op) + + private[this] def foldNext[T, R](i: Iterator[Future[T]], prevValue: R, op: (R, T) => R)(implicit executor: ExecutionContext): Future[R] = + if (!i.hasNext) successful(prevValue) + else i.next().flatMap { value => foldNext(i, op(prevValue, value), op) } + + /** A non-blocking, asynchronous fold over the specified futures, with the start value of the given zero. * The fold is performed on the thread where the last future is completed, * the result will be the first failure of any of the futures, or any failure in the actual fold, * or the result of the fold. * * Example: * {{{ - * val result = Await.result(Future.fold(futures)(0)(_ + _), 5 seconds) + * val futureSum = Future.fold(futures)(0)(_ + _) * }}} + * + * @tparam T the type of the value of the input Futures + * @tparam R the type of the value of the returned `Future` + * @param futures the `TraversableOnce` of Futures to be folded + * @param zero the start value of the fold + * @param op the fold operation to be applied to the zero and futures + * @return the `Future` holding the result of the fold */ + @deprecated("Use Future.foldLeft instead", "2.12") def fold[T, R](futures: TraversableOnce[Future[T]])(zero: R)(@deprecatedName('foldFun) op: (R, T) => R)(implicit executor: ExecutionContext): Future[R] = { if (futures.isEmpty) successful(zero) else sequence(futures).map(_.foldLeft(zero)(op)) } - /** Initiates a fold over the supplied futures where the fold-zero is the result value of the `Future` that's completed first. + /** Initiates a non-blocking, asynchronous, fold over the supplied futures + * where the fold-zero is the result value of the `Future` that's completed first. * * Example: * {{{ - * val result = Await.result(Future.reduce(futures)(_ + _), 5 seconds) + * val futureSum = Future.reduce(futures)(_ + _) * }}} + * @tparam T the type of the value of the input Futures + * @tparam R the type of the value of the returned `Future` + * @param futures the `TraversableOnce` of Futures to be reduced + * @param op the reduce operation which is applied to the results of the futures + * @return the `Future` holding the result of the reduce */ + @deprecated("Use Future.reduceLeft instead", "2.12") def reduce[T, R >: T](futures: TraversableOnce[Future[T]])(op: (R, T) => R)(implicit executor: ExecutionContext): Future[R] = { if (futures.isEmpty) failed(new NoSuchElementException("reduce attempted on empty collection")) else sequence(futures).map(_ reduceLeft op) } - /** Transforms a `TraversableOnce[A]` into a `Future[TraversableOnce[B]]` using the provided function `A => Future[B]`. + /** Initiates a non-blocking, asynchronous, left reduction over the supplied futures + * where the zero is the result value of the first `Future`. + * + * Example: + * {{{ + * val futureSum = Future.reduceLeft(futures)(_ + _) + * }}} + * @tparam T the type of the value of the input Futures + * @tparam R the type of the value of the returned `Future` + * @param futures the `scala.collection.immutable.Iterable` of Futures to be reduced + * @param op the reduce operation which is applied to the results of the futures + * @return the `Future` holding the result of the reduce + */ + def reduceLeft[T, R >: T](futures: scala.collection.immutable.Iterable[Future[T]])(op: (R, T) => R)(implicit executor: ExecutionContext): Future[R] = { + val i = futures.iterator + if (!i.hasNext) failed(new NoSuchElementException("reduceLeft attempted on empty collection")) + else i.next() flatMap { v => foldNext(i, v, op) } + } + + /** Asynchronously and non-blockingly transforms a `TraversableOnce[A]` into a `Future[TraversableOnce[B]]` + * using the provided function `A => Future[B]`. * This is useful for performing a parallel map. For example, to apply a function to all items of a list * in parallel: * * {{{ * val myFutureList = Future.traverse(myList)(x => Future(myFunc(x))) * }}} + * @tparam A the type of the value inside the Futures in the `TraversableOnce` + * @tparam B the type of the value of the returned `Future` + * @tparam M the type of the `TraversableOnce` of Futures + * @param in the `TraversableOnce` of Futures which will be sequenced + * @param fn the function to apply to the `TraversableOnce` of Futures to produce the results + * @return the `Future` of the `TraversableOnce` of results */ def traverse[A, B, M[X] <: TraversableOnce[X]](in: M[A])(fn: A => Future[B])(implicit cbf: CanBuildFrom[M[A], B, M[B]], executor: ExecutionContext): Future[M[B]] = in.foldLeft(successful(cbf(in))) { (fr, a) => @@ -575,6 +787,7 @@ object Future { for (r <- fr; b <- fb) yield (r += b) }.map(_.result()) + // This is used to run callbacks which are internal // to scala.concurrent; our own callbacks are only // ever used to eventually run another callback, diff --git a/src/library/scala/concurrent/Promise.scala b/src/library/scala/concurrent/Promise.scala index 0f4e98db57..894b134e83 100644 --- a/src/library/scala/concurrent/Promise.scala +++ b/src/library/scala/concurrent/Promise.scala @@ -26,12 +26,6 @@ import scala.util.{ Try, Success, Failure } * Note: Using this method may result in non-deterministic concurrent programs. */ trait Promise[T] { - - // used for internal callbacks defined in - // the lexical scope of this trait; - // _never_ for application callbacks. - private implicit def internalExecutor: ExecutionContext = Future.InternalCallbackExecutor - /** Future containing the value of this promise. */ def future: Future[T] @@ -73,7 +67,9 @@ trait Promise[T] { * @return This promise */ final def tryCompleteWith(other: Future[T]): this.type = { - other onComplete { this tryComplete _ } + if (other ne this.future) { // this tryCompleteWith this doesn't make much sense + other.onComplete(this tryComplete _)(Future.InternalCallbackExecutor) + } this } @@ -139,5 +135,5 @@ object Promise { * @tparam T the type of the value in the promise * @return the newly created `Promise` object */ - def fromTry[T](result: Try[T]): Promise[T] = new impl.Promise.KeptPromise[T](result) + def fromTry[T](result: Try[T]): Promise[T] = impl.Promise.KeptPromise[T](result) } diff --git a/src/library/scala/concurrent/duration/Duration.scala b/src/library/scala/concurrent/duration/Duration.scala index 182c2d172a..8b7d81d1c4 100644 --- a/src/library/scala/concurrent/duration/Duration.scala +++ b/src/library/scala/concurrent/duration/Duration.scala @@ -708,7 +708,7 @@ final class FiniteDuration(val length: Long, val unit: TimeUnit) extends Duratio final def isFinite() = true - final def toCoarsest: Duration = { + final override def toCoarsest: FiniteDuration = { def loop(length: Long, unit: TimeUnit): FiniteDuration = { def coarserOrThis(coarser: TimeUnit, divider: Int) = if (length % divider == 0) loop(length / divider, coarser) diff --git a/src/library/scala/concurrent/impl/AbstractPromise.java b/src/library/scala/concurrent/impl/AbstractPromise.java deleted file mode 100644 index b8165b6cde..0000000000 --- a/src/library/scala/concurrent/impl/AbstractPromise.java +++ /dev/null @@ -1,40 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - -package scala.concurrent.impl; - - -import scala.concurrent.util.Unsafe; -import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; - - - -abstract class AbstractPromise { - private volatile Object _ref; - - final static long _refoffset; - - static { - try { - _refoffset = Unsafe.instance.objectFieldOffset(AbstractPromise.class.getDeclaredField("_ref")); - } catch (Throwable t) { - throw new ExceptionInInitializerError(t); - } - } - - protected final boolean updateState(Object oldState, Object newState) { - return Unsafe.instance.compareAndSwapObject(this, _refoffset, oldState, newState); - } - - protected final Object getState() { - return _ref; - } - - protected final static AtomicReferenceFieldUpdater<AbstractPromise, Object> updater = - AtomicReferenceFieldUpdater.newUpdater(AbstractPromise.class, Object.class, "_ref"); -}
\ No newline at end of file diff --git a/src/library/scala/concurrent/impl/ExecutionContextImpl.scala b/src/library/scala/concurrent/impl/ExecutionContextImpl.scala index 479720287c..0c7f98ce5a 100644 --- a/src/library/scala/concurrent/impl/ExecutionContextImpl.scala +++ b/src/library/scala/concurrent/impl/ExecutionContextImpl.scala @@ -11,52 +11,88 @@ package scala.concurrent.impl import java.util.concurrent.{ LinkedBlockingQueue, Callable, Executor, ExecutorService, Executors, ThreadFactory, TimeUnit, ThreadPoolExecutor } +import java.util.concurrent.atomic.AtomicInteger import java.util.Collection import scala.concurrent.forkjoin._ import scala.concurrent.{ BlockContext, ExecutionContext, Awaitable, CanAwait, ExecutionContextExecutor, ExecutionContextExecutorService } import scala.util.control.NonFatal +import scala.annotation.tailrec +private[scala] class ExecutionContextImpl private[impl] (val executor: Executor, val reporter: Throwable => Unit) extends ExecutionContextExecutor { + require(executor ne null, "Executor must not be null") + override def execute(runnable: Runnable) = executor execute runnable + override def reportFailure(t: Throwable) = reporter(t) +} -private[scala] class ExecutionContextImpl private[impl] (es: Executor, reporter: Throwable => Unit) extends ExecutionContextExecutor { - // Placed here since the creation of the executor needs to read this val - private[this] val uncaughtExceptionHandler: Thread.UncaughtExceptionHandler = new Thread.UncaughtExceptionHandler { - def uncaughtException(thread: Thread, cause: Throwable): Unit = reporter(cause) - } - val executor: Executor = es match { - case null => createExecutorService - case some => some - } +private[concurrent] object ExecutionContextImpl { // Implement BlockContext on FJP threads - class DefaultThreadFactory(daemonic: Boolean) extends ThreadFactory with ForkJoinPool.ForkJoinWorkerThreadFactory { + final class DefaultThreadFactory( + daemonic: Boolean, + maxThreads: Int, + prefix: String, + uncaught: Thread.UncaughtExceptionHandler) extends ThreadFactory with ForkJoinPool.ForkJoinWorkerThreadFactory { + + require(prefix ne null, "DefaultThreadFactory.prefix must be non null") + require(maxThreads > 0, "DefaultThreadFactory.maxThreads must be greater than 0") + + private final val currentNumberOfThreads = new AtomicInteger(0) + + @tailrec private final def reserveThread(): Boolean = currentNumberOfThreads.get() match { + case `maxThreads` | Int.`MaxValue` => false + case other => currentNumberOfThreads.compareAndSet(other, other + 1) || reserveThread() + } + + @tailrec private final def deregisterThread(): Boolean = currentNumberOfThreads.get() match { + case 0 => false + case other => currentNumberOfThreads.compareAndSet(other, other - 1) || deregisterThread() + } + def wire[T <: Thread](thread: T): T = { thread.setDaemon(daemonic) - thread.setUncaughtExceptionHandler(uncaughtExceptionHandler) + thread.setUncaughtExceptionHandler(uncaught) + thread.setName(prefix + "-" + thread.getId()) thread } - def newThread(runnable: Runnable): Thread = wire(new Thread(runnable)) - - def newThread(fjp: ForkJoinPool): ForkJoinWorkerThread = wire(new ForkJoinWorkerThread(fjp) with BlockContext { - override def blockOn[T](thunk: =>T)(implicit permission: CanAwait): T = { - var result: T = null.asInstanceOf[T] - ForkJoinPool.managedBlock(new ForkJoinPool.ManagedBlocker { - @volatile var isdone = false - override def block(): Boolean = { - result = try thunk finally { isdone = true } - true + // As per ThreadFactory contract newThread should return `null` if cannot create new thread. + def newThread(runnable: Runnable): Thread = + if (reserveThread()) + wire(new Thread(new Runnable { + // We have to decrement the current thread count when the thread exits + override def run() = try runnable.run() finally deregisterThread() + })) else null + + def newThread(fjp: ForkJoinPool): ForkJoinWorkerThread = + if (reserveThread()) { + wire(new ForkJoinWorkerThread(fjp) with BlockContext { + // We have to decrement the current thread count when the thread exits + final override def onTermination(exception: Throwable): Unit = deregisterThread() + final override def blockOn[T](thunk: =>T)(implicit permission: CanAwait): T = { + var result: T = null.asInstanceOf[T] + ForkJoinPool.managedBlock(new ForkJoinPool.ManagedBlocker { + @volatile var isdone = false + override def block(): Boolean = { + result = try { + // When we block, switch out the BlockContext temporarily so that nested blocking does not created N new Threads + BlockContext.withBlockContext(BlockContext.defaultBlockContext) { thunk } + } finally { + isdone = true + } + + true + } + override def isReleasable = isdone + }) + result } - override def isReleasable = isdone }) - result - } - }) + } else null } - def createExecutorService: ExecutorService = { - + def createDefaultExecutorService(reporter: Throwable => Unit): ExecutorService = { def getInt(name: String, default: String) = (try System.getProperty(name, default) catch { case e: SecurityException => default }) match { @@ -65,20 +101,42 @@ private[scala] class ExecutionContextImpl private[impl] (es: Executor, reporter: } def range(floor: Int, desired: Int, ceiling: Int) = scala.math.min(scala.math.max(floor, desired), ceiling) + val numThreads = getInt("scala.concurrent.context.numThreads", "x1") + // The hard limit on the number of active threads that the thread factory will produce + // SI-8955 Deadlocks can happen if maxNoOfThreads is too low, although we're currently not sure + // about what the exact threshhold is. numThreads + 256 is conservatively high. + val maxNoOfThreads = getInt("scala.concurrent.context.maxThreads", "x1") val desiredParallelism = range( getInt("scala.concurrent.context.minThreads", "1"), - getInt("scala.concurrent.context.numThreads", "x1"), - getInt("scala.concurrent.context.maxThreads", "x1")) + numThreads, + maxNoOfThreads) + + // The thread factory must provide additional threads to support managed blocking. + val maxExtraThreads = getInt("scala.concurrent.context.maxExtraThreads", "256") + + val uncaughtExceptionHandler: Thread.UncaughtExceptionHandler = new Thread.UncaughtExceptionHandler { + override def uncaughtException(thread: Thread, cause: Throwable): Unit = reporter(cause) + } - val threadFactory = new DefaultThreadFactory(daemonic = true) + val threadFactory = new ExecutionContextImpl.DefaultThreadFactory(daemonic = true, + maxThreads = maxNoOfThreads + maxExtraThreads, + prefix = "scala-execution-context-global", + uncaught = uncaughtExceptionHandler) try { - new ForkJoinPool( - desiredParallelism, - threadFactory, - uncaughtExceptionHandler, - true) // Async all the way baby + new ForkJoinPool(desiredParallelism, threadFactory, uncaughtExceptionHandler, true) { + override def execute(runnable: Runnable): Unit = { + val fjt: ForkJoinTask[_] = runnable match { + case t: ForkJoinTask[_] => t + case r => new ExecutionContextImpl.AdaptedForkJoinTask(r) + } + Thread.currentThread match { + case fjw: ForkJoinWorkerThread if fjw.getPool eq this => fjt.fork() + case _ => super.execute(fjt) + } + } + } } catch { case NonFatal(t) => System.err.println("Failed to create ForkJoinPool for the default ExecutionContext, falling back to ThreadPoolExecutor") @@ -96,56 +154,42 @@ private[scala] class ExecutionContextImpl private[impl] (es: Executor, reporter: } } - def execute(runnable: Runnable): Unit = executor match { - case fj: ForkJoinPool => - val fjt: ForkJoinTask[_] = runnable match { - case t: ForkJoinTask[_] => t - case r => new ExecutionContextImpl.AdaptedForkJoinTask(r) - } - Thread.currentThread match { - case fjw: ForkJoinWorkerThread if fjw.getPool eq fj => fjt.fork() - case _ => fj execute fjt - } - case generic => generic execute runnable - } - - def reportFailure(t: Throwable) = reporter(t) -} - - -private[concurrent] object ExecutionContextImpl { - final class AdaptedForkJoinTask(runnable: Runnable) extends ForkJoinTask[Unit] { - final override def setRawResult(u: Unit): Unit = () - final override def getRawResult(): Unit = () - final override def exec(): Boolean = try { runnable.run(); true } catch { - case anything: Throwable ⇒ - val t = Thread.currentThread - t.getUncaughtExceptionHandler match { - case null ⇒ - case some ⇒ some.uncaughtException(t, anything) - } - throw anything - } + final override def setRawResult(u: Unit): Unit = () + final override def getRawResult(): Unit = () + final override def exec(): Boolean = try { runnable.run(); true } catch { + case anything: Throwable => + val t = Thread.currentThread + t.getUncaughtExceptionHandler match { + case null => + case some => some.uncaughtException(t, anything) } + throw anything + } + } - def fromExecutor(e: Executor, reporter: Throwable => Unit = ExecutionContext.defaultReporter): ExecutionContextImpl = new ExecutionContextImpl(e, reporter) - def fromExecutorService(es: ExecutorService, reporter: Throwable => Unit = ExecutionContext.defaultReporter): ExecutionContextImpl with ExecutionContextExecutorService = - new ExecutionContextImpl(es, reporter) with ExecutionContextExecutorService { - final def asExecutorService: ExecutorService = executor.asInstanceOf[ExecutorService] - override def execute(command: Runnable) = executor.execute(command) - override def shutdown() { asExecutorService.shutdown() } - override def shutdownNow() = asExecutorService.shutdownNow() - override def isShutdown = asExecutorService.isShutdown - override def isTerminated = asExecutorService.isTerminated - override def awaitTermination(l: Long, timeUnit: TimeUnit) = asExecutorService.awaitTermination(l, timeUnit) - override def submit[T](callable: Callable[T]) = asExecutorService.submit(callable) - override def submit[T](runnable: Runnable, t: T) = asExecutorService.submit(runnable, t) - override def submit(runnable: Runnable) = asExecutorService.submit(runnable) - override def invokeAll[T](callables: Collection[_ <: Callable[T]]) = asExecutorService.invokeAll(callables) - override def invokeAll[T](callables: Collection[_ <: Callable[T]], l: Long, timeUnit: TimeUnit) = asExecutorService.invokeAll(callables, l, timeUnit) - override def invokeAny[T](callables: Collection[_ <: Callable[T]]) = asExecutorService.invokeAny(callables) - override def invokeAny[T](callables: Collection[_ <: Callable[T]], l: Long, timeUnit: TimeUnit) = asExecutorService.invokeAny(callables, l, timeUnit) + def fromExecutor(e: Executor, reporter: Throwable => Unit = ExecutionContext.defaultReporter): ExecutionContextImpl = + new ExecutionContextImpl(Option(e).getOrElse(createDefaultExecutorService(reporter)), reporter) + + def fromExecutorService(es: ExecutorService, reporter: Throwable => Unit = ExecutionContext.defaultReporter): + ExecutionContextImpl with ExecutionContextExecutorService = { + new ExecutionContextImpl(Option(es).getOrElse(createDefaultExecutorService(reporter)), reporter) + with ExecutionContextExecutorService { + final def asExecutorService: ExecutorService = executor.asInstanceOf[ExecutorService] + override def execute(command: Runnable) = executor.execute(command) + override def shutdown() { asExecutorService.shutdown() } + override def shutdownNow() = asExecutorService.shutdownNow() + override def isShutdown = asExecutorService.isShutdown + override def isTerminated = asExecutorService.isTerminated + override def awaitTermination(l: Long, timeUnit: TimeUnit) = asExecutorService.awaitTermination(l, timeUnit) + override def submit[T](callable: Callable[T]) = asExecutorService.submit(callable) + override def submit[T](runnable: Runnable, t: T) = asExecutorService.submit(runnable, t) + override def submit(runnable: Runnable) = asExecutorService.submit(runnable) + override def invokeAll[T](callables: Collection[_ <: Callable[T]]) = asExecutorService.invokeAll(callables) + override def invokeAll[T](callables: Collection[_ <: Callable[T]], l: Long, timeUnit: TimeUnit) = asExecutorService.invokeAll(callables, l, timeUnit) + override def invokeAny[T](callables: Collection[_ <: Callable[T]]) = asExecutorService.invokeAny(callables) + override def invokeAny[T](callables: Collection[_ <: Callable[T]], l: Long, timeUnit: TimeUnit) = asExecutorService.invokeAny(callables, l, timeUnit) + } } } diff --git a/src/library/scala/concurrent/impl/Future.scala b/src/library/scala/concurrent/impl/Future.scala deleted file mode 100644 index 042d32c234..0000000000 --- a/src/library/scala/concurrent/impl/Future.scala +++ /dev/null @@ -1,34 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - -package scala.concurrent.impl - - - -import scala.concurrent.ExecutionContext -import scala.util.control.NonFatal -import scala.util.{ Success, Failure } - - -private[concurrent] object Future { - class PromiseCompletingRunnable[T](body: => T) extends Runnable { - val promise = new Promise.DefaultPromise[T]() - - override def run() = { - promise complete { - try Success(body) catch { case NonFatal(e) => Failure(e) } - } - } - } - - def apply[T](body: =>T)(implicit executor: ExecutionContext): scala.concurrent.Future[T] = { - val runnable = new PromiseCompletingRunnable(body) - executor.prepare.execute(runnable) - runnable.promise.future - } -} diff --git a/src/library/scala/concurrent/impl/Promise.scala b/src/library/scala/concurrent/impl/Promise.scala index b15601058e..078ad45be9 100644 --- a/src/library/scala/concurrent/impl/Promise.scala +++ b/src/library/scala/concurrent/impl/Promise.scala @@ -16,14 +16,42 @@ import scala.util.control.NonFatal import scala.util.{ Try, Success, Failure } import java.io.ObjectInputStream import java.util.concurrent.locks.AbstractQueuedSynchronizer +import java.util.concurrent.atomic.AtomicReference private[concurrent] trait Promise[T] extends scala.concurrent.Promise[T] with scala.concurrent.Future[T] { def future: this.type = this + + import scala.concurrent.Future + import scala.concurrent.impl.Promise.DefaultPromise + + override def transform[S](f: Try[T] => Try[S])(implicit executor: ExecutionContext): Future[S] = { + val p = new DefaultPromise[S]() + onComplete { result => p.complete(try f(result) catch { case NonFatal(t) => Failure(t) }) } + p.future + } + + // If possible, link DefaultPromises to avoid space leaks + override def transformWith[S](f: Try[T] => Future[S])(implicit executor: ExecutionContext): Future[S] = { + val p = new DefaultPromise[S]() + onComplete { + v => try f(v) match { + case fut if fut eq this => p complete v.asInstanceOf[Try[S]] + case dp: DefaultPromise[_] => dp.asInstanceOf[DefaultPromise[S]].linkRootOf(p) + case fut => p completeWith fut + } catch { case NonFatal(t) => p failure t } + } + p.future + } + + override def toString: String = value match { + case Some(result) => "Future("+result+")" + case None => "Future(<not completed>)" + } } /* Precondition: `executor` is prepared, i.e., `executor` has been returned from invocation of `prepare` on some other `ExecutionContext`. */ -private class CallbackRunnable[T](val executor: ExecutionContext, val onComplete: Try[T] => Any) extends Runnable with OnCompleteRunnable { +private final class CallbackRunnable[T](val executor: ExecutionContext, val onComplete: Try[T] => Any) extends Runnable with OnCompleteRunnable { // must be filled in before running it var value: Try[T] = null @@ -89,7 +117,7 @@ private[concurrent] object Promise { * incomplete, or as complete with the same result value. * * A DefaultPromise stores its state entirely in the AnyRef cell exposed by - * AbstractPromise. The type of object stored in the cell fully describes the + * AtomicReference. The type of object stored in the cell fully describes the * current state of the promise. * * 1. List[CallbackRunnable] - The promise is incomplete and has zero or more callbacks @@ -150,8 +178,7 @@ private[concurrent] object Promise { * DefaultPromises, and `linkedRootOf` is currently only designed to be called * by Future.flatMap. */ - class DefaultPromise[T] extends AbstractPromise with Promise[T] { self => - updateState(null, Nil) // The promise is incomplete and has no callbacks + final class DefaultPromise[T] extends AtomicReference[AnyRef](Nil) with Promise[T] { /** Get the root promise for this promise, compressing the link chain to that * promise if necessary. @@ -167,14 +194,23 @@ private[concurrent] object Promise { * be garbage collected. Also, subsequent calls to this method should be * faster as the link chain will be shorter. */ - @tailrec - private def compressedRoot(): DefaultPromise[T] = { - getState match { - case linked: DefaultPromise[_] => - val target = linked.asInstanceOf[DefaultPromise[T]].root - if (linked eq target) target else if (updateState(linked, target)) target else compressedRoot() + private def compressedRoot(): DefaultPromise[T] = + get() match { + case linked: DefaultPromise[_] => compressedRoot(linked) case _ => this } + + @tailrec + private[this] final def compressedRoot(linked: DefaultPromise[_]): DefaultPromise[T] = { + val target = linked.asInstanceOf[DefaultPromise[T]].root + if (linked eq target) target + else if (compareAndSet(linked, target)) target + else { + get() match { + case newLinked: DefaultPromise[_] => compressedRoot(newLinked) + case _ => this + } + } } /** Get the promise at the root of the chain of linked promises. Used by `compressedRoot()`. @@ -182,18 +218,16 @@ private[concurrent] object Promise { * to compress the link chain whenever possible. */ @tailrec - private def root: DefaultPromise[T] = { - getState match { + private def root: DefaultPromise[T] = + get() match { case linked: DefaultPromise[_] => linked.asInstanceOf[DefaultPromise[T]].root case _ => this } - } /** Try waiting for this promise to be completed. */ protected final def tryAwait(atMost: Duration): Boolean = if (!isCompleted) { import Duration.Undefined - import scala.concurrent.Future.InternalCallbackExecutor atMost match { case e if e eq Undefined => throw new IllegalArgumentException("cannot wait for Undefined period") case Duration.Inf => @@ -225,18 +259,18 @@ private[concurrent] object Promise { def value: Option[Try[T]] = value0 @tailrec - private def value0: Option[Try[T]] = getState match { + private def value0: Option[Try[T]] = get() match { case c: Try[_] => Some(c.asInstanceOf[Try[T]]) - case _: DefaultPromise[_] => compressedRoot().value0 + case dp: DefaultPromise[_] => compressedRoot(dp).value0 case _ => None } override def isCompleted: Boolean = isCompleted0 @tailrec - private def isCompleted0: Boolean = getState match { + private def isCompleted0: Boolean = get() match { case _: Try[_] => true - case _: DefaultPromise[_] => compressedRoot().isCompleted0 + case dp: DefaultPromise[_] => compressedRoot(dp).isCompleted0 case _ => false } @@ -254,21 +288,17 @@ private[concurrent] object Promise { */ @tailrec private def tryCompleteAndGetListeners(v: Try[T]): List[CallbackRunnable[T]] = { - getState match { + get() match { case raw: List[_] => val cur = raw.asInstanceOf[List[CallbackRunnable[T]]] - if (updateState(cur, v)) cur else tryCompleteAndGetListeners(v) - case _: DefaultPromise[_] => - compressedRoot().tryCompleteAndGetListeners(v) + if (compareAndSet(cur, v)) cur else tryCompleteAndGetListeners(v) + case dp: DefaultPromise[_] => compressedRoot(dp).tryCompleteAndGetListeners(v) case _ => null } } - def onComplete[U](func: Try[T] => U)(implicit executor: ExecutionContext): Unit = { - val preparedEC = executor.prepare() - val runnable = new CallbackRunnable[T](preparedEC, func) - dispatchOrAddCallback(runnable) - } + def onComplete[U](func: Try[T] => U)(implicit executor: ExecutionContext): Unit = + dispatchOrAddCallback(new CallbackRunnable[T](executor.prepare(), func)) /** Tries to add the callback, if already completed, it dispatches the callback to be executed. * Used by `onComplete()` to add callbacks to a promise and by `link()` to transfer callbacks @@ -276,15 +306,16 @@ private[concurrent] object Promise { */ @tailrec private def dispatchOrAddCallback(runnable: CallbackRunnable[T]): Unit = { - getState match { + get() match { case r: Try[_] => runnable.executeWithValue(r.asInstanceOf[Try[T]]) - case _: DefaultPromise[_] => compressedRoot().dispatchOrAddCallback(runnable) - case listeners: List[_] => if (updateState(listeners, runnable :: listeners)) () else dispatchOrAddCallback(runnable) + case dp: DefaultPromise[_] => compressedRoot(dp).dispatchOrAddCallback(runnable) + case listeners: List[_] => if (compareAndSet(listeners, runnable :: listeners)) () + else dispatchOrAddCallback(runnable) } } /** Link this promise to the root of another promise using `link()`. Should only be - * be called by Future.flatMap. + * be called by transformWith. */ protected[concurrent] final def linkRootOf(target: DefaultPromise[T]): Unit = link(target.compressedRoot()) @@ -299,18 +330,17 @@ private[concurrent] object Promise { */ @tailrec private def link(target: DefaultPromise[T]): Unit = if (this ne target) { - getState match { + get() match { case r: Try[_] => - if (!target.tryComplete(r.asInstanceOf[Try[T]])) { - // Currently linking is done from Future.flatMap, which should ensure only - // one promise can be completed. Therefore this situation is unexpected. + if (!target.tryComplete(r.asInstanceOf[Try[T]])) throw new IllegalStateException("Cannot link completed promises together") - } - case _: DefaultPromise[_] => - compressedRoot().link(target) - case listeners: List[_] => if (updateState(listeners, target)) { - if (!listeners.isEmpty) listeners.asInstanceOf[List[CallbackRunnable[T]]].foreach(target.dispatchOrAddCallback(_)) - } else link(target) + case dp: DefaultPromise[_] => + compressedRoot(dp).link(target) + case listeners: List[_] if compareAndSet(listeners, target) => + if (listeners.nonEmpty) + listeners.asInstanceOf[List[CallbackRunnable[T]]].foreach(target.dispatchOrAddCallback(_)) + case _ => + link(target) } } } @@ -319,23 +349,58 @@ private[concurrent] object Promise { * * Useful in Future-composition when a value to contribute is already available. */ - final class KeptPromise[T](suppliedValue: Try[T]) extends Promise[T] { + object KeptPromise { + import scala.concurrent.Future + import scala.reflect.ClassTag + + private[this] sealed trait Kept[T] extends Promise[T] { + def result: Try[T] + + override def value: Option[Try[T]] = Some(result) - val value = Some(resolveTry(suppliedValue)) + override def isCompleted: Boolean = true - override def isCompleted: Boolean = true + override def tryComplete(value: Try[T]): Boolean = false - def tryComplete(value: Try[T]): Boolean = false + override def onComplete[U](func: Try[T] => U)(implicit executor: ExecutionContext): Unit = + (new CallbackRunnable(executor.prepare(), func)).executeWithValue(result) - def onComplete[U](func: Try[T] => U)(implicit executor: ExecutionContext): Unit = { - val completedAs = value.get - val preparedEC = executor.prepare() - (new CallbackRunnable(preparedEC, func)).executeWithValue(completedAs) + override def ready(atMost: Duration)(implicit permit: CanAwait): this.type = this + + override def result(atMost: Duration)(implicit permit: CanAwait): T = result.get } - def ready(atMost: Duration)(implicit permit: CanAwait): this.type = this + private[this] final class Successful[T](val result: Success[T]) extends Kept[T] { + override def onFailure[U](pf: PartialFunction[Throwable, U])(implicit executor: ExecutionContext): Unit = () + override def failed: Future[Throwable] = KeptPromise(Failure(new NoSuchElementException("Future.failed not completed with a throwable."))).future + override def recover[U >: T](pf: PartialFunction[Throwable, U])(implicit executor: ExecutionContext): Future[U] = this + override def recoverWith[U >: T](pf: PartialFunction[Throwable, Future[U]])(implicit executor: ExecutionContext): Future[U] = this + override def fallbackTo[U >: T](that: Future[U]): Future[U] = this + } - def result(atMost: Duration)(implicit permit: CanAwait): T = value.get.get + private[this] final class Failed[T](val result: Failure[T]) extends Kept[T] { + private[this] final def thisAs[S]: Future[S] = future.asInstanceOf[Future[S]] + + override def onSuccess[U](pf: PartialFunction[T, U])(implicit executor: ExecutionContext): Unit = () + override def failed: Future[Throwable] = thisAs[Throwable] + override def foreach[U](f: T => U)(implicit executor: ExecutionContext): Unit = () + override def map[S](f: T => S)(implicit executor: ExecutionContext): Future[S] = thisAs[S] + override def flatMap[S](f: T => Future[S])(implicit executor: ExecutionContext): Future[S] = thisAs[S] + override def flatten[S](implicit ev: T <:< Future[S]): Future[S] = thisAs[S] + override def filter(p: T => Boolean)(implicit executor: ExecutionContext): Future[T] = this + override def collect[S](pf: PartialFunction[T, S])(implicit executor: ExecutionContext): Future[S] = thisAs[S] + override def zip[U](that: Future[U]): Future[(T, U)] = thisAs[(T,U)] + override def zipWith[U, R](that: Future[U])(f: (T, U) => R)(implicit executor: ExecutionContext): Future[R] = thisAs[R] + override def fallbackTo[U >: T](that: Future[U]): Future[U] = + if (this eq that) this else that.recoverWith({ case _ => this })(InternalCallbackExecutor) + override def mapTo[S](implicit tag: ClassTag[S]): Future[S] = thisAs[S] + } + + def apply[T](result: Try[T]): scala.concurrent.Promise[T] = + resolveTry(result) match { + case s @ Success(_) => new Successful(s) + case f @ Failure(_) => new Failed(f) + } } } diff --git a/src/library/scala/deprecatedName.scala b/src/library/scala/deprecatedName.scala index 07c5c8925c..a0d3aa829b 100644 --- a/src/library/scala/deprecatedName.scala +++ b/src/library/scala/deprecatedName.scala @@ -29,4 +29,6 @@ import scala.annotation.meta._ * @since 2.8.1 */ @param -class deprecatedName(name: Symbol) extends scala.annotation.StaticAnnotation +class deprecatedName(name: Symbol) extends scala.annotation.StaticAnnotation { + def this() = this(Symbol("<none>")) +} diff --git a/src/library/scala/io/Source.scala b/src/library/scala/io/Source.scala index 9f0b56b4fe..e38c197196 100644 --- a/src/library/scala/io/Source.scala +++ b/src/library/scala/io/Source.scala @@ -10,7 +10,7 @@ package scala package io import scala.collection.AbstractIterator -import java.io.{ FileInputStream, InputStream, PrintStream, File => JFile } +import java.io.{ FileInputStream, InputStream, PrintStream, File => JFile, Closeable } import java.net.{ URI, URL } /** This object provides convenience methods to create an iterable @@ -187,7 +187,7 @@ object Source { * @author Burak Emir * @version 1.0 */ -abstract class Source extends Iterator[Char] { +abstract class Source extends Iterator[Char] with Closeable { /** the actual iterator */ protected val iter: Iterator[Char] diff --git a/src/library/scala/math/package.scala b/src/library/scala/math/package.scala index 58ece8a05b..b6593d6661 100644 --- a/src/library/scala/math/package.scala +++ b/src/library/scala/math/package.scala @@ -26,7 +26,7 @@ package object math { /** Returns a `double` value with a positive sign, greater than or equal * to `0.0` and less than `1.0`. */ - def random: Double = java.lang.Math.random() + def random(): Double = java.lang.Math.random() def sin(x: Double): Double = java.lang.Math.sin(x) def cos(x: Double): Double = java.lang.Math.cos(x) diff --git a/src/library/scala/runtime/BoxesRunTime.java b/src/library/scala/runtime/BoxesRunTime.java index 9cb1dee41c..96e0f23f3d 100644 --- a/src/library/scala/runtime/BoxesRunTime.java +++ b/src/library/scala/runtime/BoxesRunTime.java @@ -179,7 +179,7 @@ public final class BoxesRunTime return xc.equals(y); } - private static boolean equalsNumChar(java.lang.Number xn, java.lang.Character yc) { + public static boolean equalsNumChar(java.lang.Number xn, java.lang.Character yc) { if (yc == null) return xn == null; diff --git a/src/library/scala/runtime/ScalaRunTime.scala b/src/library/scala/runtime/ScalaRunTime.scala index 18fcbf8276..a0d89fc0e1 100644 --- a/src/library/scala/runtime/ScalaRunTime.scala +++ b/src/library/scala/runtime/ScalaRunTime.scala @@ -13,6 +13,7 @@ import scala.collection.{ Seq, IndexedSeq, TraversableView, AbstractIterator } import scala.collection.mutable.WrappedArray import scala.collection.immutable.{ StringLike, NumericRange, List, Stream, Nil, :: } import scala.collection.generic.{ Sorted, IsTraversableLike } +import scala.collection.parallel.ParIterable import scala.reflect.{ ClassTag, classTag } import scala.util.control.ControlThrowable import java.lang.{ Class => jClass } @@ -326,6 +327,7 @@ object ScalaRunTime { case x: AnyRef if isArray(x) => arrayToString(x) case x: scala.collection.Map[_, _] => x.iterator take maxElements map mapInner mkString (x.stringPrefix + "(", ", ", ")") case x: Iterable[_] => x.iterator take maxElements map inner mkString (x.stringPrefix + "(", ", ", ")") + case x: ParIterable[_] => x.iterator take maxElements map inner mkString (x.stringPrefix + "(", ", ", ")") case x: Traversable[_] => x take maxElements map inner mkString (x.stringPrefix + "(", ", ", ")") case x: Product1[_] if isTuple(x) => "(" + inner(x._1) + ",)" // that special trailing comma case x: Product if isTuple(x) => x.productIterator map inner mkString ("(", ",", ")") diff --git a/src/library/scala/sys/SystemProperties.scala b/src/library/scala/sys/SystemProperties.scala index d2ebf8c044..6f8b13a89b 100644 --- a/src/library/scala/sys/SystemProperties.scala +++ b/src/library/scala/sys/SystemProperties.scala @@ -35,8 +35,15 @@ extends mutable.AbstractMap[String, String] override def empty = new SystemProperties override def default(key: String): String = null - def iterator: Iterator[(String, String)] = - wrapAccess(System.getProperties().asScala.iterator) getOrElse Iterator.empty + def iterator: Iterator[(String, String)] = wrapAccess { + val ps = System.getProperties() + names map (k => (k, ps getProperty k)) filter (_._2 ne null) + } getOrElse Iterator.empty + + def names: Iterator[String] = wrapAccess ( + System.getProperties().stringPropertyNames().asScala.iterator + ) getOrElse Iterator.empty + def get(key: String) = wrapAccess(Option(System.getProperty(key))) flatMap (x => x) override def contains(key: String) = diff --git a/src/library/scala/sys/process/BasicIO.scala b/src/library/scala/sys/process/BasicIO.scala index 066b2f5373..640f7e68c2 100644 --- a/src/library/scala/sys/process/BasicIO.scala +++ b/src/library/scala/sys/process/BasicIO.scala @@ -221,7 +221,7 @@ object BasicIO { */ def transferFully(in: InputStream, out: OutputStream): Unit = try transferFullyImpl(in, out) - catch onInterrupt(()) + catch onIOInterrupt(()) private[this] def appendLine(buffer: Appendable): String => Unit = line => { buffer append line diff --git a/src/library/scala/sys/process/ProcessImpl.scala b/src/library/scala/sys/process/ProcessImpl.scala index 2b7fcdeb73..d15f1a2b3d 100644 --- a/src/library/scala/sys/process/ProcessImpl.scala +++ b/src/library/scala/sys/process/ProcessImpl.scala @@ -109,45 +109,46 @@ private[process] trait ProcessImpl { } private[process] class PipedProcesses(a: ProcessBuilder, b: ProcessBuilder, defaultIO: ProcessIO, toError: Boolean) extends CompoundProcess { - protected[this] override def runAndExitValue() = { - val currentSource = new SyncVar[Option[InputStream]] - val pipeOut = new PipedOutputStream - val source = new PipeSource(currentSource, pipeOut, a.toString) + protected[this] override def runAndExitValue() = runAndExitValue(new PipeSource(a.toString), new PipeSink(b.toString)) + protected[this] def runAndExitValue(source: PipeSource, sink: PipeSink): Option[Int] = { + source connectOut sink source.start() - - val pipeIn = new PipedInputStream(pipeOut) - val currentSink = new SyncVar[Option[OutputStream]] - val sink = new PipeSink(pipeIn, currentSink, b.toString) sink.start() - def handleOutOrError(fromOutput: InputStream) = currentSource put Some(fromOutput) + /** Release PipeSource, PipeSink and Process in the correct order. + * If once connect Process with Source or Sink, then the order of releasing them + * must be Source -> Sink -> Process, otherwise IOException will be thrown. */ + def releaseResources(so: PipeSource, sk: PipeSink, p: Process *) = { + so.release() + sk.release() + p foreach( _.destroy() ) + } val firstIO = - if (toError) - defaultIO.withError(handleOutOrError) - else - defaultIO.withOutput(handleOutOrError) - val secondIO = defaultIO.withInput(toInput => currentSink put Some(toInput)) - - val second = b.run(secondIO) - val first = a.run(firstIO) - try { - runInterruptible { - val exit1 = first.exitValue() - currentSource put None - currentSink put None - val exit2 = second.exitValue() - // Since file redirection (e.g. #>) is implemented as a piped process, - // we ignore its exit value so cmd #> file doesn't always return 0. - if (b.hasExitValue) exit2 else exit1 - } { - first.destroy() - second.destroy() + if (toError) defaultIO.withError(source.connectIn) + else defaultIO.withOutput(source.connectIn) + val secondIO = defaultIO.withInput(sink.connectOut) + + val second = + try b.run(secondIO) + catch onError { err => + releaseResources(source, sink) + throw err } - } - finally { - BasicIO close pipeIn - BasicIO close pipeOut + val first = + try a.run(firstIO) + catch onError { err => + releaseResources(source, sink, second) + throw err + } + runInterruptible { + val exit1 = first.exitValue() + val exit2 = second.exitValue() + // Since file redirection (e.g. #>) is implemented as a piped process, + // we ignore its exit value so cmd #> file doesn't always return 0. + if (b.hasExitValue) exit2 else exit1 + } { + releaseResources(source, sink, first, second) } } } @@ -168,37 +169,46 @@ private[process] trait ProcessImpl { } } - private[process] class PipeSource( - currentSource: SyncVar[Option[InputStream]], - pipe: PipedOutputStream, - label: => String - ) extends PipeThread(false, () => label) { - - final override def run(): Unit = currentSource.get match { - case Some(source) => - try runloop(source, pipe) - finally currentSource.unset() - - run() - case None => - currentSource.unset() - BasicIO close pipe + private[process] class PipeSource(label: => String) extends PipeThread(false, () => label) { + protected[this] val pipe = new PipedOutputStream + protected[this] val source = new LinkedBlockingQueue[Option[InputStream]] + override def run(): Unit = { + try { + source.take match { + case Some(in) => runloop(in, pipe) + case None => + } + } + catch onInterrupt(()) + finally BasicIO close pipe + } + def connectIn(in: InputStream): Unit = source add Some(in) + def connectOut(sink: PipeSink): Unit = sink connectIn pipe + def release(): Unit = { + interrupt() + source add None + join() } } - private[process] class PipeSink( - pipe: PipedInputStream, - currentSink: SyncVar[Option[OutputStream]], - label: => String - ) extends PipeThread(true, () => label) { - - final override def run(): Unit = currentSink.get match { - case Some(sink) => - try runloop(pipe, sink) - finally currentSink.unset() - - run() - case None => - currentSink.unset() + private[process] class PipeSink(label: => String) extends PipeThread(true, () => label) { + protected[this] val pipe = new PipedInputStream + protected[this] val sink = new LinkedBlockingQueue[Option[OutputStream]] + override def run(): Unit = { + try { + sink.take match { + case Some(out) => runloop(pipe, out) + case None => + } + } + catch onInterrupt(()) + finally BasicIO close pipe + } + def connectOut(out: OutputStream): Unit = sink add Some(out) + def connectIn(pipeOut: PipedOutputStream): Unit = pipe connect pipeOut + def release(): Unit = { + interrupt() + sink add None + join() } } diff --git a/src/library/scala/sys/process/package.scala b/src/library/scala/sys/process/package.scala index b1976ad4b6..5ec2e73cb9 100644 --- a/src/library/scala/sys/process/package.scala +++ b/src/library/scala/sys/process/package.scala @@ -224,16 +224,26 @@ package scala.sys { final val processDebug = props contains "scala.process.debug" dbg("Initializing process package.") - type =?>[-A, +B] = PartialFunction[A, B] - type Closeable = java.io.Closeable - type File = java.io.File - type IOException = java.io.IOException - type InputStream = java.io.InputStream - type JProcess = java.lang.Process - type JProcessBuilder = java.lang.ProcessBuilder - type OutputStream = java.io.OutputStream - type SyncVar[T] = scala.concurrent.SyncVar[T] - type URL = java.net.URL + type =?>[-A, +B] = PartialFunction[A, B] + type Closeable = java.io.Closeable + type File = java.io.File + type IOException = java.io.IOException + type InterruptedIOException = java.io.InterruptedIOException + type InputStream = java.io.InputStream + type JProcess = java.lang.Process + type JProcessBuilder = java.lang.ProcessBuilder + type LinkedBlockingQueue[T] = java.util.concurrent.LinkedBlockingQueue[T] + type OutputStream = java.io.OutputStream + type SyncVar[T] = scala.concurrent.SyncVar[T] + type URL = java.net.URL + + def onError[T](handler: Throwable => T): Throwable =?> T = { + case e @ _ => handler(e) + } + + def onIOInterrupt[T](handler: => T): Throwable =?> T = { + case _: InterruptedIOException => handler + } def onInterrupt[T](handler: => T): Throwable =?> T = { case _: InterruptedException => handler diff --git a/src/library/scala/util/Either.scala b/src/library/scala/util/Either.scala index e196d403c2..6ea9da64f2 100644 --- a/src/library/scala/util/Either.scala +++ b/src/library/scala/util/Either.scala @@ -68,7 +68,7 @@ import scala.language.implicitConversions * @version 1.0, 11/10/2008 * @since 2.7 */ -sealed abstract class Either[+A, +B] { +sealed abstract class Either[+A, +B] extends Product with Serializable { /** * Projects this `Either` as a `Left`. */ diff --git a/src/library/scala/util/Try.scala b/src/library/scala/util/Try.scala index b0eae74043..b1b9965614 100644 --- a/src/library/scala/util/Try.scala +++ b/src/library/scala/util/Try.scala @@ -61,7 +61,7 @@ import scala.language.implicitConversions * @author based on Twitter's original implementation in com.twitter.util. * @since 2.10 */ -sealed abstract class Try[+T] { +sealed abstract class Try[+T] extends Product with Serializable { /** Returns `true` if the `Try` is a `Failure`, `false` otherwise. */ @@ -75,16 +75,11 @@ sealed abstract class Try[+T] { * * ''Note:'': This will throw an exception if it is not a success and default throws an exception. */ - def getOrElse[U >: T](default: => U): U = - if (isSuccess) get else default + def getOrElse[U >: T](default: => U): U /** Returns this `Try` if it's a `Success` or the given `default` argument if this is a `Failure`. */ - def orElse[U >: T](default: => Try[U]): Try[U] = - try if (isSuccess) this else default - catch { - case NonFatal(e) => Failure(e) - } + def orElse[U >: T](default: => Try[U]): Try[U] /** Returns the value from this `Success` or throws the exception if this is a `Failure`. */ @@ -108,6 +103,11 @@ sealed abstract class Try[+T] { def map[U](f: T => U): Try[U] /** + * Applies the given partial function to the value from this `Success` or returns this if this is a `Failure`. + */ + def collect[U](pf: PartialFunction[T, U]): Try[U] + + /** * Converts this to a `Failure` if the predicate is not satisfied. */ def filter(p: T => Boolean): Try[T] @@ -134,6 +134,7 @@ sealed abstract class Try[+T] { * collection" contract even though it seems unlikely to matter much in a * collection with max size 1. */ + @deprecatedInheritance("You were never supposed to be able to extend this class.", "2.12") class WithFilter(p: T => Boolean) { def map[U](f: T => U): Try[U] = Try.this filter p map f def flatMap[U](f: T => Try[U]): Try[U] = Try.this filter p flatMap f @@ -145,18 +146,18 @@ sealed abstract class Try[+T] { * Applies the given function `f` if this is a `Failure`, otherwise returns this if this is a `Success`. * This is like `flatMap` for the exception. */ - def recoverWith[U >: T](f: PartialFunction[Throwable, Try[U]]): Try[U] + def recoverWith[U >: T](@deprecatedName('f) pf: PartialFunction[Throwable, Try[U]]): Try[U] /** * Applies the given function `f` if this is a `Failure`, otherwise returns this if this is a `Success`. * This is like map for the exception. */ - def recover[U >: T](f: PartialFunction[Throwable, U]): Try[U] + def recover[U >: T](@deprecatedName('f) pf: PartialFunction[Throwable, U]): Try[U] /** * Returns `None` if this is a `Failure` or a `Some` containing the value if this is a `Success`. */ - def toOption: Option[T] = if (isSuccess) Some(get) else None + def toOption: Option[T] /** * Transforms a nested `Try`, ie, a `Try` of type `Try[Try[T]]`, @@ -173,13 +174,31 @@ sealed abstract class Try[+T] { /** Completes this `Try` by applying the function `f` to this if this is of type `Failure`, or conversely, by applying * `s` if this is a `Success`. */ - def transform[U](s: T => Try[U], f: Throwable => Try[U]): Try[U] = - try this match { - case Success(v) => s(v) - case Failure(e) => f(e) - } catch { - case NonFatal(e) => Failure(e) - } + def transform[U](s: T => Try[U], f: Throwable => Try[U]): Try[U] + + /** + * Returns `Left` with `Throwable` if this is a `Failure`, otherwise returns `Right` with `Success` value. + */ + def toEither: Either[Throwable, T] + + /** + * Applies `fa` if this is a `Failure` or `fb` if this is a `Success`. + * If `fb` is initially applied and throws an exception, + * then `fa` is applied with this exception. + * + * @example {{{ + * val result: Try[Throwable, Int] = Try { string.toInt } + * log(result.fold( + * ex => "Operation failed with " + ex, + * v => "Operation produced value: " + v + * )) + * }}} + * + * @param fa the function to apply if this is a `Failure` + * @param fb the function to apply if this is a `Success` + * @return the results of applying the function + */ + def fold[U](fa: Throwable => U, fb: T => U): U } @@ -192,57 +211,60 @@ object Try { try Success(r) catch { case NonFatal(e) => Failure(e) } - } final case class Failure[+T](exception: Throwable) extends Try[T] { - def isFailure: Boolean = true - def isSuccess: Boolean = false - def recoverWith[U >: T](f: PartialFunction[Throwable, Try[U]]): Try[U] = - try { - if (f isDefinedAt exception) f(exception) else this - } catch { - case NonFatal(e) => Failure(e) - } - def get: T = throw exception - def flatMap[U](f: T => Try[U]): Try[U] = this.asInstanceOf[Try[U]] - def flatten[U](implicit ev: T <:< Try[U]): Try[U] = this.asInstanceOf[Try[U]] - def foreach[U](f: T => U): Unit = () - def map[U](f: T => U): Try[U] = this.asInstanceOf[Try[U]] - def filter(p: T => Boolean): Try[T] = this - def recover[U >: T](rescueException: PartialFunction[Throwable, U]): Try[U] = - try { - if (rescueException isDefinedAt exception) { - Try(rescueException(exception)) - } else this - } catch { - case NonFatal(e) => Failure(e) - } - def failed: Try[Throwable] = Success(exception) + override def isFailure: Boolean = true + override def isSuccess: Boolean = false + override def get: T = throw exception + override def getOrElse[U >: T](default: => U): U = default + override def orElse[U >: T](default: => Try[U]): Try[U] = + try default catch { case NonFatal(e) => Failure(e) } + override def flatMap[U](f: T => Try[U]): Try[U] = this.asInstanceOf[Try[U]] + override def flatten[U](implicit ev: T <:< Try[U]): Try[U] = this.asInstanceOf[Try[U]] + override def foreach[U](f: T => U): Unit = () + override def transform[U](s: T => Try[U], f: Throwable => Try[U]): Try[U] = + try f(exception) catch { case NonFatal(e) => Failure(e) } + override def map[U](f: T => U): Try[U] = this.asInstanceOf[Try[U]] + override def collect[U](pf: PartialFunction[T, U]): Try[U] = this.asInstanceOf[Try[U]] + override def filter(p: T => Boolean): Try[T] = this + override def recover[U >: T](@deprecatedName('rescueException) pf: PartialFunction[Throwable, U]): Try[U] = + try { if (pf isDefinedAt exception) Success(pf(exception)) else this } catch { case NonFatal(e) => Failure(e) } + override def recoverWith[U >: T](@deprecatedName('f) pf: PartialFunction[Throwable, Try[U]]): Try[U] = + try { if (pf isDefinedAt exception) pf(exception) else this } catch { case NonFatal(e) => Failure(e) } + override def failed: Try[Throwable] = Success(exception) + override def toOption: Option[T] = None + override def toEither: Either[Throwable, T] = Left(exception) + override def fold[U](fa: Throwable => U, fb: T => U): U = fa(exception) } final case class Success[+T](value: T) extends Try[T] { - def isFailure: Boolean = false - def isSuccess: Boolean = true - def recoverWith[U >: T](f: PartialFunction[Throwable, Try[U]]): Try[U] = this - def get = value - def flatMap[U](f: T => Try[U]): Try[U] = - try f(value) - catch { - case NonFatal(e) => Failure(e) - } - def flatten[U](implicit ev: T <:< Try[U]): Try[U] = value - def foreach[U](f: T => U): Unit = f(value) - def map[U](f: T => U): Try[U] = Try[U](f(value)) - def filter(p: T => Boolean): Try[T] = { + override def isFailure: Boolean = false + override def isSuccess: Boolean = true + override def get = value + override def getOrElse[U >: T](default: => U): U = get + override def orElse[U >: T](default: => Try[U]): Try[U] = this + override def flatMap[U](f: T => Try[U]): Try[U] = + try f(value) catch { case NonFatal(e) => Failure(e) } + override def flatten[U](implicit ev: T <:< Try[U]): Try[U] = value + override def foreach[U](f: T => U): Unit = f(value) + override def transform[U](s: T => Try[U], f: Throwable => Try[U]): Try[U] = this flatMap s + override def map[U](f: T => U): Try[U] = Try[U](f(value)) + override def collect[U](pf: PartialFunction[T, U]): Try[U] = try { - if (p(value)) this + if (pf isDefinedAt value) Success(pf(value)) else Failure(new NoSuchElementException("Predicate does not hold for " + value)) - } catch { - case NonFatal(e) => Failure(e) - } - } - def recover[U >: T](rescueException: PartialFunction[Throwable, U]): Try[U] = this - def failed: Try[Throwable] = Failure(new UnsupportedOperationException("Success.failed")) + } catch { case NonFatal(e) => Failure(e) } + override def filter(p: T => Boolean): Try[T] = + try { + if (p(value)) this else Failure(new NoSuchElementException("Predicate does not hold for " + value)) + } catch { case NonFatal(e) => Failure(e) } + override def recover[U >: T](@deprecatedName('rescueException) pf: PartialFunction[Throwable, U]): Try[U] = this + override def recoverWith[U >: T](@deprecatedName('f) pf: PartialFunction[Throwable, Try[U]]): Try[U] = this + override def failed: Try[Throwable] = Failure(new UnsupportedOperationException("Success.failed")) + override def toOption: Option[T] = Some(value) + override def toEither: Either[Throwable, T] = Right(value) + override def fold[U](fa: Throwable => U, fb: T => U): U = + try { fb(value) } catch { case NonFatal(e) => fa(e) } } diff --git a/src/manual/scala/man1/scalac.scala b/src/manual/scala/man1/scalac.scala index c658fe89f8..3219b10293 100644 --- a/src/manual/scala/man1/scalac.scala +++ b/src/manual/scala/man1/scalac.scala @@ -152,12 +152,9 @@ object scalac extends Command { CmdOption("sourcepath", Argument("path")), "Specify location(s) of source files."), Definition( - CmdOptionBound("target:", "{jvm-1.5,jvm-1.6,jvm-1.7,jvm-1.8}"), + CmdOptionBound("target:", "{jvm-1.8}"), SeqPara( - Mono("\"jvm-1.5\"") & " target JVM 1.5 (deprecated),", - Mono("\"jvm-1.6\"") & " target JVM 1.6 (default),", - Mono("\"jvm-1.7\"") & " target JVM 1.7,", - Mono("\"jvm-1.8\"") & " target JVM 1.8,")), + Mono("\"jvm-1.8\"") & " target JVM 1.8 (default)")), Definition( CmdOption("toolcp", Argument("path")), "Add to the runner classpath."), diff --git a/src/reflect/scala/reflect/api/Symbols.scala b/src/reflect/scala/reflect/api/Symbols.scala index c01029d067..b7234ba47a 100644 --- a/src/reflect/scala/reflect/api/Symbols.scala +++ b/src/reflect/scala/reflect/api/Symbols.scala @@ -228,7 +228,7 @@ trait Symbols { self: Universe => throw new ScalaReflectionException(s"$this $msg") } - /** Used to provide a better error message for `asMethod` + /** Used to provide a better error message for `asMethod`. * * @group Tests */ @@ -257,7 +257,7 @@ trait Symbols { self: Universe => def isClass: Boolean = false /** Does this symbol represent the definition of a class implicitly associated - * with an object definition (module class in scala compiler parlance). + * with an object definition (module class in scala compiler parlance)? * If yes, `isType` is also guaranteed to be true. * * Note to compiler developers: During the "mixin" phase, trait implementation class symbols @@ -294,7 +294,7 @@ trait Symbols { self: Universe => /** For a class: the module or case class factory with the same name in the same package. * For a module: the class with the same name in the same package. - * For all others: NoSymbol + * For all others: NoSymbol. * * This API may return unexpected results for module classes, packages and package classes. * Use `companion` instead in order to get predictable results. @@ -345,7 +345,7 @@ trait Symbols { self: Universe => */ def overrides: List[Symbol] - /** The overloaded alternatives of this symbol + /** The overloaded alternatives of this symbol. * * @group Basics */ @@ -370,7 +370,7 @@ trait Symbols { self: Universe => /** Does this symbol represent a declaration or definition written in a source file as `private[this]` * or generated in tree/symbol form with the combination of flags LOCAL and PRIVATE? - * If yes, `isPrivate` is guaranteed to be true, + * If yes, `isPrivate` is guaranteed to be true. * * @group Tests */ @@ -678,7 +678,7 @@ trait Symbols { self: Universe => */ def toTypeIn(site: Type): Type - /** A type reference that refers to this type symbol + /** A type reference that refers to this type symbol. * Note if symbol is a member of a class, one almost always is interested * in `asTypeIn` with a site type instead. * @@ -727,7 +727,7 @@ trait Symbols { self: Universe => */ def isExistential : Boolean - /** For a polymorphic type, its type parameters, the empty list for all other types + /** For a polymorphic type, its type parameters, the empty list for all other types. * * @group Type */ @@ -756,12 +756,13 @@ trait Symbols { self: Universe => */ def typeParams: List[Symbol] - /** @see [[paramLists]] */ + /** @see [[paramLists]] + * + * The name ending with "ss" indicates that the result type is a list of lists. */ @deprecated("Use `paramLists` instead", "2.11.0") def paramss: List[List[Symbol]] /** All parameter lists of the method. - * The name ending with "ss" indicates that the result type is a list of lists. * * Can be used to distinguish nullary methods and methods with empty parameter lists. * For a nullary method, returns the empty list (i.e. `List()`). @@ -777,7 +778,7 @@ trait Symbols { self: Universe => */ def isVarargs: Boolean - /** The return type of the method + /** The return type of the method. * * @group Method */ @@ -911,7 +912,7 @@ trait Symbols { self: Universe => */ def superPrefix(supertpe: Type): Type - /** For a polymorphic class/trait, its type parameters, the empty list for all other classes/trait + /** For a polymorphic class/trait, its type parameters, the empty list for all other classes/trait. * * @group Class */ diff --git a/src/reflect/scala/reflect/internal/Mirrors.scala b/src/reflect/scala/reflect/internal/Mirrors.scala index 0cbb976a98..0f0f16574e 100644 --- a/src/reflect/scala/reflect/internal/Mirrors.scala +++ b/src/reflect/scala/reflect/internal/Mirrors.scala @@ -180,7 +180,7 @@ trait Mirrors extends api.Mirrors { def getPackageObject(fullname: String): ModuleSymbol = getPackageObject(newTermName(fullname)) def getPackageObject(fullname: TermName): ModuleSymbol = - (getPackage(fullname).info member nme.PACKAGE) match { + (getPackage(fullname).packageObject) match { case x: ModuleSymbol => x case _ => MissingRequirementError.notFound("package object " + fullname) } @@ -191,15 +191,6 @@ trait Mirrors extends api.Mirrors { def getPackageObjectIfDefined(fullname: TermName): Symbol = wrapMissing(getPackageObject(fullname)) - final def getPackageObjectWithMember(pre: Type, sym: Symbol): Symbol = { - // The owner of a symbol which requires package qualification may be the - // package object iself, but it also could be any superclass of the package - // object. In the latter case, we must go through the qualifier's info - // to obtain the right symbol. - if (sym.owner.isModuleClass) sym.owner.sourceModule // fast path, if the member is owned by a module class, that must be linked to the package object - else pre member nme.PACKAGE // otherwise we have to findMember - } - override def staticPackage(fullname: String): ModuleSymbol = try ensurePackageSymbol(fullname.toString, getModuleOrClass(newTermNameCached(fullname)), allowModules = false) catch { case mre: MissingRequirementError => throw new ScalaReflectionException(mre.msg) } diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala index 63e2ca0dbe..26e3cf6d0b 100644 --- a/src/reflect/scala/reflect/internal/StdNames.scala +++ b/src/reflect/scala/reflect/internal/StdNames.scala @@ -111,6 +111,7 @@ trait StdNames { val PACKAGE: NameType = "package" val ROOT: NameType = "<root>" val SPECIALIZED_SUFFIX: NameType = "$sp" + val CASE_ACCESSOR: NameType = "$access" val NESTED_IN: String = "$nestedIn" val NESTED_IN_ANON_CLASS: String = NESTED_IN + ANON_CLASS_NAME.toString.replace("$", "") diff --git a/src/reflect/scala/reflect/internal/SymbolTable.scala b/src/reflect/scala/reflect/internal/SymbolTable.scala index ef63078f90..b0145f8a89 100644 --- a/src/reflect/scala/reflect/internal/SymbolTable.scala +++ b/src/reflect/scala/reflect/internal/SymbolTable.scala @@ -332,7 +332,7 @@ abstract class SymbolTable extends macros.Universe /** if there's a `package` member object in `pkgClass`, enter its members into it. */ def openPackageModule(pkgClass: Symbol) { - val pkgModule = pkgClass.info.decl(nme.PACKAGEkw) + val pkgModule = pkgClass.packageObject def fromSource = pkgModule.rawInfo match { case ltp: SymLoader => ltp.fromSource case _ => false diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index 285d59c5e2..478b1b9732 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -819,6 +819,12 @@ trait Symbols extends api.Symbols { self: SymbolTable => */ def skipPackageObject: Symbol = this + /** The package object symbol corresponding to this package or package class symbol, or NoSymbol otherwise */ + def packageObject: Symbol = + if (isPackageClass) tpe.packageObject + else if (isPackage) moduleClass.packageObject + else NoSymbol + /** If this is a constructor, its owner: otherwise this. */ final def skipConstructor: Symbol = if (isConstructor) owner else this @@ -858,7 +864,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => def isDeprecated = hasAnnotation(DeprecatedAttr) def deprecationMessage = getAnnotation(DeprecatedAttr) flatMap (_ stringArg 0) def deprecationVersion = getAnnotation(DeprecatedAttr) flatMap (_ stringArg 1) - def deprecatedParamName = getAnnotation(DeprecatedNameAttr) flatMap (_ symbolArg 0) + def deprecatedParamName = getAnnotation(DeprecatedNameAttr) flatMap (_ symbolArg 0 orElse Some(nme.NO_NAME)) def hasDeprecatedInheritanceAnnotation = hasAnnotation(DeprecatedInheritanceAttr) def deprecatedInheritanceMessage @@ -3378,13 +3384,9 @@ trait Symbols extends api.Symbols { self: SymbolTable => def implicitMembers: Scope = { val tp = info if ((implicitMembersCacheKey1 ne tp) || (implicitMembersCacheKey2 ne tp.decls.elems)) { - // Skip a package object class, because the members are also in - // the package and we wish to avoid spurious ambiguities as in pos/t3999. - if (!isPackageObjectClass) { - implicitMembersCacheValue = tp.implicitMembers - implicitMembersCacheKey1 = tp - implicitMembersCacheKey2 = tp.decls.elems - } + implicitMembersCacheValue = tp.membersBasedOnFlags(BridgeFlags, IMPLICIT) + implicitMembersCacheKey1 = tp + implicitMembersCacheKey2 = tp.decls.elems } implicitMembersCacheValue } diff --git a/src/reflect/scala/reflect/internal/TreeGen.scala b/src/reflect/scala/reflect/internal/TreeGen.scala index b2248ad518..894038dd0a 100644 --- a/src/reflect/scala/reflect/internal/TreeGen.scala +++ b/src/reflect/scala/reflect/internal/TreeGen.scala @@ -191,8 +191,8 @@ abstract class TreeGen { ) val pkgQualifier = if (needsPackageQualifier) { - val packageObject = rootMirror.getPackageObjectWithMember(qual.tpe, sym) - Select(qual, nme.PACKAGE) setSymbol packageObject setType singleType(qual.tpe, packageObject) + val packageObject = qualsym.packageObject + Select(qual, nme.PACKAGE) setSymbol packageObject setType packageObject.typeOfThis } else qual diff --git a/src/reflect/scala/reflect/internal/TreeInfo.scala b/src/reflect/scala/reflect/internal/TreeInfo.scala index 4657fa0000..7ad5fdf096 100644 --- a/src/reflect/scala/reflect/internal/TreeInfo.scala +++ b/src/reflect/scala/reflect/internal/TreeInfo.scala @@ -128,6 +128,7 @@ abstract class TreeInfo { symOk(tree.symbol) && tree.symbol.isStable && !definitions.isByNameParamType(tree.tpe) + && !definitions.isByName(tree.symbol) && (allowVolatile || !tree.symbol.hasVolatileType) // TODO SPEC: not required by spec ) diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index f74d976b82..6ded3bcbe3 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -589,7 +589,12 @@ trait Types def nonPrivateMembersAdmitting(admit: Long): Scope = membersBasedOnFlags(BridgeAndPrivateFlags & ~admit, 0) /** A list of all implicit symbols of this type (defined or inherited) */ - def implicitMembers: Scope = membersBasedOnFlags(BridgeFlags, IMPLICIT) + def implicitMembers: Scope = { + typeSymbolDirect match { + case sym: ModuleClassSymbol => sym.implicitMembers + case _ => membersBasedOnFlags(BridgeFlags, IMPLICIT) + } + } /** A list of all deferred symbols of this type (defined or inherited) */ def deferredMembers: Scope = membersBasedOnFlags(BridgeFlags, DEFERRED) @@ -606,6 +611,8 @@ trait Types def nonPrivateMember(name: Name): Symbol = memberBasedOnName(name, BridgeAndPrivateFlags) + def packageObject: Symbol = member(nme.PACKAGE) + /** The non-private member with given name, admitting members with given flags `admit`. * "Admitting" refers to the fact that members with a PRIVATE, BRIDGE, or VBRIDGE * flag are usually excluded from findMember results, but supplying any of those flags @@ -659,7 +666,7 @@ trait Types ) if (trivial) this else { - val m = newAsSeenFromMap(pre.normalize, clazz) + val m = new AsSeenFromMap(pre.normalize, clazz) val tp = m(this) val tp1 = existentialAbstraction(m.capturedParams, tp) @@ -1600,7 +1607,14 @@ trait Types private var normalized: Type = _ private def normalizeImpl = { // TODO see comments around def intersectionType and def merge - def flatten(tps: List[Type]): List[Type] = tps flatMap { case RefinedType(parents, ds) if ds.isEmpty => flatten(parents) case tp => List(tp) } + // SI-8575 The dealias is needed here to keep subtyping transitive, example in run/t8575b.scala + def flatten(tps: List[Type]): List[Type] = { + def dealiasRefinement(tp: Type) = if (tp.dealias.isInstanceOf[RefinedType]) tp.dealias else tp + tps map dealiasRefinement flatMap { + case RefinedType(parents, ds) if ds.isEmpty => flatten(parents) + case tp => List(tp) + } + } val flattened = flatten(parents).distinct if (decls.isEmpty && hasLength(flattened, 1)) { flattened.head diff --git a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala index 1fc7aebab0..464bbad2cd 100644 --- a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala +++ b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala @@ -239,7 +239,6 @@ abstract class UnPickler { if (missing.startsWith("scala.xml")) Some(("org.scala-lang.modules", "scala-xml")) else if (missing.startsWith("scala.util.parsing")) Some(("org.scala-lang.modules", "scala-parser-combinators")) else if (missing.startsWith("scala.swing")) Some(("org.scala-lang.modules", "scala-swing")) - else if (missing.startsWith("scala.util.continuations")) Some(("org.scala-lang.plugins", "scala-continuations-library")) else None (module map { case (group, art) => diff --git a/src/reflect/scala/reflect/internal/tpe/TypeMaps.scala b/src/reflect/scala/reflect/internal/tpe/TypeMaps.scala index 15a87200f1..891fccb3e1 100644 --- a/src/reflect/scala/reflect/internal/tpe/TypeMaps.scala +++ b/src/reflect/scala/reflect/internal/tpe/TypeMaps.scala @@ -449,12 +449,15 @@ private[internal] trait TypeMaps { (pre eq NoType) || (pre eq NoPrefix) || !isPossiblePrefix(clazz) ) - def newAsSeenFromMap(pre: Type, clazz: Symbol): AsSeenFromMap = - new AsSeenFromMap(pre, clazz) + @deprecated("Use new AsSeenFromMap instead", "2.12.0") + final def newAsSeenFromMap(pre: Type, clazz: Symbol): AsSeenFromMap = new AsSeenFromMap(pre, clazz) /** A map to compute the asSeenFrom method. */ - class AsSeenFromMap(seenFromPrefix: Type, seenFromClass: Symbol) extends TypeMap with KeepOnlyTypeConstraints { + class AsSeenFromMap(seenFromPrefix0: Type, seenFromClass: Symbol) extends TypeMap with KeepOnlyTypeConstraints { + private val seenFromPrefix: Type = if (seenFromPrefix0.typeSymbolDirect.hasPackageFlag && !seenFromClass.hasPackageFlag) + seenFromPrefix0.packageObject.typeOfThis + else seenFromPrefix0 // Some example source constructs relevant in asSeenFrom: // // object CaptureThis { diff --git a/src/reflect/scala/reflect/internal/transform/Erasure.scala b/src/reflect/scala/reflect/internal/transform/Erasure.scala index 707972242a..5a03c1eeaa 100644 --- a/src/reflect/scala/reflect/internal/transform/Erasure.scala +++ b/src/reflect/scala/reflect/internal/transform/Erasure.scala @@ -282,8 +282,17 @@ trait Erasure { } object boxingErasure extends ScalaErasureMap { + private var boxPrimitives = true + + override def applyInArray(tp: Type): Type = { + val saved = boxPrimitives + boxPrimitives = false + try super.applyInArray(tp) + finally boxPrimitives = saved + } + override def eraseNormalClassRef(tref: TypeRef) = - if (isPrimitiveValueClass(tref.sym)) boxedClass(tref.sym).tpe + if (boxPrimitives && isPrimitiveValueClass(tref.sym)) boxedClass(tref.sym).tpe else super.eraseNormalClassRef(tref) override def eraseDerivedValueClassRef(tref: TypeRef) = super.eraseNormalClassRef(tref) diff --git a/src/repl/scala/tools/nsc/interpreter/ILoop.scala b/src/repl/scala/tools/nsc/interpreter/ILoop.scala index 525609171e..e8c6d02d1e 100644 --- a/src/repl/scala/tools/nsc/interpreter/ILoop.scala +++ b/src/repl/scala/tools/nsc/interpreter/ILoop.scala @@ -275,8 +275,7 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) } } - protected def newJavap() = - JavapClass(addToolsJarToLoader(), new IMain.ReplStrippingWriter(intp), Some(intp)) + protected def newJavap() = JavapClass(addToolsJarToLoader(), new IMain.ReplStrippingWriter(intp), intp) private lazy val javap = substituteAndLog[Javap]("javap", NoJavap)(newJavap()) @@ -315,7 +314,7 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) if (javap == null) s":javap unavailable, no tools.jar at $jdkHome. Set JDK_HOME." else if (line == "") - ":javap [-lcsvp] [path1 path2 ...]" + Javap.helpText else javap(words(line)) foreach { res => if (res.isError) return s"Failed: ${res.value}" diff --git a/src/repl/scala/tools/nsc/interpreter/JavapClass.scala b/src/repl/scala/tools/nsc/interpreter/JavapClass.scala index c240ab027a..04f4512717 100644 --- a/src/repl/scala/tools/nsc/interpreter/JavapClass.scala +++ b/src/repl/scala/tools/nsc/interpreter/JavapClass.scala @@ -2,13 +2,11 @@ * Copyright 2005-2013 LAMP/EPFL * @author Paul Phillips */ - package scala package tools.nsc package interpreter -import java.lang.{ ClassLoader => JavaClassLoader, Iterable => JIterable } -import scala.tools.asm.Opcodes +import java.lang.{ Iterable => JIterable } import scala.tools.nsc.util.ScalaClassLoader import java.io.{ ByteArrayInputStream, CharArrayWriter, FileNotFoundException, PrintWriter, StringWriter, Writer } import java.util.{ Locale } @@ -25,108 +23,55 @@ import scala.collection.JavaConverters._ import scala.collection.generic.Clearable import java.net.URL import scala.language.reflectiveCalls -import PartialFunction.{ cond => when } -import Javap._ +import Javap.{ JpResult, JpError, Showable, helper, toolArgs, DefaultOptions } -/** Javap command implementation. Supports platform tool for Java 6 or 7+. - * Adds a few options for REPL world, to show bodies of `App` classes and closures. +/** Javap command implementation. */ class JavapClass( val loader: ScalaClassLoader, val printWriter: PrintWriter, - intp: Option[IMain] = None + intp: IMain ) extends Javap { - import JavapTool.ToolArgs import JavapClass._ lazy val tool = JavapTool() - /** Run the tool. Option args start with "-", except that "-" itself - * denotes the last REPL result. - * The default options are "-protected -verbose". - * Byte data for filename args is retrieved with findBytes. - * @return results for invoking JpResult.show() - */ def apply(args: Seq[String]): List[JpResult] = { - val (options, classes) = args partition (s => (s startsWith "-") && s.length > 1) - val (flags, upgraded) = upgrade(options) - import flags.{ app, fun, help, raw } - - val targets = if (fun && !help) FunFinder(loader, intp).funs(classes) else classes + val (options0, targets) = args partition (s => (s startsWith "-") && s.length > 1) + val (options, filter) = { + val (opts, flag) = toolArgs(options0) + (if (opts.isEmpty) DefaultOptions else opts, flag) + } - if (help || classes.isEmpty) - List(JpResult(JavapTool.helper(printWriter))) - else if (targets.isEmpty) - List(JpResult("No closures found.")) + if ((options contains "-help") || targets.isEmpty) + List(JpResult(helper(printWriter))) else - tool(raw, upgraded)(targets map (targeted(_, app))) // JavapTool.apply + tool(options, filter)(targets map targeted) } - /** Cull our tool options. */ - private def upgrade(options: Seq[String]): (ToolArgs, Seq[String]) = - ToolArgs fromArgs options match { - case (t, s) if s.nonEmpty => (t, s) - case (t, s) => (t, JavapTool.DefaultOptions) - } - /** Associate the requested path with a possibly failed or empty array of bytes. */ - private def targeted(path: String, app: Boolean): (String, Try[Array[Byte]]) = - bytesFor(path, app) match { + private def targeted(path: String): (String, Try[Array[Byte]]) = + bytesFor(path) match { case Success((target, bytes)) => (target, Try(bytes)) case f: Failure[_] => (path, Failure(f.exception)) } - /** Find bytes. Handle "-", "-app", "Foo#bar" (by ignoring member), "#bar" (by taking "bar"). + /** Find bytes. Handle "-", "Foo#bar" (by ignoring member), "#bar" (by taking "bar"). * @return the path to use for filtering, and the byte array */ - private def bytesFor(path: String, app: Boolean) = Try { - def last = intp.get.mostRecentVar // fail if no intp + private def bytesFor(path: String) = Try { val req = path match { - case "-" => last + case "-" => intp.mostRecentVar case HashSplit(prefix, _) if prefix != null => prefix case HashSplit(_, member) if member != null => member case s => s } - val targetedBytes = if (app) findAppBody(req) else (path, findBytes(req)) - targetedBytes match { + (path, findBytes(req)) match { case (_, bytes) if bytes.isEmpty => throw new FileNotFoundException(s"Could not find class bytes for '$path'") case ok => ok } } - private def findAppBody(path: String): (String, Array[Byte]) = { - // is this new style delayedEndpoint? then find it. - // the name test is naive. could add $mangled path. - // assumes only the first match is of interest (because only one endpoint is generated). - def findNewStyle(bytes: Array[Byte]) = { - import scala.tools.asm.ClassReader - //foo/Bar.delayedEndpoint$foo$Bar$1 - val endpoint = "delayedEndpoint".r.unanchored - def isEndPoint(s: String) = (s contains '$') && when(s) { case endpoint() => true } - new ClassReader(bytes) withMethods { methods => - methods collectFirst { case m if isEndPoint(m.name) => m.name } - } - } - // try new style, and add foo#delayedEndpoint$bar$1 to filter on the endpoint - def asNewStyle(bytes: Array[Byte]) = Some(bytes) filter (_.nonEmpty) flatMap { bs => - findNewStyle(bs) map (n => (s"$path#$n", bs)) - } - // use old style, and add foo# to filter on apply method - def asOldStyle = { - def asAppBody(s: String) = { - val (cls, fix) = s.splitSuffix - s"${cls}$$delayedInit$$body${fix}" - } - val oldStyle = asAppBody(path) - val oldBytes = findBytes(oldStyle) - if (oldBytes.nonEmpty) (s"$oldStyle#", oldBytes) - else (path, oldBytes) - } - - val pathBytes = findBytes(path) - asNewStyle(pathBytes) getOrElse asOldStyle - } - def findBytes(path: String): Array[Byte] = tryFile(path) getOrElse tryClass(path) /** Assume the string is a path and try to find the classfile it represents. @@ -151,7 +96,7 @@ class JavapClass( if (0 until s.length - 1 contains i) { val name = s substring (0, i) val sufx = s substring i - val tran = intp flatMap (_ translatePath name) + val tran = intp translatePath name def loadableOrNone(strip: Boolean) = { def suffix(strip: Boolean)(x: String) = (if (strip && (x endsWith "$")) x.init else x) + sufx @@ -169,13 +114,13 @@ class JavapClass( // if repl, translate the name to something replish // (for translate, would be nicer to get the sym and ask .isClass, // instead of translatePath and then asking did I get a class back) - val q = if (intp.isEmpty) p else ( + val q = ( // only simple names get the scope treatment Some(p) filter (_ contains '.') // take path as a Name in scope - orElse (intp flatMap (_ translatePath p) filter loadable) + orElse (intp translatePath p filter loadable) // take path as a Name in scope and find its enclosing class - orElse (intp flatMap (_ translateEnclosingClass p) filter loadable) + orElse (intp translateEnclosingClass p filter loadable) // take path as a synthetic derived from some Name in scope orElse desynthesize(p) // just try it plain @@ -184,16 +129,10 @@ class JavapClass( load(q) } - /** Base class for javap tool adapters for java 6 and 7. */ - abstract class JavapTool { + class JavapTool { type ByteAry = Array[Byte] type Input = Tuple2[String, Try[ByteAry]] - /** Run the tool. */ - def apply(raw: Boolean, options: Seq[String])(inputs: Seq[Input]): List[JpResult] - - // Since the tool is loaded by reflection, check for catastrophic failure. - protected def failed: Boolean implicit protected class Failer[A](a: =>A) { def orFailed[B >: A](b: =>B) = if (failed) b else a } @@ -209,8 +148,7 @@ class JavapClass( } def filterLines(target: String, text: String): String = { - // take Foo# as Foo#apply for purposes of filtering. Useful for -fun Foo#; - // if apply is added here, it's for other than -fun: javap Foo#, perhaps m#? + // take Foo# as Foo#apply for purposes of filtering. val filterOn = target.splitHashMember._2 map { s => if (s.isEmpty) "apply" else s } var filtering = false // true if in region matching filter // turn filtering on/off given the pattern of interest @@ -253,62 +191,6 @@ class JavapClass( sw.toString } - /** Create a Showable with output massage. - * @param raw show ugly repl names - * @param target attempt to filter output to show region of interest - * @param preamble other messages to output - */ - def showWithPreamble(raw: Boolean, target: String, preamble: String = ""): Showable = - new Showable { - private def writeLines() = filterLines(target, preamble + written) - val output = writeLines() - - // ReplStrippingWriter clips and scrubs on write(String) - // circumvent it by write(mw, 0, mw.length) or wrap it in withoutUnwrapping - def show() = - if (raw && intp.isDefined) intp.get withoutUnwrapping { printWriter.write(output, 0, output.length) } - else intp.get withoutTruncating(printWriter write output) - } - } - - class JavapTool6 extends JavapTool { - import JavapTool._ - val EnvClass = loader.tryToInitializeClass[FakeEnvironment](Env).orNull - val PrinterClass = loader.tryToInitializeClass[FakePrinter](Printer).orNull - override protected def failed = (EnvClass eq null) || (PrinterClass eq null) - - val PrinterCtr = PrinterClass.getConstructor(classOf[InputStream], classOf[PrintWriter], EnvClass) orFailed null - val printWrapper = new PrintWriter(writer) - def newPrinter(in: InputStream, env: FakeEnvironment): FakePrinter = - PrinterCtr.newInstance(in, printWrapper, env) orFailed null - def showable(raw: Boolean, target: String, fp: FakePrinter): Showable = { - fp.asInstanceOf[{ def print(): Unit }].print() // run tool and flush to buffer - printWrapper.flush() // just in case - showWithPreamble(raw, target) - } - - lazy val parser = new JpOptions - def newEnv(opts: Seq[String]): FakeEnvironment = { - def result = { - val env: FakeEnvironment = EnvClass.newInstance() - parser(opts) foreach { case (name, value) => - val field = EnvClass getDeclaredField name - field setAccessible true - field.set(env, value.asInstanceOf[AnyRef]) - } - env - } - result orFailed null - } - - override def apply(raw: Boolean, options: Seq[String])(inputs: Seq[Input]): List[JpResult] = - (inputs map { - case (klass, Success(ba)) => JpResult(showable(raw, klass, newPrinter(new ByteArrayInputStream(ba), newEnv(options)))) - case (_, Failure(e)) => JpResult(e.toString) - }).toList orFailed List(noToolError) - } - - class JavapTool7 extends JavapTool { import JavapTool._ type Task = { def call(): Boolean // true = ok @@ -319,8 +201,9 @@ class JavapClass( //object TaskResult extends Enumeration { // val Ok, Error, CmdErr, SysErr, Abnormal = Value //} - val TaskClass = loader.tryToInitializeClass[Task](JavapTool.Tool).orNull - override protected def failed = TaskClass eq null + val TaskClass = loader.tryToInitializeClass[Task](JavapTask).orNull + // Since the tool is loaded by reflection, check for catastrophic failure. + protected def failed = TaskClass eq null val TaskCtor = TaskClass.getConstructor( classOf[Writer], @@ -343,12 +226,9 @@ class JavapClass( */ def messages(implicit locale: Locale = null) = diagnostics.asScala.map(_ getMessage locale).toList - // don't filter this message if raw, since the names are likely to differ - private val container = "Binary file .* contains .*".r - def reportable(raw: Boolean): String = { - val m = if (raw) messages else messages filterNot (when(_) { case container() => true }) + def reportable(): String = { clear() - if (m.nonEmpty) m mkString ("", EOL, EOL) else "" + if (messages.nonEmpty) messages mkString ("", EOL, EOL) else "" } } val reporter = new JavaReporter @@ -403,23 +283,33 @@ class JavapClass( } def fileManager(inputs: Seq[Input]) = new JavapFileManager(inputs)() - // show tool messages and tool output, with output massage - def showable(raw: Boolean, target: String): Showable = showWithPreamble(raw, target, reporter.reportable(raw)) + /** Create a Showable to show tool messages and tool output, with output massage. + * @param target attempt to filter output to show region of interest + * @param filter whether to strip REPL names + */ + def showable(target: String, filter: Boolean): Showable = + new Showable { + val output = filterLines(target, s"${reporter.reportable()}${written}") + def show() = + if (filter) intp.withoutTruncating(printWriter.write(output)) + else intp.withoutUnwrapping(printWriter.write(output, 0, output.length)) + } // eventually, use the tool interface def task(options: Seq[String], classes: Seq[String], inputs: Seq[Input]): Task = { //ServiceLoader.load(classOf[javax.tools.DisassemblerTool]). //getTask(writer, fileManager, reporter, options.asJava, classes.asJava) - TaskCtor.newInstance(writer, fileManager(inputs), reporter, options.asJava, classes.asJava) + val toolopts = options filter (_ != "-filter") + TaskCtor.newInstance(writer, fileManager(inputs), reporter, toolopts.asJava, classes.asJava) .orFailed (throw new IllegalStateException) } // a result per input - private def applyOne(raw: Boolean, options: Seq[String], klass: String, inputs: Seq[Input]): Try[JpResult] = + private def applyOne(options: Seq[String], filter: Boolean, klass: String, inputs: Seq[Input]): Try[JpResult] = Try { task(options, Seq(klass), inputs).call() } map { - case true => JpResult(showable(raw, klass)) - case _ => JpResult(reporter.reportable(raw)) + case true => JpResult(showable(klass, filter)) + case _ => JpResult(reporter.reportable()) } recoverWith { case e: java.lang.reflect.InvocationTargetException => e.getCause match { case t: IllegalArgumentException => Success(JpResult(t.getMessage)) // bad option @@ -428,139 +318,26 @@ class JavapClass( } lastly { reporter.clear() } - override def apply(raw: Boolean, options: Seq[String])(inputs: Seq[Input]): List[JpResult] = (inputs map { - case (klass, Success(_)) => applyOne(raw, options, klass, inputs).get + /** Run the tool. */ + def apply(options: Seq[String], filter: Boolean)(inputs: Seq[Input]): List[JpResult] = (inputs map { + case (klass, Success(_)) => applyOne(options, filter, klass, inputs).get case (_, Failure(e)) => JpResult(e.toString) }).toList orFailed List(noToolError) } object JavapTool { // >= 1.7 - val Tool = "com.sun.tools.javap.JavapTask" - - // < 1.7 - val Env = "sun.tools.javap.JavapEnvironment" - val Printer = "sun.tools.javap.JavapPrinter" - // "documentation" - type FakeEnvironment = AnyRef - type FakePrinter = AnyRef - - // support JavapEnvironment - class JpOptions { - private object Access { - final val PRIVATE = 0 - final val PROTECTED = 1 - final val PACKAGE = 2 - final val PUBLIC = 3 - } - private val envActionMap: Map[String, (String, Any)] = { - val map = Map( - "-l" -> (("showLineAndLocal", true)), - "-c" -> (("showDisassembled", true)), - "-s" -> (("showInternalSigs", true)), - "-verbose" -> (("showVerbose", true)), - "-private" -> (("showAccess", Access.PRIVATE)), - "-package" -> (("showAccess", Access.PACKAGE)), - "-protected" -> (("showAccess", Access.PROTECTED)), - "-public" -> (("showAccess", Access.PUBLIC)), - "-all" -> (("showallAttr", true)) - ) - map ++ List( - "-v" -> map("-verbose"), - "-p" -> map("-private") - ) - } - def apply(opts: Seq[String]): Seq[(String, Any)] = { - opts flatMap { opt => - envActionMap get opt match { - case Some(pair) => List(pair) - case _ => - val charOpts = opt.tail.toSeq map ("-" + _) - if (charOpts forall (envActionMap contains _)) - charOpts map envActionMap - else Nil - } - } - } - } - - case class ToolArgs(raw: Boolean = false, help: Boolean = false, app: Boolean = false, fun: Boolean = false) - - object ToolArgs { - def fromArgs(args: Seq[String]): (ToolArgs, Seq[String]) = ((ToolArgs(), Seq[String]()) /: (args flatMap massage)) { - case ((t,others), s) => s match { - case "-fun" => (t copy (fun=true), others :+ "-private") - case "-app" => (t copy (app=true), others) - case "-help" => (t copy (help=true), others) - case "-raw" => (t copy (raw=true), others) - case _ => (t, others :+ s) - } - } - } - - val helps = List( - "usage" -> ":javap [opts] [path or class or -]...", - "-help" -> "Prints this help message", - "-raw" -> "Don't unmangle REPL names", - "-app" -> "Show the DelayedInit body of Apps", - "-fun" -> "Show anonfuns for class or Class#method", - "-verbose/-v" -> "Stack size, number of locals, method args", - "-private/-p" -> "Private classes and members", - "-package" -> "Package-private classes and members", - "-protected" -> "Protected classes and members", - "-public" -> "Public classes and members", - "-l" -> "Line and local variable tables", - "-c" -> "Disassembled code", - "-s" -> "Internal type signatures", - "-sysinfo" -> "System info of class", - "-constants" -> "Static final constants" - ) - - // match prefixes and unpack opts, or -help on failure - def massage(arg: String): Seq[String] = { - require(arg startsWith "-") - // arg matches opt "-foo/-f" if prefix of -foo or exactly -f - val r = """(-[^/]*)(/(-.))?""".r - def maybe(opt: String, s: String): Option[String] = opt match { - // disambiguate by preferring short form - case r(lf,_,sf) if s == sf => Some(sf) - case r(lf,_,sf) if lf startsWith s => Some(lf) - case _ => None - } - def candidates(s: String) = (helps map (h => maybe(h._1, s))).flatten - // one candidate or one single-char candidate - def uniqueOf(maybes: Seq[String]) = { - def single(s: String) = s.length == 2 - if (maybes.length == 1) maybes - else if ((maybes count single) == 1) maybes filter single - else Nil - } - // each optchar must decode to exactly one option - def unpacked(s: String): Try[Seq[String]] = { - val ones = (s drop 1) map { c => - val maybes = uniqueOf(candidates(s"-$c")) - if (maybes.length == 1) Some(maybes.head) else None - } - Try(ones) filter (_ forall (_.isDefined)) map (_.flatten) - } - val res = uniqueOf(candidates(arg)) - if (res.nonEmpty) res - else (unpacked(arg) - getOrElse (Seq("-help"))) // or else someone needs help - } - - def helper(pw: PrintWriter) = new Showable { - def show() = helps foreach (p => pw write "%-12.12s%s%n".format(p._1,p._2)) - } - - val DefaultOptions = List("-protected", "-verbose") + val JavapTask = "com.sun.tools.javap.JavapTask" private def hasClass(cl: ScalaClassLoader, cn: String) = cl.tryToInitializeClass[AnyRef](cn).isDefined - def isAvailable = Seq(Env, Tool) exists (hasClass(loader, _)) + def isAvailable = hasClass(loader, JavapTask) /** Select the tool implementation for this platform. */ - def apply() = if (hasClass(loader, Tool)) new JavapTool7 else new JavapTool6 + def apply() = { + require(isAvailable) + new JavapTool + } } } @@ -571,7 +348,7 @@ object JavapClass { def apply( loader: ScalaClassLoader = ScalaClassLoader.appLoader, printWriter: PrintWriter = new PrintWriter(System.out, true), - intp: Option[IMain] = None + intp: IMain ) = new JavapClass(loader, printWriter, intp) /** Match foo#bar, both groups are optional (may be null). */ @@ -596,209 +373,29 @@ object JavapClass { } } implicit class ClassLoaderOps(val loader: ScalaClassLoader) extends AnyVal { - private def parentsOf(x: ClassLoader): List[ClassLoader] = if (x == null) Nil else x :: parentsOf(x.getParent) - def parents: List[ClassLoader] = parentsOf(loader) - /* all file locations */ - def locations = { - def alldirs = parents flatMap (_ match { - case ucl: ScalaClassLoader.URLClassLoader => ucl.classPathURLs - case jcl: java.net.URLClassLoader => jcl.getURLs - case _ => Nil - }) - val dirs = for (d <- alldirs; if d.getProtocol == "file") yield Path(new JFile(d.toURI)) - dirs - } - /* only the file location from which the given class is loaded */ - def locate(k: String): Option[Path] = { - Try { - val klass = try loader loadClass k catch { - case _: NoClassDefFoundError => null // let it snow - } - // cf ScalaClassLoader.originOfClass - klass.getProtectionDomain.getCodeSource.getLocation - } match { - case Success(null) => None - case Success(loc) if loc.isFile => Some(Path(new JFile(loc.toURI))) - case _ => None - } - } /* would classBytes succeed with a nonempty array */ def resourceable(className: String): Boolean = loader.getResource(className.asClassResource) != null - - /* class reader of class bytes */ - def classReader(resource: String): ClassReader = new ClassReader(loader classBytes resource) - } - implicit class `class reader convenience`(val reader: ClassReader) extends AnyVal { - def withMethods[A](f: Seq[MethodNode] => A): A = { - val cls = new ClassNode - reader.accept(cls, 0) - f(cls.methods.asScala) - } - } - implicit class PathOps(val p: Path) extends AnyVal { - import scala.tools.nsc.io.Jar - def isJar = Jar isJarOrZip p - } - implicit class `fun with files`(val f: AbstractFile) extends AnyVal { - def descend(path: Seq[String]): Option[AbstractFile] = { - def lookup(f: AbstractFile, path: Seq[String]): Option[AbstractFile] = path match { - case p if p.isEmpty => Option(f) - case p => Option(f.lookupName(p.head, directory = true)) flatMap (lookup(_, p.tail)) - } - lookup(f, path) - } } implicit class URLOps(val url: URL) extends AnyVal { def isFile: Boolean = url.getProtocol == "file" } - object FunFinder { - def apply(loader: ScalaClassLoader, intp: Option[IMain]) = new FunFinder(loader, intp) - } - // FunFinder.funs(ks) finds anonfuns - class FunFinder(loader: ScalaClassLoader, intp: Option[IMain]) { - - // manglese for closure: typename, $anonfun or lambda, opt method, digits - val closure = """(.*)\$(\$anonfun|lambda)(?:\$+([^$]+))?\$(\d+)""".r - - // manglese for closure - val cleese = "(?:anonfun|lambda)" - - // class k, candidate f without prefix - def isFunOfClass(k: String, f: String) = (s"${Regex quote k}\\$$+$cleese".r findPrefixOf f).nonEmpty - - // class k, candidate f without prefix, method m - def isFunOfMethod(k: String, m: String, f: String) = - (s"${Regex quote k}\\$$+$cleese\\$$+${Regex quote m}\\$$".r findPrefixOf f).nonEmpty - - def isFunOfTarget(target: Target, f: String) = - target.member map (isFunOfMethod(target.name, _, f)) getOrElse isFunOfClass(target.name, f) - - def listFunsInAbsFile(target: Target)(d: AbstractFile) = - for (f <- d; if !f.isDirectory && isFunOfTarget(target, f.name)) yield f.name - - def listFunsInDir(target: Target)(d: Directory) = { - val subdir = Path(target.prefix) - for (f <- (d / subdir).toDirectory.list; if f.isFile && isFunOfTarget(target, f.name)) - yield f.name - } - - def listFunsInJar(target: Target)(f: File) = { - import java.util.jar.JarEntry - import scala.tools.nsc.io.Jar - def maybe(e: JarEntry) = { - val (path, name) = { - val parts = e.getName split "/" - if (parts.length < 2) ("", e.getName) - else (parts.init mkString "/", parts.last) - } - if (path == target.prefix && isFunOfTarget(target, name)) Some(name) else None - } - (new Jar(f) map maybe).flatten - } - def loadable(name: String) = loader resourceable name - case class Target(path: String, member: Option[String], filter: Option[String], isRepl: Boolean, isModule: Boolean) { - val splat = path split "\\." - val name = splat.last - val prefix = if (splat.length > 1) splat.init mkString "/" else "" - val pkg = if (splat.length > 1) splat.init mkString "." else "" - val targetName = s"$name${ if (isModule) "$" else "" }" - } - // translated class, optional member, opt member to filter on, whether it is repl output and a module - def translate(s: String): Target = { - val (k0, m0) = s.splitHashMember - val isModule = k0 endsWith "$" - val k = (k0 stripSuffix "$").asClassName - val member = m0 filter (_.nonEmpty) // take Foo# as no member, not "" - val filter = m0 flatMap { case "" => Some("apply") case _ => None } // take Foo# as filter on apply - // class is either something replish or available to loader - // $line.$read$$etc$Foo#member - ((intp flatMap (_ translatePath k) filter (loadable) map (x => Target(x stripSuffix "$", member, filter, true, isModule))) - // s = "f" and $line.$read$$etc$#f is what we're after, - // ignoring any #member (except take # as filter on #apply) - orElse (intp flatMap (_ translateEnclosingClass k) map (x => Target(x stripSuffix "$", Some(k), filter, true, isModule))) - getOrElse (Target(k, member, filter, false, isModule))) - } - /** Find the classnames of anonfuns associated with k, - * where k may be an available class or a symbol in scope. - */ - def funsOf(selection: String): Seq[String] = { - // class is either something replish or available to loader - val target = translate(selection) - - // reconstitute an anonfun with a package - // if filtered, add the hash back, e.g. pkg.Foo#bar, pkg.Foo$anon$1#apply - def packaged(s: String) = { - val p = if (target.pkg.isEmpty) s else s"${target.pkg}.$s" - target.filter map (p + "#" + _) getOrElse p - } - // find closure classes in repl outdir or try asking the classloader where to look - val fs = - if (target.isRepl) - (intp.get.replOutput.dir descend target.splat.init) map { d => - listFunsInAbsFile(target)(d) map (_.asClassName) map packaged - } - else - loader locate target.path map { - case d if d.isDirectory => listFunsInDir(target)(d.toDirectory) map packaged - case j if j.isJar => listFunsInJar(target)(j.toFile) map packaged - case _ => Nil - } - val res = fs map (_.to[Seq]) getOrElse Seq() - // on second thought, we don't care about lambda method classes, just the impl methods - val rev = - res flatMap { - case x @ closure(_, "lambda", _, _) => lambdaMethod(x, target) - //target.member flatMap (_ => lambdaMethod(x, target)) getOrElse s"${target.name}#$$anonfun" - case x => Some(x) - } - rev - } - // given C$lambda$$g$n for member g and n in 1..N, find the C.accessor$x - // and the C.$anonfun$x it forwards to. - def lambdaMethod(lambda: String, target: Target): Option[String] = { - import scala.tools.asm.ClassReader - import scala.tools.asm.Opcodes.INVOKESTATIC - import scala.tools.asm.tree.{ ClassNode, MethodInsnNode } - def callees(s: String): List[(String, String)] = { - loader classReader s withMethods { ms => - val nonBridgeApplyMethods = ms filter (_.name == "apply") filter (n => (n.access & Opcodes.ACC_BRIDGE) == 0) - val instructions = nonBridgeApplyMethods flatMap (_.instructions.toArray) - instructions.collect { - case i: MethodInsnNode => (i.owner, i.name) - }.toList - } - } - callees(lambda) match { - case (k, _) :: Nil if target.isModule && !(k endsWith "$") => None - case (k, m) :: _ => Some(s"${k}#${m}") - case _ => None - } - } - /** Translate the supplied targets to patterns for anonfuns. - * Pattern is typename $ label [[$]$func] $n where label is $anonfun or lambda, - * and lambda includes the extra dollar, func is a method name, and n is an int. - * The typename for a nested class is dollar notation, Betty$Bippy. - * - * If C has anonfun closure classes, then use C$$anonfun$f$1 (various names, C# filters on apply). - * If C has lambda closure classes, then use C#$anonfun (special-cased by output filter). - */ - def funs(ks: Seq[String]): Seq[String] = ks flatMap funsOf - } } -trait Javap { - def loader: ScalaClassLoader - def printWriter: PrintWriter +abstract class Javap { + /** Run the tool. Option args start with "-", except that "-" itself + * denotes the last REPL result. + * The default options are "-protected -verbose". + * Byte data for filename args is retrieved with findBytes. + * @return results for invoking JpResult.show() + */ def apply(args: Seq[String]): List[Javap.JpResult] - def tryFile(path: String): Option[Array[Byte]] - def tryClass(path: String): Array[Byte] } object Javap { - def isAvailable(cl: ScalaClassLoader = ScalaClassLoader.appLoader) = JavapClass(cl).JavapTool.isAvailable + def isAvailable(cl: ScalaClassLoader = ScalaClassLoader.appLoader) = JavapClass(cl, intp = null).JavapTool.isAvailable def apply(path: String): Unit = apply(Seq(path)) - def apply(args: Seq[String]): Unit = JavapClass() apply args foreach (_.show()) + def apply(args: Seq[String]): Unit = JavapClass(intp=null) apply args foreach (_.show()) private[interpreter] trait Showable { def show(): Unit @@ -830,13 +427,70 @@ object Javap { def isError = false def show() = value.show() // output to tool's PrintWriter } + + def toolArgs(args: Seq[String]): (Seq[String], Boolean) = { + val (opts, rest) = args flatMap massage partition (_ != "-filter") + (opts, rest.nonEmpty) + } + + val helps = List( + "usage" -> ":javap [opts] [path or class or -]...", + "-help" -> "Prints this help message", + "-verbose/-v" -> "Stack size, number of locals, method args", + "-private/-p" -> "Private classes and members", + "-package" -> "Package-private classes and members", + "-protected" -> "Protected classes and members", + "-public" -> "Public classes and members", + "-l" -> "Line and local variable tables", + "-c" -> "Disassembled code", + "-s" -> "Internal type signatures", + "-sysinfo" -> "System info of class", + "-constants" -> "Static final constants", + "-filter" -> "Filter REPL machinery from output" + ) + + // match prefixes and unpack opts, or -help on failure + private def massage(arg: String): Seq[String] = { + require(arg startsWith "-") + // arg matches opt "-foo/-f" if prefix of -foo or exactly -f + val r = """(-[^/]*)(?:/(-.))?""".r + def maybe(opt: String, s: String): Option[String] = opt match { + // disambiguate by preferring short form + case r(lf, sf) if s == sf => Some(sf) + case r(lf, sf) if lf startsWith s => Some(lf) + case _ => None + } + def candidates(s: String) = (helps map (h => maybe(h._1, s))).flatten + // one candidate or one single-char candidate + def uniqueOf(maybes: Seq[String]) = { + def single(s: String) = s.length == 2 + if (maybes.length == 1) maybes + else if ((maybes count single) == 1) maybes filter single + else Nil + } + // each optchar must decode to exactly one option + def unpacked(s: String): Try[Seq[String]] = { + val ones = (s drop 1) map { c => + val maybes = uniqueOf(candidates(s"-$c")) + if (maybes.length == 1) Some(maybes.head) else None + } + Try(ones) filter (_ forall (_.isDefined)) map (_.flatten) + } + val res = uniqueOf(candidates(arg)) + if (res.nonEmpty) res + else (unpacked(arg) + getOrElse (Seq("-help"))) // or else someone needs help + } + + def helpText: String = (helps map { case (name, help) => f"$name%-12.12s$help%n" }).mkString + + def helper(pw: PrintWriter) = new Showable { + def show() = pw print helpText + } + + val DefaultOptions = List("-protected", "-verbose") } object NoJavap extends Javap { - import Javap._ - def loader: ScalaClassLoader = getClass.getClassLoader - def printWriter: PrintWriter = new PrintWriter(System.err, true) - def apply(args: Seq[String]): List[JpResult] = Nil - def tryFile(path: String): Option[Array[Byte]] = None - def tryClass(path: String): Array[Byte] = Array() + def apply(args: Seq[String]): List[Javap.JpResult] = Nil } diff --git a/src/scaladoc/scala/tools/nsc/doc/base/MemberLookupBase.scala b/src/scaladoc/scala/tools/nsc/doc/base/MemberLookupBase.scala index cc217d2f80..f853df0484 100755 --- a/src/scaladoc/scala/tools/nsc/doc/base/MemberLookupBase.scala +++ b/src/scaladoc/scala/tools/nsc/doc/base/MemberLookupBase.scala @@ -62,15 +62,15 @@ trait MemberLookupBase { syms.flatMap { case (sym, owner) => // reconstruct the original link def linkName(sym: Symbol) = { - def nameString(s: Symbol) = s.nameString + (if ((s.isModule || s.isModuleClass) && !s.isPackage) "$" else "") - val packageSuffix = if (sym.isPackage) ".package" else "" + def nameString(s: Symbol) = s.nameString + (if ((s.isModule || s.isModuleClass) && !s.hasPackageFlag) "$" else "") + val packageSuffix = if (sym.hasPackageFlag) ".package" else "" sym.ownerChain.reverse.filterNot(isRoot(_)).map(nameString(_)).mkString(".") + packageSuffix } - if (sym.isClass || sym.isModule || sym.isTrait || sym.isPackage) + if (sym.isClass || sym.isModule || sym.isTrait || sym.hasPackageFlag) findExternalLink(sym, linkName(sym)) - else if (owner.isClass || owner.isModule || owner.isTrait || owner.isPackage) + else if (owner.isClass || owner.isModule || owner.isTrait || owner.hasPackageFlag) findExternalLink(sym, linkName(owner) + "@" + externalSignature(sym)) else None diff --git a/src/scaladoc/scala/tools/nsc/doc/html/page/Template.scala b/src/scaladoc/scala/tools/nsc/doc/html/page/Template.scala index 81036b4908..99f989aadf 100644 --- a/src/scaladoc/scala/tools/nsc/doc/html/page/Template.scala +++ b/src/scaladoc/scala/tools/nsc/doc/html/page/Template.scala @@ -147,7 +147,7 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp { if (tpl.linearizationTemplates.isEmpty && tpl.conversions.isEmpty) NodeSeq.Empty else { if (!tpl.linearizationTemplates.isEmpty) - <div id="ancestors"> + <div class="ancestors"> <span class="filtertype">Inherited<br/> </span> <ol id="linearization"> @@ -157,7 +157,7 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp else NodeSeq.Empty } ++ { if (!tpl.conversions.isEmpty) - <div id="ancestors"> + <div class="ancestors"> <span class="filtertype">Implicitly<br/> </span> <ol id="implicits"> { @@ -171,7 +171,7 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp </div> else NodeSeq.Empty } ++ - <div id="ancestors"> + <div class="ancestors"> <span class="filtertype"></span> <ol> <li class="hideall out"><span>Hide All</span></li> @@ -204,28 +204,28 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp } { if (absValueMembers.isEmpty) NodeSeq.Empty else - <div id="values" class="values members"> + <div class="values members"> <h3>Abstract Value Members</h3> <ol>{ absValueMembers map (memberToHtml(_, tpl)) }</ol> </div> } { if (concValueMembers.isEmpty) NodeSeq.Empty else - <div id="values" class="values members"> + <div class="values members"> <h3>{ if (absValueMembers.isEmpty) "Value Members" else "Concrete Value Members" }</h3> <ol>{ concValueMembers map (memberToHtml(_, tpl)) }</ol> </div> } { if (shadowedImplicitMembers.isEmpty) NodeSeq.Empty else - <div id="values" class="values members"> + <div class="values members"> <h3>Shadowed Implicit Value Members</h3> <ol>{ shadowedImplicitMembers map (memberToHtml(_, tpl)) }</ol> </div> } { if (deprValueMembers.isEmpty) NodeSeq.Empty else - <div id="values" class="values members"> + <div class="values members"> <h3>Deprecated Value Members</h3> <ol>{ deprValueMembers map (memberToHtml(_, tpl)) }</ol> </div> @@ -290,13 +290,19 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp } def memberToHtml(mbr: MemberEntity, inTpl: DocTemplateEntity): NodeSeq = { + // Sometimes it's same, do we need signatureCompat still? + val sig = if (mbr.signature == mbr.signatureCompat) { + <a id={ mbr.signature }/> + } else { + <a id={ mbr.signature }/><a id={ mbr.signatureCompat }/> + } + val memberComment = memberToCommentHtml(mbr, inTpl, isSelf = false) <li name={ mbr.definitionName } visbl={ if (mbr.visibility.isProtected) "prt" else "pub" } data-isabs={ mbr.isAbstract.toString } fullComment={ if(memberComment.filter(_.label=="div").isEmpty) "no" else "yes" } group={ mbr.group }> - <a id={ mbr.signature }/> - <a id={ mbr.signatureCompat }/> + { sig } { signature(mbr, isSelf = false) } { memberComment } </li> diff --git a/src/scaladoc/scala/tools/nsc/doc/html/page/diagram/DotDiagramGenerator.scala b/src/scaladoc/scala/tools/nsc/doc/html/page/diagram/DotDiagramGenerator.scala index 320a8e23b2..4c0ba32856 100644 --- a/src/scaladoc/scala/tools/nsc/doc/html/page/diagram/DotDiagramGenerator.scala +++ b/src/scaladoc/scala/tools/nsc/doc/html/page/diagram/DotDiagramGenerator.scala @@ -364,7 +364,7 @@ class DotDiagramGenerator(settings: doc.Settings, dotRunner: DotRunner) extends // add an id and class attribute to the SVG element case Elem(prefix, "svg", attribs, scope, child @ _*) => { val klass = if (isInheritanceDiagram) "class-diagram" else "package-diagram" - Elem(prefix, "svg", attribs, scope, child map(x => transform(x)) : _*) % + Elem(prefix, "svg", attribs, scope, true, child map(x => transform(x)) : _*) % new UnprefixedAttribute("id", "graph" + counter, Null) % new UnprefixedAttribute("class", klass, Null) } @@ -378,7 +378,7 @@ class DotDiagramGenerator(settings: doc.Settings, dotRunner: DotRunner) extends // assign id and class attributes to edges and nodes: // the id attribute generated by dot has the format: "{class}|{id}" case g @ Elem(prefix, "g", attribs, scope, children @ _*) if (List("edge", "node").contains((g \ "@class").toString)) => { - var res = new Elem(prefix, "g", attribs, scope, (children map(x => transform(x))): _*) + var res = new Elem(prefix, "g", attribs, scope, true, (children map(x => transform(x))): _*) val dotId = (g \ "@id").toString if (dotId.count(_ == '|') == 1) { val Array(klass, id) = dotId.toString.split("\\|") @@ -395,11 +395,11 @@ class DotDiagramGenerator(settings: doc.Settings, dotRunner: DotRunner) extends val imageNode = <image xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href={ ("./lib/" + kind + "_diagram.png") } width="16px" height="16px" preserveAspectRatio="xMinYMin meet" x={ xposition.get.toString } y={ yposition.get.toString }/> val anchorNode = (g \ "a") match { case Seq(Elem(prefix, "a", attribs, scope, children @ _*)) => - transform(new Elem(prefix, "a", attribs, scope, (children ++ imageNode): _*)) + transform(new Elem(prefix, "a", attribs, scope, true, (children ++ imageNode): _*)) case _ => g \ "a" } - res = new Elem(prefix, "g", attribs, scope, anchorNode: _*) + res = new Elem(prefix, "g", attribs, scope, true, anchorNode: _*) DiagramStats.addFixedImage() } } @@ -413,7 +413,7 @@ class DotDiagramGenerator(settings: doc.Settings, dotRunner: DotRunner) extends scala.xml.Text("") // apply recursively case Elem(prefix, label, attribs, scope, child @ _*) => - Elem(prefix, label, attribs, scope, child map(x => transform(x)) : _*) + Elem(prefix, label, attribs, scope, true, child map(x => transform(x)) : _*) case x => x } diff --git a/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/template.css b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/template.css index e84d7c1ca6..f158aa7309 100644 --- a/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/template.css +++ b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/template.css @@ -218,7 +218,7 @@ dl.attributes > dd { height: 18px; } -#values ol li:last-child { +.values ol li:last-child { margin-bottom: 5px; } diff --git a/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/template.js b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/template.js index 798a2d430b..c1e3010834 100644 --- a/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/template.js +++ b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/template.js @@ -147,19 +147,19 @@ $(document).ready(function(){ filter(); }); - $("#mbrsel > div[id=ancestors] > ol > li.hideall").click(function() { + $("#mbrsel > div.ancestors > ol > li.hideall").click(function() { $("#linearization li.in").removeClass("in").addClass("out"); $("#linearization li:first").removeClass("out").addClass("in"); $("#implicits li.in").removeClass("in").addClass("out"); - if ($(this).hasClass("out") && $("#mbrsel > div[id=ancestors] > ol > li.showall").hasClass("in")) { + if ($(this).hasClass("out") && $("#mbrsel > div.ancestors > ol > li.showall").hasClass("in")) { $(this).removeClass("out").addClass("in"); - $("#mbrsel > div[id=ancestors] > ol > li.showall").removeClass("in").addClass("out"); + $("#mbrsel > div.ancestors > ol > li.showall").removeClass("in").addClass("out"); } filter(); }) - $("#mbrsel > div[id=ancestors] > ol > li.showall").click(function() { + $("#mbrsel > div.ancestors > ol > li.showall").click(function() { var filteredLinearization = $("#linearization li.out").filter(function() { return ! isHiddenClass($(this).attr("name")); @@ -172,9 +172,9 @@ $(document).ready(function(){ }); filteredImplicits.removeClass("out").addClass("in"); - if ($(this).hasClass("out") && $("#mbrsel > div[id=ancestors] > ol > li.hideall").hasClass("in")) { + if ($(this).hasClass("out") && $("#mbrsel > div.ancestors > ol > li.hideall").hasClass("in")) { $(this).removeClass("out").addClass("in"); - $("#mbrsel > div[id=ancestors] > ol > li.hideall").removeClass("in").addClass("out"); + $("#mbrsel > div.ancestors > ol > li.hideall").removeClass("in").addClass("out"); } filter(); @@ -275,7 +275,7 @@ function orderAlpha() { $("#order > ol > li.group").removeClass("in").addClass("out"); $("#template > div.parent").hide(); $("#template > div.conversion").hide(); - $("#mbrsel > div[id=ancestors]").show(); + $("#mbrsel > div.ancestors").show(); filter(); }; @@ -285,7 +285,7 @@ function orderInherit() { $("#order > ol > li.group").removeClass("in").addClass("out"); $("#template > div.parent").show(); $("#template > div.conversion").show(); - $("#mbrsel > div[id=ancestors]").hide(); + $("#mbrsel > div.ancestors").hide(); filter(); }; @@ -295,7 +295,7 @@ function orderGroup() { $("#order > ol > li.inherit").removeClass("in").addClass("out"); $("#template > div.parent").hide(); $("#template > div.conversion").hide(); - $("#mbrsel > div[id=ancestors]").show(); + $("#mbrsel > div.ancestors").show(); filter(); }; @@ -350,7 +350,7 @@ function initInherit() { } }); - $("#values > ol > li").each(function(){ + $(".values > ol > li").each(function(){ var mbr = $(this); this.mbrText = mbr.find("> .fullcomment .cmt").text(); var qualName = mbr.attr("name"); diff --git a/src/scaladoc/scala/tools/nsc/doc/model/MemberLookup.scala b/src/scaladoc/scala/tools/nsc/doc/model/MemberLookup.scala index 64eb1adbea..20aaab29fc 100644 --- a/src/scaladoc/scala/tools/nsc/doc/model/MemberLookup.scala +++ b/src/scaladoc/scala/tools/nsc/doc/model/MemberLookup.scala @@ -40,7 +40,7 @@ trait MemberLookup extends base.MemberLookupBase { override def findExternalLink(sym: Symbol, name: String): Option[LinkToExternal] = { val sym1 = if (sym == AnyClass || sym == AnyRefClass || sym == AnyValClass || sym == NothingClass) ListClass - else if (sym.isPackage) + else if (sym.hasPackageFlag) /* Get package object which has associatedFile ne null */ sym.info.member(newTermName("package")) else sym diff --git a/src/scaladoc/scala/tools/nsc/doc/model/ModelFactory.scala b/src/scaladoc/scala/tools/nsc/doc/model/ModelFactory.scala index 3cbcbc433e..178af3d4ba 100644 --- a/src/scaladoc/scala/tools/nsc/doc/model/ModelFactory.scala +++ b/src/scaladoc/scala/tools/nsc/doc/model/ModelFactory.scala @@ -93,10 +93,10 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { trait TemplateImpl extends EntityImpl with TemplateEntity { override def qualifiedName: String = if (inTemplate == null || inTemplate.isRootPackage) name else optimize(inTemplate.qualifiedName + "." + name) - def isPackage = sym.isPackage + def isPackage = sym.hasPackageFlag def isTrait = sym.isTrait def isClass = sym.isClass && !sym.isTrait - def isObject = sym.isModule && !sym.isPackage + def isObject = sym.isModule && !sym.hasPackageFlag def isCaseClass = sym.isCaseClass def isRootPackage = false def selfType = if (sym.thisSym eq sym) None else Some(makeType(sym.thisSym.typeOfThis, this)) @@ -254,7 +254,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { def valueParams: List[List[ValueParam]] = Nil /** TODO, these are now only computed for DocTemplates */ def parentTypes = - if (sym.isPackage || sym == AnyClass) List() else { + if (sym.hasPackageFlag || sym == AnyClass) List() else { val tps = (this match { case a: AliasType => sym.tpe.dealias.parents case a: AbstractType => sym.info.bounds match { @@ -665,7 +665,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { s != EmptyPackage && s != RootPackage } }) - else if (bSym.isPackage) // (2) + else if (bSym.hasPackageFlag) // (2) if (settings.skipPackage(makeQualifiedName(bSym))) None else @@ -778,7 +778,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { Some(new MemberTemplateImpl(bSym, inTpl) with AliasImpl with AliasType { override def isAliasType = true }) - else if (!modelFinished && (bSym.isPackage || templateShouldDocument(bSym, inTpl))) + else if (!modelFinished && (bSym.hasPackageFlag || templateShouldDocument(bSym, inTpl))) modelCreation.createTemplate(bSym, inTpl) else None diff --git a/src/scaladoc/scala/tools/nsc/doc/model/ModelFactoryTypeSupport.scala b/src/scaladoc/scala/tools/nsc/doc/model/ModelFactoryTypeSupport.scala index 2b7e2506d4..ea72fa6095 100644 --- a/src/scaladoc/scala/tools/nsc/doc/model/ModelFactoryTypeSupport.scala +++ b/src/scaladoc/scala/tools/nsc/doc/model/ModelFactoryTypeSupport.scala @@ -94,7 +94,7 @@ trait ModelFactoryTypeSupport { LinkToMember(bMbr, oTpl) case _ => val name = makeQualifiedName(bSym) - if (!bSym.owner.isPackage) + if (!bSym.owner.hasPackageFlag) Tooltip(name) else findExternalLink(bSym, name).getOrElse ( diff --git a/src/scaladoc/scala/tools/nsc/doc/model/TreeFactory.scala b/src/scaladoc/scala/tools/nsc/doc/model/TreeFactory.scala index 86a7a67160..c1228e8735 100755 --- a/src/scaladoc/scala/tools/nsc/doc/model/TreeFactory.scala +++ b/src/scaladoc/scala/tools/nsc/doc/model/TreeFactory.scala @@ -49,7 +49,7 @@ trait TreeFactory { thisTreeFactory: ModelFactory with TreeFactory => case _ => } else if (asym.isTerm && asym.owner.isClass){ - if (asym.isSetter) asym = asym.getter(asym.owner) + if (asym.isSetter) asym = asym.getterIn(asym.owner) makeTemplate(asym.owner) match { case docTmpl: DocTemplateImpl => val mbrs: Option[MemberImpl] = findMember(asym, docTmpl) diff --git a/src/scaladoc/scala/tools/nsc/doc/model/diagram/DiagramDirectiveParser.scala b/src/scaladoc/scala/tools/nsc/doc/model/diagram/DiagramDirectiveParser.scala index 44d8886e4e..b300752a34 100644 --- a/src/scaladoc/scala/tools/nsc/doc/model/diagram/DiagramDirectiveParser.scala +++ b/src/scaladoc/scala/tools/nsc/doc/model/diagram/DiagramDirectiveParser.scala @@ -177,7 +177,7 @@ trait DiagramDirectiveParser { def warning(message: String) = { // we need the position from the package object (well, ideally its comment, but yeah ...) - val sym = if (template.sym.isPackage) template.sym.info.member(global.nme.PACKAGE) else template.sym + val sym = if (template.sym.hasPackageFlag) template.sym.packageObject else template.sym assert((sym != global.NoSymbol) || (sym == global.rootMirror.RootPackage)) global.reporter.warning(sym.pos, message) } |