diff options
422 files changed, 3761 insertions, 22278 deletions
diff --git a/bincompat-backward.whitelist.conf b/bincompat-backward.whitelist.conf index a1706d103d..637bd586e0 100644 --- a/bincompat-backward.whitelist.conf +++ b/bincompat-backward.whitelist.conf @@ -186,6 +186,15 @@ filter { matchName="scala.reflect.runtime.SynchronizedOps.newNestedScope" problemName=MissingMethodProblem }, + // see github.com/scala/scala/pull/3925, SI-8627, SI-6440 + { + matchName="scala.collection.TraversableLike.filterImpl" + problemName=MissingMethodProblem + }, + { + matchName="scala.collection.immutable.Stream.filteredTail" + problemName=MissingMethodProblem + }, // https://github.com/scala/scala/pull/3848 -- SI-8680 { matchName="scala.collection.immutable.Stream.scala$collection$immutable$Stream$$loop$6" diff --git a/bincompat-forward.whitelist.conf b/bincompat-forward.whitelist.conf index 8fadb65f39..552c0d85f5 100644 --- a/bincompat-forward.whitelist.conf +++ b/bincompat-forward.whitelist.conf @@ -272,6 +272,103 @@ filter { matchName="scala.reflect.api.PredefTypeCreator" problemName=MissingClassProblem }, + // see github.com/scala/scala/pull/3925, SI-8627, SI-6440 + { + matchName="scala.collection.IterableViewLike#AbstractTransformed.filterImpl" + problemName=MissingMethodProblem + }, + { + matchName="scala.collection.AbstractTraversable.filterImpl" + problemName=MissingMethodProblem + }, + { + matchName="scala.collection.TraversableViewLike#AbstractTransformed.filterImpl" + problemName=MissingMethodProblem + }, + { + matchName="scala.collection.TraversableLike.filterImpl" + problemName=MissingMethodProblem + }, + { + matchName="scala.collection.SeqViewLike#AbstractTransformed.filterImpl" + problemName=MissingMethodProblem + }, + { + matchName="scala.collection.immutable.TreeSet.filterImpl" + problemName=MissingMethodProblem + }, + { + matchName="scala.collection.immutable.Stream.filteredTail" + problemName=MissingMethodProblem + }, + { + matchName="scala.collection.immutable.Stream.filterImpl" + problemName=MissingMethodProblem + }, + { + matchName="scala.collection.immutable.Stream.filterImpl" + problemName=MissingMethodProblem + }, + { + matchName="scala.collection.immutable.StringOps.filterImpl" + problemName=MissingMethodProblem + }, + { + matchName="scala.collection.immutable.TreeMap.filterImpl" + problemName=MissingMethodProblem + }, + { + matchName="scala.collection.concurrent.TrieMap.filterImpl" + problemName=MissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofByte.filterImpl" + problemName=MissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofLong.filterImpl" + problemName=MissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofUnit.filterImpl" + problemName=MissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofInt.filterImpl" + problemName=MissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofChar.filterImpl" + problemName=MissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofRef.filterImpl" + problemName=MissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofDouble.filterImpl" + problemName=MissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofFloat.filterImpl" + problemName=MissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofBoolean.filterImpl" + problemName=MissingMethodProblem + }, + { + matchName="scala.collection.mutable.ArrayOps#ofShort.filterImpl" + problemName=MissingMethodProblem + }, + { + matchName="scala.collection.mutable.TreeSet.filterImpl" + problemName=MissingMethodProblem + }, + { + matchName="scala.reflect.io.AbstractFile.filterImpl" + problemName=MissingMethodProblem + }, // https://github.com/scala/scala/pull/3848 -- SI-8680 { matchName="scala.collection.immutable.Stream.scala$collection$immutable$Stream$$loop$6" diff --git a/build-ant-macros.xml b/build-ant-macros.xml index ace86cac49..d0c9c4d310 100644 --- a/build-ant-macros.xml +++ b/build-ant-macros.xml @@ -105,7 +105,7 @@ <then> <stopwatch name="@{project}.timer"/> <mkdir dir="${@{project}-classes}"/> - <javac debug="true" srcdir="${src.dir}/@{project}" destdir="${@{project}-classes}" classpath="${@{project}-classes}" includes="**/*.java" target="1.6" source="1.5" compiler="javac1.6"> + <javac debug="true" srcdir="${src.dir}/@{project}" destdir="${@{project}-classes}" classpath="${@{project}-classes}" includes="**/*.java" target="1.8" source="1.8" compiler="javac1.8"> <compilerarg line="${javac.args} @{args}"/> </javac> <if> @@ -126,13 +126,13 @@ <attribute name="stage"/> <!-- current stage (locker, quick, strap) --> <attribute name="project"/> - <!-- project: library/reflect/compiler/actors --> + <!-- project: library/reflect/compiler --> <attribute name="destproject" default="@{project}"/> <!-- overrides the output directory; used when building multiple projects into the same directory--> <attribute name="args" default=""/> <attribute name="excludes" default=""/> <sequential> - <javac debug="true" srcdir="${src.dir}/@{project}" destdir="${build-@{stage}.dir}/classes/@{destproject}" includes="**/*.java" excludes="@{excludes}" target="1.6" source="1.5"> + <javac debug="true" srcdir="${src.dir}/@{project}" destdir="${build-@{stage}.dir}/classes/@{destproject}" includes="**/*.java" excludes="@{excludes}" target="1.8" source="1.8"> <compilerarg line="${javac.args} @{args}"/> <classpath refid="@{stage}.@{destproject}.build.path"/> </javac> @@ -193,7 +193,7 @@ <attribute name="stage"/> <!-- current stage (locker, quick, strap) --> <attribute name="project"/> - <!-- project: library/reflect/compiler/actors --> + <!-- project: library/reflect/compiler --> <attribute name="srcpath" default="NOT SET"/> <!-- needed to compile the library --> <attribute name="args" default=""/> @@ -262,7 +262,7 @@ <attribute name="stage"/> <!-- current stage (locker, quick, strap) --> <attribute name="project"/> - <!-- project: library/reflect/compiler/actors --> + <!-- project: library/reflect/compiler --> <attribute name="srcpath" default="NOT SET"/> <!-- needed to compile the library --> <attribute name="args" default=""/> @@ -474,9 +474,7 @@ <filter token="SCALA_COMPILER_INTERACTIVE_VERSION" value="${scala-compiler-interactive.version.number}"/> <filter token="XML_VERSION" value="${scala-xml.version.number}" /> <filter token="PARSER_COMBINATORS_VERSION" value="${scala-parser-combinators.version.number}" /> - <filter token="CONTINUATIONS_PLUGIN_VERSION" value="${scala-continuations-plugin.version.number}" /> - <filter token="CONTINUATIONS_LIBRARY_VERSION" value="${scala-continuations-library.version.number}" /> - <filter token="SCALA_SWING_VERSION" value="${scala-swing.version.number}" /> + <filter token="SCALA_SWING_VERSION" value="${scala-swing.version.number}" /> </filterset> </copy> <bnd classpath="${@{project}.jar}" eclipse="false" failok="false" exceptions="true" files="${build-osgi.dir}/${@{project}.name}.bnd" output="${build-osgi.dir}"/> @@ -600,14 +598,10 @@ <filter token="SCALA_FULL_VERSION" value="${scala.full.version}" /> <filter token="XML_VERSION" value="${scala-xml.version.number}" /> <filter token="PARSER_COMBINATORS_VERSION" value="${scala-parser-combinators.version.number}" /> - <filter token="CONTINUATIONS_PLUGIN_VERSION" value="${scala-continuations-plugin.version.number}" /> - <filter token="CONTINUATIONS_LIBRARY_VERSION" value="${scala-continuations-library.version.number}" /> - <filter token="SCALA_SWING_VERSION" value="${scala-swing.version.number}" /> + <filter token="SCALA_SWING_VERSION" value="${scala-swing.version.number}" /> <filter token="RELEASE_REPOSITORY" value="${remote.release.repository}" /> <filter token="SNAPSHOT_REPOSITORY" value="${remote.snapshot.repository}" /> <filter token="JLINE_VERSION" value="${jline.version}" /> - <filter token="AKKA_ACTOR_VERSION" value="${akka-actor.version.number}" /> - <filter token="ACTORS_MIGRATION_VERSION" value="${actors-migration.version.number}" /> <!-- TODO modularize compiler. <filter token="SCALA_COMPILER_DOC_VERSION" value="${scala-compiler-doc.version.number}" /> @@ -746,7 +740,6 @@ <deploy-one name="scala-compiler-interactive" local="@{local}" signed="@{signed}"/> --> - <deploy-one name="scala-actors" local="@{local}" signed="@{signed}"/> <deploy-one name="scalap" local="@{local}" signed="@{signed}"/> </sequential> </macrodef> diff --git a/build.number b/build.number index f5c5adfc0f..7c7e26fd09 100644 --- a/build.number +++ b/build.number @@ -3,8 +3,8 @@ # SNAPSHOT / nightly builds and local builds of source checkouts. version.major=2 -version.minor=11 -version.patch=7 +version.minor=12 +version.patch=0 # This is the -N part of a version (2.9.1-1). If it's 0, it's dropped from maven versions. It should not be used again. version.bnum=0 @@ -83,7 +83,7 @@ lazy val commonSettings = clearSourceAndResourceDirectories ++ Seq[Setting[_]]( // we always assume that Java classes are standalone and do not have any dependency // on Scala classes compileOrder := CompileOrder.JavaThenScala, - javacOptions in Compile ++= Seq("-g", "-source", "1.5", "-target", "1.6"), + javacOptions in Compile ++= Seq("-g", "-source", "1.8", "-target", "1.8"), // we don't want any unmanaged jars; as a reminder: unmanaged jar is a jar stored // directly on the file system and it's not resolved through Ivy // Ant's build stored unmanaged jars in `lib/` directory @@ -212,13 +212,6 @@ lazy val scaladoc = configureAsSubproject(project) lazy val scalap = configureAsSubproject(project). dependsOn(compiler) -// deprecated Scala Actors project -// TODO: it packages into actors.jar but it should be scala-actors.jar -lazy val actors = configureAsSubproject(project) - .settings(generatePropertiesFileSettings: _*) - .settings(name := "scala-actors") - .dependsOn(library) - lazy val forkjoin = configureAsForkOfJavaProject(project) lazy val partestExtras = configureAsSubproject(Project("partest-extras", file(".") / "src" / "partest-extras")) @@ -259,7 +252,7 @@ lazy val partestJavaAgent = (project in file(".") / "src" / "partest-javaagent") ) lazy val test = project. - dependsOn(compiler, interactive, actors, repl, scalap, partestExtras, partestJavaAgent, scaladoc). + dependsOn(compiler, interactive, repl, scalap, partestExtras, partestJavaAgent, scaladoc). configs(IntegrationTest). settings(disableDocsAndPublishingTasks: _*). settings(commonSettings: _*). @@ -290,7 +283,7 @@ lazy val test = project. lazy val root = (project in file(".")). aggregate(library, forkjoin, reflect, compiler, interactive, repl, - scaladoc, scalap, actors, partestExtras, junit).settings( + scaladoc, scalap, partestExtras, junit).settings( sources in Compile := Seq.empty, onLoadMessage := """|*** Welcome to the sbt build definition for Scala! *** |This build definition has an EXPERIMENTAL status. If you are not @@ -75,8 +75,8 @@ TODO: <target name="nightly"><optimized name="all.done"/></target> <target name="nightly.checkall"> <antcall target="all.done"> <param name="partest.scalac_opts" value="-Ycheck:all"/></antcall></target> - <!-- The IDE build requires actors/swing/continuations, so need to publish them during PR validation until they are modules --> - <target name="publish-opt-nodocs" description="Publishes Scala (optimized) without generating docs/testing (library/reflect/compiler/actors/swing/continuations)."> + <!-- The IDE build requires swing, so need to publish them during PR validation until they are modules --> + <target name="publish-opt-nodocs" description="Publishes Scala (optimized) without generating docs/testing (library/reflect/compiler/swing)."> <antcall target="publish"> <param name="docs.skip" value="1"/> <param name="scalac.args.optimise" value="-optimise"/> @@ -193,7 +193,7 @@ TODO: <!-- if ANT_OPTS is already set by the environment, it will be unaltered, but if it is unset it will take this default value. --> - <property name="env.ANT_OPTS" value="-Xms1536M -Xmx1536M -Xss1M -XX:MaxPermSize=192M -XX:+UseParallelGC" /> + <property name="env.ANT_OPTS" value="-Xms1536M -Xmx1536M -Xss1M -XX:+UseParallelGC" /> <property name="scalacfork.jvmargs" value="${env.ANT_OPTS} ${jvm.opts}"/> @@ -349,9 +349,6 @@ TODO: necessary cross suffix (usually something like "_2.11.0-M6". --> <prepareCross name="scala-xml" /> <prepareCross name="scala-parser-combinators" /> - <property name="scala-continuations-plugin.cross.suffix" value="_${scala.full.version}"/> - <prepareCross name="scala-continuations-plugin" /> - <prepareCross name="scala-continuations-library"/> <prepareCross name="scala-swing"/> <prepareCross name="partest"/> <prepareCross name="scalacheck"/> @@ -390,8 +387,6 @@ TODO: <artifact:remoteRepository refid="extra-repo"/> <dependency groupId="org.scala-lang.modules" artifactId="scala-xml${scala-xml.cross}" version="${scala-xml.version.number}"/> <dependency groupId="org.scala-lang.modules" artifactId="scala-parser-combinators${scala-parser-combinators.cross}" version="${scala-parser-combinators.version.number}"/> - <dependency groupId="org.scala-lang.plugins" artifactId="scala-continuations-plugin${scala-continuations-plugin.cross}" version="${scala-continuations-plugin.version.number}"/> - <dependency groupId="org.scala-lang.plugins" artifactId="scala-continuations-library${scala-continuations-library.cross}" version="${scala-continuations-library.version.number}"/> <dependency groupId="org.scala-lang.modules" artifactId="scala-swing${scala-swing.cross}" version="${scala-swing.version.number}"/> </artifact:dependencies> @@ -410,8 +405,6 @@ TODO: <propertyForCrossedArtifact name="scala-parser-combinators" jar="org.scala-lang.modules:scala-parser-combinators"/> <propertyForCrossedArtifact name="scala-xml" jar="org.scala-lang.modules:scala-xml"/> - <propertyForCrossedArtifact name="scala-continuations-plugin" jar="org.scala-lang.plugins:scala-continuations-plugin"/> - <propertyForCrossedArtifact name="scala-continuations-library" jar="org.scala-lang.plugins:scala-continuations-library"/> <propertyForCrossedArtifact name="scala-swing" jar="org.scala-lang.modules:scala-swing"/> <!-- BND support --> @@ -488,20 +481,12 @@ TODO: <!-- some default in case something went wrong getting the revision --> <property name="version.number" value="-unknown-"/> - <condition property="has.java6"> - <equals arg1="${ant.java.version}" arg2="1.6"/> - </condition> - <condition property="has.java7"> - <equals arg1="${ant.java.version}" arg2="1.7"/> - </condition> <condition property="has.java8"> <equals arg1="${ant.java.version}" arg2="1.8"/> </condition> <condition property="has.unsupported.jdk"> <not><or> <isset property="has.java8" /> - <isset property="has.java7" /> - <isset property="has.java6" /> </or></not> </condition> @@ -602,14 +587,9 @@ TODO: <echo message="Updating `versions.properties`:"/> <echo message="starr.version = ${starr.version}"/> <echo message="scala.binary.version = ${scala.binary.version}"/> - <echo message="scala.full.version = ${scala.full.version}"/> <echo message="scala-xml.version.number = ${scala-xml.version.number}"/> <echo message="scala-parser-combinators.version.number = ${scala-parser-combinators.version.number}"/> - <echo message="scala-continuations-plugin.version.number = ${scala-continuations-plugin.version.number}"/> - <echo message="scala-continuations-library.version.number = ${scala-continuations-library.version.number}"/> <echo message="scala-swing.version.number = ${scala-swing.version.number}"/> - <echo message="akka-actor.version.number = ${akka-actor.version.number}"/> - <echo message="actors-migration.version.number = ${actors-migration.version.number}"/> <echo message="jline.version = ${jline.version}"/> <echo message="partest.version.number = ${partest.version.number}"/> <echo message="scalacheck.version.number = ${scalacheck.version.number}"/> @@ -617,14 +597,9 @@ TODO: <propertyfile file="versions.properties"> <entry key="starr.version" value="${starr.version}"/> <entry key="scala.binary.version" value="${scala.binary.version}"/> - <entry key="scala.full.version" value="${scala.full.version}"/> <entry key="scala-xml.version.number" value="${scala-xml.version.number}"/> <entry key="scala-parser-combinators.version.number" value="${scala-parser-combinators.version.number}"/> - <entry key="scala-continuations-plugin.version.number" value="${scala-continuations-plugin.version.number}"/> - <entry key="scala-continuations-library.version.number" value="${scala-continuations-library.version.number}"/> <entry key="scala-swing.version.number" value="${scala-swing.version.number}"/> - <entry key="akka-actor.version.number" value="${akka-actor.version.number}"/> - <entry key="actors-migration.version.number" value="${actors-migration.version.number}"/> <entry key="jline.version" value="${jline.version}"/> <entry key="partest.version.number" value="${partest.version.number}"/> <entry key="scalacheck.version.number" value="${scalacheck.version.number}"/> @@ -660,26 +635,12 @@ TODO: <property name="scaladoc.version" value="${scala-compiler-doc.version.number}"/> <property name="scaladoc.targetjar" value="scala-compiler-doc_${scala.binary.version}-${scala-compiler-doc.version.number}.jar"/> - <property name="actors.description" value="Scala Actors Library"/> - <property name="swing.description" value="Scala Swing Library"/> <property name="swing.package" value="modules."/> <property name="swing.jar" value="${scala-swing}"/> <property name="swing.src" value="false"/> <property name="swing.srcjar" value="${scala-swing-sources}"/> - <property name="continuations-plugin.description" value="Scala Delimited Continuations Compiler Plugin"/> - <property name="continuations-plugin.package" value="plugins." /> - <property name="continuations-plugin.jar" value="${scala-continuations-plugin}"/> - <property name="continuations-plugin.src" value="false"/> - <property name="continuations-plugin.srcjar" value="${scala-continuations-plugin-sources}"/> - - <property name="continuations-library.description" value="Scala Delimited Continuations Library"/> - <property name="continuations-library.package" value="plugins." /> - <property name="continuations-library.jar" value="${scala-continuations-library}"/> - <property name="continuations-library.src" value="false"/> - <property name="continuations-library.srcjar" value="${scala-continuations-library-sources}"/> - <property name="parser-combinators.description" value="Scala Parser Combinators Library"/> <property name="parser-combinators.package" value="modules."/> <property name="parser-combinators.jar" value="${scala-parser-combinators}"/> @@ -700,7 +661,7 @@ TODO: <property name="partest-javaagent.description" value="Scala Compiler Testing Tool (compiler-specific java agent)"/> <!-- projects without project-specific options: forkjoin, manual, bin, repl --> - <for list="actors,compiler,interactive,scaladoc,library,parser-combinators,partest,partest-extras,partest-javaagent,reflect,scalap,swing,xml,continuations-plugin,continuations-library,repl-jline" param="project"> + <for list="compiler,interactive,scaladoc,library,parser-combinators,partest,partest-extras,partest-javaagent,reflect,scalap,swing,xml,repl-jline" param="project"> <sequential> <!-- description is mandatory --> <init-project-prop project="@{project}" name="package" default=""/> <!-- used by mvn-package, copy-bundle, make-bundle --> @@ -749,7 +710,7 @@ TODO: There must be a variable of the shape @{stage}.@{project}.build.path for all @{stage} in locker, quick, strap and all @{project} in library, reflect, compiler - when stage is quick, @{project} also includes: actors, repl, scalap + when stage is quick, @{project} also includes: repl, scalap NOTE: interactive, scaladoc, are only used upto quick; they are still packed into the compiler jar --> @@ -784,11 +745,6 @@ TODO: <path refid="scala-java8-compat.libs"/> </path> - <path id="quick.actors.build.path"> - <path refid="quick.library.build.path"/> - <pathelement location="${build-quick.dir}/classes/actors"/> - </path> - <path id="quick.reflect.build.path"> <path refid="quick.library.build.path"/> <pathelement location="${build-quick.dir}/classes/reflect"/> @@ -818,7 +774,13 @@ TODO: <path id="quick.partest-extras.build.path"> <path refid="asm.classpath"/> - <path refid="partest.classpath"/> + <restrict> + <path refid="partest.classpath"/> + <rsel:not><rsel:or> + <rsel:name name="scala-library*.jar"/> + </rsel:or></rsel:not> + </restrict> + <path refid="quick.compiler.build.path"/> <pathelement location="${build-quick.dir}/classes/repl"/> <!-- for the java dependency: Profiler.java --> @@ -843,7 +805,6 @@ TODO: <path id="quick.bin.tool.path"> <path refid="quick.repl.build.path"/> - <path refid="quick.actors.build.path"/> <pathelement location="${build-quick.dir}/classes/scalap"/> <pathelement location="${build-quick.dir}/classes/scaladoc"/> <path refid="external-modules-nocore"/> @@ -863,7 +824,6 @@ TODO: <pathelement location="${library.jar}"/> <pathelement location="${xml.jar}"/> <pathelement location="${parser-combinators.jar}"/> - <pathelement location="${actors.jar}"/> <pathelement location="${reflect.jar}"/> <pathelement location="${compiler.jar}"/> <!-- TODO modularize compiler: <pathelement location="${scaladoc.jar}"/> --> @@ -878,10 +838,6 @@ TODO: <fileset refid="scala-java8-compat.fileset"/> </path> - <path id="pack.actors.files"> - <fileset dir="${build-quick.dir}/classes/actors"/> - </path> - <path id="pack.repl-jline.files"> <fileset dir="${build-quick.dir}/classes/repl-jline"/> </path> <path id="pack.compiler.files"> @@ -931,7 +887,6 @@ TODO: <path id="docs.scaladoc.build.path"> <path refid="quick.scaladoc.build.path"/> </path> <path id="docs.interactive.build.path"> <path refid="quick.interactive.build.path"/> </path> <path id="docs.scalap.build.path"> <path refid="quick.scalap.build.path"/> </path> - <path id="docs.actors.build.path"> <path refid="quick.actors.build.path"/> </path> <!-- run-time classpath for scaladoc TODO: resolve through maven --> <path id="scaladoc.classpath"> @@ -987,9 +942,8 @@ TODO: <pathelement location="${interactive.jar}"/> --> - <!-- TODO: move scalap & actors out of repo --> + <!-- TODO: move scalap out of repo --> <pathelement location="${scalap.jar}"/> - <pathelement location="${actors.jar}"/> <!-- partest's dependencies, which marks most of its dependencies as provided, (but not scala-library, so we filter that one out...) @@ -1012,7 +966,6 @@ TODO: <rsel:name name="scala-library*.jar"/> <rsel:name name="scala-compiler*.jar"/> <rsel:name name="scala-reflect*.jar"/> - <rsel:name name="scala-actors*.jar"/> <rsel:name name="scala-parser-combinators*.jar"/> <rsel:name name="scala-xml*.jar"/> </rsel:or></rsel:not> @@ -1040,7 +993,6 @@ TODO: <pathelement location="${build-osgi.dir}/org.scala-lang.scala-library.jar"/> <pathelement location="${build-osgi.dir}/org.scala-lang.scala-reflect.jar"/> <pathelement location="${build-osgi.dir}/org.scala-lang.scala-compiler.jar"/> - <pathelement location="${build-osgi.dir}/org.scala-lang.scala-actors.jar"/> <path refid="pax.exam.classpath"/> <path refid="forkjoin.classpath"/> </path> @@ -1204,9 +1156,6 @@ TODO: <target name="quick.scalap" depends="quick.repl"> <staged-build with="locker" stage="quick" project="scalap"/> </target> - <target name="quick.actors" depends="quick.lib"> - <staged-build with="locker" stage="quick" project="actors"/> </target> - <target name="quick.modules" depends="quick.repl, quick.scaladoc, quick.interactive, quick.scalap"/> @@ -1258,14 +1207,12 @@ TODO: <target name="pack.interactive" depends="quick.interactive"> <staged-pack project="interactive"/> </target> --> - <target name="pack.actors" depends="quick.actors"> <staged-pack project="actors"/> </target> - <target name="pack.scalap" depends="quick.scalap"> <staged-pack project="scalap"/> </target> <target name="pack.core" depends="pack.reflect, pack.comp, pack.lib"/> <!-- TODO modularize compiler: pack.scaladoc, pack.interactive, --> - <target name="pack.modules" depends="pack.actors, pack.scalap"> + <target name="pack.modules" depends="pack.scalap"> <copy todir="${build-pack.dir}/lib"> <path refid="external-modules-nocore" /> <mapper type="flatten" /> @@ -1371,10 +1318,6 @@ TODO: <include name="${scaladoc.jar}"/> --> - <file name="${actors.jar}"/> - - <file name="${continuations-plugin.jar}"/> - <file name="${continuations-library.jar}"/> <file name="${parser-combinators.jar}"/> <file name="${xml.jar}"/> <file name="${swing.jar}"/> @@ -1399,13 +1342,6 @@ TODO: </make-bundle> --> - <make-bundle project="actors"> - <fileset dir="${src.dir}/actors"/> - </make-bundle> - - - <make-bundle project="continuations-plugin"/> - <make-bundle project="continuations-library"/> <make-bundle project="parser-combinators"/> <make-bundle project="xml"/> <make-bundle project="swing"/> @@ -1552,6 +1488,10 @@ TODO: <mkdir dir="${test.junit.classes}"/> <echo message="Note: details of failed tests will be output to ${build-junit.dir}"/> + <propertyfile file = "${test.junit.classes}/classpath.properties"> + <entry key = "test.junit.compiler.build.path" value="${toString:test.junit.compiler.build.path}"/> + </propertyfile> + <if><isset property="test.method" /><then><property name="test.methods" value="${test.method}" /></then></if> <junit fork="yes" haltonfailure="yes" printsummary="on"> <classpath refid="test.junit.compiler.build.path"/> @@ -1647,8 +1587,9 @@ TODO: <target name="test.bc-opt" description="Optimized version of test.bc."> <optimized name="test.bc"/></target> <target name="test.bc" depends="bc.prepare, pack.lib, pack.reflect" unless="test.bc.skip"> - <bc.check project="library"/> - <bc.check project="reflect"/> + <echo message="binary compatibility testing disabled in the 2.12.x branch"/> + <!-- <bc.check project="library"/> --> + <!-- <bc.check project="reflect"/> --> </target> <!-- =========================================================================== @@ -1715,12 +1656,6 @@ TODO: </target> --> - <target name="docs.actors" depends="docs.start" unless="docs.skip"> - <staged-docs project="actors"> - <include name="**/*.scala"/> - </staged-docs> - </target> - <target name="docs.scalap" depends="docs.start" unless="docs.skip"> <staged-docs project="scalap"> <include name="**/*.scala"/> @@ -1729,7 +1664,7 @@ TODO: <target name="docs.core" depends="docs.lib, docs.reflect, docs.comp" unless="docs.skip"/> <!-- TODO modularize compiler: docs.scaladoc, docs.interactive, --> - <target name="docs.done" depends="docs.core, docs.actors, docs.scalap" unless="docs.skip"/> + <target name="docs.done" depends="docs.core, docs.scalap" unless="docs.skip"/> <!-- doc/ and man/ --> <target name="pack.doc" depends="scaladoc.task" unless="docs.skip"> <!-- depends on scaladoc.task for scalac taskdef --> @@ -1804,8 +1739,6 @@ MAIN DISTRIBUTION PACKAGING <mvn-package project="scaladoc"/> --> - <mvn-package project="actors"/> - <!-- don't bother fitting scalap into the mould: it will move out soon --> <copy tofile="${dist.maven}/scalap/scalap-pom.xml" file="${src.dir}/build/maven/scalap-pom.xml" overwrite="true"/> <copy tofile="${dist.maven}/scalap/scalap.jar" file="${scalap.jar}" overwrite="true"/> diff --git a/dbuild-meta.json b/dbuild-meta.json index 90d0104ec1..4806f9fa5a 100644 --- a/dbuild-meta.json +++ b/dbuild-meta.json @@ -1,100 +1,82 @@ { - "version": "2.11.0", - "subproj": [], - "projects": [ + "projects" : [ { - "artifacts": [ + "artifacts" : [ { - "extension": "jar", - "name": "scala-library", - "organization": "org.scala-lang" + "extension" : "jar", + "name" : "scala-library", + "organization" : "org.scala-lang" } ], - "dependencies": [], - "name": "scala-library", - "organization": "org.scala-lang" + "dependencies" : [], + "name" : "scala-library", + "organization" : "org.scala-lang" }, { - "artifacts": [ + "artifacts" : [ { - "extension": "jar", - "name": "scala-reflect", - "organization": "org.scala-lang" + "extension" : "jar", + "name" : "scala-reflect", + "organization" : "org.scala-lang" } ], - "dependencies": [ + "dependencies" : [ { - "extension": "jar", - "name": "scala-library", - "organization": "org.scala-lang" + "extension" : "jar", + "name" : "scala-library", + "organization" : "org.scala-lang" } ], - "name": "scala-reflect", - "organization": "org.scala-lang" + "name" : "scala-reflect", + "organization" : "org.scala-lang" }, { - "artifacts": [ + "artifacts" : [ { - "extension": "jar", - "name": "scala-compiler", - "organization": "org.scala-lang" + "extension" : "jar", + "name" : "scala-compiler", + "organization" : "org.scala-lang" } ], - "dependencies": [ + "dependencies" : [ { - "extension": "jar", - "name": "scala-reflect", - "organization": "org.scala-lang" + "extension" : "jar", + "name" : "scala-reflect", + "organization" : "org.scala-lang" }, { - "extension": "jar", - "name": "scala-xml", - "organization": "org.scala-lang.modules" + "extension" : "jar", + "name" : "scala-xml", + "organization" : "org.scala-lang.modules" }, { - "extension": "jar", - "name": "scala-parser-combinators", - "organization": "org.scala-lang.modules" + "extension" : "jar", + "name" : "scala-parser-combinators", + "organization" : "org.scala-lang.modules" } ], - "name": "scala-compiler", - "organization": "org.scala-lang" + "name" : "scala-compiler", + "organization" : "org.scala-lang" }, { - "artifacts": [ + "artifacts" : [ { - "extension": "jar", - "name": "scala-actors", - "organization": "org.scala-lang" + "extension" : "jar", + "name" : "scalap", + "organization" : "org.scala-lang" } ], - "dependencies": [ + "dependencies" : [ { - "extension": "jar", - "name": "scala-library", - "organization": "org.scala-lang" + "extension" : "jar", + "name" : "scala-compiler", + "organization" : "org.scala-lang" } ], - "name": "scala-actors", - "organization": "org.scala-lang" - }, - { - "artifacts": [ - { - "extension": "jar", - "name": "scalap", - "organization": "org.scala-lang" - } - ], - "dependencies": [ - { - "extension": "jar", - "name": "scala-compiler", - "organization": "org.scala-lang" - } - ], - "name": "scalap", - "organization": "org.scala-lang" + "name" : "scalap", + "organization" : "org.scala-lang" } - ] + ], + "subproj" : [], + "version" : "2.12.0" } diff --git a/scripts/jobs/integrate/bootstrap b/scripts/jobs/integrate/bootstrap index 5048f3fdb9..ccc62c0d45 100755 --- a/scripts/jobs/integrate/bootstrap +++ b/scripts/jobs/integrate/bootstrap @@ -187,7 +187,7 @@ sbtBuild() { sbtResolve() { cd $baseDir/resolutionScratch_ touch build.sbt - # Can be set to `full` if a module requires cross-versioning against the full Scala version, like the continuations plugin. + # Can be set to `full` if a module requires cross-versioning against the full Scala version, like the continuations plugin used to. cross=${4-binary} echo "### sbtResolve: $sbtCmd $sbtArgs " "${scalaVersionTasks[@]}" "\"$1\" % \"$2\" % \"$3\" cross CrossVersion.$cross" $sbtCmd $sbtArgs "${scalaVersionTasks[@]}" \ @@ -251,27 +251,6 @@ buildPartest() { # fi # } -buildContinuations() { - if [ "$CONT_PLUG_BUILT" != "yes" ] && [ "$forceRebuild" != "yes" ] && ( sbtResolve "org.scala-lang.plugins" "scala-continuations-plugin" $CONTINUATIONS_VER full ) - then echo "Found scala-continuations-plugin $CONTINUATIONS_VER; not building." - else - update scala scala-continuations $CONTINUATIONS_REF && gfxd - - $sbtCmd $sbtArgs 'project plugin' "${scalaVersionTasks[@]}" "${publishTasks[@]}" \ - 'set version := "'$CONTINUATIONS_VER'"' $clean "compile:package" test "${buildTasks[@]}" # https://github.com/scala/scala-continuations/pull/4 - CONT_PLUG_BUILT="yes" - fi - - if [ "$CONT_LIB_BUILT" != "yes" ] && [ "$forceRebuild" != "yes" ] && ( sbtResolve "org.scala-lang.plugins" "scala-continuations-library" $CONTINUATIONS_VER ) - then echo "Found scala-continuations-library $CONTINUATIONS_VER; not building." - else - update scala scala-continuations $CONTINUATIONS_REF && gfxd - $sbtCmd $sbtArgs 'project library' "${scalaVersionTasks[@]}" "${publishTasks[@]}" \ - 'set version := "'$CONTINUATIONS_VER'"' $clean test "${buildTasks[@]}" - CONT_LIB_BUILT="yes" - fi -} - buildSwing() { if [ "$SWING_BUILT" != "yes" ] && [ "$forceRebuild" != "yes" ] && ( sbtResolve "org.scala-lang.modules" "scala-swing" $SWING_VER ) then echo "Found scala-swing $SWING_VER; not building." @@ -282,18 +261,6 @@ buildSwing() { fi } -buildActorsMigration(){ - if [ "$ACTORS_MIGRATION_BUILT" != "yes" ] && [ "$forceRebuild" != "yes" ] && ( sbtResolve "org.scala-lang" "scala-actors-migration" $ACTORS_MIGRATION_VER ) - then echo "Found scala-actors-migration $ACTORS_MIGRATION_VER; not building." - else - update scala actors-migration "$ACTORS_MIGRATION_REF" && gfxd - # not running tests because - # [error] Test scala.actors.migration.NestedReact.testNestedReactAkka failed: java.util.concurrent.TimeoutException: Futures timed out after [20 seconds] - sbtBuild 'set version := "'$ACTORS_MIGRATION_VER'"' 'set VersionKeys.continuationsVersion := "'$CONTINUATIONS_VER'"' $clean "${buildTasks[@]}" - ACTORS_MIGRATION_BUILT="yes" - fi -} - # should only be called with publishTasks publishing to private-repo buildScalacheck(){ if [ "$SCALACHECK_BUILT" != "yes" ] && [ "$forceRebuild" != "yes" ] && ( sbtResolve "org.scalacheck" "scalacheck" $SCALACHECK_VER ) @@ -311,9 +278,7 @@ buildModules() { buildTasks=($publishPrivateTask) buildXML buildParsers - buildContinuations buildSwing - buildActorsMigration buildScalacheck buildPartest # buildPartestIface @@ -324,9 +289,7 @@ buildPublishedModules() { buildTasks=($publishSonatypeTaskModules) buildXML buildParsers - buildContinuations buildSwing - buildActorsMigration buildPartest # buildPartestIface } @@ -367,7 +330,7 @@ scalaVerToBinary() { determineScalaVersion() { cd $WORKSPACE parseScalaProperties "versions.properties" - echo "repo_ref=2.11.x" >> $baseDir/jenkins.properties # for the -dist downstream jobs that build the actual archives + echo "repo_ref=2.12.x" >> $baseDir/jenkins.properties # for the -dist downstream jobs that build the actual archives # each of the branches below defines the following vars: SCALA_VER_BASE, SCALA_VER_SUFFIX, SCALADOC_SOURCE_LINKS_VER, publishToSonatype @@ -433,17 +396,13 @@ deriveModuleVersions() { # use versions.properties as defaults when no version specified on the command line XML_VER=${XML_VER-$scala_xml_version_number} PARSERS_VER=${PARSERS_VER-$scala_parser_combinators_version_number} - CONTINUATIONS_VER=${CONTINUATIONS_VER-$scala_continuations_plugin_version_number} SWING_VER=${SWING_VER-$scala_swing_version_number} - ACTORS_MIGRATION_VER=${ACTORS_MIGRATION_VER-$actors_migration_version_number} PARTEST_VER=${PARTEST_VER-$partest_version_number} SCALACHECK_VER=${SCALACHECK_VER-$scalacheck_version_number} XML_REF="v$XML_VER" PARSERS_REF="v$PARSERS_VER" - CONTINUATIONS_REF="v$CONTINUATIONS_VER" SWING_REF="v$SWING_VER" - ACTORS_MIGRATION_REF="v$ACTORS_MIGRATION_VER" PARTEST_REF="v$PARTEST_VER" # PARTEST_IFACE_REF="v$PARTEST_IFACE_VER" SCALACHECK_REF="$SCALACHECK_VER" # no `v` in their tags @@ -451,25 +410,19 @@ deriveModuleVersions() { # use HEAD as default when no revision is specified on the command line XML_REF=${XML_REF-"HEAD"} PARSERS_REF=${PARSERS_REF-"HEAD"} - CONTINUATIONS_REF=${CONTINUATIONS_REF-"HEAD"} SWING_REF=${SWING_REF-"HEAD"} - ACTORS_MIGRATION_REF=${ACTORS_MIGRATION_REF-"HEAD"} PARTEST_REF=${PARTEST_REF-"HEAD"} # PARTEST_IFACE_REF=${PARTEST_IFACE_REF-"HEAD"} SCALACHECK_REF=${SCALACHECK_REF-"HEAD"} XML_VER=$(deriveVersion scala scala-xml "$XML_REF") PARSERS_VER=$(deriveVersion scala scala-parser-combinators "$PARSERS_REF") - CONTINUATIONS_VER=$(deriveVersion scala scala-continuations "$CONTINUATIONS_REF") SWING_VER=$(deriveVersion scala scala-swing "$SWING_REF") - ACTORS_MIGRATION_VER=$(deriveVersion scala actors-migration "$ACTORS_MIGRATION_REF") PARTEST_VER=$(deriveVersion scala scala-partest "$PARTEST_REF") SCALACHECK_VER=$(deriveVersionAnyTag rickynils scalacheck "$SCALACHECK_REF") fi echo "Module versions (versioning strategy: $moduleVersioning):" - echo "ACTORS_MIGRATION = $ACTORS_MIGRATION_VER at $ACTORS_MIGRATION_REF" - echo "CONTINUATIONS = $CONTINUATIONS_VER at $CONTINUATIONS_REF" echo "PARSERS = $PARSERS_VER at $PARSERS_REF" echo "PARTEST = $PARTEST_VER at $PARTEST_REF" echo "SCALACHECK = $SCALACHECK_VER at $SCALACHECK_REF" @@ -508,9 +461,6 @@ constructUpdatedModuleVersions() { # force the new module versions for building the core. these may be different from the values in versions.properties, # either because the variables (XML_VER) were provided, or because we're building the modules from HEAD. # in the common case, the values are the same as in versions.properties. - updatedModuleVersions=("${updatedModuleVersions[@]}" "-Dactors-migration.version.number=$ACTORS_MIGRATION_VER") - updatedModuleVersions=("${updatedModuleVersions[@]}" "-Dscala-continuations-library.version.number=$CONTINUATIONS_VER") - updatedModuleVersions=("${updatedModuleVersions[@]}" "-Dscala-continuations-plugin.version.number=$CONTINUATIONS_VER") updatedModuleVersions=("${updatedModuleVersions[@]}" "-Dscala-parser-combinators.version.number=$PARSERS_VER") updatedModuleVersions=("${updatedModuleVersions[@]}" "-Dscala-swing.version.number=$SWING_VER") updatedModuleVersions=("${updatedModuleVersions[@]}" "-Dscala-xml.version.number=$XML_VER") @@ -518,8 +468,7 @@ constructUpdatedModuleVersions() { updatedModuleVersions=("${updatedModuleVersions[@]}" "-Dpartest.version.number=$PARTEST_VER") updatedModuleVersions=("${updatedModuleVersions[@]}" "-Dscalacheck.version.number=$SCALACHECK_VER") - # allow overriding the akka-actors and jline version using a jenkins build parameter - if [ ! -z "$AKKA_ACTOR_VER" ]; then updatedModuleVersions=("${updatedModuleVersions[@]}" "-Dakka-actor.version.number=$AKKA_ACTOR_VER"); fi + # allow overriding the jline version using a jenkins build parameter if [ ! -z "$JLINE_VER" ] ; then updatedModuleVersions=("${updatedModuleVersions[@]}" "-Djline.version=$JLINE_VER"); fi if [ ! -z "$SCALA_BINARY_VER" ]; then updatedModuleVersions=("${updatedModuleVersions[@]}" "-Dscala.binary.version=$SCALA_BINARY_VER"); fi @@ -575,10 +524,7 @@ bootstrap() { cd $baseDir rm -rf build/ # must leave everything else in $baseDir for downstream jobs - # scala.full.version determines the dependency of scala-dist on the continuations plugin, - # which is fully cross-versioned (for $SCALA_VER, the version we're releasing) ant -Dstarr.version=$SCALA_VER\ - -Dscala.full.version=$SCALA_VER\ -Dextra.repo.url=$releaseTempRepoUrl\ -Dmaven.version.suffix=$SCALA_VER_SUFFIX\ ${updatedModuleVersions[@]} \ diff --git a/scripts/jobs/integrate/ide b/scripts/jobs/integrate/ide index 1651ad2892..c39facbc3d 100755 --- a/scripts/jobs/integrate/ide +++ b/scripts/jobs/integrate/ide @@ -3,6 +3,9 @@ # requires env: scalaVersion (specifies binary already built from above checkout), WORKSPACE (provided by jenkins), repo_ref (HEAD of the scala checkout), # requires files: $baseDir/versions.properties (from checkout -- defines version numbers for modules used to build scala for dbuild...) +echo "IDE integration not yet available on 2.12.x. Punting." +exit 0 + # TODO: remove when integration is up and running if [ "woele$_scabot_last" != "woele1" ]; then echo "Scabot didn't mark this as last commit -- skipping."; exit 0; fi 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/BCodeIdiomatic.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeIdiomatic.scala index 8f2a17a2bf..a25f5cad63 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/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/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/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/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/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/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/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) } diff --git a/test/files/filters b/test/files/filters index 51a7507848..e91ca0eb36 100644 --- a/test/files/filters +++ b/test/files/filters @@ -1,6 +1,7 @@ # #Java HotSpot(TM) 64-Bit Server VM warning: Failed to reserve shared memory (errno = 28). Java HotSpot\(TM\) .* warning: +OpenJDK .* warning: # Hotspot receiving VM options through the $_JAVA_OPTIONS # env variable outputs them on stderr Picked up _JAVA_OPTIONS: diff --git a/test/files/jvm/actor-exceptions.check b/test/files/jvm/actor-exceptions.check deleted file mode 100644 index d86bac9de5..0000000000 --- a/test/files/jvm/actor-exceptions.check +++ /dev/null @@ -1 +0,0 @@ -OK diff --git a/test/files/jvm/actor-exceptions.scala b/test/files/jvm/actor-exceptions.scala deleted file mode 100644 index bdd983a0e8..0000000000 --- a/test/files/jvm/actor-exceptions.scala +++ /dev/null @@ -1,67 +0,0 @@ - - -@deprecated("Suppress warnings", since="2.11") -object Test { -import scala.actors.{Actor, Exit} -import Actor._ - -case class MyException(text: String) extends Exception { - override def fillInStackTrace() = this -} - -case class MyOtherException(text: String) extends Exception { - override def fillInStackTrace() = this -} - -object Master extends Actor { - trapExit = true - def act() { - try { - link(Slave) - Slave.start() - for (i <- 0 until 10) Slave ! A - react { - case Exit(from, reason) => - println("OK") - } - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - } -} - -object Slave extends Actor { - override def toString = "Slave" - override def exceptionHandler: PartialFunction[Exception, Unit] = { - case MyException(text) => - case other if !other.isInstanceOf[scala.util.control.ControlThrowable] => super.exceptionHandler(other) - } - def act() { - try { - var cnt = 0 - loop { - react { - case A => - cnt += 1 - if (cnt % 2 != 0) throw MyException("problem") - if (cnt == 10) { - throw MyOtherException("unhandled") - } - } - } - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] && - !e.isInstanceOf[MyException] && - !e.isInstanceOf[MyOtherException] => - e.printStackTrace() - } - } -} - -case object A - - def main(args: Array[String]) { - Master.start() - } -} diff --git a/test/files/jvm/actor-executor.check b/test/files/jvm/actor-executor.check deleted file mode 100644 index bdbdb5c6a2..0000000000 --- a/test/files/jvm/actor-executor.check +++ /dev/null @@ -1,20 +0,0 @@ -Two: OK -One: OK -Two: OK -One: OK -Two: OK -One: OK -Two: OK -One: OK -Two: OK -One: OK -Two: OK -One: OK -Two: OK -One: OK -Two: OK -One: OK -Two: OK -One: OK -Two: OK -One: OK diff --git a/test/files/jvm/actor-executor.scala b/test/files/jvm/actor-executor.scala deleted file mode 100644 index 0fc28b4d85..0000000000 --- a/test/files/jvm/actor-executor.scala +++ /dev/null @@ -1,78 +0,0 @@ - - -@deprecated("Suppress warnings", since="2.11") -object Test { -import java.util.concurrent.Executors -import scala.actors.{Actor, SchedulerAdapter} -import Actor._ - -trait AdaptedActor extends Actor { - override def scheduler = - Test.scheduler -} - -object One extends AdaptedActor { - def act() { - try { - Two.start() - var i = 0 - loopWhile (i < 10000) { - i += 1 - Two ! 'MsgForTwo - react { - case 'MsgForOne => - if (i % 1000 == 0) - println("One: OK") - if (i == 10000) - Test.executor.shutdown() - } - } - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - } -} - -object Two extends AdaptedActor { - def act() { - try { - var i = 0 - loopWhile (i < 10000) { - i += 1 - react { - case 'MsgForTwo => - if (i % 1000 == 0) - println("Two: OK") - One ! 'MsgForOne - } - } - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - } -} - - val executor = - Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()) - - val scheduler = - new SchedulerAdapter { - def execute(block: => Unit) { - val task = new Runnable { - def run() { block } - } - try { - executor.execute(task) - } catch { - case ree: java.util.concurrent.RejectedExecutionException => - task.run() - } - } - } - - def main(args: Array[String]) { - One.start() - } -} diff --git a/test/files/jvm/actor-executor2.check b/test/files/jvm/actor-executor2.check deleted file mode 100644 index da78f45836..0000000000 --- a/test/files/jvm/actor-executor2.check +++ /dev/null @@ -1,21 +0,0 @@ -Two: OK -One: OK -Two: OK -One: OK -Two: OK -One: OK -Two: OK -One: OK -Two: OK -One: OK -Two: OK -One: OK -Two: OK -One: OK -Two: OK -One: OK -Two: OK -One: OK -Two: OK -One: OK -One exited diff --git a/test/files/jvm/actor-executor2.scala b/test/files/jvm/actor-executor2.scala deleted file mode 100644 index 5badf2ae7e..0000000000 --- a/test/files/jvm/actor-executor2.scala +++ /dev/null @@ -1,92 +0,0 @@ - - - -@deprecated("Suppress warnings", since="2.11") -object Test { -import scala.actors.{Actor, SchedulerAdapter, Exit} -import Actor._ -import java.util.concurrent.{Executors, RejectedExecutionException} - -object One extends AdaptedActor { - def act() { - try { - Two.start() - var i = 0 - loopWhile (i < Test.NUM_MSG) { - i += 1 - Two ! 'MsgForTwo - react { - case 'MsgForOne => - if (i % (Test.NUM_MSG/10) == 0) - println("One: OK") - } - } - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - } -} - -object Two extends AdaptedActor { - def act() { - try { - var i = 0 - loopWhile (i < Test.NUM_MSG) { - i += 1 - react { - case 'MsgForTwo => - if (i % (Test.NUM_MSG/10) == 0) - println("Two: OK") - One ! 'MsgForOne - } - } - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - } -} - -trait AdaptedActor extends Actor { - override def scheduler = - Test.scheduler -} - - val NUM_MSG = 100000 - - val executor = - Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()) - - val scheduler = - new SchedulerAdapter { - def execute(block: => Unit) { - val task = new Runnable { - def run() { block } - } - try { - executor.execute(task) - } catch { - case ree: RejectedExecutionException => - task.run() // run task on current thread - } - } - } - - def main(args: Array[String]) { - try { - self.trapExit = true - link(One) - One.start() - - receive { - case Exit(from, reason) => - println("One exited") - Test.executor.shutdown() - } - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - } -} diff --git a/test/files/jvm/actor-executor3.check b/test/files/jvm/actor-executor3.check deleted file mode 100644 index bdbdb5c6a2..0000000000 --- a/test/files/jvm/actor-executor3.check +++ /dev/null @@ -1,20 +0,0 @@ -Two: OK -One: OK -Two: OK -One: OK -Two: OK -One: OK -Two: OK -One: OK -Two: OK -One: OK -Two: OK -One: OK -Two: OK -One: OK -Two: OK -One: OK -Two: OK -One: OK -Two: OK -One: OK diff --git a/test/files/jvm/actor-executor3.scala b/test/files/jvm/actor-executor3.scala deleted file mode 100644 index f8b57d84b3..0000000000 --- a/test/files/jvm/actor-executor3.scala +++ /dev/null @@ -1,66 +0,0 @@ - - - -@deprecated("Suppress warnings", since="2.11") -object Test { -import scala.actors.Actor -import scala.actors.scheduler.ExecutorScheduler -import java.util.concurrent.Executors - -object One extends AdaptedActor { - def act() { - try { - Two.start() - var i = 0 - loopWhile (i < Test.NUM_MSG) { - i += 1 - Two ! 'MsgForTwo - react { - case 'MsgForOne => - if (i % (Test.NUM_MSG/10) == 0) - println("One: OK") - } - } - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - } -} - -object Two extends AdaptedActor { - def act() { - try { - var i = 0 - loopWhile (i < Test.NUM_MSG) { - i += 1 - react { - case 'MsgForTwo => - if (i % (Test.NUM_MSG/10) == 0) - println("Two: OK") - One ! 'MsgForOne - } - } - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - } -} - -trait AdaptedActor extends Actor { - override def scheduler = - Test.scheduler -} - - val NUM_MSG = 100000 - - val executor = - Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()) - - val scheduler = ExecutorScheduler(executor) - - def main(args: Array[String]) { - One.start() - } -} diff --git a/test/files/jvm/actor-getstate.check b/test/files/jvm/actor-getstate.check deleted file mode 100644 index 2c94e48371..0000000000 --- a/test/files/jvm/actor-getstate.check +++ /dev/null @@ -1,2 +0,0 @@ -OK -OK diff --git a/test/files/jvm/actor-getstate.scala b/test/files/jvm/actor-getstate.scala deleted file mode 100644 index 425efbe5e6..0000000000 --- a/test/files/jvm/actor-getstate.scala +++ /dev/null @@ -1,87 +0,0 @@ - - -@deprecated("Suppress warnings", since="2.11") -object Test { - import scala.actors.{Reactor, Actor, TIMEOUT} - import Actor._ - - def assert(cond: => Boolean, hint: String) { - if (!cond) - println("FAIL ["+hint+"]") - } - - def expectActorState(a: Reactor[T] forSome { type T }, s: Actor.State.Value) { - var done = false - var i = 0 - while (!done) { - i = i + 1 - if (i == 10) { // only wait for 2 seconds total - println("FAIL ["+a+": expected "+s+"]") - done = true - } - - Thread.sleep(200) - if (a.getState == s) // success - done = true - } - } - - def main(args: Array[String]) { - actor { - val a = new Reactor[Any] { - def act() { - assert(getState == Actor.State.Runnable, "runnable1") - react { - case 'go => - println("OK") - } - } - } - expectActorState(a, Actor.State.New) - - a.start() - expectActorState(a, Actor.State.Suspended) - - a ! 'go - expectActorState(a, Actor.State.Terminated) - - val b = new Actor { - def act() { - assert(getState == Actor.State.Runnable, "runnable2: "+getState) - react { - case 'go => - reactWithin(100000) { - case TIMEOUT => - case 'go => - receive { - case 'go => - } - receiveWithin(100000) { - case TIMEOUT => - case 'go => - println("OK") - } - } - } - } - } - expectActorState(b, Actor.State.New) - - b.start() - expectActorState(b, Actor.State.Suspended) - - b ! 'go - expectActorState(b, Actor.State.TimedSuspended) - - b ! 'go - expectActorState(b, Actor.State.Blocked) - - b ! 'go - expectActorState(b, Actor.State.TimedBlocked) - - b ! 'go - expectActorState(b, Actor.State.Terminated) - } - } - -} diff --git a/test/files/jvm/actor-link-getstate.check b/test/files/jvm/actor-link-getstate.check deleted file mode 100644 index 9755447320..0000000000 --- a/test/files/jvm/actor-link-getstate.check +++ /dev/null @@ -1,2 +0,0 @@ -Done -Terminated diff --git a/test/files/jvm/actor-link-getstate.scala b/test/files/jvm/actor-link-getstate.scala deleted file mode 100644 index d8b8ada1e6..0000000000 --- a/test/files/jvm/actor-link-getstate.scala +++ /dev/null @@ -1,65 +0,0 @@ - - -@deprecated("Suppress warnings", since="2.11") -object Test { - import scala.actors.{Actor, Exit} - import scala.actors.Actor._ - -case class MyException(text: String) extends Exception(text) { - override def fillInStackTrace() = this -} - -object Slave extends Actor { - def act() { - try { - loop { - react { - case 'doWork => - Console.out.println("Done") - reply('done) - } - } - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - } -} - -object Master extends Actor { - override def toString = "Master" - def act() { - try { - link(Slave) - Slave ! 'doWork - react { - case 'done => - throw new MyException("Master crashed") - } - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - } -} - - - def main(args: Array[String]) { - actor { - try { - self.trapExit = true - link(Slave) - Slave.start() - Master.start() - react { - case Exit(from, reason) if (from == Slave) => - Console.out.println(Slave.getState) - } - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - } - } - -} diff --git a/test/files/jvm/actor-looping.check b/test/files/jvm/actor-looping.check deleted file mode 100644 index a6f5c2e73a..0000000000 --- a/test/files/jvm/actor-looping.check +++ /dev/null @@ -1,5 +0,0 @@ -received A -received A -received A -received A -received last A diff --git a/test/files/jvm/actor-looping.scala b/test/files/jvm/actor-looping.scala deleted file mode 100644 index 7bc6f1e5c5..0000000000 --- a/test/files/jvm/actor-looping.scala +++ /dev/null @@ -1,33 +0,0 @@ - - -@deprecated("Suppress warnings", since="2.11") -object Test { - import scala.actors.Actor._ - case object A - - def main(args: Array[String]) { - val a = actor { - try { - var cnt = 0 - loop { - react { - case A => - cnt += 1 - if (cnt % 2 != 0) continue - if (cnt < 10) - println("received A") - else { - println("received last A") - exit() - } - } - } - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - } - - for (i <- 0 until 10) a ! A - } -} diff --git a/test/files/jvm/actor-normal-exit.check b/test/files/jvm/actor-normal-exit.check deleted file mode 100644 index 6865f83b90..0000000000 --- a/test/files/jvm/actor-normal-exit.check +++ /dev/null @@ -1,2 +0,0 @@ -Done -slave exited for reason 'normal diff --git a/test/files/jvm/actor-normal-exit.scala b/test/files/jvm/actor-normal-exit.scala deleted file mode 100644 index 90495866e2..0000000000 --- a/test/files/jvm/actor-normal-exit.scala +++ /dev/null @@ -1,38 +0,0 @@ - - - -@deprecated("Suppress warnings", since="2.11") -object Test { - import scala.actors.{Actor, Exit} - object Master extends Actor { - trapExit = true - def act() { - try { - Slave.start() - react { - case Exit(from, reason) => - println("slave exited for reason " + reason) - } - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - } - } - - object Slave extends Actor { - def act() { - try { - link(Master) - println("Done") - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - } - } - - def main(args: Array[String]) { - Master.start() - } -} diff --git a/test/files/jvm/actor-receivewithin.check b/test/files/jvm/actor-receivewithin.check deleted file mode 100644 index a6a3e88c61..0000000000 --- a/test/files/jvm/actor-receivewithin.check +++ /dev/null @@ -1,16 +0,0 @@ -'msg -'msg -'msg -'msg -'msg -TIMEOUT -TIMEOUT -TIMEOUT -TIMEOUT -TIMEOUT -'msg2 -'msg2 -'msg2 -'msg2 -'msg2 -TIMEOUT diff --git a/test/files/jvm/actor-receivewithin.scala b/test/files/jvm/actor-receivewithin.scala deleted file mode 100644 index 5982462502..0000000000 --- a/test/files/jvm/actor-receivewithin.scala +++ /dev/null @@ -1,72 +0,0 @@ - - -@deprecated("Suppress warnings", since="2.11") -object Test { -import scala.actors.{Actor, TIMEOUT} - -object A extends Actor { - def act() { - receive { - case 'done => - var cnt = 0 - while (cnt < 500) { - cnt += 1 - receiveWithin (0) { - case 'msg => - if (cnt % 100 == 0) - println("'msg") - case TIMEOUT => - // should not happen - println("FAIL1") - } - } - cnt = 0 - while (cnt < 500) { - cnt += 1 - receiveWithin (0) { - case 'msg => - // should not happen - println("FAIL2") - case TIMEOUT => - if (cnt % 100 == 0) - println("TIMEOUT") - } - } - B ! 'next - receive { case 'done => } - cnt = 0 - while (cnt < 501) { - cnt += 1 - receiveWithin (500) { - case 'msg2 => - if (cnt % 100 == 0) - println("'msg2") - case TIMEOUT => - println("TIMEOUT") - } - } - } - } -} - -object B extends Actor { - def act() { - A.start() - for (_ <- 1 to 500) { - A ! 'msg - } - A ! 'done - receive { - case 'next => - for (_ <- 1 to 500) { - A ! 'msg2 - } - A ! 'done - } - } -} - - def main(args:Array[String]) { - B.start() - } -} diff --git a/test/files/jvm/actor-sync-send-timeout.scala b/test/files/jvm/actor-sync-send-timeout.scala deleted file mode 100644 index 66a0b0a6ff..0000000000 --- a/test/files/jvm/actor-sync-send-timeout.scala +++ /dev/null @@ -1,48 +0,0 @@ -@deprecated("Suppress warnings", since="2.11") -object Test { -import scala.actors.Actor - -/* This test is a regression test for SI-4759. - */ - val Runs = 5 - - def main(args: Array[String]) = { - var i = 0 - while (i < Runs) { - i += 1 - A1 ! 1 - Thread.sleep(500) - } - //println("done sending to A1") - } - -object A2 extends Actor { - this.start() - def act() { - loop { - react { - case 'stop => - //println("A2 exiting") - exit() - case _ => - } - } - } -} - -object A1 extends Actor { - this.start() - def act() { - var i = 0 - loopWhile(i < Test.Runs) { - i += 1 - react { - case any => - A2 !? (500, any) - if (i == Test.Runs) - A2 ! 'stop - } - } - } -} -} diff --git a/test/files/jvm/actor-termination.check b/test/files/jvm/actor-termination.check deleted file mode 100644 index e3f44d8b18..0000000000 --- a/test/files/jvm/actor-termination.check +++ /dev/null @@ -1,2 +0,0 @@ -I'm going to make you wait. -Ok, I'm done. diff --git a/test/files/jvm/actor-termination.scala b/test/files/jvm/actor-termination.scala deleted file mode 100644 index 4a6bf92d48..0000000000 --- a/test/files/jvm/actor-termination.scala +++ /dev/null @@ -1,19 +0,0 @@ - -/* Test that an actor that hasn't finished prevents termination */ - -@deprecated("Suppress warnings", since="2.11") -object Test { - import scala.actors.Actor - def main(args: Array[String]) { - Actor.actor { - try { - println("I'm going to make you wait.") - Thread.sleep(5000) - println("Ok, I'm done.") - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - } - } -} diff --git a/test/files/jvm/actor-uncaught-exception.check b/test/files/jvm/actor-uncaught-exception.check deleted file mode 100644 index 2c94e48371..0000000000 --- a/test/files/jvm/actor-uncaught-exception.check +++ /dev/null @@ -1,2 +0,0 @@ -OK -OK diff --git a/test/files/jvm/actor-uncaught-exception.scala b/test/files/jvm/actor-uncaught-exception.scala deleted file mode 100644 index c28ad2fa3c..0000000000 --- a/test/files/jvm/actor-uncaught-exception.scala +++ /dev/null @@ -1,64 +0,0 @@ -@deprecated("Suppress warnings", since="2.11") -object Test { -import scala.actors.{Actor, Exit} - -class MyException(msg: String) extends Exception(msg) { - override def fillInStackTrace() = this -} - - - case object StartError extends Actor { - def act() { - try { - throw new MyException("I don't want to run!") - } catch { - case e: Throwable if (!e.isInstanceOf[scala.util.control.ControlThrowable] && - !e.isInstanceOf[MyException]) => - e.printStackTrace() - } - } - } - - case object MessageError extends Actor { - def act() { - try { - react { - case _ => throw new MyException("No message for me!") - } - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - } - } - - case object Supervisor extends Actor { - def act() { - try { - trapExit = true - link(StartError) - link(MessageError) - StartError.start() - MessageError.start() - - Actor.loop { - react { - case Exit(actor, reason) => - println("OK") - if (actor == StartError) - MessageError ! 'ping - else - exit() - } - } - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - } - } - - def main(args: Array[String]) { - Supervisor.start() - } -} diff --git a/test/files/jvm/actor-uncaught-exception2.check b/test/files/jvm/actor-uncaught-exception2.check deleted file mode 100644 index a54f374aed..0000000000 --- a/test/files/jvm/actor-uncaught-exception2.check +++ /dev/null @@ -1,2 +0,0 @@ -UncaughtException(StartError,None,None,Test$MyException: I don't want to run!) -UncaughtException(MessageError,Some('ping),Some(Supervisor),Test$MyException: No message for me!) diff --git a/test/files/jvm/actor-uncaught-exception2.scala b/test/files/jvm/actor-uncaught-exception2.scala deleted file mode 100644 index 8327b4e19d..0000000000 --- a/test/files/jvm/actor-uncaught-exception2.scala +++ /dev/null @@ -1,63 +0,0 @@ -@deprecated("Suppress warnings", since="2.11") -object Test { -import scala.actors.{Actor, Exit, Debug} - -class MyException(msg: String) extends Exception(msg) { - override def fillInStackTrace() = this -} - - case object StartError extends Actor { - def act() { - try { - throw new MyException("I don't want to run!") - } catch { - case e: Throwable if (!e.isInstanceOf[scala.util.control.ControlThrowable] && - !e.isInstanceOf[MyException]) => - e.printStackTrace() - } - } - } - - case object MessageError extends Actor { - def act() { - try { - react { - case _ => throw new MyException("No message for me!") - } - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - } - } - - case object Supervisor extends Actor { - def act() { - try { - trapExit = true - link(StartError) - link(MessageError) - StartError.start() - MessageError.start() - - Actor.loop { - react { - case Exit(actor, reason) => - println(reason) - if (actor == StartError) - MessageError ! 'ping - else - exit() - } - } - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - } - } - - def main(args: Array[String]) { - Supervisor.start() - } -} diff --git a/test/files/jvm/daemon-actor-termination.check b/test/files/jvm/daemon-actor-termination.check deleted file mode 100644 index b2ff72fd0b..0000000000 --- a/test/files/jvm/daemon-actor-termination.check +++ /dev/null @@ -1,2 +0,0 @@ -MSG1 -MSG2 diff --git a/test/files/jvm/daemon-actor-termination.scala b/test/files/jvm/daemon-actor-termination.scala deleted file mode 100644 index 9bac6340ba..0000000000 --- a/test/files/jvm/daemon-actor-termination.scala +++ /dev/null @@ -1,40 +0,0 @@ - -/* Test that a daemon Actor that hasn't finished does not prevent termination */ - -@deprecated("Suppress warnings", since="2.11") -object Test { - - import scala.actors.{Actor, DaemonActor} - class MyDaemon extends DaemonActor { - def act() { - try { - react { - case 'hello => - println("MSG1") - reply(()) - react { - case 'bye => - println("done") - } - } - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - } - } - - def main(args: Array[String]) { - val daemon = new MyDaemon - daemon.start() - Actor.actor { - try { - daemon !? 'hello - println("MSG2") - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - } - } -} diff --git a/test/files/jvm/future-alarm.check b/test/files/jvm/future-alarm.check deleted file mode 100644 index 01a87d1c4c..0000000000 --- a/test/files/jvm/future-alarm.check +++ /dev/null @@ -1,20 +0,0 @@ -OK -OK -OK -OK -OK -OK -OK -OK -OK -OK -OK -OK -OK -OK -OK -OK -OK -OK -OK -OK diff --git a/test/files/jvm/future-alarm.scala b/test/files/jvm/future-alarm.scala deleted file mode 100644 index 3e71fa681c..0000000000 --- a/test/files/jvm/future-alarm.scala +++ /dev/null @@ -1,23 +0,0 @@ - - -@deprecated("Suppress warnings", since="2.11") -object Test { - import scala.actors.Futures - def main(args: Array[String]) { - try { - for (i <- 1 to 100000) { - Futures.alarm(0) - if (i % 10000 == 0) - println("OK") - } - for (_ <- 1 to 10) { - val ft = Futures.alarm(100) - ft() - println("OK") - } - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - } -} diff --git a/test/files/jvm/future-awaitall-zero.check b/test/files/jvm/future-awaitall-zero.check deleted file mode 100644 index d86bac9de5..0000000000 --- a/test/files/jvm/future-awaitall-zero.check +++ /dev/null @@ -1 +0,0 @@ -OK diff --git a/test/files/jvm/future-awaitall-zero.scala b/test/files/jvm/future-awaitall-zero.scala deleted file mode 100644 index 56f4bab16f..0000000000 --- a/test/files/jvm/future-awaitall-zero.scala +++ /dev/null @@ -1,24 +0,0 @@ - - -@deprecated("Suppress warnings", since="2.11") -object Test { - import scala.actors.Futures._ - import scala.actors.Actor._ - def main(args: Array[String]) { - try { - val ft1 = future { reactWithin(10000) { - case _ => println("FAIL") - } } - - val ft2 = future { reactWithin(20000) { - case _ => println("FAIL") - } } - - val res = awaitAll(0, ft1, ft2) - println("OK") - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - } -} diff --git a/test/files/jvm/future-spec.check b/test/files/jvm/future-spec.check index df1629dd7e..5c80aa5586 100644 --- a/test/files/jvm/future-spec.check +++ b/test/files/jvm/future-spec.check @@ -1 +1 @@ -warning: there was one deprecation warning; re-run with -deprecation for details +warning: there were 21 deprecation warnings; re-run with -deprecation for details diff --git a/test/files/jvm/future-spec/FutureTests.scala b/test/files/jvm/future-spec/FutureTests.scala index a290af9cd3..6b34d5bfaa 100644 --- a/test/files/jvm/future-spec/FutureTests.scala +++ b/test/files/jvm/future-spec/FutureTests.scala @@ -17,6 +17,19 @@ class FutureTests extends MinimalScalaTest { case "NoReply" => Promise[String]().future } + def fail(msg: String): Nothing = throw new AssertionError(msg) + + def ECNotUsed[T](f: ExecutionContext => T): T = { + val p = Promise[Runnable]() + val unusedEC: ExecutionContext = new ExecutionContext { + def execute(r: Runnable) = p.success(r) + def reportFailure(t: Throwable): Unit = p.failure(t) + } + val t = f(unusedEC) + assert(p.future.value == None, "Future executed logic!") + t + } + val defaultTimeout = 5 seconds /* future specification */ @@ -68,6 +81,60 @@ class FutureTests extends MinimalScalaTest { } } + "Futures" should { + "have proper toString representations" in { + import ExecutionContext.Implicits.global + val s = 5 + val f = new Exception("foo") + val t = Try(throw f) + + val expectFailureString = "Future(Failure("+f+"))" + val expectSuccessString = "Future(Success(5))" + val expectNotCompleteString = "Future(<not completed>)" + + Future.successful(s).toString mustBe expectSuccessString + Future.failed(f).toString mustBe expectFailureString + Future.fromTry(t).toString mustBe expectFailureString + val p = Promise[Int]() + p.toString mustBe expectNotCompleteString + Promise[Int]().success(s).toString mustBe expectSuccessString + Promise[Int]().failure(f).toString mustBe expectFailureString + Await.ready(Future { throw f }, 2000 millis).toString mustBe expectFailureString + Await.ready(Future { s }, 2000 millis).toString mustBe expectSuccessString + + Future.never.toString mustBe "Future(<never>)" + Future.unit.toString mustBe "Future(Success(()))" + } + + "have proper const representation for success" in { + val s = "foo" + val f = Future.successful(s) + + ECNotUsed(ec => f.onFailure({ case _ => fail("onFailure should not have been called") })(ec)) + assert( ECNotUsed(ec => f.recover({ case _ => fail("recover should not have been called")})(ec)) eq f) + assert( ECNotUsed(ec => f.recoverWith({ case _ => fail("flatMap should not have been called")})(ec)) eq f) + assert(f.fallbackTo(f) eq f, "Future.fallbackTo must be the same instance as Future.fallbackTo") + } + + "have proper const representation for failure" in { + val e = new Exception("foo") + val f = Future.failed[Future[String]](e) + + assert(f.mapTo[String] eq f, "Future.mapTo must be the same instance as Future.mapTo") + assert(f.zip(f) eq f, "Future.zip must be the same instance as Future.zip") + assert(f.flatten eq f, "Future.flatten must be the same instance as Future.flatten") + assert(f.failed eq f, "Future.failed must be the same instance as Future.failed") + + ECNotUsed(ec => f.foreach(_ => fail("foreach should not have been called"))(ec)) + ECNotUsed(ec => f.onSuccess({ case _ => fail("onSuccess should not have been called") })(ec)) + assert( ECNotUsed(ec => f.map(_ => fail("map should not have been called"))(ec)) eq f) + assert( ECNotUsed(ec => f.flatMap(_ => fail("flatMap should not have been called"))(ec)) eq f) + assert( ECNotUsed(ec => f.filter(_ => fail("filter should not have been called"))(ec)) eq f) + assert( ECNotUsed(ec => f.collect({ case _ => fail("collect should not have been called")})(ec)) eq f) + assert( ECNotUsed(ec => f.zipWith(f)({ (_,_) => fail("zipWith should not have been called")})(ec)) eq f) + } + } + "The Future companion object" should { "call ExecutionContext.prepare on apply" in { val p = Promise[Boolean]() @@ -85,6 +152,49 @@ class FutureTests extends MinimalScalaTest { Await.result(f, defaultTimeout) mustBe ("foo") Await.result(p.future, defaultTimeout) mustBe (true) } + + "have a unit member representing an already completed Future containing Unit" in { + assert(Future.unit ne null, "Future.unit must not be null") + assert(Future.unit eq Future.unit, "Future.unit must be the same instance as Future.unit") + assert(Future.unit.isCompleted, "Future.unit must already be completed") + assert(Future.unit.value.get == Success(()), "Future.unit must contain a Success(())") + } + + "have a never member representing a never completed Future of Nothing" in { + + val test: Future[Nothing] = Future.never + + //Verify stable identifier + test match { + case Future.`never` => + case _ => fail("Future.never did not match Future.`never`") + } + + assert(test eq Future.never, "Future.never must be the same instance as Future.never") + assert(test ne null, "Future.never must not be null") + assert(!test.isCompleted && test.value.isEmpty, "Future.never must never be completed") + assert(test.failed eq test) + assert(test.asInstanceOf[Future[Future[Nothing]]].flatten eq test) + assert(test.zip(test) eq test) + assert(test.fallbackTo(test) eq test) + assert(test.mapTo[String] eq test) + + ECNotUsed(ec => test.foreach(_ => fail("foreach should not have been called"))(ec)) + ECNotUsed(ec => test.onSuccess({ case _ => fail("onSuccess should not have been called") })(ec)) + ECNotUsed(ec => test.onFailure({ case _ => fail("onFailure should not have been called") })(ec)) + ECNotUsed(ec => test.onComplete({ case _ => fail("onComplete should not have been called") })(ec)) + ECNotUsed(ec => test.transform(identity, identity)(ec) eq test) + ECNotUsed(ec => test.transform(identity)(ec) eq test) + ECNotUsed(ec => test.transformWith(_ => fail("transformWith should not have been called"))(ec) eq test) + ECNotUsed(ec => test.map(identity)(ec) eq test) + ECNotUsed(ec => test.flatMap(_ => fail("flatMap should not have been called"))(ec) eq test) + ECNotUsed(ec => test.filter(_ => fail("filter should not have been called"))(ec) eq test) + ECNotUsed(ec => test.collect({ case _ => fail("collect should not have been called")})(ec) eq test) + ECNotUsed(ec => test.recover({ case _ => fail("recover should not have been called")})(ec) eq test) + ECNotUsed(ec => test.recoverWith({ case _ => fail("recoverWith should not have been called")})(ec) eq test) + ECNotUsed(ec => test.andThen({ case _ => fail("andThen should not have been called")})(ec) eq test) + ECNotUsed(ec => test.zipWith(test)({ (_,_) => fail("zipWith should not have been called")})(ec) eq test) + } } "The default ExecutionContext" should { @@ -218,6 +328,142 @@ class FutureTests extends MinimalScalaTest { } mustBe (r) } + "transform results to results" in { + val f1 = Future.successful("foo").transform(_.map(_.toUpperCase)) + val f2 = Future("bar").transform(_.map(_.toUpperCase)) + Await.result(f1, defaultTimeout) mustBe "FOO" + Await.result(f2, defaultTimeout) mustBe "BAR" + } + + "transform failures to failures" in { + val initial = new Exception("Initial") + val expected1 = new Exception("Expected1") + val expected2 = new Exception("Expected2") + val f1 = Future(throw initial) transform { + case Failure(`initial`) => Failure(expected1) + case x => x + } + val f2 = Future.failed(initial) transform { + case Failure(`initial`) => Failure(expected2) + case x => x + } + + intercept[Exception] { Await.result(f1, defaultTimeout) } mustBe expected1 + intercept[Exception] { Await.result(f2, defaultTimeout) } mustBe expected2 + } + + "transform failures to results" in { + val initial1 = new Exception("Initial1") + val initial2 = new Exception("Initial2") + val f1 = Future.failed[String](initial1) transform { + case Failure(`initial1`) => Success("foo") + case x => x + } + val f2 = Future[String](throw initial2) transform { + case Failure(`initial2`) => Success("bar") + case x => x + } + Await.result(f1, defaultTimeout) mustBe "foo" + Await.result(f2, defaultTimeout) mustBe "bar" + } + + "transform results to failures" in { + val expected1 = new Exception("Expected1") + val expected2 = new Exception("Expected2") + val expected3 = new Exception("Expected3") + val f1 = Future.successful("foo") transform { + case Success("foo") => Failure(expected1) + case x => x + } + val f2 = Future("bar") transform { + case Success("bar") => Failure(expected2) + case x => x + } + val f3 = Future("bar") transform { + case Success("bar") => throw expected3 + case x => x + } + intercept[Exception] { Await.result(f1, defaultTimeout) } mustBe expected1 + intercept[Exception] { Await.result(f2, defaultTimeout) } mustBe expected2 + intercept[Exception] { Await.result(f3, defaultTimeout) } mustBe expected3 + } + + "transformWith results" in { + val f1 = Future.successful("foo").transformWith { + case Success(r) => Future(r.toUpperCase) + case f @ Failure(_) => Future.fromTry(f) + } + val f2 = Future("bar").transformWith { + case Success(r) => Future(r.toUpperCase) + case f @ Failure(_) => Future.fromTry(f) + } + Await.result(f1, defaultTimeout) mustBe "FOO" + Await.result(f2, defaultTimeout) mustBe "BAR" + } + + "transformWith failures" in { + val initial = new Exception("Initial") + val expected1 = new Exception("Expected1") + val expected2 = new Exception("Expected2") + val expected3 = new Exception("Expected3") + + val f1 = Future[Int](throw initial).transformWith { + case Failure(`initial`) => Future failed expected1 + case x => Future fromTry x + } + val f2 = Future.failed[Int](initial).transformWith { + case Failure(`initial`) => Future failed expected2 + case x => Future fromTry x + } + val f3 = Future[Int](throw initial).transformWith { + case Failure(`initial`) => throw expected3 + case x => Future fromTry x + } + + intercept[Exception] { Await.result(f1, defaultTimeout) } mustBe expected1 + intercept[Exception] { Await.result(f2, defaultTimeout) } mustBe expected2 + intercept[Exception] { Await.result(f3, defaultTimeout) } mustBe expected3 + } + + "transformWith failures to future success" in { + val initial = new Exception("Initial") + val f1 = Future.failed[String](initial).transformWith { + case Failure(`initial`) => Future("FOO") + case _ => Future failed initial + } + val f2 = Future[String](throw initial).transformWith { + case Failure(`initial`) => Future("BAR") + case _ => Future failed initial + } + Await.result(f1, defaultTimeout) mustBe "FOO" + Await.result(f2, defaultTimeout) mustBe "BAR" + } + + "transformWith results to future failures" in { + val initial = new Exception("Initial") + val expected1 = new Exception("Expected1") + val expected2 = new Exception("Expected2") + val expected3 = new Exception("Expected3") + + val f1 = Future[String]("FOO") transformWith { + case Success("FOO") => Future failed expected1 + case _ => Future successful "FOO" + } + val f2 = Future.successful("FOO") transformWith { + case Success("FOO") => Future failed expected2 + case _ => Future successful "FOO" + } + val f3 = Future.successful("FOO") transformWith { + case Success("FOO") => throw expected3 + case _ => Future successful "FOO" + } + + + intercept[Exception] { Await.result(f1, defaultTimeout) } mustBe expected1 + intercept[Exception] { Await.result(f2, defaultTimeout) } mustBe expected2 + intercept[Exception] { Await.result(f3, defaultTimeout) } mustBe expected3 + } + "andThen like a boss" in { val q = new java.util.concurrent.LinkedBlockingQueue[Int] for (i <- 1 to 1000) { @@ -281,6 +527,33 @@ class FutureTests extends MinimalScalaTest { Await.result(successful, timeout) mustBe (("foo", "foo")) } + "zipWith" in { + val timeout = 10000 millis + val f = new IllegalStateException("test") + intercept[IllegalStateException] { + val failed = Future.failed[String](f).zipWith(Future.successful("foo")) { _ -> _ } + Await.result(failed, timeout) + } mustBe (f) + + intercept[IllegalStateException] { + val failed = Future.successful("foo").zipWith(Future.failed[String](f)) { _ -> _ } + Await.result(failed, timeout) + } mustBe (f) + + intercept[IllegalStateException] { + val failed = Future.failed[String](f).zipWith(Future.failed[String](f)) { _ -> _ } + Await.result(failed, timeout) + } mustBe (f) + + val successful = Future.successful("foo").zipWith(Future.successful("foo")) { _ -> _ } + Await.result(successful, timeout) mustBe (("foo", "foo")) + + val failure = Future.successful("foo").zipWith(Future.successful("foo")) { (_,_) => throw f } + intercept[IllegalStateException] { + Await.result(failure, timeout) + } mustBe (f) + } + "fold" in { val timeout = 10000 millis def async(add: Int, wait: Int) = Future { diff --git a/test/files/jvm/future-termination.check b/test/files/jvm/future-termination.check deleted file mode 100644 index dc335465d4..0000000000 --- a/test/files/jvm/future-termination.check +++ /dev/null @@ -1 +0,0 @@ -I can't wait that long, bye. diff --git a/test/files/jvm/future-termination.scala b/test/files/jvm/future-termination.scala deleted file mode 100644 index 90ea336ce8..0000000000 --- a/test/files/jvm/future-termination.scala +++ /dev/null @@ -1,21 +0,0 @@ - -/* Test that unevaluated futures do not prevent program termination */ - - -@deprecated("Suppress warnings", since="2.11") -object Test { - import scala.actors.Futures - def main(args: Array[String]) { - try { - val meaningOfLife = Futures.future { - Thread.sleep(5000) // pretend this is a harder problem than it is - println("I have the answer!") - 42 - } - println("I can't wait that long, bye.") - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - } -} diff --git a/test/files/jvm/reactor-exceptionOnSend.check b/test/files/jvm/reactor-exceptionOnSend.check deleted file mode 100644 index 45d62e26a7..0000000000 --- a/test/files/jvm/reactor-exceptionOnSend.check +++ /dev/null @@ -1,2 +0,0 @@ -receiver handles exception -process diff --git a/test/files/jvm/reactor-exceptionOnSend.scala b/test/files/jvm/reactor-exceptionOnSend.scala deleted file mode 100644 index 6d79fc9d13..0000000000 --- a/test/files/jvm/reactor-exceptionOnSend.scala +++ /dev/null @@ -1,58 +0,0 @@ - - -@deprecated("Suppress warnings", since="2.11") -object Test { -import scala.actors.Reactor -import scala.actors.Actor._ - -case class MyException(text: String) extends Exception(text) - -object A extends Reactor[Any] { - override def exceptionHandler = { - case MyException(text) => - println("receiver handles exception") - } - - def guard(): Boolean = - if (state == 0) { - state = 1 - throw MyException("illegal state") - } else - true - - var state = 0 - - def act() { - try { - loop { - react { - case 'hello if guard() => - println("process") - exit() - } - } - } catch { - case e: Throwable if (!e.isInstanceOf[scala.util.control.ControlThrowable] && - !e.isInstanceOf[MyException]) => - e.printStackTrace() - } - } -} - -object B extends Reactor[Any] { - def act() { - try { - A.start() - A ! 'hello - A ! 'hello - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - } -} - - def main(args: Array[String]) { - B.start() - } -} diff --git a/test/files/jvm/reactor-producer-consumer.check b/test/files/jvm/reactor-producer-consumer.check deleted file mode 100644 index d971cea19e..0000000000 --- a/test/files/jvm/reactor-producer-consumer.check +++ /dev/null @@ -1,10 +0,0 @@ -42 -42 -42 -42 -42 -42 -42 -42 -42 -42 diff --git a/test/files/jvm/reactor-producer-consumer.scala b/test/files/jvm/reactor-producer-consumer.scala deleted file mode 100644 index ec34febe01..0000000000 --- a/test/files/jvm/reactor-producer-consumer.scala +++ /dev/null @@ -1,97 +0,0 @@ - - -@deprecated("Suppress warnings", since="2.11") -object Test { - import scala.actors.Reactor - case class Stop() - case class Get(from: Reactor[Any]) - case class Put(x: Int) - - class UnboundedBuffer extends Reactor[Any] { - def act() { - try { - react { - case Stop() => - case Get(from) => - val consumer = from - react { - case msg @ Put(x) => - consumer ! x - act() - } - } - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - } - } - - class Producer(buf: UnboundedBuffer, n: Int, delay: Long, parent: Reactor[Any]) extends Reactor[Any] { - def act() { - try { - var i = 0 - while (i < n) { - i += 1 - if (delay > 0) Thread.sleep(delay) - buf ! Put(42) - } - parent ! Stop() - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - } - } - - class Consumer(buf: UnboundedBuffer, n: Int, delay: Long, parent: Reactor[Any]) extends Reactor[Any] { - val step = n / 10 - var i = 0 - def act() { - try { - if (i < n) { - i += 1 - if (delay > 0) Thread.sleep(delay) - buf ! Get(this) - react { - case res => - if (i % step == 0) - println(res) - act() - } - } else { - parent ! Stop() - } - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - } - } - - def main(args: Array[String]) { - val parent = new Reactor[Any] { - def act() { - try { - val buffer = new UnboundedBuffer - buffer.start() - val producer = new Producer(buffer, 10000, 0, this) - producer.start() - val consumer = new Consumer(buffer, 10000, 0, this) - consumer.start() - react { - case Stop() => - react { - case Stop() => - buffer ! Stop() - } - } - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - } - } - parent.start() - } -} diff --git a/test/files/jvm/reactor.check b/test/files/jvm/reactor.check deleted file mode 100644 index 7b16085797..0000000000 --- a/test/files/jvm/reactor.check +++ /dev/null @@ -1,22 +0,0 @@ -Pong: ping 0 -Ping: pong -Pong: ping 10000 -Ping: pong -Pong: ping 20000 -Ping: pong -Pong: ping 30000 -Ping: pong -Pong: ping 40000 -Ping: pong -Pong: ping 50000 -Ping: pong -Pong: ping 60000 -Ping: pong -Pong: ping 70000 -Ping: pong -Pong: ping 80000 -Ping: pong -Pong: ping 90000 -Ping: pong -Ping: stop -Pong: stop diff --git a/test/files/jvm/reactor.scala b/test/files/jvm/reactor.scala deleted file mode 100644 index 91ded27f07..0000000000 --- a/test/files/jvm/reactor.scala +++ /dev/null @@ -1,72 +0,0 @@ -/** - * Ping pong example for Reactor. - * - * @author Philipp Haller - */ - -@deprecated("Suppress warnings", since="2.11") -object Test { - -import scala.actors.Reactor - -case class Ping(from: Reactor[Any]) -case object Pong -case object Stop - - def main(args: Array[String]) { - val pong = new PongActor - val ping = new PingActor(100000, pong) - ping.start - pong.start - } - -class PingActor(count: Int, pong: Reactor[Any]) extends Reactor[Any] { - def act() { - try { - var pingsLeft = count - 1 - pong ! Ping(this) - loop { - react { - case Pong => - if (pingsLeft % 10000 == 0) - println("Ping: pong") - if (pingsLeft > 0) { - pong ! Ping(this) - pingsLeft -= 1 - } else { - println("Ping: stop") - pong ! Stop - exit() - } - } - } - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - } -} - -class PongActor extends Reactor[Any] { - def act() { - try { - var pongCount = 0 - loop { - react { - case Ping(from) => - if (pongCount % 10000 == 0) - println("Pong: ping "+pongCount) - from ! Pong - pongCount += 1 - case Stop => - println("Pong: stop") - exit() - } - } - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - } -} -} diff --git a/test/files/jvm/replyablereactor.check b/test/files/jvm/replyablereactor.check deleted file mode 100644 index 0944b17279..0000000000 --- a/test/files/jvm/replyablereactor.check +++ /dev/null @@ -1,5 +0,0 @@ -'hello -'hello -'hello -'hello -'hello diff --git a/test/files/jvm/replyablereactor.scala b/test/files/jvm/replyablereactor.scala deleted file mode 100644 index 4c4e13d9ab..0000000000 --- a/test/files/jvm/replyablereactor.scala +++ /dev/null @@ -1,59 +0,0 @@ - - -@deprecated("Suppress warnings", since="2.11") -object Test { -import scala.actors.ReplyReactor - -class MyActor extends ReplyReactor { - def act() { - try { - loop { - react { - case 'hello => - sender ! 'hello - case 'stop => - exit() - } - } - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - } -} - - def main(args: Array[String]) { - val a = new MyActor - a.start() - - val b = new ReplyReactor { - def act() { - try { - react { - case r: MyActor => - var i = 0 - loop { - i += 1 - val ft = r !! 'hello - ft.inputChannel.react { - case msg => - if (i % 10000 == 0) - println(msg) - if (i >= 50000) { - r ! 'stop - exit() - } - } - } - } - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - } - } - b.start() - - b ! a - } -} diff --git a/test/files/jvm/replyablereactor2.check b/test/files/jvm/replyablereactor2.check deleted file mode 100644 index 0944b17279..0000000000 --- a/test/files/jvm/replyablereactor2.check +++ /dev/null @@ -1,5 +0,0 @@ -'hello -'hello -'hello -'hello -'hello diff --git a/test/files/jvm/replyablereactor2.scala b/test/files/jvm/replyablereactor2.scala deleted file mode 100644 index 21f33cce56..0000000000 --- a/test/files/jvm/replyablereactor2.scala +++ /dev/null @@ -1,58 +0,0 @@ - - -@deprecated("Suppress warnings", since="2.11") -object Test { -import scala.actors._ -import scala.actors.Actor._ - -class MyActor extends ReplyReactor { - def act() { - try { - loop { - react { - case 'hello => - sender ! 'hello - case 'stop => - exit() - } - } - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - } -} - - def main(args: Array[String]) { - val a = new MyActor - a.start() - - val b = new Reactor[Any] { - def act() { - try { - react { - case r: MyActor => - var i = 0 - loop { - i += 1 - val ft = r !! 'hello - val msg = ft() - if (i % 10000 == 0) - println(msg) - if (i >= 50000) { - r ! 'stop - exit() - } - } - } - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - } - } - b.start() - - b ! a - } -} diff --git a/test/files/jvm/replyablereactor3.check b/test/files/jvm/replyablereactor3.check deleted file mode 100644 index 0944b17279..0000000000 --- a/test/files/jvm/replyablereactor3.check +++ /dev/null @@ -1,5 +0,0 @@ -'hello -'hello -'hello -'hello -'hello diff --git a/test/files/jvm/replyablereactor3.scala b/test/files/jvm/replyablereactor3.scala deleted file mode 100644 index 5810ed053f..0000000000 --- a/test/files/jvm/replyablereactor3.scala +++ /dev/null @@ -1,57 +0,0 @@ - - -@deprecated("Suppress warnings", since="2.11") -object Test { -import scala.actors._ -import scala.actors.Actor._ - -class MyActor extends ReplyReactor { - def act() { - try { - loop { - react { - case 'hello => - sender ! 'hello - case 'stop => - exit() - } - } - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - } -} - - def main(args: Array[String]) { - val a = new MyActor - a.start() - - val b = new Reactor[Any] { - def act() { - try { - react { - case r: MyActor => - var i = 0 - loop { - i += 1 - val msg = r !? 'hello - if (i % 10000 == 0) - println(msg) - if (i >= 50000) { - r ! 'stop - exit() - } - } - } - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - } - } - b.start() - - b ! a - } -} diff --git a/test/files/jvm/replyablereactor4.check b/test/files/jvm/replyablereactor4.check deleted file mode 100644 index cac0fffe3b..0000000000 --- a/test/files/jvm/replyablereactor4.check +++ /dev/null @@ -1,5 +0,0 @@ -Some('hello) -Some('hello) -Some('hello) -Some('hello) -Some('hello) diff --git a/test/files/jvm/replyablereactor4.scala b/test/files/jvm/replyablereactor4.scala deleted file mode 100644 index 95d63684dd..0000000000 --- a/test/files/jvm/replyablereactor4.scala +++ /dev/null @@ -1,57 +0,0 @@ - - -@deprecated("Suppress warnings", since="2.11") -object Test { -import scala.actors._ -import scala.actors.Actor._ - -class MyActor extends ReplyReactor { - def act() { - try { - loop { - react { - case 'hello => - sender ! 'hello - case 'stop => - exit() - } - } - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - } -} - - def main(args: Array[String]) { - val a = new MyActor - a.start() - - val b = new Reactor[Any] { - def act() { - try { - react { - case r: MyActor => - var i = 0 - loop { - i += 1 - val msg = r !? (500, 'hello) - if (i % 200000 == 0) - println(msg) - if (i >= 1000000) { - r ! 'stop - exit() - } - } - } - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - } - } - b.start() - - b ! a - } -} diff --git a/test/files/jvm/replyreactor-react-sender.check b/test/files/jvm/replyreactor-react-sender.check deleted file mode 100644 index d86bac9de5..0000000000 --- a/test/files/jvm/replyreactor-react-sender.check +++ /dev/null @@ -1 +0,0 @@ -OK diff --git a/test/files/jvm/replyreactor-react-sender.scala b/test/files/jvm/replyreactor-react-sender.scala deleted file mode 100644 index fdcea09035..0000000000 --- a/test/files/jvm/replyreactor-react-sender.scala +++ /dev/null @@ -1,53 +0,0 @@ - - -@deprecated("Suppress warnings", since="2.11") -object Test { - import scala.actors.ReplyReactor - import scala.actors.Actor._ - - val NUM = 2000 - - def main(args: Array[String]) { - var b: ReplyReactor = null - - val a = new ReplyReactor { - def act() { - try { - var i = 0 - loopWhile (i < NUM) { - i += 1 - react { - case 'hello if sender == this => b ! 'fail - case 'hello if sender == b => // do nothing - } - } andThen { - b ! 'ok - } - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - } - } - a.start() - - b = new ReplyReactor { - def act() { - try { - for (_ <- 0 until NUM) - a ! 'hello - react { - case 'fail => println("FAIL") - case 'ok => println("OK") - case other => println(other) - } - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - } - } - b.start() - } - -} diff --git a/test/files/jvm/replyreactor.check b/test/files/jvm/replyreactor.check deleted file mode 100644 index 4b2fea867a..0000000000 --- a/test/files/jvm/replyreactor.check +++ /dev/null @@ -1 +0,0 @@ -'hello diff --git a/test/files/jvm/replyreactor.scala b/test/files/jvm/replyreactor.scala deleted file mode 100644 index 7512fb0eb2..0000000000 --- a/test/files/jvm/replyreactor.scala +++ /dev/null @@ -1,43 +0,0 @@ - - -@deprecated("Suppress warnings", since="2.11") -object Test { - import scala.actors.ReplyReactor - def main(args: Array[String]) { - val a = new ReplyReactor { - def act() { - try { - react { - case 'hello => - sender ! 'hello - } - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - } - } - a.start() - - val b = new ReplyReactor { - def act() { - try { - react { - case r: ReplyReactor => - r ! 'hello - react { - case any => - println(any) - } - } - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - } - } - b.start() - - b ! a - } -} diff --git a/test/files/jvm/scala-concurrent-tck.check b/test/files/jvm/scala-concurrent-tck.check new file mode 100644 index 0000000000..bbe73c9982 --- /dev/null +++ b/test/files/jvm/scala-concurrent-tck.check @@ -0,0 +1 @@ +warning: there were 74 deprecation warnings; re-run with -deprecation for details diff --git a/test/files/jvm/scala-concurrent-tck.scala b/test/files/jvm/scala-concurrent-tck.scala index ce86d4aef0..ba405e97bd 100644 --- a/test/files/jvm/scala-concurrent-tck.scala +++ b/test/files/jvm/scala-concurrent-tck.scala @@ -165,6 +165,100 @@ def testTransformFailure(): Unit = once { g onFailure { case e => done(e eq transformed) } } + def testTransformResultToResult(): Unit = once { + done => + Future("foo").transform { + case Success(s) => Success(s.toUpperCase) + case Failure(f) => throw new Exception("test failed") + } onComplete { + case Success("FOO") => done(true) + case _ => done(false) + } + } + + def testTransformResultToFailure(): Unit = once { + done => + val e = new Exception("expected") + Future("foo").transform { + case Success(s) => Failure(e) + case Failure(f) => throw new Exception("test failed") + } onComplete { + case Failure(`e`) => done(true) + case _ => done(false) + } + } + + def testTransformFailureToResult(): Unit = once { + done => + val e = "foo" + Future(throw new Exception("initial")).transform { + case Success(s) => throw new Exception("test failed") + case Failure(f) => Success(e) + } onComplete { + case Success(`e`) => done(true) + case _ => done(false) + } + } + + def testTransformFailureToFailure(): Unit = once { + done => + val e = new Exception("expected") + Future(throw new Exception("initial")).transform { + case Success(s) => throw new Exception("test failed") + case Failure(f) => Failure(e) + } onComplete { + case Failure(`e`) => done(true) + case _ => done(false) + } + } + + def testTransformWithResultToResult(): Unit = once { + done => + Future("foo").transformWith { + case Success(s) => Future(s.toUpperCase) + case Failure(f) => throw new Exception("test failed") + } onComplete { + case Success("FOO") => done(true) + case _ => done(false) + } + } + + def testTransformWithResultToFailure(): Unit = once { + done => + val e = new Exception("expected") + Future("foo").transformWith { + case Success(s) => Future(throw e) + case Failure(f) => throw new Exception("test failed") + } onComplete { + case Failure(`e`) => done(true) + case _ => done(false) + } + } + + def testTransformWithFailureToResult(): Unit = once { + done => + val e = "foo" + Future(throw new Exception("initial")).transformWith { + case Success(s) => throw new Exception("test failed") + case Failure(f) => Future(e) + } onComplete { + case Success(`e`) => done(true) + case _ => done(false) + } + } + + def testTransformWithFailureToFailure(): Unit = once { + done => + val e = new Exception("expected") + Future(throw new Exception("initial")).transformWith { + case Success(s) => throw new Exception("test failed") + case Failure(f) => Future(throw e) + } onComplete { + case Failure(`e`) => done(true) + case _ => done(false) + } + } + def testFoldFailure(): Unit = once { done => val f = Future[Unit] { throw new Exception("expected") } @@ -352,6 +446,14 @@ def testTransformFailure(): Unit = once { h onFailure { case e => done(e eq cause) } } + def testFallbackToThis(): Unit = { + def check(f: Future[Int]) = assert((f fallbackTo f) eq f) + + check(Future { 1 }) + check(Future.successful(1)) + check(Future.failed[Int](new Exception)) + } + testMapSuccess() testMapFailure() testFlatMapSuccess() @@ -373,6 +475,16 @@ def testTransformFailure(): Unit = once { testFallbackToFailure() testTransformSuccess() testTransformSuccessPF() + testTransformFailure() + testTransformFailurePF() + testTransformResultToResult() + testTransformResultToFailure() + testTransformFailureToResult() + testTransformFailureToFailure() + testTransformWithResultToResult() + testTransformWithResultToFailure() + testTransformWithFailureToResult() + testTransformWithFailureToFailure() } @@ -593,6 +705,17 @@ trait Exceptions extends TestBase { } +trait GlobalExecutionContext extends TestBase { + def testNameOfGlobalECThreads(): Unit = once { + done => Future({ + val expectedName = "scala-execution-context-global-"+ Thread.currentThread.getId + done(expectedName == Thread.currentThread.getName) + })(ExecutionContext.global) + } + + testNameOfGlobalECThreads() +} + trait CustomExecutionContext extends TestBase { import scala.concurrent.{ ExecutionContext, Awaitable } @@ -772,6 +895,7 @@ with FutureProjections with Promises with BlockContexts with Exceptions +with GlobalExecutionContext with CustomExecutionContext with ExecutionContextPrepare { diff --git a/test/files/jvm/scheduler-adapter.check b/test/files/jvm/scheduler-adapter.check deleted file mode 100644 index b278674cf0..0000000000 --- a/test/files/jvm/scheduler-adapter.check +++ /dev/null @@ -1,6 +0,0 @@ -before -before -before -Two: received msg -before -One: received msg diff --git a/test/files/jvm/scheduler-adapter.scala b/test/files/jvm/scheduler-adapter.scala deleted file mode 100644 index 1c9cfe7019..0000000000 --- a/test/files/jvm/scheduler-adapter.scala +++ /dev/null @@ -1,54 +0,0 @@ - - -@deprecated("Suppress warnings", since="2.11") -object Test { -import scala.actors.{Actor, SchedulerAdapter} - -trait AdaptedActor extends Actor { - override def scheduler = - Test.adapted -} - -object One extends AdaptedActor { - def act() { - try { - Two.start() - Two ! 'MsgForTwo - react { - case 'MsgForOne => - println("One: received msg") - } - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - } -} - -object Two extends AdaptedActor { - def act() { - try { - react { - case 'MsgForTwo => - println("Two: received msg") - One ! 'MsgForOne - } - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - } -} - - val adapted = - new SchedulerAdapter { - def execute(block: => Unit) { - println("before") - block - } - } - - def main(args: Array[String]) { - One.start() - } -} diff --git a/test/files/jvm/t1449.check b/test/files/jvm/t1449.check deleted file mode 100644 index d81cc0710e..0000000000 --- a/test/files/jvm/t1449.check +++ /dev/null @@ -1 +0,0 @@ -42 diff --git a/test/files/jvm/t1449.scala b/test/files/jvm/t1449.scala deleted file mode 100644 index 7917d6f6d5..0000000000 --- a/test/files/jvm/t1449.scala +++ /dev/null @@ -1,28 +0,0 @@ - - -@deprecated("Suppress warnings", since="2.11") -object Test { - import scala.actors.Actor._ - import scala.actors.Future - import scala.actors.Futures._ - def main(args: Array[String]) { - val a = actor { - try { - react { - case ft: Future[a] => - println(ft()) - } - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - } - try { - val ft = future { 42 } - a ! ft - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - } -} diff --git a/test/files/jvm/t1948.scala b/test/files/jvm/t1948.scala deleted file mode 100644 index 95777b8037..0000000000 --- a/test/files/jvm/t1948.scala +++ /dev/null @@ -1,26 +0,0 @@ - - -@deprecated("Suppress warnings", since="2.11") -object Test { - import scala.actors._ - import scala.actors.Actor._ - - def main (args: Array[String]) { - val actors = (1 to 1000).toList map { x => actor { - try { - loop { react { - case x: Array[Int] => reply ("OK"); exit }} - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - } } - try { - actors foreach { x => x !? new Array[Int] (1000000) } - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - } - -} diff --git a/test/files/jvm/t2359.check b/test/files/jvm/t2359.check deleted file mode 100644 index 8a1218a102..0000000000 --- a/test/files/jvm/t2359.check +++ /dev/null @@ -1,5 +0,0 @@ -1 -2 -3 -4 -5 diff --git a/test/files/jvm/t2359.scala b/test/files/jvm/t2359.scala deleted file mode 100644 index 76b78d44f7..0000000000 --- a/test/files/jvm/t2359.scala +++ /dev/null @@ -1,48 +0,0 @@ - - -@deprecated("Suppress warnings", since="2.11") -object Test { - import scala.actors.Futures._ - def main(args: Array[String]) { - val x = future { - try { - System.out.println(1) - future { - try { - System.out.println(2) - future { - try { - System.out.println(3) - future { - try { - System.out.println(4) - future { - try { - System.out.println(5) - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - }() - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - }() - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - }() - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - }() - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - }() - } -} diff --git a/test/files/jvm/t2530.check b/test/files/jvm/t2530.check deleted file mode 100644 index 0f1c02158d..0000000000 --- a/test/files/jvm/t2530.check +++ /dev/null @@ -1,21 +0,0 @@ - Iteration 1 succeeded - Iteration 2 succeeded - Iteration 3 succeeded - Iteration 4 succeeded - Iteration 5 succeeded - Iteration 6 succeeded - Iteration 7 succeeded - Iteration 8 succeeded - Iteration 9 succeeded - Iteration 10 succeeded - Iteration 11 succeeded - Iteration 12 succeeded - Iteration 13 succeeded - Iteration 14 succeeded - Iteration 15 succeeded - Iteration 16 succeeded - Iteration 17 succeeded - Iteration 18 succeeded - Iteration 19 succeeded - Iteration 20 succeeded -Test done with no deadlock. Try again, it will not occur... diff --git a/test/files/jvm/t2530.scala b/test/files/jvm/t2530.scala deleted file mode 100644 index b41661e623..0000000000 --- a/test/files/jvm/t2530.scala +++ /dev/null @@ -1,98 +0,0 @@ - - -@deprecated("Suppress warnings", since="2.11") -object Test { - import scala.actors.{Future, Futures} - - def main(args:Array[String]) : Unit = { - //scala.actors.Debug.level = 3 - val size = /*if (args.length > 0) Integer.parseInt(args(0)) else*/ 8 - val (m,n) = (size, size) - def random = (for (i <- 0 until m*n) yield java.lang.Math.random).toArray - val A = Matrix(m, n, random) - val B = Matrix(m, n, random) - val format = new java.text.DecimalFormat("000.00'ms'"); - var iter = 1 - val done = 21 - while (iter < done) { - val start = System.nanoTime() - val result = A * B - val time = System.nanoTime() - start - result match { - case Some(result) => { - printf(" Iteration %2d succeeded %n", iter/*, format.format(time / 1e6)*/) - iter += 1 - } - case None => { - printf(">>>> Iteration %2d failed after %s <<<<< %n", iter, format.format(time / 1e6)) - iter = done - } - } - } - println("Test done with no deadlock. Try again, it will not occur...") - } - -case class Matrix(numRows: Int, numCols: Int, values: Array[Double]) { - - def this(m:Int, n:Int) = this(m, n, new Array[Double](m*n)) - - def offset(i:Int, j:Int) = i * numCols + j - def apply(i:Int, j:Int) = values( offset(i,j) ) - def update(i:Int, j:Int, value:Double) = values(offset(i, j)) = value; - - def *(by:Matrix) = { - val aM = numRows - val aN = numCols - assert(aM == by.numCols) - assert(aN == by.numRows) - val resultMatrix = new Matrix(aM, aM) - val m = aM.asInstanceOf[Int] - val n = aN.asInstanceOf[Int] - - val rows = for (j <- 0 until m) yield { - Futures.future { - try { - val b_j = new Array[Double](n) - var k = 0 - while (k < n) { // sadly, while loops are still faster than for loops - b_j(k) = by(k,j) - k += 1 - } - var i = 0 - while (i < m) { - var s = 0.0d; - k = 0 - while (k < n) { - s += Matrix.this(i,k) * b_j(k) - k += 1 - } - resultMatrix(i,j) = s - i += 1 - } - //printf("future %d of %d completed.%n", j, m) - j - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - } - } - - // rows.foreach { x=> x() } // This appears to force sequential execution, so use: - // timeout is 10 years; see http://lampsvn.epfl.ch/trac/scala/ticket/2515 - val done: List[Option[Any]] = try { - Futures.awaitAll(10*365*24*60*60*1000, rows.toArray : _*) // list to array, as varargs. - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - List() - } - - if (done.contains(None)) - None - else - Some(resultMatrix) - } - -} -} diff --git a/test/files/jvm/t3102.check b/test/files/jvm/t3102.check deleted file mode 100644 index d705e0b20e..0000000000 --- a/test/files/jvm/t3102.check +++ /dev/null @@ -1,2 +0,0 @@ -42 -OK diff --git a/test/files/jvm/t3102.scala b/test/files/jvm/t3102.scala deleted file mode 100644 index d0e0704859..0000000000 --- a/test/files/jvm/t3102.scala +++ /dev/null @@ -1,39 +0,0 @@ - - -@deprecated("Suppress warnings", since="2.11") -object Test { - import scala.actors.{Actor, TIMEOUT} - import Actor._ - - def main(args: Array[String]) { - val a = actor { - try { - react { - case 'hello => - reply(42) - } - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - } - - val b = actor { - try { - self.trapExit = true - val ft = a !! 'hello - println(ft()) - // no message should be left over in mailbox - reactWithin(0) { - case TIMEOUT => - println("OK") - case any => - println(any) - } - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - } - } -} diff --git a/test/files/jvm/t3356.check b/test/files/jvm/t3356.check deleted file mode 100644 index 25f47b70c9..0000000000 --- a/test/files/jvm/t3356.check +++ /dev/null @@ -1,3 +0,0 @@ -sending download requests -Couldn't download image because of java.lang.Exception: no connection -Couldn't download image because of java.lang.Exception: no connection diff --git a/test/files/jvm/t3356.scala b/test/files/jvm/t3356.scala deleted file mode 100644 index 53bfd737cd..0000000000 --- a/test/files/jvm/t3356.scala +++ /dev/null @@ -1,58 +0,0 @@ - - -@deprecated("Suppress warnings", since="2.11") -object Test { -import scala.actors.{Actor, Exit, !, UncaughtException} -import Actor._ - -case class ImageInfo(text: String) { - def downloadImage(): ImageData = { - ImageData(text) - } -} - -case class ImageData(text: String) -case class Download(info: ImageInfo) - - - def scanForImageInfo(url: String): List[ImageInfo] = - List(ImageInfo("A"), ImageInfo("B")) - - def renderImage(data: ImageData) { - println("rendering image "+data.text) - } - - def renderImages(url: String) { - val imageInfos = scanForImageInfo(url) - println("sending download requests") - val dataFutures = for (info <- imageInfos) yield { - val loader = link { - react { case Download(info) => - throw new Exception("no connection") - reply(info.downloadImage()) - }; {} - } - loader !! Download(info) - } - var i = 0 - loopWhile (i < imageInfos.size) { - i += 1 - val FutureInput = dataFutures(i-1).inputChannel - react { - case FutureInput ! (data @ ImageData(_)) => - renderImage(data) - case Exit(from, UncaughtException(_, Some(Download(info)), _, _, cause)) => - println("Couldn't download image because of "+cause) - } - } - println("OK, all images rendered.") - } - - def main(args: Array[String]) { - actor { - self.trapExit = true - renderImages("panorama.epfl.ch") - } - } - -} diff --git a/test/files/jvm/t3365.check b/test/files/jvm/t3365.check deleted file mode 100644 index 0944b17279..0000000000 --- a/test/files/jvm/t3365.check +++ /dev/null @@ -1,5 +0,0 @@ -'hello -'hello -'hello -'hello -'hello diff --git a/test/files/jvm/t3365.scala b/test/files/jvm/t3365.scala deleted file mode 100644 index 8321428093..0000000000 --- a/test/files/jvm/t3365.scala +++ /dev/null @@ -1,68 +0,0 @@ - - -@deprecated("Suppress warnings", since="2.11") -object Test { -import scala.actors.{ReplyReactor, Channel, Actor, Future} - -case class ChannelMsg(chan: Channel[Any]) - -class MyActor extends Actor { - def act() { - try { - val chan = new Channel[Any](this) - loop { - react { - case other: ReplyReactor => - other ! ChannelMsg(chan) - loop { - chan.react { - case 'hello => - reply('hello) - case 'stop => - exit() - } - } - } - } - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - } -} - - def main(args: Array[String]) { - val a = new MyActor - a.start() - - val b = new Actor { - def act() { - try { - react { - case ChannelMsg(c) => - var i = 0 - loop { - i += 1 - val ft: Future[Any] = c !! 'hello - ft.inputChannel.react { - case msg => - if (i % 10000 == 0) - println(msg) - if (i >= 50000) { - c ! 'stop - exit() - } - } - } - } - } catch { - case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => - e.printStackTrace() - } - } - } - b.start() - - a ! b - } -} diff --git a/test/files/jvm/t3407.check b/test/files/jvm/t3407.check deleted file mode 100644 index a133c88bbe..0000000000 --- a/test/files/jvm/t3407.check +++ /dev/null @@ -1,10 +0,0 @@ -result: 42 -result: 42 -result: 42 -result: 42 -result: 42 -result: 42 -result: 42 -result: 42 -result: 42 -result: 42 diff --git a/test/files/jvm/t3407.scala b/test/files/jvm/t3407.scala deleted file mode 100644 index 757fa3a438..0000000000 --- a/test/files/jvm/t3407.scala +++ /dev/null @@ -1,21 +0,0 @@ - - -@deprecated("Suppress warnings", since="2.11") -object Test { - import scala.actors._, scala.actors.Actor._ - - def main(args: Array[String]) { - for (i <- 1 to 10) { - val ft = Futures.future { 42 } - println("result: " + ft()) - } - - for (i <- 1 to 10) { - receiveWithin(0) { - case TIMEOUT => - case msg => println("unexpected: " + msg) - } - } - } - -} diff --git a/test/files/jvm/t3412-channel.check b/test/files/jvm/t3412-channel.check deleted file mode 100644 index 954c6e835d..0000000000 --- a/test/files/jvm/t3412-channel.check +++ /dev/null @@ -1,10 +0,0 @@ -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 diff --git a/test/files/jvm/t3412-channel.scala b/test/files/jvm/t3412-channel.scala deleted file mode 100644 index af319d2303..0000000000 --- a/test/files/jvm/t3412-channel.scala +++ /dev/null @@ -1,40 +0,0 @@ - - -@deprecated("Suppress warnings", since="2.11") -object Test { - import scala.actors._, scala.actors.Actor._, scala.actors.Futures._ - - def main(args: Array[String]) { - - actor { - val C: Channel[Int] = new Channel[Int](self) - - def respondAll(fts: List[Future[Int]], cnt: Int): Unit = - fts match { - case List() => C ! 0 - case ft :: rest => - if (cnt % 100 == 0) - println(ft()) - respondAll(rest, cnt + 1) - } - - actor { - val fts = for (_ <- 1 to 1000) - yield C !! (3, {case x: Int => x}) - - actor { - respondAll(fts.toList, 0) - } - } - - loop { - C.react { - case 0 => exit() - case i => reply(i * 2) - } - } - } - - } - -} diff --git a/test/files/jvm/t3412.check b/test/files/jvm/t3412.check deleted file mode 100644 index 954c6e835d..0000000000 --- a/test/files/jvm/t3412.check +++ /dev/null @@ -1,10 +0,0 @@ -6 -6 -6 -6 -6 -6 -6 -6 -6 -6 diff --git a/test/files/jvm/t3412.scala b/test/files/jvm/t3412.scala deleted file mode 100644 index fde6c04cb7..0000000000 --- a/test/files/jvm/t3412.scala +++ /dev/null @@ -1,34 +0,0 @@ - - -@deprecated("Suppress warnings", since="2.11") -object Test { - import scala.actors._, scala.actors.Actor._, scala.actors.Futures._ - - def main(args: Array[String]) { - - val a = actor { - loop { react { - case i: Int => reply(i * 2) - case 'stop => exit() - } } - } - - val fts = for (_ <- 1 to 1000) - yield a !! (3, {case x: Int => x}) - - def respondAll(fts: List[Future[Int]], cnt: Int): Unit = - fts match { - case List() => a ! 'stop - case ft :: rest => - if (cnt % 100 == 0) - println(ft()) - respondAll(rest, cnt + 1) - } - - actor { - respondAll(fts.toList, 0) - } - - } - -} diff --git a/test/files/jvm/t3470.check b/test/files/jvm/t3470.check deleted file mode 100644 index 94cb526756..0000000000 --- a/test/files/jvm/t3470.check +++ /dev/null @@ -1,3 +0,0 @@ -A: started: 1 -A: started: 2 -A: started: 3 diff --git a/test/files/jvm/t3470.scala b/test/files/jvm/t3470.scala deleted file mode 100644 index bcb1d4f8de..0000000000 --- a/test/files/jvm/t3470.scala +++ /dev/null @@ -1,32 +0,0 @@ - - -@deprecated("Suppress warnings", since="2.11") -object Test { - import scala.actors._ - - def expectActorState(a: Reactor[T] forSome { type T }, s: Actor.State.Value) { - var done = false - var i = 0 - while (!done) { - i = i + 1 - if (i == 10) { // only wait for 2 seconds total - println("FAIL ["+a+": expected "+s+"]") - done = true - } - - Thread.sleep(200) - if (a.getState == s) // success - done = true - } - } - - def main(args: Array[String]) { - val a = new Actor { var c = 0; def act() = { c += 1; println("A: started: " + c) } } - a.start() - expectActorState(a, Actor.State.Terminated) - a.restart() - expectActorState(a, Actor.State.Terminated) - a.restart() - } - -} diff --git a/test/files/jvm/t3838.check b/test/files/jvm/t3838.check deleted file mode 100644 index 154227a350..0000000000 --- a/test/files/jvm/t3838.check +++ /dev/null @@ -1 +0,0 @@ -caught java.lang.RuntimeException: unhandled timeout diff --git a/test/files/jvm/t3838.scala b/test/files/jvm/t3838.scala deleted file mode 100644 index a1a71d1049..0000000000 --- a/test/files/jvm/t3838.scala +++ /dev/null @@ -1,17 +0,0 @@ - - -@deprecated("Suppress warnings", since="2.11") -object Test { - import scala.actors.Actor._ - def main(args: Array[String]) { - actor { - try { - receiveWithin(1) { - case str: String => println(str) - } - } catch { - case e: Exception => println("caught "+e) - } - } - } -} diff --git a/test/files/jvm/t7146.scala b/test/files/jvm/t7146.scala index aaa3dc7ca4..ea734472d5 100644 --- a/test/files/jvm/t7146.scala +++ b/test/files/jvm/t7146.scala @@ -10,7 +10,7 @@ object Test { ExecutionContext.global.toString.startsWith("scala.concurrent.impl.ExecutionContextImpl")) val i = ExecutionContext.global.asInstanceOf[{ def executor: Executor }] println("should be scala.concurrent.forkjoin.ForkJoinPool == " + - i.executor.toString.startsWith("scala.concurrent.forkjoin.ForkJoinPool")) + (i.executor.getClass.getSuperclass.getName == "scala.concurrent.forkjoin.ForkJoinPool")) val u = i.executor. asInstanceOf[{ def getUncaughtExceptionHandler: Thread.UncaughtExceptionHandler }]. getUncaughtExceptionHandler diff --git a/test/files/jvm/t8582.check b/test/files/jvm/t8582.check index e388366270..0e4da90398 100644 --- a/test/files/jvm/t8582.check +++ b/test/files/jvm/t8582.check @@ -1,3 +1,6 @@ +t8582.scala:17: warning: class BeanInfo in package beans is deprecated: the generation of BeanInfo classes is no longer supported + class C1 + ^ getClass on module gives module class class p1.p2.Singleton$Singleton$ diff --git a/test/files/jvm/t8582.flags b/test/files/jvm/t8582.flags new file mode 100644 index 0000000000..dcc59ebe32 --- /dev/null +++ b/test/files/jvm/t8582.flags @@ -0,0 +1 @@ +-deprecation diff --git a/test/files/jvm/try-type-tests.scala b/test/files/jvm/try-type-tests.scala index 962afbd30f..b3926020f0 100644 --- a/test/files/jvm/try-type-tests.scala +++ b/test/files/jvm/try-type-tests.scala @@ -118,6 +118,44 @@ trait TryStandard { assert(f.transform(succ, fail).get == 0) } + def testSuccessEither(): Unit = { + val t = Success(1) + assert(t.toEither.isRight) + } + + def testFailureEither(): Unit = { + val t = Failure(new Exception("foo")) + assert(t.toEither.isLeft) + } + + def testFoldSuccess(): Unit = { + val t = Success(1) + val res = t.fold("Throws " + _, "Returns " + _) + assert(res == "Returns 1") + } + + def testFoldFailure(): Unit = { + val t = Failure(new Exception("foo")) + val res = t.fold("Throws " + _, "Returns " + _) + assert(res == "Throws java.lang.Exception: foo") + } + + def testFoldSuccessFailure(): Unit = { + val t = Success(1) + val res = t.fold("Throws " + _, _ => throw new Exception("foo")) + assert(res == "Throws java.lang.Exception: foo") + } + + def testFoldFailureFailure(): Unit = { + val t = Failure(new Exception("foo")) + val res = try { + t.fold(_ => throw new Exception("bar"), "Returns " + _) + } catch { + case e: Throwable => "Throws " + e + } + assert(res == "Throws java.lang.Exception: bar") + } + testForeachSuccess() testForeachFailure() testFlatMapSuccess() @@ -136,6 +174,11 @@ trait TryStandard { testFailedFailure() testSuccessTransform() testFailureTransform() + testSuccessEither() + testFailureEither() + testFoldSuccess() + testFoldFailure() + testFoldSuccessFailure() } object Test diff --git a/test/files/neg/beanInfoDeprecation.check b/test/files/neg/beanInfoDeprecation.check new file mode 100644 index 0000000000..788b277818 --- /dev/null +++ b/test/files/neg/beanInfoDeprecation.check @@ -0,0 +1,6 @@ +beanInfoDeprecation.scala:2: warning: class BeanInfo in package beans is deprecated: the generation of BeanInfo classes is no longer supported +class C + ^ +error: No warnings can be incurred under -Xfatal-warnings. +one warning found +one error found diff --git a/test/files/neg/beanInfoDeprecation.flags b/test/files/neg/beanInfoDeprecation.flags new file mode 100644 index 0000000000..c6bfaf1f64 --- /dev/null +++ b/test/files/neg/beanInfoDeprecation.flags @@ -0,0 +1 @@ +-deprecation -Xfatal-warnings diff --git a/test/files/neg/beanInfoDeprecation.scala b/test/files/neg/beanInfoDeprecation.scala new file mode 100644 index 0000000000..c7e3a86202 --- /dev/null +++ b/test/files/neg/beanInfoDeprecation.scala @@ -0,0 +1,2 @@ +@scala.beans.BeanInfo +class C diff --git a/test/files/neg/deprecated-target.check b/test/files/neg/deprecated-target.check new file mode 100644 index 0000000000..307d3d25ab --- /dev/null +++ b/test/files/neg/deprecated-target.check @@ -0,0 +1,4 @@ +warning: -target is deprecated: -target:jvm-1.7 is deprecated, forcing use of jvm-1.8 +error: No warnings can be incurred under -Xfatal-warnings. +one warning found +one error found diff --git a/test/files/neg/deprecated-target.flags b/test/files/neg/deprecated-target.flags new file mode 100644 index 0000000000..458ded8123 --- /dev/null +++ b/test/files/neg/deprecated-target.flags @@ -0,0 +1 @@ +-target:jvm-1.7 -deprecation -Xfatal-warnings diff --git a/test/files/neg/deprecated-target.scala b/test/files/neg/deprecated-target.scala new file mode 100644 index 0000000000..9dccdd5e59 --- /dev/null +++ b/test/files/neg/deprecated-target.scala @@ -0,0 +1 @@ +class C
\ No newline at end of file diff --git a/test/files/neg/logImplicits.check b/test/files/neg/logImplicits.check index 270882b71a..df7b359767 100644 --- a/test/files/neg/logImplicits.check +++ b/test/files/neg/logImplicits.check @@ -1,10 +1,10 @@ -logImplicits.scala:2: applied implicit conversion from xs.type to ?{def size: ?} = implicit def byteArrayOps(xs: Array[Byte]): scala.collection.mutable.ArrayOps[Byte] +logImplicits.scala:2: applied implicit conversion from xs.type to ?{def size: ?} = implicit def _byteArrayOps(xs: Array[Byte]): scala.collection.mutable.ArrayOps.ofByte def f(xs: Array[Byte]) = xs.size ^ logImplicits.scala:7: applied implicit conversion from String("abc") to ?{def map: ?} = implicit def augmentString(x: String): scala.collection.immutable.StringOps def f = "abc" map (_ + 1) ^ -logImplicits.scala:15: inferred view from String("abc") to Int = C.this.convert:(p: String("abc"))Int +logImplicits.scala:15: inferred view from String("abc") to Int = C.this.convert:(p: String)Int math.max(122, x: Int) ^ logImplicits.scala:19: applied implicit conversion from Int(1) to ?{def ->: ?} = implicit def ArrowAssoc[A](self: A): ArrowAssoc[A] diff --git a/test/files/neg/names-defaults-neg.check b/test/files/neg/names-defaults-neg.check index a43bf66811..8a6aafd67a 100644 --- a/test/files/neg/names-defaults-neg.check +++ b/test/files/neg/names-defaults-neg.check @@ -118,68 +118,74 @@ names-defaults-neg.scala:93: warning: the parameter name y has been deprecated. names-defaults-neg.scala:93: error: parameter 'b' is already specified at parameter position 1 deprNam3(y = 10, b = 2) ^ -names-defaults-neg.scala:98: error: unknown parameter name: m +names-defaults-neg.scala:96: warning: naming parameter deprNam4Arg has been deprecated. + deprNam4(deprNam4Arg = null) + ^ +names-defaults-neg.scala:98: warning: naming parameter deprNam5Arg has been deprecated. + deprNam5(deprNam5Arg = null) + ^ +names-defaults-neg.scala:102: error: unknown parameter name: m f3818(y = 1, m = 1) ^ -names-defaults-neg.scala:131: error: reference to var2 is ambiguous; it is both a method parameter and a variable in scope. +names-defaults-neg.scala:135: error: reference to var2 is ambiguous; it is both a method parameter and a variable in scope. delay(var2 = 40) ^ -names-defaults-neg.scala:134: error: missing parameter type for expanded function ((x$1) => a = x$1) +names-defaults-neg.scala:138: error: missing parameter type for expanded function ((x$1) => a = x$1) val taf2: Int => Unit = testAnnFun(a = _, b = get("+")) ^ -names-defaults-neg.scala:134: error: not found: value a +names-defaults-neg.scala:138: error: not found: value a val taf2: Int => Unit = testAnnFun(a = _, b = get("+")) ^ -names-defaults-neg.scala:134: error: not found: value get +names-defaults-neg.scala:138: error: not found: value get val taf2: Int => Unit = testAnnFun(a = _, b = get("+")) ^ -names-defaults-neg.scala:135: error: parameter 'a' is already specified at parameter position 1 +names-defaults-neg.scala:139: error: parameter 'a' is already specified at parameter position 1 val taf3 = testAnnFun(b = _: String, a = get(8)) ^ -names-defaults-neg.scala:136: error: missing parameter type for expanded function ((x$3) => testAnnFun(x$3, ((x$4) => b = x$4))) +names-defaults-neg.scala:140: error: missing parameter type for expanded function ((x$3) => testAnnFun(x$3, ((x$4) => b = x$4))) val taf4: (Int, String) => Unit = testAnnFun(_, b = _) ^ -names-defaults-neg.scala:136: error: missing parameter type for expanded function ((x$4) => b = x$4) +names-defaults-neg.scala:140: error: missing parameter type for expanded function ((x$4) => b = x$4) val taf4: (Int, String) => Unit = testAnnFun(_, b = _) ^ -names-defaults-neg.scala:136: error: not found: value b +names-defaults-neg.scala:140: error: not found: value b val taf4: (Int, String) => Unit = testAnnFun(_, b = _) ^ -names-defaults-neg.scala:144: error: variable definition needs type because 'x' is used as a named argument in its body. +names-defaults-neg.scala:148: error: variable definition needs type because 'x' is used as a named argument in its body. def t3 { var x = t.f(x = 1) } ^ -names-defaults-neg.scala:147: error: variable definition needs type because 'x' is used as a named argument in its body. +names-defaults-neg.scala:151: error: variable definition needs type because 'x' is used as a named argument in its body. object t6 { var x = t.f(x = 1) } ^ -names-defaults-neg.scala:147: warning: failed to determine if 'x = ...' is a named argument or an assignment expression. +names-defaults-neg.scala:151: warning: failed to determine if 'x = ...' is a named argument or an assignment expression. an explicit type is required for the definition mentioned in the error message above. object t6 { var x = t.f(x = 1) } ^ -names-defaults-neg.scala:150: error: variable definition needs type because 'x' is used as a named argument in its body. +names-defaults-neg.scala:154: error: variable definition needs type because 'x' is used as a named argument in its body. class t9 { var x = t.f(x = 1) } ^ -names-defaults-neg.scala:150: warning: failed to determine if 'x = ...' is a named argument or an assignment expression. +names-defaults-neg.scala:154: warning: failed to determine if 'x = ...' is a named argument or an assignment expression. an explicit type is required for the definition mentioned in the error message above. class t9 { var x = t.f(x = 1) } ^ -names-defaults-neg.scala:164: error: variable definition needs type because 'x' is used as a named argument in its body. +names-defaults-neg.scala:168: error: variable definition needs type because 'x' is used as a named argument in its body. def u3 { var x = u.f(x = 1) } ^ -names-defaults-neg.scala:167: error: variable definition needs type because 'x' is used as a named argument in its body. +names-defaults-neg.scala:171: error: variable definition needs type because 'x' is used as a named argument in its body. def u6 { var x = u.f(x = "32") } ^ -names-defaults-neg.scala:170: error: reference to x is ambiguous; it is both a method parameter and a variable in scope. +names-defaults-neg.scala:174: error: reference to x is ambiguous; it is both a method parameter and a variable in scope. def u9 { var x: Int = u.f(x = 1) } ^ -names-defaults-neg.scala:177: error: variable definition needs type because 'x' is used as a named argument in its body. +names-defaults-neg.scala:181: error: variable definition needs type because 'x' is used as a named argument in its body. class u15 { var x = u.f(x = 1) } ^ -names-defaults-neg.scala:177: warning: failed to determine if 'x = ...' is a named argument or an assignment expression. +names-defaults-neg.scala:181: warning: failed to determine if 'x = ...' is a named argument or an assignment expression. an explicit type is required for the definition mentioned in the error message above. class u15 { var x = u.f(x = 1) } ^ -names-defaults-neg.scala:180: error: reference to x is ambiguous; it is both a method parameter and a variable in scope. +names-defaults-neg.scala:184: error: reference to x is ambiguous; it is both a method parameter and a variable in scope. class u18 { var x: Int = u.f(x = 1) } ^ -four warnings found +6 warnings found 46 errors found diff --git a/test/files/neg/names-defaults-neg.scala b/test/files/neg/names-defaults-neg.scala index a97b590bf2..b326d3b5bd 100644 --- a/test/files/neg/names-defaults-neg.scala +++ b/test/files/neg/names-defaults-neg.scala @@ -92,6 +92,10 @@ object Test extends App { def deprNam3(@deprecatedName('x) a: Int, @deprecatedName('y) b: Int) = a + b deprNam3(y = 10, b = 2) + def deprNam4(@deprecatedName('deprNam4Arg) deprNam4Arg: String) = 0 + deprNam4(deprNam4Arg = null) + def deprNam5(@deprecatedName deprNam5Arg: String) = 0 + deprNam5(deprNam5Arg = null) // t3818 def f3818(x: Int = 1, y: Int, z: Int = 1) = 0 diff --git a/test/files/neg/t6289.check b/test/files/neg/t6289.check index 989932750f..7b2b4b2d32 100644 --- a/test/files/neg/t6289.check +++ b/test/files/neg/t6289.check @@ -1,9 +1,3 @@ -#partest java6 -t6289/J.java:2: method does not override or implement a method from a supertype - @Override public void foo() { } - ^ -1 error -#partest !java6 t6289/J.java:2: error: method does not override or implement a method from a supertype @Override public void foo() { } ^ diff --git a/test/files/neg/t8764.check b/test/files/neg/t8764.check deleted file mode 100644 index 6d89ebe106..0000000000 --- a/test/files/neg/t8764.check +++ /dev/null @@ -1,6 +0,0 @@ -t8764.scala:8: error: type mismatch; - found : AnyVal - required: Double - val d: Double = a.productElement(0) - ^ -one error found diff --git a/test/files/neg/t8764.flags b/test/files/neg/t8764.flags deleted file mode 100644 index 48fd867160..0000000000 --- a/test/files/neg/t8764.flags +++ /dev/null @@ -1 +0,0 @@ --Xexperimental diff --git a/test/files/neg/t8764.scala b/test/files/neg/t8764.scala deleted file mode 100644 index dc5bfb0160..0000000000 --- a/test/files/neg/t8764.scala +++ /dev/null @@ -1,9 +0,0 @@ -object Main { - - case class IntAndDouble(i: Int, d: Double) - - // a.productElement used to be Int => Double - // now: Int => AnyVal - val a = IntAndDouble(1, 5.0) - val d: Double = a.productElement(0) -} diff --git a/test/files/neg/t8849.check b/test/files/neg/t8849.check new file mode 100644 index 0000000000..15b00aee8b --- /dev/null +++ b/test/files/neg/t8849.check @@ -0,0 +1,7 @@ +t8849.scala:8: error: ambiguous implicit values: + both value global in object Implicits of type => scala.concurrent.ExecutionContext + and value dummy of type scala.concurrent.ExecutionContext + match expected type scala.concurrent.ExecutionContext + require(implicitly[ExecutionContext] eq dummy) + ^ +one error found diff --git a/test/files/neg/t8849.scala b/test/files/neg/t8849.scala new file mode 100644 index 0000000000..336f16b40f --- /dev/null +++ b/test/files/neg/t8849.scala @@ -0,0 +1,10 @@ +import scala.concurrent.ExecutionContext +import ExecutionContext.Implicits.global + +object Test { + def main(args: Array[String]): Unit = { + implicit val dummy: ExecutionContext = null + require(scala.concurrent.ExecutionContext.Implicits.global ne null) + require(implicitly[ExecutionContext] eq dummy) + } +}
\ No newline at end of file diff --git a/test/files/pos/MailBox.scala b/test/files/pos/MailBox.scala index 8e27bd362d..6bb25adb19 100644 --- a/test/files/pos/MailBox.scala +++ b/test/files/pos/MailBox.scala @@ -1,6 +1,6 @@ package test; -import scala.actors.TIMEOUT; +object TIMEOUT class MailBox { diff --git a/test/files/pos/alladin763.scala b/test/files/pos/alladin763.scala new file mode 100644 index 0000000000..29c9b25318 --- /dev/null +++ b/test/files/pos/alladin763.scala @@ -0,0 +1,37 @@ +// Test from http://lrytz.github.io/scala-aladdin-bugtracker/displayItem.do%3Fid=763.html +// and expanded with package object variants + + +trait Foo { type T; def apply() : T } +object e extends Foo { type T = Int; def apply() = 42 } + +package p { + trait T[X] { def O : { def apply(): X } } + object `package` extends T[Int] { + def O: { def apply(): Int } = new { def apply(): Int = 42 } + } + + object Test { + val x: Int = O() + } +} + +object Test { + + val f = new Foo { type T = Int; def apply() = 42 } + + def main(args: Array[String]): Unit = { + val g = new Foo { type T = Int; def apply() = 42 } + + (e: Foo)() + val ee: Int = e() + + (f: Foo)() + val ff: Int = f() + + (g: Foo)() + val gg: Int = g() + + val pp: Int = p.O() + } +} diff --git a/test/files/pos/functions.scala b/test/files/pos/functions.scala index 0207523dde..25d1c46eac 100644 --- a/test/files/pos/functions.scala +++ b/test/files/pos/functions.scala @@ -1,4 +1,6 @@ -import scala.actors.Actor +object Actor { + def receive[A](f: PartialFunction[Any, A]): A = ??? +} object Test { diff --git a/test/files/pos/t533.scala b/test/files/pos/t533.scala deleted file mode 100644 index 0a6515fed3..0000000000 --- a/test/files/pos/t533.scala +++ /dev/null @@ -1,11 +0,0 @@ -import scala.actors._ - -object test extends Actor { - def act() { - receive { - case TIMEOUT => Console.println("TIMEOUT") - //case _ => Console.println("_") - } - } -} - diff --git a/test/files/pos/t6778.scala b/test/files/pos/t6778.scala new file mode 100644 index 0000000000..b7483c8fce --- /dev/null +++ b/test/files/pos/t6778.scala @@ -0,0 +1,5 @@ +object test extends AnyRef with App { + // Check that random can be called with parenthesis. + scala.math.random() +} + diff --git a/test/files/pos/t7784.scala b/test/files/pos/t7784.scala new file mode 100644 index 0000000000..e6824a4203 --- /dev/null +++ b/test/files/pos/t7784.scala @@ -0,0 +1,13 @@ +object Test { + final val a = "" + var b: a.type = a + b = a + + final val x = classOf[Object] + var y: x.type = x + y = x + + final val e = Thread.State.NEW + var e1: e.type = e + e1 = e +} diff --git a/test/files/pos/t8462.scala b/test/files/pos/t8462.scala new file mode 100644 index 0000000000..6946cf8e5e --- /dev/null +++ b/test/files/pos/t8462.scala @@ -0,0 +1,11 @@ + +trait ConstantOps { + def exprs = ( + 1 << 2L : Int, // was: error: type mismatch; found : Long(4L) + 64 >> 2L : Int, // was: error: type mismatch; found : Long(4L) + 64 >>> 2L : Int, // was: error: type mismatch; found : Long(4L) + 'a' << 2L : Int, + 'a' >> 2L : Int, + 'a'>>> 2L : Int + ) +} diff --git a/test/files/pos/t8862a.scala b/test/files/pos/t8862a.scala new file mode 100644 index 0000000000..f9576707ba --- /dev/null +++ b/test/files/pos/t8862a.scala @@ -0,0 +1,47 @@ +package p { + + abstract class C[A] { + def x: A + implicit def oops: A = x + implicit def oopso: Option[A] = None + } + + package q { + + class Oops + + object `package` extends C[Oops] { + override def x = new Oops + } + + object Blah { + oops + oopso + + // implicits found in enclosing context + implicitly[Oops] + implicitly[Option[Oops]] + } + } +} + +package other { + + object Blah { + // implicits found through this import + import p.q._ + + oops + oopso + + implicitly[Oops] + implicitly[Option[Oops]] + } + + + object Blee { + // implicits found through the companion implicits + implicitly[p.q.Oops] + implicitly[Option[p.q.Oops]] + } +} diff --git a/test/files/pos/t8862b.scala b/test/files/pos/t8862b.scala new file mode 100644 index 0000000000..8be7fb5fab --- /dev/null +++ b/test/files/pos/t8862b.scala @@ -0,0 +1,12 @@ +package p { + trait T[X] { def O : { def apply(): X } } + object `package` extends T[Int] { + def O: { def apply(): Int } = new { def apply(): Int = 42 } + } + + object Test { + def main(args: Array[String]): Unit = { + val x: Int = O() + } + } +} diff --git a/test/files/pos/t9074.scala b/test/files/pos/t9074.scala new file mode 100644 index 0000000000..67db281f54 --- /dev/null +++ b/test/files/pos/t9074.scala @@ -0,0 +1,24 @@ +package blam { + + package foo { + + trait F[T] { + def f(d: Double, t: T): T = ??? + def f(d: Int, t: T): T = ??? + def f(d: String, t: T): T = ??? + + def g[A](a: T): T = ??? + def g(a: Int) = ??? + } + } + + package object foo extends foo.F[Double] { + override def f(d: Double, t: Double): Double = ??? + } +} + +object Test { + import blam._ + foo.f("3", 4.0) + foo.g[Any](1d) : Double +} diff --git a/test/files/pos/t9074b.scala b/test/files/pos/t9074b.scala new file mode 100644 index 0000000000..dadcebf399 --- /dev/null +++ b/test/files/pos/t9074b.scala @@ -0,0 +1,15 @@ +trait Echo [T] { + def echo(t: T): Unit +} + +trait IntEcho extends Echo[Int] { + def echo(t: Int) = println(t) +} + +object echo extends IntEcho +package object echo1 extends IntEcho + +object App extends App { + echo.echo(1) + echo1.echo(1) +} diff --git a/test/files/pos/t9131.scala b/test/files/pos/t9131.scala new file mode 100644 index 0000000000..1a186a0a24 --- /dev/null +++ b/test/files/pos/t9131.scala @@ -0,0 +1,12 @@ +class Test { + + def byNameFunc(f: (=> (() => Any)) => Any): Unit = () + + def test = { + // "value apply is not a member of => () => Any" + byNameFunc(z => z()) + // okay + byNameFunc(z => z.apply()) + byNameFunc(z => {val f = z; f()}) + } +} diff --git a/test/files/pos/t9326a.scala b/test/files/pos/t9326a.scala new file mode 100644 index 0000000000..aefc735585 --- /dev/null +++ b/test/files/pos/t9326a.scala @@ -0,0 +1,6 @@ +package p + +trait M[A] + +class C extends M[Tuple1[X] forSome { type X }] + diff --git a/test/files/run/analyzerPlugins.check b/test/files/run/analyzerPlugins.check index 9803465ddc..1bb7c6ceab 100644 --- a/test/files/run/analyzerPlugins.check +++ b/test/files/run/analyzerPlugins.check @@ -19,7 +19,7 @@ canAdaptAnnotations(Trees$Typed, Any) [1] canAdaptAnnotations(Trees$Typed, Int) [1] lub(List(Int @testAnn, Int)) [1] pluginsPt(?, Trees$Annotated) [7] -pluginsPt(?, Trees$Apply) [8] +pluginsPt(?, Trees$Apply) [11] pluginsPt(?, Trees$ApplyImplicitView) [2] pluginsPt(?, Trees$Assign) [7] pluginsPt(?, Trees$Block) [4] @@ -31,7 +31,7 @@ pluginsPt(?, Trees$Literal) [16] pluginsPt(?, Trees$New) [5] pluginsPt(?, Trees$PackageDef) [1] pluginsPt(?, Trees$Return) [1] -pluginsPt(?, Trees$Select) [47] +pluginsPt(?, Trees$Select) [50] pluginsPt(?, Trees$Super) [2] pluginsPt(?, Trees$This) [20] pluginsPt(?, Trees$TypeApply) [3] @@ -93,6 +93,7 @@ pluginsTypeSigAccessor(value x) [1] pluginsTypeSigAccessor(value y) [1] pluginsTypeSigAccessor(variable count) [2] pluginsTyped( <: Int, Trees$TypeBoundsTree) [2] +pluginsTyped(()Double, Trees$Select) [6] pluginsTyped(()Object, Trees$Select) [1] pluginsTyped(()String, Trees$Ident) [1] pluginsTyped(()String, Trees$TypeApply) [1] @@ -112,7 +113,7 @@ pluginsTyped(<notype>, Trees$PackageDef) [1] pluginsTyped(<notype>, Trees$TypeDef) [1] pluginsTyped(<notype>, Trees$ValDef) [21] pluginsTyped(=> Boolean @testAnn, Trees$Select) [1] -pluginsTyped(=> Double, Trees$Select) [4] +pluginsTyped(=> Double, Trees$Select) [1] pluginsTyped(=> Int, Trees$Select) [5] pluginsTyped(=> Int, Trees$TypeApply) [1] pluginsTyped(=> String @testAnn, Trees$Select) [1] @@ -131,6 +132,7 @@ pluginsTyped(Boolean(false), Trees$Literal) [2] pluginsTyped(Boolean, Trees$Apply) [1] pluginsTyped(Boolean, Trees$Select) [4] pluginsTyped(Char('c'), Trees$Literal) [2] +pluginsTyped(Double, Trees$Apply) [3] pluginsTyped(Double, Trees$Select) [6] pluginsTyped(Int @testAnn, Trees$TypeTree) [2] pluginsTyped(Int @testAnn, Trees$Typed) [2] diff --git a/test/files/run/classfile-format-51.scala b/test/files/run/classfile-format-51.scala index 7523130afa..da322bb5d9 100644 --- a/test/files/run/classfile-format-51.scala +++ b/test/files/run/classfile-format-51.scala @@ -1,6 +1,5 @@ import java.io.{File, FileOutputStream} -import scala.tools.nsc.settings.ScalaVersion import scala.tools.partest._ import scala.tools.asm import asm.{AnnotationVisitor, ClassWriter, FieldVisitor, Handle, MethodVisitor, Opcodes} diff --git a/test/files/run/classfile-format-52.scala b/test/files/run/classfile-format-52.scala index 453f61ac84..e278d40b8b 100644 --- a/test/files/run/classfile-format-52.scala +++ b/test/files/run/classfile-format-52.scala @@ -1,6 +1,5 @@ import java.io.{File, FileOutputStream} -import scala.tools.nsc.settings.ScalaVersion import scala.tools.partest._ import scala.tools.asm import asm.{AnnotationVisitor, ClassWriter, FieldVisitor, Handle, MethodVisitor, Opcodes} diff --git a/test/files/run/concurrent-stream.check b/test/files/run/concurrent-stream.check deleted file mode 100644 index d4adf84490..0000000000 --- a/test/files/run/concurrent-stream.check +++ /dev/null @@ -1,3 +0,0 @@ -Testing standard cons. -Evaluation 0: List(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) -Evaluation 1: List(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) diff --git a/test/files/run/concurrent-stream.scala b/test/files/run/concurrent-stream.scala deleted file mode 100644 index 9d5ba0428e..0000000000 --- a/test/files/run/concurrent-stream.scala +++ /dev/null @@ -1,37 +0,0 @@ -// test concurrent calls to Stream.tail -@deprecated("Suppress warnings", since="2.11") -object Test { - - def slowRange(from: Int, until: Int, cons: (Int, => Stream[Int]) => Stream[Int]): Stream[Int] = { - var current = from - def next: Stream[Int] = { - Thread.sleep(100) - if (current >= until) Stream.empty - else { - val stream = cons(current, next) - current += 1 - stream - } - } - next - } - - def testCons(cons: (Int, => Stream[Int]) => Stream[Int]): Unit = { - import scala.actors.Actor._ - - val stream = slowRange(0, 10, cons) - val main = self - actor { main ! stream.toList } - actor { main ! stream.toList } - val eval0 = receive { case list: List[Int @unchecked] => list } - val eval1 = receive { case list: List[Int @unchecked] => list } - println("Evaluation 0: " + eval0) - println("Evaluation 1: " + eval1) - } - - def main(args: Array[String]) { - println("Testing standard cons.") - testCons(Stream.cons.apply(_, _)) - } -} - diff --git a/test/files/run/duration-coarsest.scala b/test/files/run/duration-coarsest.scala index 51cb79287a..81fbb3cc84 100644 --- a/test/files/run/duration-coarsest.scala +++ b/test/files/run/duration-coarsest.scala @@ -25,4 +25,7 @@ object Test extends App { 23 hours, 40 days ) foreach (x => assert(x == x.toCoarsest, x)) -}
\ No newline at end of file + + // toCoarsest on a FiniteDuration should return a FiniteDuration + val finite: FiniteDuration = 1.second.toCoarsest +} diff --git a/test/files/run/future-flatmap-exec-count.check b/test/files/run/future-flatmap-exec-count.check index dd9dce64ed..7065c133e0 100644 --- a/test/files/run/future-flatmap-exec-count.check +++ b/test/files/run/future-flatmap-exec-count.check @@ -1,3 +1,4 @@ +warning: there was one deprecation warning; re-run with -deprecation for details mapping execute() flatmapping diff --git a/test/files/run/inline-ex-handlers.check b/test/files/run/inline-ex-handlers.check index 7c885d2cc9..27a277d314 100644 --- a/test/files/run/inline-ex-handlers.check +++ b/test/files/run/inline-ex-handlers.check @@ -123,12 +123,12 @@ 300 RETURN(UNIT) @@ -583,6 +603,6 @@ with finalizer: null -- catch (Throwable) in ArrayBuffer(7, 9, 10) starting at: 6 -+ catch (Throwable) in ArrayBuffer(7, 9, 10, 11) starting at: 6 +- catch (Throwable) in Vector(7, 9, 10) starting at: 6 ++ catch (Throwable) in Vector(7, 9, 10, 11) starting at: 6 consisting of blocks: List(6) with finalizer: null -- catch (Throwable) in ArrayBuffer(4, 6, 7, 9, 10) starting at: 3 -+ catch (Throwable) in ArrayBuffer(4, 6, 7, 9, 10, 11, 12) starting at: 3 +- catch (Throwable) in Vector(4, 6, 7, 9, 10) starting at: 3 ++ catch (Throwable) in Vector(4, 6, 7, 9, 10, 11, 12) starting at: 3 consisting of blocks: List(3) @@ -618,3 +638,3 @@ startBlock: 1 @@ -171,8 +171,8 @@ } @@ -690,3 +730,3 @@ with finalizer: null -- catch (<none>) in ArrayBuffer(4, 5, 6, 8) starting at: 3 -+ catch (<none>) in ArrayBuffer(4, 5, 6, 8, 10) starting at: 3 +- catch (<none>) in Vector(4, 5, 6, 8) starting at: 3 ++ catch (<none>) in Vector(4, 5, 6, 8, 10) starting at: 3 consisting of blocks: List(3) @@ -714,5 +754,5 @@ def main(args: Array[String] (ARRAY[REF(class String)])): Unit { @@ -276,12 +276,12 @@ } @@ -852,6 +918,6 @@ with finalizer: null -- catch (Throwable) in ArrayBuffer(13, 14, 15, 18, 20, 21, 23) starting at: 4 -+ catch (Throwable) in ArrayBuffer(13, 14, 15, 18, 20, 21, 23, 25) starting at: 4 +- catch (Throwable) in Vector(13, 14, 15, 18, 20, 21, 23) starting at: 4 ++ catch (Throwable) in Vector(13, 14, 15, 18, 20, 21, 23, 25) starting at: 4 consisting of blocks: List(9, 8, 6, 5, 4) with finalizer: null -- catch (<none>) in ArrayBuffer(4, 5, 6, 9, 13, 14, 15, 18, 20, 21, 23) starting at: 3 -+ catch (<none>) in ArrayBuffer(4, 5, 6, 9, 13, 14, 15, 18, 20, 21, 23, 25, 26) starting at: 3 +- catch (<none>) in Vector(4, 5, 6, 9, 13, 14, 15, 18, 20, 21, 23) starting at: 3 ++ catch (<none>) in Vector(4, 5, 6, 9, 13, 14, 15, 18, 20, 21, 23, 25, 26) starting at: 3 consisting of blocks: List(3) @@ -879,5 +945,5 @@ def main(args: Array[String] (ARRAY[REF(class String)])): Unit { @@ -317,8 +317,8 @@ 127 CALL_METHOD scala.Predef.println (dynamic) @@ -964,3 +1034,3 @@ with finalizer: null -- catch (IllegalArgumentException) in ArrayBuffer(6, 7, 8, 11, 13, 14, 16) starting at: 3 -+ catch (IllegalArgumentException) in ArrayBuffer(6, 7, 8, 11, 13, 14, 16, 17) starting at: 3 +- catch (IllegalArgumentException) in Vector(6, 7, 8, 11, 13, 14, 16) starting at: 3 ++ catch (IllegalArgumentException) in Vector(6, 7, 8, 11, 13, 14, 16, 17) starting at: 3 consisting of blocks: List(3) @@ -988,5 +1058,5 @@ def main(args: Array[String] (ARRAY[REF(class String)])): Unit { diff --git a/test/files/run/lub-visibility.check b/test/files/run/lub-visibility.check index 70734966f0..135cb3cb76 100644 --- a/test/files/run/lub-visibility.check +++ b/test/files/run/lub-visibility.check @@ -6,6 +6,6 @@ scala> // should infer List[scala.collection.immutable.Seq[Nothing]] scala> // but reverted that for SI-5534. scala> val x = List(List(), Vector()) -x: List[scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing] with java.io.Serializable] = List(List(), Vector()) +x: List[scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing] with Serializable] = List(List(), Vector()) scala> :quit diff --git a/test/files/run/nothingTypeDce.flags b/test/files/run/nothingTypeDce.flags index d85321ca0e..fde52cc7df 100644 --- a/test/files/run/nothingTypeDce.flags +++ b/test/files/run/nothingTypeDce.flags @@ -1 +1 @@ --target:jvm-1.6 -Ybackend:GenBCode -Yopt:unreachable-code +-Ybackend:GenBCode -Yopt:unreachable-code diff --git a/test/files/run/nothingTypeDce.scala b/test/files/run/nothingTypeDce.scala index 5f3692fd33..92d3ca6f89 100644 --- a/test/files/run/nothingTypeDce.scala +++ b/test/files/run/nothingTypeDce.scala @@ -1,7 +1,6 @@ // See comment in BCodeBodyBuilder -// -target:jvm-1.6 -Ybackend:GenBCode -Yopt:unreachable-code -// target enables stack map frames generation +// -Ybackend:GenBCode -Yopt:unreachable-code class C { // can't just emit a call to ???, that returns value of type Nothing$ (not Int). diff --git a/test/files/run/nothingTypeNoFramesNoDce.check b/test/files/run/nothingTypeNoFramesNoDce.check deleted file mode 100644 index b1d08b45ff..0000000000 --- a/test/files/run/nothingTypeNoFramesNoDce.check +++ /dev/null @@ -1 +0,0 @@ -warning: -target:jvm-1.5 is deprecated: use target for Java 1.6 or above. diff --git a/test/files/run/nothingTypeNoFramesNoDce.flags b/test/files/run/nothingTypeNoFramesNoDce.flags deleted file mode 100644 index a035c86179..0000000000 --- a/test/files/run/nothingTypeNoFramesNoDce.flags +++ /dev/null @@ -1 +0,0 @@ --target:jvm-1.5 -Ybackend:GenBCode -Yopt:l:none -deprecation diff --git a/test/files/run/nothingTypeNoFramesNoDce.scala b/test/files/run/nothingTypeNoFramesNoDce.scala deleted file mode 100644 index 3d1298303a..0000000000 --- a/test/files/run/nothingTypeNoFramesNoDce.scala +++ /dev/null @@ -1,61 +0,0 @@ -// See comment in BCodeBodyBuilder - -// -target:jvm-1.5 -Ybackend:GenBCode -Yopt:l:none -// target disables stack map frame generation. in this mode, the ClssWriter just emits dead code as is. - -class C { - // can't just emit a call to ???, that returns value of type Nothing$ (not Int). - def f1: Int = ??? - - def f2: Int = throw new Error("") - - def f3(x: Boolean) = { - var y = 0 - // cannot assign an object of type Nothing$ to Int - if (x) y = ??? - else y = 1 - y - } - - def f4(x: Boolean) = { - var y = 0 - // tests that whatever is emitted after the throw is valid (what? depends on opts, presence of stack map frames) - if (x) y = throw new Error("") - else y = 1 - y - } - - def f5(x: Boolean) = { - // stack heights need to be the smae. ??? looks to the jvm like returning a value of - // type Nothing$, need to drop or throw it. - println( - if (x) { ???; 10 } - else 20 - ) - } - - def f6(x: Boolean) = { - println( - if (x) { throw new Error(""); 10 } - else 20 - ) - } - - def f7(x: Boolean) = { - println( - if (x) throw new Error("") - else 20 - ) - } - - def f8(x: Boolean) = { - println( - if (x) throw new Error("") - else 20 - ) - } -} - -object Test extends App { - new C() -} diff --git a/test/files/run/nothingTypeNoOpt.flags b/test/files/run/nothingTypeNoOpt.flags index b3b518051b..d3e4d61e19 100644 --- a/test/files/run/nothingTypeNoOpt.flags +++ b/test/files/run/nothingTypeNoOpt.flags @@ -1 +1 @@ --target:jvm-1.6 -Ybackend:GenBCode -Yopt:l:none +-Ybackend:GenBCode -Yopt:l:none diff --git a/test/files/run/repl-javap-app.check b/test/files/run/repl-javap-app.check deleted file mode 100644 index eb3718f44b..0000000000 --- a/test/files/run/repl-javap-app.check +++ /dev/null @@ -1,63 +0,0 @@ -#partest java6 -Welcome to Scala -Type in expressions to have them evaluated. -Type :help for more information. - -scala> :javap -app MyApp$ -public final void delayedEndpoint$MyApp$1(); - Code: - Stack=2, Locals=1, Args_size=1 - 0: getstatic #XX; //Field scala/Console$.MODULE$:Lscala/Console$; - 3: ldc #XX; //String Hello, delayed world. - 5: invokevirtual #XX; //Method scala/Console$.println:(Ljava/lang/Object;)V - 8: return - LocalVariableTable: - Start Length Slot Name Signature - 0 9 0 this LMyApp$; - -scala> :quit -#partest java7 -Welcome to Scala -Type in expressions to have them evaluated. -Type :help for more information. - -scala> :javap -app MyApp$ - public final void delayedEndpoint$MyApp$1(); - flags: ACC_PUBLIC, ACC_FINAL - Code: - stack=2, locals=1, args_size=1 - 0: getstatic #XX // Field scala/Console$.MODULE$:Lscala/Console$; - 3: ldc #XX // String Hello, delayed world. - 5: invokevirtual #XX // Method scala/Console$.println:(Ljava/lang/Object;)V - 8: return - LocalVariableTable: - Start Length Slot Name Signature - 0 9 0 this LMyApp$; - LineNumberTable: - line 5: 0 -} - -scala> :quit -#partest java8 -Welcome to Scala -Type in expressions to have them evaluated. -Type :help for more information. - -scala> :javap -app MyApp$ - public final void delayedEndpoint$MyApp$1(); - descriptor: ()V - flags: ACC_PUBLIC, ACC_FINAL - Code: - stack=2, locals=1, args_size=1 - 0: getstatic #XX // Field scala/Console$.MODULE$:Lscala/Console$; - 3: ldc #XX // String Hello, delayed world. - 5: invokevirtual #XX // Method scala/Console$.println:(Ljava/lang/Object;)V - 8: return - LocalVariableTable: - Start Length Slot Name Signature - 0 9 0 this LMyApp$; - LineNumberTable: - line 5: 0 -} - -scala> :quit diff --git a/test/files/run/repl-javap-app.scala b/test/files/run/repl-javap-app.scala deleted file mode 100644 index ad6076c2d5..0000000000 --- a/test/files/run/repl-javap-app.scala +++ /dev/null @@ -1,21 +0,0 @@ - -import scala.tools.partest.ReplTest - -object MyApp extends App { - Console println "Hello, delayed world." -} - -object Test extends ReplTest { - def code = ":javap -app MyApp$" - - override def welcoming = true - - // The constant pool indices are not the same for GenASM / GenBCode, so - // replacing the exact numbers by XX. - lazy val hasConstantPoolRef = """(.*)(#\d\d)(.*)""".r - - override def normalize(s: String) = s match { - case hasConstantPoolRef(start, ref, end) => start + "#XX" + end - case _ => super.normalize(s) - } -} diff --git a/test/files/run/t2251b.check b/test/files/run/t2251b.check index 4231fc6ea6..b60698d605 100644 --- a/test/files/run/t2251b.check +++ b/test/files/run/t2251b.check @@ -1,4 +1,4 @@ -TypeTag[List[scala.collection.immutable.LinearSeq[B[_ >: D with C <: B[_ >: D with C <: A]]] with scala.collection.AbstractSeq[B[_ >: D with C <: B[_ >: D with C <: A]]] with java.io.Serializable]] +TypeTag[List[scala.collection.immutable.LinearSeq[B[_ >: D with C <: B[_ >: D with C <: A]]] with scala.collection.AbstractSeq[B[_ >: D with C <: B[_ >: D with C <: A]]] with Serializable]] TypeTag[List[scala.collection.immutable.Iterable[B[_ >: F with E with D with C <: B[_ >: F with E with D with C <: A]]] with F with Int => Any]] TypeTag[List[scala.collection.immutable.Seq[B[_ >: D with C <: B[_ >: D with C <: A]]] with scala.collection.AbstractSeq[B[_ >: D with C <: B[_ >: D with C <: A]]] with Serializable]] TypeTag[List[scala.collection.Set[_ >: G with F <: B[_ >: G with F <: B[_ >: G with F <: A]]]]] @@ -6,6 +6,6 @@ TypeTag[List[scala.collection.Set[_ >: G with F <: B[_ >: G with F <: B[_ >: G w TypeTag[List[scala.collection.Set[_ >: G with F <: B[_ >: G with F <: B[_ >: G with F <: A]]]]] TypeTag[List[Seq[B[_ >: G with F <: B[_ >: G with F <: A]]]]] TypeTag[List[scala.collection.Map[_ >: F with C <: B[_ >: F with C <: B[_ >: F with C <: A]], B[_ >: G with D <: B[_ >: G with D <: A]]]]] -TypeTag[List[scala.collection.AbstractSeq[B[_ >: G with F <: B[_ >: G with F <: A]]] with scala.collection.LinearSeq[B[_ >: G with F <: B[_ >: G with F <: A]]] with java.io.Serializable]] +TypeTag[List[scala.collection.AbstractSeq[B[_ >: G with F <: B[_ >: G with F <: A]]] with scala.collection.LinearSeq[B[_ >: G with F <: B[_ >: G with F <: A]]] with Serializable]] TypeTag[List[Seq[B[_ >: G with F <: B[_ >: G with F <: A]]]]] TypeTag[List[Seq[B[_ >: G with F <: B[_ >: G with F <: A]]]]] diff --git a/test/files/run/t4332.scala b/test/files/run/t4332.scala index 5a67922911..1c7e7d73de 100644 --- a/test/files/run/t4332.scala +++ b/test/files/run/t4332.scala @@ -12,7 +12,7 @@ object Test extends DirectTest { } def isExempt(sym: Symbol) = { - val exempt = Set("view", "repr", "sliceWithKnownDelta", "sliceWithKnownBound", "transform") + val exempt = Set("view", "repr", "sliceWithKnownDelta", "sliceWithKnownBound", "transform", "filterImpl") (exempt contains sym.name.decoded) } diff --git a/test/files/run/t6827.check b/test/files/run/t6827.check index 3a3a71c67d..4889e05be8 100644 --- a/test/files/run/t6827.check +++ b/test/files/run/t6827.check @@ -1,6 +1,6 @@ -start at -5: java.lang.IllegalArgumentException: requirement failed: start -5 out of range 10 -start at -1: java.lang.IllegalArgumentException: requirement failed: start -1 out of range 10 -start at limit: java.lang.IllegalArgumentException: requirement failed: start 10 out of range 10 +start at -5: java.lang.ArrayIndexOutOfBoundsException: -5 +start at -1: java.lang.ArrayIndexOutOfBoundsException: -1 +start at limit: ok start at limit-1: ok first 10: ok read all: ok @@ -8,8 +8,8 @@ test huge len: ok 5 from 5: ok 20 from 5: ok test len overflow: ok -start beyond limit: java.lang.IllegalArgumentException: requirement failed: start 30 out of range 10 +start beyond limit: ok read 0: ok read -1: ok -invalid read 0: java.lang.IllegalArgumentException: requirement failed: start 30 out of range 10 -invalid read -1: java.lang.IllegalArgumentException: requirement failed: start 30 out of range 10 +invalid read 0: ok +invalid read -1: ok diff --git a/test/files/run/t6827.scala b/test/files/run/t6827.scala index 8e17af09e2..eb020711bb 100644 --- a/test/files/run/t6827.scala +++ b/test/files/run/t6827.scala @@ -31,4 +31,24 @@ object Test extends App { // okay, see SI-7128 "...".toIterator.copyToArray(new Array[Char](0), 0, 0) + + + // Bonus test from @som-snytt to check for overflow in + // index calculations. + def testOverflow(start: Int, len: Int, expected: List[Char]) { + def copyFromIterator = { + val arr = Array.fill[Char](3)('-') + "abc".toIterator.copyToArray(arr, start, len) + arr.toList + } + def copyFromArray = { + val arr = Array.fill[Char](3)('-') + "abc".toArray.copyToArray(arr, start, len) + arr.toList + } + assert(copyFromIterator == expected) + assert(copyFromArray == expected) + } + testOverflow(1, Int.MaxValue - 1, "-ab".toList) + testOverflow(1, Int.MaxValue, "-ab".toList) } diff --git a/test/files/run/t7521/Test.scala b/test/files/run/t7521/Test.scala new file mode 100644 index 0000000000..e9816ad6cb --- /dev/null +++ b/test/files/run/t7521/Test.scala @@ -0,0 +1,5 @@ +object Test { + def main(args: Array[String]): Unit = { + new Wrapper(new Array[Int](1)) + } +} diff --git a/test/files/run/t7521/Wrapper.scala b/test/files/run/t7521/Wrapper.scala new file mode 100644 index 0000000000..0b923f8924 --- /dev/null +++ b/test/files/run/t7521/Wrapper.scala @@ -0,0 +1 @@ +class Wrapper[Repr](val xs: Repr) extends AnyVal diff --git a/test/files/run/t7521b.check b/test/files/run/t7521b.check new file mode 100644 index 0000000000..4d96df106d --- /dev/null +++ b/test/files/run/t7521b.check @@ -0,0 +1,7 @@ += Java Erased Signatures = +public int C.a(Wrapper) +public int C.b(Wrapper) + += Java Generic Signatures = +public int C.a(Wrapper<int[]>) +public int C.b(Wrapper<java.lang.Object>) diff --git a/test/files/run/t7521b.scala b/test/files/run/t7521b.scala new file mode 100644 index 0000000000..c9e27f28b4 --- /dev/null +++ b/test/files/run/t7521b.scala @@ -0,0 +1,20 @@ +class Wrapper[X](x: X) + +class C { + def a(w: Wrapper[Array[Int]]) = 0 + def b(w: Wrapper[Int]) = 0 +} + +object Test { + def main(args: Array[String]): Unit = { + val c = new C + c.a(new Wrapper(Array(1, 2))) + c.b(new Wrapper(1)) + + val methods = classOf[C].getDeclaredMethods.sortBy(_.getName) + println("= Java Erased Signatures =") + println(methods.mkString("\n")) + println("\n= Java Generic Signatures =") + println(methods.map(_.toGenericString).mkString("\n")) + } +} diff --git a/test/files/run/t7775.scala b/test/files/run/t7775.scala index 48b0d89974..bc69064e17 100644 --- a/test/files/run/t7775.scala +++ b/test/files/run/t7775.scala @@ -1,3 +1,45 @@ +import scala.concurrent._, duration._ +import ExecutionContext.Implicits.global +import scala.tools.reflect.WrappedProperties.AccessControl._ +import java.util.concurrent.CyclicBarrier + +object Test extends App { + @volatile var done = false + val barrier = new CyclicBarrier(2) + + val probe = Future { + val attempts = 1024 // previously, failed after a few + def fail(i: Int) = s"Failed at $i" + barrier.await() + for (i <- 1 to attempts ; p <- systemProperties) + p match { case (k, v) => assert (k != null && v != null, fail(i)) } + } + probe onComplete { + case _ => done = true + } + + System.setProperty("foo", "fooz") + System.setProperty("bar", "barz") + barrier.await() // just for fun, wait to start mucking with properties + + // continually modify properties trying to break live iteration over sys props + // hint: don't iterate lively over sys props + var alt = true + while (!done) { + if (alt) { + System.getProperties.remove("foo") + System.setProperty("bar", "barz") + alt = false + } else { + System.getProperties.remove("bar") + System.setProperty("foo", "fooz") + alt = true + } + } + Await.result(probe, Duration.Inf) +} + +/* import scala.concurrent.{duration, Future, Await, ExecutionContext} import scala.tools.nsc.Settings import ExecutionContext.Implicits.global @@ -15,3 +57,4 @@ object Test { Await.result(compiler, duration.Duration.Inf) } } +*/ diff --git a/test/files/run/t8575.scala b/test/files/run/t8575.scala new file mode 100644 index 0000000000..fb8f603f3e --- /dev/null +++ b/test/files/run/t8575.scala @@ -0,0 +1,32 @@ +class E[F] +class A +class B +class C + +trait TypeMember { + type X + + // This call throws an AbstractMethodError, because it invokes the erasure of + // consume(X): Unit that is consume(Object): Unit. But the corresponding + // bridge method is not generated. + consume(value) + + def value: X + def consume(x: X): Unit +} + +object Test extends TypeMember { + type F = A with B + + // works if replaced by type X = E[A with B with C] + type X = E[F with C] + + def value = new E[F with C] + + // This call passes, since it invokes consume(E): Unit + def consume(x: X) {} + + def main(args: Array[String]) { + consume(value) + } +} diff --git a/test/files/run/t8575b.scala b/test/files/run/t8575b.scala new file mode 100644 index 0000000000..0d731ccf9f --- /dev/null +++ b/test/files/run/t8575b.scala @@ -0,0 +1,17 @@ +class A +class B +class C + +object Test { + type F = A with B + + def main(args: Array[String]) { + import reflect.runtime.universe._ + val t1 = typeOf[F with C] + val t2 = typeOf[(A with B) with C] + val t3 = typeOf[A with B with C] + assert(t1 =:= t2) + assert(t2 =:= t3) + assert(t3 =:= t1) + } +} diff --git a/test/files/run/t8575c.scala b/test/files/run/t8575c.scala new file mode 100644 index 0000000000..8219952299 --- /dev/null +++ b/test/files/run/t8575c.scala @@ -0,0 +1,23 @@ +class C + +trait TypeMember { + type X + type Y + type Z +} + +object Test extends TypeMember { + type A = X with Y + type B = Z with A + type F = A with B + + def main(args: Array[String]) { + import reflect.runtime.universe._ + val t1 = typeOf[F with C] + val t2 = typeOf[(A with B) with C] + val t3 = typeOf[A with B with C] + assert(t1 =:= t2) + assert(t2 =:= t3) + assert(t3 =:= t1) + } +} diff --git a/test/files/run/t8710.scala b/test/files/run/t8710.scala new file mode 100644 index 0000000000..15aab5b8a4 --- /dev/null +++ b/test/files/run/t8710.scala @@ -0,0 +1,17 @@ +class Bar(val x: Int) extends AnyVal { + def f: String = f(0) + private def f(x: Int): String = "" +} + +class Baz(val x: Int) extends AnyVal { + def f: String = "123" + private def f(x: Int): String = "" +} +object Baz { + def x(b: Baz) = b.f(0) +} + +object Test extends App { + new Bar(23).f + new Baz(23).f +} diff --git a/test/files/run/t8764.check b/test/files/run/t8764.check deleted file mode 100644 index 6260069602..0000000000 --- a/test/files/run/t8764.check +++ /dev/null @@ -1,5 +0,0 @@ -IntOnly: should return an unboxed int -Int: int -IntAndDouble: should just box and return Anyval -Double: class java.lang.Double -Int: class java.lang.Integer diff --git a/test/files/run/t8764.flags b/test/files/run/t8764.flags deleted file mode 100644 index 48fd867160..0000000000 --- a/test/files/run/t8764.flags +++ /dev/null @@ -1 +0,0 @@ --Xexperimental diff --git a/test/files/run/t8764.scala b/test/files/run/t8764.scala deleted file mode 100644 index decc658f6e..0000000000 --- a/test/files/run/t8764.scala +++ /dev/null @@ -1,16 +0,0 @@ -object Test extends App { -case class IntOnly(i: Int, j: Int) - -println("IntOnly: should return an unboxed int") -val a = IntOnly(1, 2) -val i: Int = a.productElement(0) -println(s"Int: ${a.productElement(0).getClass}") - -case class IntAndDouble(i: Int, d: Double) - -println("IntAndDouble: should just box and return Anyval") -val b = IntAndDouble(1, 2.0) -val j: AnyVal = b.productElement(0) -println(s"Double: ${b.productElement(1).getClass}") -println(s"Int: ${b.productElement(0).getClass}") -} diff --git a/test/files/run/t8918-unary-ids.scala b/test/files/run/t8918-unary-ids.scala new file mode 100644 index 0000000000..3aa990f72c --- /dev/null +++ b/test/files/run/t8918-unary-ids.scala @@ -0,0 +1,49 @@ + + +import scala.tools.partest.SessionTest + +// Taking unary ids as plain +object Test extends SessionTest { + def session = +"""Type in expressions to have them evaluated. +Type :help for more information. + +scala> val - = 42 +-: Int = 42 + +scala> val i = - +i: Int = 42 + +scala> - { 42 } +res0: Int = -42 + +scala> - if (true) 1 else 2 +<console>:1: error: illegal start of simple expression +- if (true) 1 else 2 + ^ + +scala> - - 1 +<console>:1: error: ';' expected but integer literal found. +- - 1 + ^ + +scala> -.-(1) +res1: Int = 41 + +scala> - +res2: Int = 42 + +scala> - - +res3: Int = -42 + +scala> + - +res4: Int = 42 + +scala> object X { def -(i: Int) = 42 - i ; def f(g: Int => Int) = g(7) ; def j = f(-) } +defined object X + +scala> X.j +res5: Int = 35 + +scala> :quit""" +} diff --git a/test/files/run/t8944/A_1.scala b/test/files/run/t8944/A_1.scala new file mode 100644 index 0000000000..7ff80327b0 --- /dev/null +++ b/test/files/run/t8944/A_1.scala @@ -0,0 +1 @@ +case class A(private val x: String) diff --git a/test/files/run/t8944/A_2.scala b/test/files/run/t8944/A_2.scala new file mode 100644 index 0000000000..3dcdea1583 --- /dev/null +++ b/test/files/run/t8944/A_2.scala @@ -0,0 +1,6 @@ +case class Other(private val x: String) // consume a fresh name suffix + +// the param accessor will now be called "x$2", +// whereas the previously compiled client expects it to be called +// x$1 +case class A(private val x: String) diff --git a/test/files/run/t8944/Test_1.scala b/test/files/run/t8944/Test_1.scala new file mode 100644 index 0000000000..fe466693cf --- /dev/null +++ b/test/files/run/t8944/Test_1.scala @@ -0,0 +1,3 @@ +object Test extends App { + val A("") = new A("") +} diff --git a/test/files/run/t8944b.scala b/test/files/run/t8944b.scala new file mode 100644 index 0000000000..f469122ce6 --- /dev/null +++ b/test/files/run/t8944b.scala @@ -0,0 +1,9 @@ +case class A(private var foo: Any) { + def m = { def foo = 42 /*will be lamba lifted to `A#foo$1`*/ } +} +object Test { + def main(args: Array[String]): Unit = { + val A("") = new A("") + new A("").m + } +} diff --git a/test/files/run/t8944c.check b/test/files/run/t8944c.check new file mode 100644 index 0000000000..7738f76980 --- /dev/null +++ b/test/files/run/t8944c.check @@ -0,0 +1,5 @@ +private java.lang.Object Foo.ant() +public java.lang.Object Foo.ant$access$0() +private scala.collection.Seq Foo.cat() +public scala.collection.Seq Foo.cat$access$2() +public java.lang.Object Foo.elk() diff --git a/test/files/run/t8944c.scala b/test/files/run/t8944c.scala new file mode 100644 index 0000000000..95c2143851 --- /dev/null +++ b/test/files/run/t8944c.scala @@ -0,0 +1,8 @@ +case class Foo[A](private val ant: Any, elk: Any, private val cat: A*) + +object Test { + def main(args: Array[String]): Unit = { + def pred(name: String) = Set("ant", "elk", "cat").exists(name contains _) + println(classOf[Foo[_]].getDeclaredMethods.filter(m => pred(m.getName)).sortBy(_.getName).mkString("\n")) + } +} diff --git a/test/files/run/t8955.scala b/test/files/run/t8955.scala new file mode 100644 index 0000000000..afa31aa5d7 --- /dev/null +++ b/test/files/run/t8955.scala @@ -0,0 +1,12 @@ +import scala.collection.parallel.immutable.ParSet + +object Test { + def main(args: Array[String]): Unit = { + for (i <- 1 to 2000) test() + } + + def test() { + ParSet[Int]((1 to 10000): _*) foreach (x => ()) // hangs non deterministically + } +} + diff --git a/test/files/run/t9174.check b/test/files/run/t9174.check new file mode 100644 index 0000000000..9320a081ff --- /dev/null +++ b/test/files/run/t9174.check @@ -0,0 +1,19 @@ +Type in expressions to have them evaluated. +Type :help for more information. + +scala> import scala.util.{Success, Failure} +import scala.util.{Success, Failure} + +scala> def f1(b: Boolean) = if (b) Left(1) else Right(2) +f1: (b: Boolean)scala.util.Either[Int,Int] + +scala> def f2(b: Boolean) = if (b) Nil else 1 :: Nil +f2: (b: Boolean)List[Int] + +scala> def f3(b: Boolean) = if (b) Stream.Empty else new Stream.Cons(1, Stream.Empty) +f3: (b: Boolean)scala.collection.immutable.Stream[Int] + +scala> def f4(b: Boolean) = if (b) Success(1) else Failure(new Exception("")) +f4: (b: Boolean)scala.util.Try[Int] + +scala> :quit diff --git a/test/files/run/t9174.scala b/test/files/run/t9174.scala new file mode 100644 index 0000000000..0c70e9bca9 --- /dev/null +++ b/test/files/run/t9174.scala @@ -0,0 +1,11 @@ +import scala.tools.partest.ReplTest + +object Test extends ReplTest { + def code = """ + |import scala.util.{Success, Failure} + |def f1(b: Boolean) = if (b) Left(1) else Right(2) + |def f2(b: Boolean) = if (b) Nil else 1 :: Nil + |def f3(b: Boolean) = if (b) Stream.Empty else new Stream.Cons(1, Stream.Empty) + |def f4(b: Boolean) = if (b) Success(1) else Failure(new Exception("")) + |""".stripMargin +} diff --git a/test/files/run/t9200/Test.java b/test/files/run/t9200/Test.java new file mode 100644 index 0000000000..8ff0314f6c --- /dev/null +++ b/test/files/run/t9200/Test.java @@ -0,0 +1,6 @@ +public class Test { + public static void main(String[] args) { + new C1(new C2()); // Was NoSuchMethodError + } +} + diff --git a/test/files/run/t9200/test.scala b/test/files/run/t9200/test.scala new file mode 100644 index 0000000000..6fa7e91571 --- /dev/null +++ b/test/files/run/t9200/test.scala @@ -0,0 +1,12 @@ +trait W + +trait T1 +trait T2 extends T1 + +object O1 { + type t = T1 with T2 +} + +class C1[w<:W](o: O1.t) + +class C2 extends T1 with T2 diff --git a/test/files/scalacheck/concurrent-map.scala b/test/files/scalacheck/concurrent-map.scala new file mode 100755 index 0000000000..7c9b8d4169 --- /dev/null +++ b/test/files/scalacheck/concurrent-map.scala @@ -0,0 +1,76 @@ + + + +import java.util.concurrent._ +import scala.collection._ +import scala.collection.JavaConverters._ +import org.scalacheck._ +import org.scalacheck.Prop._ +import org.scalacheck.Gen._ + + + +case class Wrap(i: Int) { + override def hashCode = i * 0x9e3775cd +} + + +object Test extends Properties("concurrent.TrieMap") { + + /* generators */ + + val sizes = choose(0, 20000) + + val threadCounts = choose(2, 16) + + val threadCountsAndSizes = for { + p <- threadCounts + sz <- sizes + } yield (p, sz); + + + /* helpers */ + + def inParallel[T](totalThreads: Int)(body: Int => T): Seq[T] = { + val threads = for (idx <- 0 until totalThreads) yield new Thread { + setName("ParThread-" + idx) + private var res: T = _ + override def run() { + res = body(idx) + } + def result = { + this.join() + res + } + } + + threads foreach (_.start()) + threads map (_.result) + } + + property("concurrent getOrElseUpdate insertions") = forAll(threadCounts, sizes) { + (p, sz) => + val chm = new ConcurrentHashMap[Wrap, Int]().asScala + + val results = inParallel(p) { + idx => + for (i <- 0 until sz) yield chm.getOrElseUpdate(new Wrap(i), idx) + } + + val resultSets = for (i <- 0 until sz) yield results.map(_(i)).toSet + val largerThanOne = resultSets.zipWithIndex.find(_._1.size != 1) + val allThreadsAgreeOnWhoInserted = { + largerThanOne == None + } :| s"$p threads agree on who inserted [disagreement (differentResults, position) = $largerThanOne]" + + allThreadsAgreeOnWhoInserted + } + + +} + + + + + + diff --git a/test/junit/scala/collection/IteratorTest.scala b/test/junit/scala/collection/IteratorTest.scala index 1c1e50aed9..b0639ef365 100644 --- a/test/junit/scala/collection/IteratorTest.scala +++ b/test/junit/scala/collection/IteratorTest.scala @@ -135,6 +135,20 @@ class IteratorTest { assertEquals(3, List(1, 2, 3, 4, 5).iterator.indexWhere { x: Int => x >= 4 }) assertEquals(-1, List(1, 2, 3, 4, 5).iterator.indexWhere { x: Int => x >= 16 }) } + @Test def indexOfFrom(): Unit = { + assertEquals(1, List(1, 2, 3, 4, 5).iterator.indexOf(2, 0)) + assertEquals(1, List(1, 2, 3, 4, 5).iterator.indexOf(2, 1)) + assertEquals(-1, List(1, 2, 3, 4, 5).iterator.indexOf(2, 2)) + assertEquals(4, List(1, 2, 3, 2, 1).iterator.indexOf(1, 1)) + assertEquals(1, List(1, 2, 3, 2, 1).iterator.indexOf(2, 1)) + } + @Test def indexWhereFrom(): Unit = { + assertEquals(1, List(1, 2, 3, 4, 5).iterator.indexWhere(_ == 2, 0)) + assertEquals(1, List(1, 2, 3, 4, 5).iterator.indexWhere(_ == 2, 1)) + assertEquals(-1, List(1, 2, 3, 4, 5).iterator.indexWhere(_ == 2, 2)) + assertEquals(4, List(1, 2, 3, 2, 1).iterator.indexWhere(_ < 2, 1)) + assertEquals(1, List(1, 2, 3, 2, 1).iterator.indexWhere(_ <= 2, 1)) + } // iterator-iterate-lazy.scala // was java.lang.UnsupportedOperationException: tail of empty list @Test def iterateIsSufficientlyLazy(): Unit = { @@ -154,6 +168,14 @@ class IteratorTest { results += (Stream from 1).toIterator.drop(10).toStream.drop(10).toIterator.next() assertSameElements(List(1,1,21), results) } + // SI-8552 + @Test def indexOfShouldWorkForTwoParams(): Unit = { + assertEquals(1, List(1, 2, 3).iterator.indexOf(2, 0)) + assertEquals(-1, List(5 -> 0).iterator.indexOf(5, 0)) + assertEquals(0, List(5 -> 0).iterator.indexOf((5, 0))) + assertEquals(-1, List(5 -> 0, 9 -> 2, 0 -> 3).iterator.indexOf(9, 2)) + assertEquals(1, List(5 -> 0, 9 -> 2, 0 -> 3).iterator.indexOf(9 -> 2)) + } // SI-9332 @Test def spanExhaustsLeadingIterator(): Unit = { def it = Iterator.iterate(0)(_ + 1).take(6) diff --git a/test/junit/scala/collection/SeqViewTest.scala b/test/junit/scala/collection/SeqViewTest.scala new file mode 100644 index 0000000000..24474fc4b9 --- /dev/null +++ b/test/junit/scala/collection/SeqViewTest.scala @@ -0,0 +1,16 @@ +package scala.collection + +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import org.junit.Assert._ +import org.junit.Test + +@RunWith(classOf[JUnit4]) +class SeqViewTest { + + @Test + def test_SI8691() { + // Really just testing to make sure ++: doesn't throw an exception + assert( Seq(1,2) ++: Seq(3,4).view == Seq(1,2,3,4) ) + } +} diff --git a/test/junit/scala/collection/SetMapConsistencyTest.scala b/test/junit/scala/collection/SetMapConsistencyTest.scala index 261c11a98b..0749e61c09 100644 --- a/test/junit/scala/collection/SetMapConsistencyTest.scala +++ b/test/junit/scala/collection/SetMapConsistencyTest.scala @@ -529,4 +529,15 @@ class SetMapConsistencyTest { assert(nit == 4) assert(nfe == 4) } + + @Test + def test_SI8727() { + import scala.tools.testing.AssertUtil._ + type NSEE = NoSuchElementException + val map = Map(0 -> "zero", 1 -> "one") + val m = map.filterKeys(i => if (map contains i) true else throw new NSEE) + assert{ (m contains 0) && (m get 0).nonEmpty } + assertThrows[NSEE]{ m contains 2 } + assertThrows[NSEE]{ m get 2 } + } } diff --git a/test/junit/scala/collection/convert/NullSafetyTest.scala b/test/junit/scala/collection/convert/NullSafetyTest.scala new file mode 100644 index 0000000000..de5481d9e2 --- /dev/null +++ b/test/junit/scala/collection/convert/NullSafetyTest.scala @@ -0,0 +1,279 @@ +package scala.collection.convert + +import java.{util => ju, lang => jl} +import ju.{concurrent => juc} + +import org.junit.Test +import org.junit.experimental.runners.Enclosed +import org.junit.runner.RunWith + +import scala.collection.JavaConversions._ +import scala.collection.JavaConverters._ +import scala.collection.{mutable, concurrent} + +@RunWith(classOf[Enclosed]) +object NullSafetyTest { + + /* + * Pertinent: SI-9113 + * Tests to insure that wrappers return null instead of wrapping it as a collection + */ + + class ToScala { + + @Test def testIteratorWrapping(): Unit = { + val nullJIterator: ju.Iterator[AnyRef] = null + val iterator: Iterator[AnyRef] = nullJIterator + + assert(iterator == null) + } + + @Test def testEnumerationWrapping(): Unit = { + val nullJEnumeration: ju.Enumeration[AnyRef] = null + val enumeration: Iterator[AnyRef] = nullJEnumeration + + assert(enumeration == null) + } + + @Test def testIterableWrapping(): Unit = { + val nullJIterable: jl.Iterable[AnyRef] = null + val iterable: Iterable[AnyRef] = nullJIterable + + assert(iterable == null) + } + + @Test def testCollectionWrapping(): Unit = { + val nullJCollection: ju.Collection[AnyRef] = null + val collection: Iterable[AnyRef] = nullJCollection + + assert(collection == null) + } + + @Test def testBufferWrapping(): Unit = { + val nullJList: ju.List[AnyRef] = null + val buffer: mutable.Buffer[AnyRef] = nullJList + + assert(buffer == null) + } + + @Test def testSetWrapping(): Unit = { + val nullJSet: ju.Set[AnyRef] = null + val set: mutable.Set[AnyRef] = nullJSet + + assert(set == null) + } + + @Test def testMapWrapping(): Unit = { + val nullJMap: ju.Map[AnyRef, AnyRef] = null + val map: mutable.Map[AnyRef, AnyRef] = nullJMap + + assert(map == null) + } + + @Test def testConcurrentMapWrapping(): Unit = { + val nullJConMap: juc.ConcurrentMap[AnyRef, AnyRef] = null + val conMap: concurrent.Map[AnyRef, AnyRef] = nullJConMap + + assert(conMap == null) + } + + @Test def testDictionaryWrapping(): Unit = { + val nullJDict: ju.Dictionary[AnyRef, AnyRef] = null + val dict: mutable.Map[AnyRef, AnyRef] = nullJDict + + assert(dict == null) + } + + + @Test def testPropertyWrapping(): Unit = { + val nullJProps: ju.Properties = null + val props: mutable.Map[String, String] = nullJProps + + assert(props == null) + } + + @Test def testIteratorDecoration(): Unit = { + val nullJIterator: ju.Iterator[AnyRef] = null + + assert(nullJIterator.asScala == null) + } + + @Test def testEnumerationDecoration(): Unit = { + val nullJEnumeration: ju.Enumeration[AnyRef] = null + + assert(nullJEnumeration.asScala == null) + } + + @Test def testIterableDecoration(): Unit = { + val nullJIterable: jl.Iterable[AnyRef] = null + + assert(nullJIterable.asScala == null) + } + + @Test def testCollectionDecoration(): Unit = { + val nullJCollection: ju.Collection[AnyRef] = null + + assert(nullJCollection.asScala == null) + } + + @Test def testBufferDecoration(): Unit = { + val nullJBuffer: ju.List[AnyRef] = null + + assert(nullJBuffer.asScala == null) + } + + @Test def testSetDecoration(): Unit = { + val nullJSet: ju.Set[AnyRef] = null + + assert(nullJSet.asScala == null) + } + + @Test def testMapDecoration(): Unit = { + val nullJMap: ju.Map[AnyRef, AnyRef] = null + + assert(nullJMap.asScala == null) + } + + @Test def testConcurrentMapDecoration(): Unit = { + val nullJConMap: juc.ConcurrentMap[AnyRef, AnyRef] = null + + assert(nullJConMap.asScala == null) + } + + @Test def testDictionaryDecoration(): Unit = { + val nullJDict: ju.Dictionary[AnyRef, AnyRef] = null + + assert(nullJDict.asScala == null) + } + + @Test def testPropertiesDecoration(): Unit = { + val nullJProperties: ju.Properties = null + + assert(nullJProperties.asScala == null) + } + } + + class ToJava { + + @Test def testIteratorWrapping(): Unit = { + val nullIterator: Iterator[AnyRef] = null + val jIterator: ju.Iterator[AnyRef] = nullIterator + + assert(jIterator == null) + } + + @Test def testEnumerationWrapping(): Unit = { + val nullEnumeration: Iterator[AnyRef] = null + val enumeration: ju.Iterator[AnyRef] = nullEnumeration + + assert(enumeration == null) + } + + @Test def testIterableWrapping(): Unit = { + val nullIterable: Iterable[AnyRef] = null + val iterable: jl.Iterable[AnyRef] = asJavaIterable(nullIterable) + + assert(iterable == null) + } + + @Test def testCollectionWrapping(): Unit = { + val nullCollection: Iterable[AnyRef] = null + val collection: ju.Collection[AnyRef] = nullCollection + + assert(collection == null) + } + + @Test def testBufferWrapping(): Unit = { + val nullList: mutable.Buffer[AnyRef] = null + val buffer: ju.List[AnyRef] = nullList + + assert(buffer == null) + } + + @Test def testSetWrapping(): Unit = { + val nullSet: mutable.Set[AnyRef] = null + val set: ju.Set[AnyRef] = nullSet + + assert(set == null) + } + + @Test def testMapWrapping(): Unit = { + val nullMap: mutable.Map[AnyRef, AnyRef] = null + val map: ju.Map[AnyRef, AnyRef] = nullMap + + assert(map == null) + } + + @Test def testConcurrentMapWrapping(): Unit = { + val nullConMap: concurrent.Map[AnyRef, AnyRef] = null + val conMap: juc.ConcurrentMap[AnyRef, AnyRef] = nullConMap + + assert(conMap == null) + } + + @Test def testDictionaryWrapping(): Unit = { + val nullDict: mutable.Map[AnyRef, AnyRef] = null + val dict: ju.Dictionary[AnyRef, AnyRef] = nullDict + + assert(dict == null) + } + + // Implicit conversion to ju.Properties is not available + + @Test def testIteratorDecoration(): Unit = { + val nullIterator: Iterator[AnyRef] = null + + assert(nullIterator.asJava == null) + } + + @Test def testEnumerationDecoration(): Unit = { + val nullEnumeration: Iterator[AnyRef] = null + + assert(nullEnumeration.asJavaEnumeration == null) + } + + @Test def testIterableDecoration(): Unit = { + val nullIterable: Iterable[AnyRef] = null + + assert(nullIterable.asJava == null) + } + + @Test def testCollectionDecoration(): Unit = { + val nullCollection: Iterable[AnyRef] = null + + assert(nullCollection.asJavaCollection == null) + } + + @Test def testBufferDecoration(): Unit = { + val nullBuffer: mutable.Buffer[AnyRef] = null + + assert(nullBuffer.asJava == null) + } + + @Test def testSetDecoration(): Unit = { + val nullSet: Set[AnyRef] = null + + assert(nullSet.asJava == null) + } + + @Test def testMapDecoration(): Unit = { + val nullMap: mutable.Map[AnyRef, AnyRef] = null + + assert(nullMap.asJava == null) + } + + @Test def testConcurrentMapDecoration(): Unit = { + val nullConMap: concurrent.Map[AnyRef, AnyRef] = null + + assert(nullConMap.asJava == null) + } + + @Test def testDictionaryDecoration(): Unit = { + val nullDict: mutable.Map[AnyRef, AnyRef] = null + + assert(nullDict.asJavaDictionary == null) + } + + // Decorator conversion to ju.Properties is not available + } +} diff --git a/test/junit/scala/collection/immutable/StreamTest.scala b/test/junit/scala/collection/immutable/StreamTest.scala new file mode 100644 index 0000000000..437cbc8926 --- /dev/null +++ b/test/junit/scala/collection/immutable/StreamTest.scala @@ -0,0 +1,108 @@ +package scala.collection.immutable + +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import org.junit.Test +import org.junit.Assert._ + +import scala.ref.WeakReference +import scala.util.Try + +@RunWith(classOf[JUnit4]) +class StreamTest { + + @Test + def t6727_and_t6440(): Unit = { + assertTrue(Stream.continually(()).filter(_ => true).take(2) == Seq((), ())) + assertTrue(Stream.continually(()).filterNot(_ => false).take(2) == Seq((), ())) + assertTrue(Stream(1,2,3,4,5).filter(_ < 4) == Seq(1,2,3)) + assertTrue(Stream(1,2,3,4,5).filterNot(_ > 4) == Seq(1,2,3,4)) + } + + /** Test helper to verify that the given Stream operation allows + * GC of the head during processing of the tail. + */ + def assertStreamOpAllowsGC(op: (=> Stream[Int], Int => Unit) => Any, f: Int => Unit): Unit = { + val msgSuccessGC = "GC success" + val msgFailureGC = "GC failure" + + // A stream of 500 elements at most. We will test that the head can be collected + // while processing the tail. After each element we will GC and wait 10 ms, so a + // failure to collect will take roughly 5 seconds. + val ref = WeakReference( Stream.from(1).take(500) ) + + def gcAndThrowIfCollected(n: Int): Unit = { + System.gc() // try to GC + Thread.sleep(10) // give it 10 ms + if (ref.get.isEmpty) throw new RuntimeException(msgSuccessGC) // we're done if head collected + f(n) + } + + val res = Try { op(ref(), gcAndThrowIfCollected) }.failed // success is indicated by an + val msg = res.map(_.getMessage).getOrElse(msgFailureGC) // exception with expected message + // failure is indicated by no + assertTrue(msg == msgSuccessGC) // exception, or one with different message + } + + @Test + def foreach_allows_GC() { + assertStreamOpAllowsGC(_.foreach(_), _ => ()) + } + + @Test + def filter_all_foreach_allows_GC() { + assertStreamOpAllowsGC(_.filter(_ => true).foreach(_), _ => ()) + } + + @Test // SI-8990 + def withFilter_after_first_foreach_allows_GC: Unit = { + assertStreamOpAllowsGC(_.withFilter(_ > 1).foreach(_), _ => ()) + } + + @Test // SI-8990 + def withFilter_after_first_withFilter_foreach_allows_GC: Unit = { + assertStreamOpAllowsGC(_.withFilter(_ > 1).withFilter(_ < 100).foreach(_), _ => ()) + } + + @Test // SI-8990 + def withFilter_can_retry_after_exception_thrown_in_filter: Unit = { + // use mutable state to control an intermittent failure in filtering the Stream + var shouldThrow = true + + val wf = Stream.from(1).take(10).withFilter { n => + if (shouldThrow && n == 5) throw new RuntimeException("n == 5") else n > 5 + } + + assertTrue( Try { wf.map(identity) }.isFailure ) // throws on n == 5 + + shouldThrow = false // won't throw next time + + assertTrue( wf.map(identity).length == 5 ) // success instead of NPE + } + + /** Test helper to verify that the given Stream operation is properly lazy in the tail */ + def assertStreamOpLazyInTail(op: (=> Stream[Int]) => Stream[Int], expectedEvaluated: List[Int]): Unit = { + // mutable state to record every strict evaluation + var evaluated: List[Int] = Nil + + def trackEffectsOnNaturals: Stream[Int] = { + def loop(i: Int): Stream[Int] = { evaluated ++= List(i); i #:: loop(i + 1) } + loop(1) + } + + // call op on a stream which records every strict evaluation + val result = op(trackEffectsOnNaturals) + + assertTrue( evaluated == expectedEvaluated ) + } + + @Test // SI-9134 + def filter_map_properly_lazy_in_tail: Unit = { + assertStreamOpLazyInTail(_.filter(_ % 2 == 0).map(identity), List(1, 2)) + } + + @Test // SI-9134 + def withFilter_map_properly_lazy_in_tail: Unit = { + assertStreamOpLazyInTail(_.withFilter(_ % 2 == 0).map(identity), List(1, 2)) + } +} diff --git a/test/junit/scala/sys/process/t7350.scala b/test/junit/scala/sys/process/t7350.scala new file mode 100644 index 0000000000..7f3e8897f2 --- /dev/null +++ b/test/junit/scala/sys/process/t7350.scala @@ -0,0 +1,298 @@ + +package scala.sys.process + +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import org.junit.Test +import java.io.{InputStream, OutputStream, PipedInputStream, PipedOutputStream, ByteArrayInputStream, + ByteArrayOutputStream, IOException, Closeable} +import java.lang.reflect.InvocationTargetException +import scala.concurrent.{Await, Future} +import scala.concurrent.duration.{Duration, SECONDS} +import scala.concurrent.ExecutionContext.Implicits.global +import scala.util.control.Exception.ignoring + +// Each test normally ends in a moment, but for failure cases, waits until one second. + +@RunWith(classOf[JUnit4]) +class PipedProcessTest { + class ProcessMock(error: Boolean) extends Process { + var destroyCount = 0 + def exitValue(): Int = { + if (error) { + throw new InterruptedException() + } + 0 + } + def destroy(): Unit = { destroyCount += 1 } + } + + class ProcessBuilderMock(process: Process, error: Boolean) extends ProcessBuilder.AbstractBuilder { + override def run(io: ProcessIO): Process = { + if (error) { + throw new IOException() + } + process + } + } + + class PipeSinkMock extends Process.PipeSink("PipeSinkMock") { + var releaseCount = 0 + override val pipe = null + override val sink = null + override def run(): Unit = {} + override def connectOut(out: OutputStream): Unit = {} + override def connectIn(pipeOut: PipedOutputStream): Unit = {} + override def release(): Unit = { releaseCount += 1 } + } + + class PipeSourceMock extends Process.PipeSource("PipeSourceMock") { + var releaseCount = 0 + override val pipe = null + override val source = null + override def run(): Unit = {} + override def connectIn(in: InputStream): Unit = {} + override def connectOut(sink: Process.PipeSink): Unit = {} + override def release(): Unit = { releaseCount += 1 } + } + + class PipedProcesses(a: ProcessBuilder, b: ProcessBuilder, defaultIO: ProcessIO, toError: Boolean) + extends Process.PipedProcesses(a, b, defaultIO, toError) { + def callRunAndExitValue(source: Process.PipeSource, sink: Process.PipeSink) = { + val m = classOf[Process.PipedProcesses].getDeclaredMethod("runAndExitValue", classOf[Process.PipeSource], classOf[Process.PipeSink]) + m.setAccessible(true) + try m.invoke(this, source, sink).asInstanceOf[Option[Int]] + catch { + case err: InvocationTargetException => throw err.getTargetException + } + } + } + + // PipedProcesses need not to release resources when it normally end + @Test + def normallyEnd() { + val io = BasicIO(false, ProcessLogger(_ => ())) + val source = new PipeSourceMock + val sink = new PipeSinkMock + val a = new ProcessMock(error = false) + val b = new ProcessMock(error = false) + val p = new PipedProcesses(new ProcessBuilderMock(a, error = false), new ProcessBuilderMock(b, error = false), io, false) + val f = Future { + p.callRunAndExitValue(source, sink) + } + Await.result(f, Duration(1, SECONDS)) + assert(source.releaseCount == 0) + assert(sink.releaseCount == 0) + assert(a.destroyCount == 0) + assert(b.destroyCount == 0) + } + + // PipedProcesses must release resources when b.run() failed + @Test + def bFailed() { + val io = BasicIO(false, ProcessLogger(_ => ())) + val source = new PipeSourceMock + val sink = new PipeSinkMock + val a = new ProcessMock(error = false) + val b = new ProcessMock(error = false) + val p = new PipedProcesses(new ProcessBuilderMock(a, error = false), new ProcessBuilderMock(b, error = true), io, false) + val f = Future { + ignoring(classOf[IOException]) { + p.callRunAndExitValue(source, sink) + } + } + Await.result(f, Duration(1, SECONDS)) + assert(source.releaseCount == 1) + assert(sink.releaseCount == 1) + assert(a.destroyCount == 0) + assert(b.destroyCount == 0) + } + + // PipedProcesses must release resources when a.run() failed + @Test + def aFailed() { + val io = BasicIO(false, ProcessLogger(_ => ())) + val source = new PipeSourceMock + val sink = new PipeSinkMock + val a = new ProcessMock(error = false) + val b = new ProcessMock(error = false) + val p = new PipedProcesses(new ProcessBuilderMock(a, error = true), new ProcessBuilderMock(b, error = false), io, false) + val f = Future { + ignoring(classOf[IOException]) { + p.callRunAndExitValue(source, sink) + } + } + Await.result(f, Duration(1, SECONDS)) + assert(source.releaseCount == 1) + assert(sink.releaseCount == 1) + assert(a.destroyCount == 0) + assert(b.destroyCount == 1) + } + + // PipedProcesses must release resources when interrupted during waiting for first.exitValue() + @Test + def firstInterrupted() { + val io = BasicIO(false, ProcessLogger(_ => ())) + val source = new PipeSourceMock + val sink = new PipeSinkMock + val a = new ProcessMock(error = true) + val b = new ProcessMock(error = false) + val p = new PipedProcesses(new ProcessBuilderMock(a, error = false), new ProcessBuilderMock(b, error = false), io, false) + val f = Future { + p.callRunAndExitValue(source, sink) + } + Await.result(f, Duration(1, SECONDS)) + assert(source.releaseCount == 1) + assert(sink.releaseCount == 1) + assert(a.destroyCount == 1) + assert(b.destroyCount == 1) + } + + // PipedProcesses must release resources when interrupted during waiting for second.exitValue() + @Test + def secondInterrupted() { + val io = BasicIO(false, ProcessLogger(_ => ())) + val source = new PipeSourceMock + val sink = new PipeSinkMock + val a = new ProcessMock(error = false) + val b = new ProcessMock(error = true) + val p = new PipedProcesses(new ProcessBuilderMock(a, error = false), new ProcessBuilderMock(b, error = false), io, false) + val f = Future { + p.callRunAndExitValue(source, sink) + } + Await.result(f, Duration(1, SECONDS)) + assert(source.releaseCount == 1) + assert(sink.releaseCount == 1) + assert(a.destroyCount == 1) + assert(b.destroyCount == 1) + } +} + +@RunWith(classOf[JUnit4]) +class PipeSourceSinkTest { + def throwsIOException(f: => Unit) = { + try { f; false } + catch { case _: IOException => true } + } + + class PipeSink extends Process.PipeSink("TestPipeSink") { + def ensureRunloopStarted() = { + while (sink.size() > 0) { + Thread.sleep(1) + } + } + def isReleased = { + val field = classOf[Process.PipeSink].getDeclaredField("pipe") + field.setAccessible(true) + val pipe = field.get(this).asInstanceOf[PipedInputStream] + !this.isAlive && throwsIOException { pipe.read() } + } + } + + class PipeSource extends Process.PipeSource("TestPipeSource") { + def ensureRunloopStarted() = { + while (source.size() > 0) { + Thread.sleep(1) + } + } + def isReleased = { + val field = classOf[Process.PipeSource].getDeclaredField("pipe") + field.setAccessible(true) + val pipe = field.get(this).asInstanceOf[PipedOutputStream] + !this.isAlive && throwsIOException { pipe.write(1) } + } + } + + trait CloseChecking extends Closeable { + var closed = false + override def close() = closed = true + } + class DebugOutputStream extends ByteArrayOutputStream with CloseChecking + class DebugInputStream(s: String) extends ByteArrayInputStream(s.getBytes()) with CloseChecking + class DebugInfinityInputStream extends InputStream with CloseChecking { + def read() = 1 + } + + def sourceSink() = { + val source = new PipeSource + val sink = new PipeSink + source connectOut sink + source.start() + sink.start() + (source, sink) + } + + // PipeSource and PipeSink must release resources when it normally end + @Test + def normallyEnd() { + val in = new DebugInputStream("aaa") + val (source, sink) = sourceSink() + val out = new DebugOutputStream + source connectIn in + sink connectOut out + val f = Future { + source.join() + sink.join() + } + Await.result(f, Duration(1, SECONDS)) + assert(in.closed == true) + assert(out.closed == true) + assert(source.isReleased == true) + assert(sink.isReleased == true) + } + + // PipeSource and PipeSink must release resources when interrupted during waiting for source.take() + @Test + def sourceInterrupted() { + val (source, sink) = sourceSink() + val out = new DebugOutputStream + sink connectOut out + val f = Future { + sink.ensureRunloopStarted() + source.release() + sink.release() + } + Await.result(f, Duration(1, SECONDS)) + assert(out.closed == true) + assert(source.isReleased == true) + assert(sink.isReleased == true) + } + + // PipeSource and PipeSink must release resources when interrupted during waiting for sink.take() + @Test + def sinkInterrupted() { + val in = new DebugInputStream("aaa") + val (source, sink) = sourceSink() + source connectIn in + val f = Future { + source.ensureRunloopStarted() + source.release() + sink.release() + } + Await.result(f, Duration(1, SECONDS)) + assert(in.closed == true) + assert(source.isReleased == true) + assert(sink.isReleased == true) + } + + // PipeSource and PipeSink must release resources when interrupted during copy streams" + @Test + def runloopInterrupted() { + val in = new DebugInfinityInputStream + val (source, sink) = sourceSink() + val out = new DebugOutputStream + source connectIn in + sink connectOut out + val f = Future { + source.ensureRunloopStarted() + sink.ensureRunloopStarted() + source.release() + sink.release() + } + Await.result(f, Duration(1, SECONDS)) + assert(in.closed == true) + assert(out.closed == true) + assert(source.isReleased == true) + assert(sink.isReleased == true) + } +} diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/CompactLocalVariablesTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/CompactLocalVariablesTest.scala index 76492cfa23..cd298f822a 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/opt/CompactLocalVariablesTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/opt/CompactLocalVariablesTest.scala @@ -17,8 +17,8 @@ class CompactLocalVariablesTest { // recurse-unreachable-jumps is required for eliminating catch blocks, in the first dce round they // are still live.only after eliminating the empty handler the catch blocks become unreachable. - val methodOptCompiler = newCompiler(extraArgs = "-target:jvm-1.6 -Ybackend:GenBCode -Yopt:unreachable-code,compact-locals") - val noCompactVarsCompiler = newCompiler(extraArgs = "-target:jvm-1.6 -Ybackend:GenBCode -Yopt:unreachable-code") + val methodOptCompiler = newCompiler(extraArgs = "-Ybackend:GenBCode -Yopt:unreachable-code,compact-locals") + val noCompactVarsCompiler = newCompiler(extraArgs = "-Ybackend:GenBCode -Yopt:unreachable-code") @Test def compactUnused(): Unit = { diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/MethodLevelOpts.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/MethodLevelOpts.scala index 5ef2458c0a..8d910629ca 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/opt/MethodLevelOpts.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/opt/MethodLevelOpts.scala @@ -16,7 +16,7 @@ import ASMConverters._ import scala.tools.testing.ClearAfterClass object MethodLevelOpts extends ClearAfterClass.Clearable { - var methodOptCompiler = newCompiler(extraArgs = "-target:jvm-1.6 -Ybackend:GenBCode -Yopt:l:method") + var methodOptCompiler = newCompiler(extraArgs = "-Ybackend:GenBCode -Yopt:l:method") def clear(): Unit = { methodOptCompiler = null } } diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/UnreachableCodeTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/UnreachableCodeTest.scala index 902af7b7fa..0ac206669a 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/opt/UnreachableCodeTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/opt/UnreachableCodeTest.scala @@ -18,18 +18,14 @@ import scala.tools.testing.ClearAfterClass object UnreachableCodeTest extends ClearAfterClass.Clearable { // jvm-1.6 enables emitting stack map frames, which impacts the code generation wrt dead basic blocks, // see comment in BCodeBodyBuilder - var methodOptCompiler = newCompiler(extraArgs = "-target:jvm-1.6 -Ybackend:GenBCode -Yopt:l:method") - var dceCompiler = newCompiler(extraArgs = "-target:jvm-1.6 -Ybackend:GenBCode -Yopt:unreachable-code") - var noOptCompiler = newCompiler(extraArgs = "-target:jvm-1.6 -Ybackend:GenBCode -Yopt:l:none") - - // jvm-1.5 disables computing stack map frames, and it emits dead code as-is. note that this flag triggers a deprecation warning - var noOptNoFramesCompiler = newCompiler(extraArgs = "-target:jvm-1.5 -Ybackend:GenBCode -Yopt:l:none -deprecation") + var methodOptCompiler = newCompiler(extraArgs = "-Ybackend:GenBCode -Yopt:l:method") + var dceCompiler = newCompiler(extraArgs = "-Ybackend:GenBCode -Yopt:unreachable-code") + var noOptCompiler = newCompiler(extraArgs = "-Ybackend:GenBCode -Yopt:l:none") def clear(): Unit = { methodOptCompiler = null dceCompiler = null noOptCompiler = null - noOptNoFramesCompiler = null } } @@ -40,7 +36,6 @@ class UnreachableCodeTest extends ClearAfterClass { val methodOptCompiler = UnreachableCodeTest.methodOptCompiler val dceCompiler = UnreachableCodeTest.dceCompiler val noOptCompiler = UnreachableCodeTest.noOptCompiler - val noOptNoFramesCompiler = UnreachableCodeTest.noOptNoFramesCompiler def assertEliminateDead(code: (Instruction, Boolean)*): Unit = { val method = genMethod()(code.map(_._1): _*) @@ -152,11 +147,6 @@ class UnreachableCodeTest extends ClearAfterClass { // Finally, instructions in the dead basic blocks are replaced by ATHROW, as explained in // a comment in BCodeBodyBuilder. assertSameCode(noDce.dropNonOp, List(Op(ICONST_1), Op(IRETURN), Op(ATHROW), Op(ATHROW))) - - // when NOT computing stack map frames, ASM's ClassWriter does not replace dead code by NOP/ATHROW - val warn = "target:jvm-1.5 is deprecated" - val noDceNoFrames = singleMethodInstructions(noOptNoFramesCompiler)(code, allowMessage = _.msg contains warn) - assertSameCode(noDceNoFrames.dropNonOp, List(Op(ICONST_1), Op(IRETURN), Op(ICONST_2), Op(IRETURN))) } @Test diff --git a/test/junit/scala/tools/nsc/settings/ScalaVersionTest.scala b/test/junit/scala/tools/nsc/settings/ScalaVersionTest.scala index 77a2da828e..acbf39fe23 100644 --- a/test/junit/scala/tools/nsc/settings/ScalaVersionTest.scala +++ b/test/junit/scala/tools/nsc/settings/ScalaVersionTest.scala @@ -13,6 +13,48 @@ class ScalaVersionTest { @Test def versionUnparse() { val v = "2.11.3" - assertEquals(ScalaVersion(v).unparse, v) + assertEquals(v, ScalaVersion(v).unparse) + assertEquals("2.11.3-RC4", ScalaVersion("2.11.3-rc4").unparse) + } + + // SI-9167 + @Test def `version parses with rigor`() { + import settings.{ SpecificScalaVersion => V } + import ScalaVersion._ + + // no-brainers + assertEquals(V(2,11,7,Final), ScalaVersion("2.11.7")) + assertEquals(V(2,11,7,Final), ScalaVersion("2.11.7-FINAL")) + assertEquals(V(2,11,7,Milestone(3)), ScalaVersion("2.11.7-M3")) + assertEquals(V(2,11,7,RC(3)), ScalaVersion("2.11.7-RC3")) + assertEquals(V(2,11,7,Development("devbuild")), ScalaVersion("2.11.7-devbuild")) + + // partial-brainers + assertEquals(V(2,11,7,Milestone(3)), ScalaVersion("2.11.7-m3")) + assertEquals(V(2,11,7,RC(3)), ScalaVersion("2.11.7-rc3")) + assertEquals(V(2,11,7,Development("maybegood")), ScalaVersion("2.11.7-maybegood")) + assertEquals(V(2,11,7,Development("RCCola")), ScalaVersion("2.11.7-RCCola")) + assertEquals(V(2,11,7,Development("RC1.5")), ScalaVersion("2.11.7-RC1.5")) + assertEquals(V(2,11,7,Development("")), ScalaVersion("2.11.7-")) + assertEquals(V(2,11,7,Development("0.5")), ScalaVersion("2.11.7-0.5")) + assertEquals(V(2,11,7,Development("devbuild\nSI-9167")), ScalaVersion("2.11.7-devbuild\nSI-9167")) + assertEquals(V(2,11,7,Development("final")), ScalaVersion("2.11.7-final")) + + // oh really + assertEquals(NoScalaVersion, ScalaVersion("none")) + assertEquals(AnyScalaVersion, ScalaVersion("any")) + + assertThrows[NumberFormatException] { ScalaVersion("2.11.7.2") } + assertThrows[NumberFormatException] { ScalaVersion("2.11.7.beta") } + assertThrows[NumberFormatException] { ScalaVersion("2.x.7") } + assertThrows[NumberFormatException] { ScalaVersion("2.-11.7") } + assertThrows[NumberFormatException] { ScalaVersion("2. ") } + assertThrows[NumberFormatException] { ScalaVersion("2.1 .7") } + assertThrows[NumberFormatException] { ScalaVersion("2.") } + assertThrows[NumberFormatException] { ScalaVersion("2..") } + assertThrows[NumberFormatException] { ScalaVersion("2...") } + assertThrows[NumberFormatException] { ScalaVersion("2-") } + assertThrows[NumberFormatException] { ScalaVersion("2-.") } // scalacheck territory + assertThrows[NumberFormatException] { ScalaVersion("any.7") } } } diff --git a/test/long-running/jvm/memleak2_actor.scala b/test/long-running/jvm/memleak2_actor.scala deleted file mode 100644 index 1673b12dac..0000000000 --- a/test/long-running/jvm/memleak2_actor.scala +++ /dev/null @@ -1,39 +0,0 @@ -import scala.actors._ -import Actor._ - -case object Start -case object EndMe - -class A extends Actor { - def act = loop { - react { - case Start => - case EndMe => - exit() - } - } -} - -object Test { - - def z(in: Long) = if (in / 1024L == 0L) in - else if (in / (1024L * 1024L) == 0L) (in / 1024L).toString + "K" - else (in / (1024L * 1024L)).toString + "M" - - def main(args: Array[String]) { - val rt = Runtime.getRuntime() - for (o <- 1 to 300000) { - println("Outer [2AN] "+o) - var a: List[A] = Nil - for (i <- 1 to 10000) { - var t = new A - a = t :: a - t.start - t ! Start - } - for (act <- a) act ! EndMe - //rt.gc() - println("Free "+z(rt.freeMemory())+" total "+z(rt.totalMemory())) - } - } -} diff --git a/test/pending/jvm/actor-executor4.check b/test/pending/jvm/actor-executor4.check deleted file mode 100644 index da78f45836..0000000000 --- a/test/pending/jvm/actor-executor4.check +++ /dev/null @@ -1,21 +0,0 @@ -Two: OK -One: OK -Two: OK -One: OK -Two: OK -One: OK -Two: OK -One: OK -Two: OK -One: OK -Two: OK -One: OK -Two: OK -One: OK -Two: OK -One: OK -Two: OK -One: OK -Two: OK -One: OK -One exited diff --git a/test/pending/jvm/actor-executor4.scala b/test/pending/jvm/actor-executor4.scala deleted file mode 100644 index a912d76094..0000000000 --- a/test/pending/jvm/actor-executor4.scala +++ /dev/null @@ -1,64 +0,0 @@ -import scala.actors.{Actor, Exit} -import scala.actors.scheduler.ExecutorScheduler -import java.util.concurrent.Executors - -object One extends AdaptedActor { - def act() { - Two.start() - var i = 0 - loopWhile (i < Test.NUM_MSG) { - i += 1 - Two ! 'MsgForTwo - react { - case 'MsgForOne => - if (i % (Test.NUM_MSG/10) == 0) - println("One: OK") - } - } - } -} - -object Two extends AdaptedActor { - def act() { - var i = 0 - loopWhile (i < Test.NUM_MSG) { - i += 1 - react { - case 'MsgForTwo => - if (i % (Test.NUM_MSG/10) == 0) - println("Two: OK") - One ! 'MsgForOne - } - } - } -} - -trait AdaptedActor extends Actor { - override def scheduler = - Test.scheduler -} - -object Test { - val NUM_MSG = 100000 - - val scheduler = - ExecutorScheduler( - Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()), - false) - - def main(args: Array[String]) { - (new AdaptedActor { - def act() { - trapExit = true - link(One) - One.start() - - receive { - case Exit(from, reason) => - println("One exited") - Test.scheduler.shutdown() - } - } - }).start() - } -} diff --git a/test/pending/jvm/actor-receive-sender.check b/test/pending/jvm/actor-receive-sender.check deleted file mode 100644 index 2c94e48371..0000000000 --- a/test/pending/jvm/actor-receive-sender.check +++ /dev/null @@ -1,2 +0,0 @@ -OK -OK diff --git a/test/pending/jvm/actor-receive-sender.scala b/test/pending/jvm/actor-receive-sender.scala deleted file mode 100644 index ea7c40cced..0000000000 --- a/test/pending/jvm/actor-receive-sender.scala +++ /dev/null @@ -1,51 +0,0 @@ -import scala.actors.{Actor, TIMEOUT, Exit} -import scala.actors.Actor._ - -object Test { - - val NUM = 2000 - - def main(args: Array[String]) { - var b: Actor = null - var c: Actor = null - - val a = actor { - for (_ <- 0 until NUM) - receive { - case 'hello if sender == b => // do nothing - } - b ! 'ok - for (_ <- 0 until NUM) - receiveWithin (1000) { - case 'bye if sender == b => // do nothing - case TIMEOUT => b ! 'fail - } - b ! 'ok - } - - b = actor { - self.trapExit = true - link(a) - - for (_ <- 0 until NUM) - a ! 'hello - - val proceed = receive { - case Exit(from, reason) => println("FAIL"); false - case 'ok => println("OK"); true - case other => println(other); false - } - - if (proceed) { - for (_ <- 0 until NUM) - a ! 'bye - receive { - case Exit(from, reason) => println("FAIL") - case 'ok => println("OK") - case other => println(other) - } - } - } - } - -} diff --git a/test/pending/jvm/actorgc_leak.check b/test/pending/jvm/actorgc_leak.check deleted file mode 100644 index a965a70ed4..0000000000 --- a/test/pending/jvm/actorgc_leak.check +++ /dev/null @@ -1 +0,0 @@ -Done diff --git a/test/pending/jvm/actorgc_leak.scala b/test/pending/jvm/actorgc_leak.scala deleted file mode 100644 index de3e04f1e8..0000000000 --- a/test/pending/jvm/actorgc_leak.scala +++ /dev/null @@ -1,63 +0,0 @@ - -import scala.actors.Actor - -object Test { - class FatActorFactory extends Actor { - def act() { - var cnt = 0 - Actor.loopWhile(cnt < fatActors) { - //if ((cnt % 5) == 0) println(cnt) - val fa = new FatActor() - fa.start() - cnt += 1 - if (cnt == fatActors) Monitor ! 'done - } - } - } - - class FatActor extends Actor { - def act() { - fat = new Array[Int](fatness) - react { - case 'hi => exit() - } - } - private var fat: Array[Int] = _ - } - - object Monitor extends Actor { - private var cnt = 0 - def act() { - Actor.loop { - react { - case 'done => { - cnt += 1 - if (cnt == factories) System.exit(0) // once GC pressure stops FatActors stop being collected, and as - } // a result ActorGC never finds out that they are defunct - } - } - } - } - - val factories = 4 // the number of factories to start - val fatActors = 50 // the number of FatActors for each factory to produce - val fatness = 1024*1024*10 - - def main(args: Array[String]) { - scala.actors.Scheduler.impl.shutdown() - val sched = { - val s = new scala.actors.FJTaskScheduler2 - s.start() - s - } - scala.actors.Scheduler.impl = sched - - Monitor.start() - for(i <- 1 to factories) { - //if ((i % 50) == 0) println(i) - val fa = new FatActorFactory() - fa.start() - } - println("Done") - } -} diff --git a/test/pending/jvm/reactWithinZero.check b/test/pending/jvm/reactWithinZero.check deleted file mode 100644 index cf2a2facf9..0000000000 --- a/test/pending/jvm/reactWithinZero.check +++ /dev/null @@ -1,2 +0,0 @@ -TIMEOUT -'ack diff --git a/test/pending/jvm/reactWithinZero.scala b/test/pending/jvm/reactWithinZero.scala deleted file mode 100644 index 0786ce271d..0000000000 --- a/test/pending/jvm/reactWithinZero.scala +++ /dev/null @@ -1,18 +0,0 @@ -import scala.actors.{Actor, TIMEOUT} - -class A extends Actor { - def act() = reactWithin(0) { - case TIMEOUT => - println("TIMEOUT") - reply('ack) - act() - case x => println(x) - } -} - -object Test { - def main(args: Array[String]): Unit = { - val a = new A - a.start() - } -} diff --git a/test/pending/jvm/receiveWithinZero.check b/test/pending/jvm/receiveWithinZero.check deleted file mode 100644 index cf2a2facf9..0000000000 --- a/test/pending/jvm/receiveWithinZero.check +++ /dev/null @@ -1,2 +0,0 @@ -TIMEOUT -'ack diff --git a/test/pending/jvm/receiveWithinZero.scala b/test/pending/jvm/receiveWithinZero.scala deleted file mode 100644 index 315dd9c86a..0000000000 --- a/test/pending/jvm/receiveWithinZero.scala +++ /dev/null @@ -1,18 +0,0 @@ -import scala.actors.{Actor, TIMEOUT} - -class A extends Actor { - def act() = receiveWithin(0) { - case TIMEOUT => - println("TIMEOUT") - reply('ack) - act() - case x => println(x) - } -} - -object Test { - def main(args: Array[String]): Unit = { - val a = new A - a.start() - } -} diff --git a/test/pending/jvm/t1801.check b/test/pending/jvm/t1801.check deleted file mode 100644 index bf78a99db9..0000000000 --- a/test/pending/jvm/t1801.check +++ /dev/null @@ -1,6 +0,0 @@ -0 -100 -200 -300 -400 -done! diff --git a/test/pending/jvm/t1801.scala b/test/pending/jvm/t1801.scala deleted file mode 100644 index 6ed7c56336..0000000000 --- a/test/pending/jvm/t1801.scala +++ /dev/null @@ -1,31 +0,0 @@ -import scala.actors.Actor._ - -object Test { - val rt = Runtime.getRuntime() - val sender = actor { - var cnt = 0 - while(cnt < 500) { - if ((cnt % 100) == 0) println(cnt) - receiver ! new Array[Int] (148576) - cnt += 1 - //println ("Used Mem: " + (((rt.totalMemory() - rt.freeMemory()) / 1048576.) formatted "%.2f") + " Mb") - } - receiver ! 'exit - } - - val receiver = actor { - loop { - react { - case x: Array[Int] => ()//println ("received " + x.length) - case 'exit => { - println("done!") - exit() - } - } - } - } - - def main (args: Array[String]) { - sender - } -} diff --git a/test/pending/jvm/t2515.check b/test/pending/jvm/t2515.check deleted file mode 100644 index 8cb8bde11e..0000000000 --- a/test/pending/jvm/t2515.check +++ /dev/null @@ -1,10 +0,0 @@ -Iteration 1 succeeded -Iteration 2 succeeded -Iteration 3 succeeded -Iteration 4 succeeded -Iteration 5 succeeded -Iteration 6 succeeded -Iteration 7 succeeded -Iteration 8 succeeded -Iteration 9 succeeded -Iteration 10 succeeded diff --git a/test/pending/jvm/t2515.scala b/test/pending/jvm/t2515.scala deleted file mode 100644 index ee655967f3..0000000000 --- a/test/pending/jvm/t2515.scala +++ /dev/null @@ -1,43 +0,0 @@ -import scala.actors.{Futures, TIMEOUT} -import scala.actors.Actor._ - -object Test { - - def compute(): Option[Boolean] = { - val fts = for (j <- 0 until 5) yield Futures.future { - receiveWithin (100) { - case TIMEOUT => true - case other => false - } - } - val done = Futures.awaitAll(2000, fts.toArray: _*) // list to array, as varargs - if (done.contains(None)) - None - else - Some(true) - } - - def main(args:Array[String]) : Unit = { - val ft = Futures.future { - val format = new java.text.DecimalFormat("000.00'ms'") - var iter = 1 - val done = 11 - while (iter < done) { - val start = System.nanoTime() - val result = compute() - val time = System.nanoTime() - start - result match { - case Some(result) => - //printf("Iteration %2d succeeded after %s %n", iter, format.format(time / 1e6)) - printf("Iteration %2d succeeded%n", iter) - iter += 1 - case None => - printf(">>>> Iteration %2d failed after %s <<<<< %n", iter, format.format(time / 1e6)) - iter = done - } - } - } - ft() - } - -} diff --git a/test/pending/jvm/terminateLinked.check b/test/pending/jvm/terminateLinked.check deleted file mode 100644 index a965a70ed4..0000000000 --- a/test/pending/jvm/terminateLinked.check +++ /dev/null @@ -1 +0,0 @@ -Done diff --git a/test/pending/jvm/terminateLinked.scala b/test/pending/jvm/terminateLinked.scala deleted file mode 100644 index 2a3b7fb49e..0000000000 --- a/test/pending/jvm/terminateLinked.scala +++ /dev/null @@ -1,24 +0,0 @@ -import scala.actors.Actor -import Actor._ - -object Test { - def main(args: Array[String]) { - val a = actor { - for (_ <- 1 to 10) - receive { - case b: Actor => link(b) - } - throw new Exception - } - - for (_ <- 1 to 10) - actor { - a ! self - react { - case _ => - } - } - - println("Done") - } -} diff --git a/test/pending/jvm/timeout.check b/test/pending/jvm/timeout.check deleted file mode 100644 index d86bac9de5..0000000000 --- a/test/pending/jvm/timeout.check +++ /dev/null @@ -1 +0,0 @@ -OK diff --git a/test/pending/jvm/timeout.scala b/test/pending/jvm/timeout.scala deleted file mode 100644 index 8f29f8ddbe..0000000000 --- a/test/pending/jvm/timeout.scala +++ /dev/null @@ -1,38 +0,0 @@ -// Test is in pending because although it succeeds locally, -// it takes too long on the machine which runs nightly tests. -// -// [partest] EXPECTED: 100 < x < 900 -// [partest] ACTUAL: 1519 - -import scala.actors.Actor._ -import scala.actors.TIMEOUT - -object Test extends Application { - case class Timing(time: Long) - - actor { - val a = actor { - react { - case 'doTiming => - val s = sender - reactWithin(500) { - case TIMEOUT => - s ! Timing(System.currentTimeMillis) - } - } - } - - val start = System.currentTimeMillis - (a !? 'doTiming) match { - case Timing(end) => - val delay = end - start - - if (delay > 100 && delay < 900) - println("OK") - else { - println("EXPECTED: 100 < x < 900") - println("ACTUAL: "+delay) - } - } - } -} diff --git a/test/pending/run/t5698/client.scala b/test/pending/run/t5698/client.scala deleted file mode 100644 index de672c1809..0000000000 --- a/test/pending/run/t5698/client.scala +++ /dev/null @@ -1,9 +0,0 @@ -package client - - - -object Client extends App { - val peer = actors.remote.Node("localhost", 23456) - val a = actors.remote.RemoteActor.select(peer, 'test) - a ! server.TestMsg -} diff --git a/test/pending/run/t5698/server.scala b/test/pending/run/t5698/server.scala deleted file mode 100644 index e8f3cea225..0000000000 --- a/test/pending/run/t5698/server.scala +++ /dev/null @@ -1,22 +0,0 @@ -package server - - - -object Server extends App { - - class ServerActor extends actors.Actor { - def act() { - actors.remote.RemoteActor.alive(23456) - actors.remote.RemoteActor.register('test, actors.Actor.self) - loop { - react { - case TestMsg => println("Yay!") - } - } - } - } - - val a = new ServerActor - a.start() - -} diff --git a/test/pending/run/t5698/testmsg.scala b/test/pending/run/t5698/testmsg.scala deleted file mode 100644 index 004ff0b8c7..0000000000 --- a/test/pending/run/t5698/testmsg.scala +++ /dev/null @@ -1,5 +0,0 @@ -package server - - - -case object TestMsg diff --git a/test/scaladoc/filters b/test/scaladoc/filters index 51a7507848..e91ca0eb36 100644 --- a/test/scaladoc/filters +++ b/test/scaladoc/filters @@ -1,6 +1,7 @@ # #Java HotSpot(TM) 64-Bit Server VM warning: Failed to reserve shared memory (errno = 28). Java HotSpot\(TM\) .* warning: +OpenJDK .* warning: # Hotspot receiving VM options through the $_JAVA_OPTIONS # env variable outputs them on stderr Picked up _JAVA_OPTIONS: diff --git a/test/scaladoc/run/t7905.check b/test/scaladoc/run/t7905.check new file mode 100644 index 0000000000..619c56180b --- /dev/null +++ b/test/scaladoc/run/t7905.check @@ -0,0 +1 @@ +Done. diff --git a/test/scaladoc/run/t7905.scala b/test/scaladoc/run/t7905.scala new file mode 100644 index 0000000000..8570724470 --- /dev/null +++ b/test/scaladoc/run/t7905.scala @@ -0,0 +1,36 @@ +import scala.tools.nsc.doc.model._ +import scala.tools.partest.ScaladocModelTest + +object Test extends ScaladocModelTest { + override def code = """ + object A { + val foo = new B { + val bar = new C { + val baz: A.this.type = A.this + } + } + } + + trait B { + type E = bar.D + + val bar: C + } + + trait C { + trait D + } + + trait G { + type F = A.foo.E + + def m(f: F) = f match { + case _: A.foo.bar.D => // error here + } + } + """ + + def scaladocSettings = "" + + def testModel(root: Package) = () +} diff --git a/test/scaladoc/scalacheck/HtmlFactoryTest.scala b/test/scaladoc/scalacheck/HtmlFactoryTest.scala index 578e0382eb..913667b79b 100644 --- a/test/scaladoc/scalacheck/HtmlFactoryTest.scala +++ b/test/scaladoc/scalacheck/HtmlFactoryTest.scala @@ -779,6 +779,11 @@ object Test extends Properties("HtmlFactory") { linkElement \@ "href" == expectedUrl && linkElement \@ "target" == "_top" } + def assertValuesLink(memberName: String, expectedUrl: String): Boolean = { + val linkElement: NodeSeq = node \\ "div" \@ ("class", "values members") \\ "li" \@ ("name", memberName) \\ "span" \@ ("class", "permalink") \ "a" + linkElement \@ "href" == expectedUrl && linkElement \@ "target" == "_top" + } + } val files = createTemplates("SI-8144.scala") @@ -791,12 +796,12 @@ object Test extends Properties("HtmlFactory") { property("SI-8144: Members' permalink - package") = check("some/package.html") { node => ("type link" |: node.assertTypeLink("../index.html#some.package")) && - ("member: some.pack" |: node.assertMemberLink("values")("some.pack", "../index.html#some.package@pack")) + ("member: some.pack" |: node.assertValuesLink("some.pack", "../index.html#some.package@pack")) } property("SI-8144: Members' permalink - inner package") = check("some/pack/package.html") { node => ("type link" |: node.assertTypeLink("../../index.html#some.pack.package")) && - ("member: SomeType (object)" |: node.assertMemberLink("values")("some.pack.SomeType", "../../index.html#some.pack.package@SomeType")) && + ("member: SomeType (object)" |: node.assertValuesLink("some.pack.SomeType", "../../index.html#some.pack.package@SomeType")) && ("member: SomeType (class)" |: node.assertMemberLink("types")("some.pack.SomeType", "../../index.html#some.pack.package@SomeTypeextendsAnyRef")) } @@ -809,8 +814,8 @@ object Test extends Properties("HtmlFactory") { ("type link" |: node.assertTypeLink("../../index.html#some.pack.SomeType")) && ("constructor " |: node.assertMemberLink("constructors")("some.pack.SomeType#<init>", "../../index.html#some.pack.SomeType@<init>(arg:String):some.pack.SomeType")) && ( "member: type TypeAlias" |: node.assertMemberLink("types")("some.pack.SomeType.TypeAlias", "../../index.html#some.pack.SomeType@TypeAlias=String")) && - ( "member: def >#<():Int " |: node.assertMemberLink("values")("some.pack.SomeType#>#<", "../../index.html#some.pack.SomeType@>#<():Int")) && - ( "member: def >@<():TypeAlias " |: node.assertMemberLink("values")("some.pack.SomeType#>@<", "../../index.html#some.pack.SomeType@>@<():SomeType.this.TypeAlias")) + ( "member: def >#<():Int " |: node.assertValuesLink("some.pack.SomeType#>#<", "../../index.html#some.pack.SomeType@>#<():Int")) && + ( "member: def >@<():TypeAlias " |: node.assertValuesLink("some.pack.SomeType#>@<", "../../index.html#some.pack.SomeType@>@<():SomeType.this.TypeAlias")) } } diff --git a/versions.properties b/versions.properties index a7ec8caedc..470c9341cd 100644 --- a/versions.properties +++ b/versions.properties @@ -1,4 +1,4 @@ -#Wed, 23 Jul 2014 08:37:26 +0200 +#Fri, 01 May 2015 16:27:16 +0000 # NOTE: this file determines the content of the scala-distribution # via scala-dist-pom.xml and scala-library-all-pom.xml # when adding new properties that influence a release, @@ -8,7 +8,7 @@ # The scala version used for boostrapping. This has no impact on the final classfiles: # there are two stages (locker and quick), so compiler and library are always built # with themselves. Stability is ensured by building a third stage (strap). -starr.version=2.11.6 +starr.version=2.12.0-M1 # These are the versions of the modules that go with this release. # These properties are used during PR validation and in dbuild builds. @@ -19,19 +19,12 @@ starr.version=2.11.6 # - After 2.x.0 is released, the binary version is 2.x. # - During milestones and RCs, modules are cross-built against the full version. # So the value is the full version (e.g. 2.12.0-M1). -scala.binary.version=2.11 -# e.g. 2.11.0-RC1, 2.11.0, 2.11.1-RC1, 2.11.1 -# this defines the dependency on scala-continuations-plugin in scala-dist's pom -scala.full.version=2.11.6 +scala.binary.version=2.12.0-M1 # external modules shipped with distribution, as specified by scala-library-all's pom scala-xml.version.number=1.0.4 scala-parser-combinators.version.number=1.0.4 -scala-continuations-plugin.version.number=1.0.2 -scala-continuations-library.version.number=1.0.2 scala-swing.version.number=1.0.2 -akka-actor.version.number=2.3.10 -actors-migration.version.number=1.1.0 jline.version=2.12.1 scala-asm.version=5.0.4-scala-1 |