changeset 91:7387387cff9a

Annotations: basic generators working. (Legacy code is being removed)
author shade
date Thu, 13 Mar 2014 19:03:50 +0400
parents 755271d4752e
children 982044a7f3bc
files jcstress-core/src/main/java/org/openjdk/jcstress/JCStress.java jcstress-core/src/main/java/org/openjdk/jcstress/Main.java jcstress-core/src/main/java/org/openjdk/jcstress/infra/annotations/Actor.java jcstress-core/src/main/java/org/openjdk/jcstress/infra/annotations/Arbiter.java jcstress-core/src/main/java/org/openjdk/jcstress/infra/annotations/ConcurrencyStressTest.java jcstress-core/src/main/java/org/openjdk/jcstress/infra/annotations/Result.java jcstress-core/src/main/java/org/openjdk/jcstress/infra/annotations/State.java jcstress-core/src/main/java/org/openjdk/jcstress/infra/processors/ConcurrencyStressTestProcessor.java jcstress-core/src/main/java/org/openjdk/jcstress/infra/processors/GenerationException.java jcstress-core/src/main/java/org/openjdk/jcstress/infra/processors/TestInfo.java jcstress-core/src/main/java/org/openjdk/jcstress/infra/results/IntResult2.java jcstress-core/src/main/java/org/openjdk/jcstress/infra/runners/Runner.java jcstress-core/src/main/java/org/openjdk/jcstress/infra/runners/TestList.java jcstress-core/src/main/resources/META-INF/services/javax.annotation.processing.Processor tests-custom/src/main/java/org/openjdk/jcstress/tests/volatiles/DekkerTest.java
diffstat 15 files changed, 888 insertions(+), 118 deletions(-) [+]
line wrap: on
line diff
--- a/jcstress-core/src/main/java/org/openjdk/jcstress/JCStress.java	Thu Mar 13 18:43:36 2014 +0400
+++ b/jcstress-core/src/main/java/org/openjdk/jcstress/JCStress.java	Thu Mar 13 19:03:50 2014 +0400
@@ -37,13 +37,8 @@
 import org.openjdk.jcstress.infra.grading.ConsoleReportPrinter;
 import org.openjdk.jcstress.infra.grading.ExceptionReportPrinter;
 import org.openjdk.jcstress.infra.grading.HTMLReportPrinter;
-import org.openjdk.jcstress.infra.runners.Actor1_Runner;
-import org.openjdk.jcstress.infra.runners.Actor2_Arbiter1_Runner;
-import org.openjdk.jcstress.infra.runners.Actor2_Runner;
-import org.openjdk.jcstress.infra.runners.Actor3_Runner;
-import org.openjdk.jcstress.infra.runners.Actor4_Runner;
 import org.openjdk.jcstress.infra.runners.Runner;
-import org.openjdk.jcstress.infra.runners.TerminationRunner;
+import org.openjdk.jcstress.infra.runners.TestList;
 import org.openjdk.jcstress.tests.Actor1_Test;
 import org.openjdk.jcstress.tests.Actor2_Arbiter1_Test;
 import org.openjdk.jcstress.tests.Actor2_Test;
@@ -60,14 +55,12 @@
 import java.io.PrintStream;
 import java.io.PrintWriter;
 import java.lang.management.ManagementFactory;
-import java.lang.management.RuntimeMXBean;
+import java.lang.reflect.Constructor;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Comparator;
 import java.util.List;
-import java.util.Properties;
-import java.util.Set;
 import java.util.SortedSet;
 import java.util.TreeSet;
 import java.util.concurrent.ExecutionException;
@@ -75,6 +68,7 @@
 import java.util.concurrent.Executors;
 import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.regex.Pattern;
 
 /**
  * JCStress main entry point.
@@ -103,7 +97,7 @@
     }
 
     public void run(Options opts) throws Exception {
-        SortedSet<Class<? extends ConcurrencyTest>> tests = filterTests(opts.getTestFilter(), ConcurrencyTest.class);
+        SortedSet<String> tests = getTests(opts.getTestFilter());
 
         if (!opts.shouldParse()) {
             opts.printSettingsOn(out);
@@ -117,7 +111,7 @@
             scheduler = new Scheduler(opts.getUserCPUs());
 
             if (opts.shouldFork()) {
-                for (Class<? extends ConcurrencyTest> test : tests) {
+                for (String test : tests) {
                     for (int f = 0; f < opts.getForks(); f++) {
                         runForked(opts, test, sink);
                     }
@@ -152,18 +146,13 @@
         out.println("Done.");
     }
 
-    void runForked(final Options opts, final Class<? extends ConcurrencyTest> test, final TestResultCollector collector) {
+    void runForked(final Options opts, final String test, final TestResultCollector collector) {
         try {
             scheduler.schedule(new Scheduler.ScheduledTask() {
                 @Override
                 public int getTokens() {
-                    if (Actor1_Test.class.isAssignableFrom(test)) return 1;
-                    if (Actor2_Test.class.isAssignableFrom(test)) return 2;
-                    if (Actor3_Test.class.isAssignableFrom(test)) return 3;
-                    if (Actor4_Test.class.isAssignableFrom(test)) return 4;
-                    if (Actor2_Arbiter1_Test.class.isAssignableFrom(test)) return 3;
-                    if (TerminationTest.class.isAssignableFrom(test)) return 2;
-                    return 1;
+                    // FIXME: Expose the number of tokens
+                    return 2;
                 }
 
                 @Override
@@ -176,9 +165,9 @@
         }
     }
 
-    void runForked0(Options opts, Class<? extends ConcurrencyTest> test, TestResultCollector collector) {
+    void runForked0(Options opts, String test, TestResultCollector collector) {
         try {
-            Collection<String> commandString = getSeparateExecutionCommand(opts, test.getName());
+            Collection<String> commandString = getSeparateExecutionCommand(opts, test);
             Process p = Runtime.getRuntime().exec(commandString.toArray(new String[commandString.size()]));
 
             ByteArrayOutputStream baos = new ByteArrayOutputStream();
@@ -196,7 +185,7 @@
 
             if (ecode != 0) {
                 // Test had failed, record this.
-                TestResult result = new TestResult(test.getName(), Status.VM_ERROR);
+                TestResult result = new TestResult(test, Status.VM_ERROR);
                 String s = new String(baos.toByteArray()).trim();
                 result.addAuxData(s);
                 collector.add(result);
@@ -210,7 +199,7 @@
     }
 
     public void run(Options opts, boolean alreadyForked, TestResultCollector collector) throws Exception {
-        run(opts, filterTests(opts.getTestFilter(), ConcurrencyTest.class), alreadyForked, collector);
+        run(opts, TestList.tests(), alreadyForked, collector);
     }
 
     public void async(final Runner runner) throws ExecutionException, InterruptedException {
@@ -232,53 +221,13 @@
         });
     }
 
-    @SuppressWarnings("unchecked")
-    public void run(Options opts, Set<Class<? extends ConcurrencyTest>> tests, boolean alreadyForked, TestResultCollector collector) throws Exception {
-
-        for (Class<? extends ConcurrencyTest> test : tests) {
-            if (Actor2_Arbiter1_Test.class.isAssignableFrom(test)) {
-                @SuppressWarnings("unchecked")
-                Actor2_Arbiter1_Test<Object, ? extends Result> obj = (Actor2_Arbiter1_Test<Object, ? extends Result>) test.newInstance();
-                async(new Actor2_Arbiter1_Runner(opts, obj, collector, pool));
-            }
-
-            if (Actor1_Test.class.isAssignableFrom(test)) {
-                @SuppressWarnings("unchecked")
-                Actor1_Test<Object, ? extends Result> obj = (Actor1_Test<Object, ? extends Result>) test.newInstance();
-                async(new Actor1_Runner(opts, obj, collector, pool));
-            }
-
-            if (Actor2_Test.class.isAssignableFrom(test)) {
-                @SuppressWarnings("unchecked")
-                Actor2_Test<Object, ? extends Result> obj = (Actor2_Test<Object, ? extends Result>) test.newInstance();
-                async(new Actor2_Runner(opts, obj, collector, pool));
-            }
-
-            if (Actor3_Test.class.isAssignableFrom(test)) {
-                @SuppressWarnings("unchecked")
-                Actor3_Test<Object, ? extends Result> obj = (Actor3_Test<Object, ? extends Result>) test.newInstance();
-                async(new Actor3_Runner(opts, obj, collector, pool));
-            }
-
-            if (Actor4_Test.class.isAssignableFrom(test)) {
-                @SuppressWarnings("unchecked")
-                Actor4_Test<Object, ? extends Result> obj = (Actor4_Test<Object, ? extends Result>) test.newInstance();
-                async(new Actor4_Runner(opts, obj, collector, pool));
-            }
-
-            if (TerminationTest.class.isAssignableFrom(test)) {
-                if (!alreadyForked && !opts.shouldNeverFork()) {
-                    for (int f = 0; f < opts.getForks(); f++) {
-                        runForked(opts, test, collector);
-                    }
-                } else {
-                    @SuppressWarnings("unchecked")
-                    TerminationTest<Object> obj = (TerminationTest<Object>) test.newInstance();
-                    async(new TerminationRunner<Object>(opts, obj, collector, pool));
-                }
-            }
+    private void run(Options opts, Collection<String> tests, boolean alreadyForked, TestResultCollector collector) throws Exception {
+        for (String test : tests) {
+            Class<?> aClass = Class.forName(TestList.getRunner(test));
+            Constructor<?> cnstr = aClass.getConstructor(Options.class, TestResultCollector.class, ExecutorService.class);
+            Runner<? extends Result> o = (Runner<? extends Result>) cnstr.newInstance(opts, collector, pool);
+            async(o);
         }
-
     }
 
     public Collection<String> getSeparateExecutionCommand(Options opts, String test) {
@@ -335,34 +284,16 @@
         return System.getProperty("os.name").contains("indows");
     }
 
-    static <T> SortedSet<Class<? extends T>> filterTests(final String filter, Class<T> klass) {
-        SortedSet<Class<? extends T>> s = new TreeSet<Class<? extends T>>(new Comparator<Class<? extends T>>() {
-            @Override
-            public int compare(Class<? extends T> o1, Class<? extends T> o2) {
-                return o1.getName().compareTo(o2.getName());
+    static SortedSet<String> getTests(final String filter) {
+        SortedSet<String> s = new TreeSet<String>();
+
+        Pattern pattern = Pattern.compile(filter);
+        for (String testName : TestList.tests()) {
+            if (pattern.matcher(testName).matches()) {
+                s.add(testName);
             }
-        });
-
-        // speculatively handle the case when there is a direct hit
-        try {
-            @SuppressWarnings("unchecked")
-            Class<? extends T> k = (Class<? extends T>) Class.forName(filter);
-            if (klass.isAssignableFrom(k)) {
-                s.add(k);
-            }
-
-            return s;
-        } catch (ClassNotFoundException e) {
-            // continue
         }
-
-        for (Class<?> c : Reflections.lookupClassesImplementing(klass, filter)) {
-            @SuppressWarnings("unchecked")
-            Class<? extends T> c1 = (Class<? extends T>) c;
-            s.add(c1);
-        }
-
         return s;
-    }
+   }
 
 }
\ No newline at end of file
--- a/jcstress-core/src/main/java/org/openjdk/jcstress/Main.java	Thu Mar 13 18:43:36 2014 +0400
+++ b/jcstress-core/src/main/java/org/openjdk/jcstress/Main.java	Thu Mar 13 19:03:50 2014 +0400
@@ -54,8 +54,8 @@
         }
 
         if (opts.shouldList()) {
-            for (Class<? extends ConcurrencyTest> test : org.openjdk.jcstress.JCStress.filterTests(opts.getTestFilter(), ConcurrencyTest.class)) {
-                System.out.println(test.getName());
+            for (String test : org.openjdk.jcstress.JCStress.getTests(opts.getTestFilter())) {
+                System.out.println(test);
             }
         } else {
             boolean vmSupportInited;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jcstress-core/src/main/java/org/openjdk/jcstress/infra/annotations/Actor.java	Thu Mar 13 19:03:50 2014 +0400
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.jcstress.infra.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Actor {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jcstress-core/src/main/java/org/openjdk/jcstress/infra/annotations/Arbiter.java	Thu Mar 13 19:03:50 2014 +0400
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.jcstress.infra.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Arbiter {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jcstress-core/src/main/java/org/openjdk/jcstress/infra/annotations/ConcurrencyStressTest.java	Thu Mar 13 19:03:50 2014 +0400
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.jcstress.infra.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ConcurrencyStressTest {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jcstress-core/src/main/java/org/openjdk/jcstress/infra/annotations/Result.java	Thu Mar 13 19:03:50 2014 +0400
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.jcstress.infra.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Result {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jcstress-core/src/main/java/org/openjdk/jcstress/infra/annotations/State.java	Thu Mar 13 19:03:50 2014 +0400
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.jcstress.infra.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface State {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jcstress-core/src/main/java/org/openjdk/jcstress/infra/processors/ConcurrencyStressTestProcessor.java	Thu Mar 13 19:03:50 2014 +0400
@@ -0,0 +1,438 @@
+/*
+ * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.jcstress.infra.processors;
+
+import org.openjdk.jcstress.Options;
+import org.openjdk.jcstress.infra.annotations.Actor;
+import org.openjdk.jcstress.infra.annotations.Arbiter;
+import org.openjdk.jcstress.infra.annotations.ConcurrencyStressTest;
+import org.openjdk.jcstress.infra.annotations.Result;
+import org.openjdk.jcstress.infra.annotations.State;
+import org.openjdk.jcstress.infra.collectors.TestResultCollector;
+import org.openjdk.jcstress.infra.runners.Control;
+import org.openjdk.jcstress.infra.runners.Runner;
+import org.openjdk.jcstress.infra.runners.StateHolder;
+import org.openjdk.jcstress.infra.runners.TestList;
+import org.openjdk.jcstress.util.ArrayUtils;
+import org.openjdk.jcstress.util.Counter;
+import org.openjdk.jcstress.util.Counters;
+import org.openjdk.jcstress.util.Reflections;
+
+import javax.annotation.Generated;
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.RoundEnvironment;
+import javax.annotation.processing.SupportedSourceVersion;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Name;
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.util.ElementFilter;
+import javax.tools.Diagnostic;
+import javax.tools.FileObject;
+import javax.tools.StandardLocation;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.Writer;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
+import java.util.concurrent.atomic.AtomicReference;
+
+
+@SupportedSourceVersion(SourceVersion.RELEASE_6)
+public class ConcurrencyStressTestProcessor extends AbstractProcessor {
+
+    private final List<TestInfo> tests = new ArrayList<TestInfo>();
+
+    @Override
+    public Set<String> getSupportedAnnotationTypes() {
+        return Collections.singleton(ConcurrencyStressTest.class.getName());
+    }
+
+    @Override
+    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+        if (!roundEnv.processingOver()) {
+            Set<? extends Element> set = roundEnv.getElementsAnnotatedWith(ConcurrencyStressTest.class);
+            for (Element el : set) {
+                TypeElement e = (TypeElement) el;
+                try {
+                    TestInfo info = parseAndValidate(e);
+                    generate(info);
+                    tests.add(info);
+                } catch (GenerationException ex) {
+                    processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, ex.getMessage(), ex.getElement());
+                }
+            }
+        } else {
+            try {
+                FileObject file = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", TestList.LIST.substring(1));
+                PrintWriter writer = new PrintWriter(file.openWriter());
+                for (TestInfo test : tests) {
+                    writer.println(test.getTest().getQualifiedName() + "," + test.getGeneratedName());
+                }
+                writer.close();
+            } catch (IOException ex) {
+                processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Error writing MicroBenchmark list " + ex);
+            }
+        }
+        return true;
+    }
+
+    private TestInfo parseAndValidate(TypeElement e) {
+        TestInfo info = new TestInfo();
+
+        info.setTest(e);
+
+        for (ExecutableElement method : ElementFilter.methodsIn(e.getEnclosedElements())) {
+            if (method.getAnnotation(Actor.class) != null) {
+                info.addActor(method);
+            }
+
+            if (method.getAnnotation(Arbiter.class) != null) {
+                info.setArbiter(method);
+            }
+
+            for (VariableElement var : method.getParameters()) {
+                TypeElement paramClass = (TypeElement) processingEnv.getTypeUtils().asElement(var.asType());
+                if (paramClass.getAnnotation(State.class) != null) {
+                    info.setState(paramClass);
+                } else if (paramClass.getAnnotation(Result.class) != null) {
+                    info.setResult(paramClass);
+                } else {
+                    throw new GenerationException("The parameter for @" + Actor.class.getSimpleName() +
+                            " methods requires either @" + State.class.getSimpleName() + " or @" + Result.class +
+                            " annotated class", var);
+                }
+            }
+        }
+
+        if (e.getAnnotation(State.class) != null) {
+            info.setState(e);
+        } else if (e.getAnnotation(Result.class) != null) {
+            info.setResult(e);
+        }
+
+        if (info.getState() == null) {
+            throw new GenerationException("@" + ConcurrencyStressTest.class.getSimpleName() + " defines no @" +
+                    State.class.getSimpleName() + " to work with", e);
+        }
+
+        if (info.getResult() == null) {
+            throw new GenerationException("@" + ConcurrencyStressTest.class.getSimpleName() + " defines no @" +
+                    Result.class.getSimpleName() + " to work with", e);
+        }
+
+        String packageName = getPackageName(info.getTest()) + ".generated";
+        String testName = info.getTest().getSimpleName().toString();
+
+        info.setGeneratedName(packageName + "." + testName);
+
+        return info;
+    }
+
+    private void generate(TestInfo info) {
+        PrintWriter pw;
+        Writer writer;
+        try {
+            writer = processingEnv.getFiler().createSourceFile(info.getTest().getQualifiedName().toString()).openWriter();
+            pw = new PrintWriter(writer, true);
+        } catch (IOException e) {
+            throw new GenerationException("IOException", info.getTest());
+        }
+
+        String t = info.getTest().getQualifiedName().toString();
+        String tShort = info.getTest().getSimpleName().toString();
+        String s = info.getState().getSimpleName().toString();
+        String r = info.getResult().getSimpleName().toString();
+
+        pw.println("package " + getPackageName(info.getTest()) + ".generated;");
+
+        printImports(pw, info);
+
+        pw.println("public class " + tShort + " extends Runner<" + r + "> {");
+        pw.println();
+
+        pw.println("    public " + tShort + "(Options opts, TestResultCollector collector, ExecutorService pool) {");
+        pw.println("        super(opts, collector, pool, \"" + t + "\");");
+        pw.println("    }");
+        pw.println();
+
+        pw.println("    @Override");
+        pw.println("    public int requiredThreads() {");
+        pw.println("        return " + info.getActors().size() + ";");
+        pw.println("    }");
+        pw.println();
+
+        pw.println("    @Override");
+        pw.println("    public void sanityCheck() throws Throwable {");
+        pw.println("        " + t + " t = new " + t + "();");
+        pw.println("        " + s + " s = new " + s + "();");
+        pw.println("        " + r + " r = new " + r + "();");
+
+        for (ExecutableElement el : info.getActors()) {
+            emitMethod(pw, el, "        t." + el.getSimpleName(), "s", "r");
+        }
+        if (info.getArbiter() != null) {
+            emitMethod(pw, info.getArbiter(), "        t." + info.getArbiter().getSimpleName(), "s", "r");
+        }
+
+        pw.println("    }");
+        pw.println();
+
+        pw.println("    @Override");
+        pw.println("    public Counter<" + r + "> internalRun() {");
+        pw.println("        " + t + " test = new " + t + "();");
+        pw.println("        " + s + "[] poison = new " + s + "[0];");
+        pw.println();
+        pw.println("        Counter<" + r + "> counter = Counters.newCounter(" + r + ".class);");
+        pw.println();
+        pw.println("        " + s + "[] newStride = new " + s + "[control.minStride];");
+        pw.println("        for (int c = 0; c < control.minStride; c++) {");
+        pw.println("            newStride[c] = new " + s + "();");
+        pw.println("        }");
+        pw.println();
+        pw.println("        " + r + "[] newResult = new " + r + "[control.minStride];");
+        pw.println("        for (int c = 0; c < control.minStride; c++) {");
+        pw.println("            newResult[c] = new " + r + "();");
+        pw.println("        }");
+        pw.println();
+        pw.println("        StateHolder<" + s + ", " + r + "> holder = new StateHolder<" + s + ", " + r + ">(newStride, newResult, " + info.getActors().size() + ");");
+        pw.println();
+        pw.println("        final AtomicReference<StateHolder<" + s + "," + r + ">> version = new AtomicReference<StateHolder<" + s + ", " + r + ">>();");
+        pw.println("        version.set(holder);");
+        pw.println();
+        pw.println("        final AtomicInteger epoch = new AtomicInteger();");
+        pw.println();
+        pw.println("        Collection<Future<?>> tasks = new ArrayList<Future<?>>();");
+        pw.println();
+        pw.println("        control.isStopped = false;");
+
+        for (ExecutableElement a : info.getActors()) {
+            pw.println("        tasks.add(pool.submit(new Runner_" + a.getSimpleName() + "(control, counter, test, poison, version, epoch)));");
+        }
+
+        pw.println();
+        pw.println("        try {");
+        pw.println("            TimeUnit.MILLISECONDS.sleep(control.time);");
+        pw.println("        } catch (InterruptedException e) {");
+        pw.println("            // do nothing");
+        pw.println("        }");
+        pw.println();
+        pw.println("        control.isStopped = true;");
+        pw.println();
+        pw.println("        waitFor(tasks);");
+        pw.println();
+        pw.println("        return counter;");
+        pw.println("    }\n");
+
+        for (ExecutableElement a : info.getActors()) {
+            pw.println("public static class Runner_" + a.getSimpleName() + " implements Callable {");
+            pw.println("    final Control control;");
+            pw.println("    final Counter<" + r + "> counter;");
+            pw.println("    final " + t + " test;");
+            pw.println("    final " + s + "[] poison;");
+            pw.println("    final AtomicReference<StateHolder<" + s + "," + r + ">> version;");
+            pw.println("    final AtomicInteger epoch;");
+            pw.println();
+            pw.println("    public Runner_" + a.getSimpleName() + "(Control control, Counter<" + r + "> counter, " + t + " test, " + s + "[] poison, AtomicReference<StateHolder<" + s + "," + r + ">> version, AtomicInteger epoch) {");
+            pw.println("        this.control = control;");
+            pw.println("        this.counter = counter;");
+            pw.println("        this.test = test;");
+            pw.println("        this.poison = poison;");
+            pw.println("        this.version = version;");
+            pw.println("        this.epoch = epoch;");
+            pw.println("    }");
+            pw.println();
+            pw.println("    public Void call() {");
+            pw.println("        int lastLoops = 0;");
+            pw.println("        int[] indices = null;");
+            pw.println("        int curEpoch = 0;");
+            pw.println();
+            pw.println("        boolean shouldYield = control.shouldYield;");
+            pw.println("        int maxStride = control.maxStride;");
+            pw.println();
+            pw.println("        Counter<" + r + "> lCounter = counter;");
+            pw.println("        " + t + " lt = test;");
+            pw.println("        " + s + "[] lPoison = poison;");
+            pw.println();
+            pw.println("        while (true) {");
+            pw.println("            StateHolder<" + s + ", " + r + "> holder = version.get();");
+            pw.println("            " + s + "[] cur = holder.s;");
+            pw.println("            " + r + "[] res = holder.r;");
+            pw.println();
+            pw.println("            if (cur == lPoison) {");
+            pw.println("                return null;");
+            pw.println("            }");
+            pw.println();
+            pw.println("            int loops = holder.loops;");
+            pw.println();
+            pw.println("            if (loops != lastLoops) {");
+            pw.println("                lastLoops = loops;");
+            pw.println("                indices = ArrayUtils.generatePermutation(loops);");
+            pw.println("            }");
+            pw.println();
+            pw.println("            holder.announceReady();");
+            pw.println("            while (holder.notAllReady) {");
+            pw.println("                if (shouldYield) Thread.yield();");
+            pw.println("            }");
+            pw.println();
+            pw.println("            holder.announceStarted();");
+            pw.println();
+            pw.println("            for (int l = 0; l < loops; l++) {");
+            pw.println("                int index = indices[l];");
+
+            emitMethod(pw, a, "                lt." + a.getSimpleName(), "cur[index]", "res[index]");
+
+            pw.println("            }");
+            pw.println();
+            pw.println("            holder.announceFinished();");
+            pw.println("            holder.hasLaggedWorkers |= holder.notAllStarted;");
+            pw.println();
+            pw.println("            while (holder.notAllFinished) {");
+            pw.println("                if (shouldYield) Thread.yield();");
+            pw.println("            }");
+            pw.println();
+            pw.println("            if (epoch.compareAndSet(curEpoch, curEpoch + 1)) {");
+
+            if (info.getArbiter() != null) {
+                pw.println();
+                pw.println("                for (int l = 0; l < loops; l++) {");
+                pw.println("                    int index = indices[l];");
+                emitMethod(pw, info.getArbiter(), "                test." + info.getArbiter().getSimpleName(), "cur[index]", "res[index]");
+                pw.println("                }");
+            }
+            pw.println();
+            pw.println("                for (" + r + " r1 : res) {");
+            pw.println("                    lCounter.record(r1);");
+            pw.println("                }");
+            pw.println();
+            pw.println("                StateHolder<" + s + ", " + r + "> newHolder;");
+            pw.println("                if (control.isStopped) {");
+            pw.println("                    newHolder = new StateHolder<" + s + ", " + r + ">(lPoison, null, holder.countWorkers);");
+            pw.println("                } else {");
+            pw.println("                    int newLoops = holder.hasLaggedWorkers ? Math.min(loops * 2, maxStride) : loops;");
+            pw.println();
+            pw.println("                    for (int c = 0; c < loops; c++) {");
+            pw.println("                        res[c].reset();");
+            pw.println("                    }");
+            pw.println();
+            pw.println("                    " + s + "[] newStride = cur;");
+            pw.println("                    " + r + "[] newRes = res;");
+            pw.println("                    if (newLoops > loops) {");
+            pw.println("                        newStride = Arrays.copyOf(cur, newLoops);");
+            pw.println("                        newRes = Arrays.copyOf(res, newLoops);");
+            pw.println("                        for (int c = loops; c < newLoops; c++) {");
+            pw.println("                            newRes[c] = new " + r + "();");
+            pw.println("                        }");
+            pw.println("                    }");
+            pw.println();
+            pw.println("                    for (int c = 0; c < newLoops; c++) {");
+            pw.println("                        newStride[c] = new " + s + "();");
+            pw.println("                    }");
+            pw.println();
+            pw.println("                    newHolder = new StateHolder<" + s + ", " + r + ">(newStride, newRes, holder.countWorkers);");
+            pw.println("                }");
+            pw.println();
+            pw.println("                version.set(newHolder);");
+            pw.println("            }");
+            pw.println();
+            pw.println("            curEpoch += 1;");
+            pw.println("            while (curEpoch != epoch.get()) {");
+            pw.println("                if (shouldYield) Thread.yield();");
+            pw.println("            }");
+            pw.println();
+            pw.println("            holder.announceConsumed();");
+            pw.println("            while (holder.notAllConsumed) {");
+            pw.println("                if (shouldYield) Thread.yield();");
+            pw.println("            }");
+            pw.println("        }");
+            pw.println("    }");
+            pw.println("}");
+        }
+        pw.println("}");
+
+        pw.close();
+    }
+
+    private void emitMethod(PrintWriter pw, ExecutableElement el, String lvalue, String stateAccessor, String resultAccessor) {
+        pw.print("                " + lvalue + "(");
+
+        boolean isFirst = true;
+        for (VariableElement var : el.getParameters()) {
+            if (isFirst) {
+                isFirst = false;
+            } else {
+                pw.print(", ");
+            }
+            TypeElement paramClass = (TypeElement) processingEnv.getTypeUtils().asElement(var.asType());
+            if (paramClass.getAnnotation(State.class) != null) {
+                pw.print(stateAccessor);
+            } else if (paramClass.getAnnotation(Result.class) != null) {
+                pw.print(resultAccessor);
+            }
+        }
+        pw.println(");");
+    }
+
+    private void printImports(PrintWriter pw, TestInfo info) {
+        Class<?>[] imports = new Class<?>[] {
+                Options.class, Result.class, TestResultCollector.class,
+                Counter.class, Counters.class, Runner.class, Override.class, StateHolder.class,
+                ArrayList.class, Collection.class, ExecutorService.class,
+                Future.class, TimeUnit.class, AtomicInteger.class, AtomicReference.class, Callable.class,
+                ArrayUtils.class, Arrays.class, Control.class
+        };
+
+        for (Class<?> c : imports) {
+            pw.println("import " + c.getName() + ';');
+        }
+        pw.println("import " + info.getState().getQualifiedName() + ";");
+        pw.println("import " + info.getResult().getQualifiedName() + ";");
+        pw.println();
+    }
+
+    public String getPackageName(Element el) {
+        Element walk = el;
+        while (walk.getKind() != ElementKind.PACKAGE) {
+            walk = walk.getEnclosingElement();
+        }
+        return ((PackageElement)walk).getQualifiedName().toString();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jcstress-core/src/main/java/org/openjdk/jcstress/infra/processors/GenerationException.java	Thu Mar 13 19:03:50 2014 +0400
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.jcstress.infra.processors;
+
+import javax.lang.model.element.Element;
+
+public class GenerationException extends RuntimeException {
+    private Element element;
+
+    public GenerationException(String s, Element e) {
+        super(s);
+        element = e;
+    }
+
+    public Element getElement() {
+        return element;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jcstress-core/src/main/java/org/openjdk/jcstress/infra/processors/TestInfo.java	Thu Mar 13 19:03:50 2014 +0400
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.jcstress.infra.processors;
+
+import org.openjdk.jcstress.infra.annotations.Arbiter;
+import org.openjdk.jcstress.infra.annotations.Result;
+import org.openjdk.jcstress.infra.annotations.State;
+
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import java.util.ArrayList;
+import java.util.List;
+
+public class TestInfo {
+
+    private List<ExecutableElement> actors;
+    private TypeElement state;
+    private TypeElement result;
+    private ExecutableElement arbiter;
+    private TypeElement test;
+    private String generatedName;
+
+    public TestInfo() {
+        actors = new ArrayList<ExecutableElement>();
+    }
+
+    public void addActor(ExecutableElement element) {
+        actors.add(element);
+    }
+
+    public void setState(TypeElement element) {
+        if (state == null || state.equals(element)) {
+            state = element;
+        } else {
+            throw new GenerationException("We can only have a single @" + State.class.getSimpleName() + " per test.", element);
+        }
+    }
+
+    public void setArbiter(ExecutableElement element) {
+        if (arbiter == null || arbiter.equals(element)) {
+            arbiter = element;
+        } else {
+            throw new GenerationException("We can only have a single @" + Arbiter.class.getSimpleName() + " per test.", element);
+        }
+    }
+
+    public void setResult(TypeElement element) {
+        if (result == null || result.equals(element)) {
+            result = element;
+        } else {
+            throw new GenerationException("We can only have a single @" + Result.class.getSimpleName() + " per test.", element);
+        }
+    }
+
+    public void setTest(TypeElement element) {
+        if (test == null || test.equals(element)) {
+            test = element;
+        } else {
+            throw new GenerationException("We can only have a single test.", element);
+        }
+    }
+
+    public TypeElement getState() {
+        return state;
+    }
+
+    public TypeElement getResult() {
+        return result;
+    }
+
+    public TypeElement getTest() {
+        return test;
+    }
+
+    public List<ExecutableElement> getActors() {
+        return actors;
+    }
+
+    public ExecutableElement getArbiter() {
+        return arbiter;
+    }
+
+    public void setGeneratedName(String generatedName) {
+        this.generatedName = generatedName;
+    }
+
+    public String getGeneratedName() {
+        return generatedName;
+    }
+}
--- a/jcstress-core/src/main/java/org/openjdk/jcstress/infra/results/IntResult2.java	Thu Mar 13 18:43:36 2014 +0400
+++ b/jcstress-core/src/main/java/org/openjdk/jcstress/infra/results/IntResult2.java	Thu Mar 13 19:03:50 2014 +0400
@@ -29,6 +29,7 @@
 
 import java.io.Serializable;
 
+@org.openjdk.jcstress.infra.annotations.Result
 public class IntResult2 implements Serializable, Result {
 
     @Contended
--- a/jcstress-core/src/main/java/org/openjdk/jcstress/infra/runners/Runner.java	Thu Mar 13 18:43:36 2014 +0400
+++ b/jcstress-core/src/main/java/org/openjdk/jcstress/infra/runners/Runner.java	Thu Mar 13 19:03:50 2014 +0400
@@ -57,7 +57,7 @@
     protected final PrintWriter testLog;
     protected final String testName;
 
-    public Runner(Options opts, TestResultCollector collector, ExecutorService pool, String testName) throws FileNotFoundException, JAXBException {
+    public Runner(Options opts, TestResultCollector collector, ExecutorService pool, String testName) {
         this.collector = collector;
         this.pool = pool;
         this.testName = testName;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jcstress-core/src/main/java/org/openjdk/jcstress/infra/runners/TestList.java	Thu Mar 13 19:03:50 2014 +0400
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.jcstress.infra.runners;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class TestList {
+
+    public static final String LIST = "/META-INF/TestList";
+
+    private static volatile Map<String, String> tests;
+
+    private static Map<String, String> getTests() {
+        if (tests == null) {
+            Map<String, String> m = new HashMap<String, String>();
+            InputStream stream = null;
+            try {
+                stream = TestList.class.getResourceAsStream(LIST);
+                BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
+
+                String line;
+                while ((line = reader.readLine()) != null) {
+                    String[] ls = line.split(",");
+                    m.put(ls[0], ls[1]);
+                }
+            } catch (IOException e) {
+                // FIXME: Print warning
+            } finally {
+                if (stream != null) {
+                    try {
+                        stream.close();
+                    } catch (IOException e) {
+                        // swallow
+                    }
+                }
+            }
+            tests = m;
+        }
+        return tests;
+    }
+
+    public static Collection<String> tests() {
+        return getTests().keySet();
+    }
+
+    public static String getRunner(String test) {
+        return tests.get(test);
+    }
+}
--- a/jcstress-core/src/main/resources/META-INF/services/javax.annotation.processing.Processor	Thu Mar 13 18:43:36 2014 +0400
+++ b/jcstress-core/src/main/resources/META-INF/services/javax.annotation.processing.Processor	Thu Mar 13 19:03:50 2014 +0400
@@ -22,3 +22,4 @@
 #    questions.
 #
 org.openjdk.jcstress.util.InterfaceListProcessor
+org.openjdk.jcstress.infra.processors.ConcurrencyStressTestProcessor
--- a/tests-custom/src/main/java/org/openjdk/jcstress/tests/volatiles/DekkerTest.java	Thu Mar 13 18:43:36 2014 +0400
+++ b/tests-custom/src/main/java/org/openjdk/jcstress/tests/volatiles/DekkerTest.java	Thu Mar 13 19:03:50 2014 +0400
@@ -24,36 +24,30 @@
  */
 package org.openjdk.jcstress.tests.volatiles;
 
+import org.openjdk.jcstress.infra.annotations.ConcurrencyStressTest;
+import org.openjdk.jcstress.infra.annotations.Actor;
+import org.openjdk.jcstress.infra.annotations.State;
+import org.openjdk.jcstress.infra.results.IntResult2;
 
-import org.openjdk.jcstress.infra.results.IntResult2;
-import org.openjdk.jcstress.tests.Actor2_Test;
+@ConcurrencyStressTest
+public class DekkerTest  {
 
-public class DekkerTest implements Actor2_Test<DekkerTest.State, IntResult2> {
-
-    @Override
-    public State newState() {
-        return new State();
-    }
-
-    @Override
-    public void actor1(State s, IntResult2 r) {
+    @Actor
+    public void actor1(S s, IntResult2 r) {
         s.a = 1;
         r.r1 = s.b;
     }
 
-    @Override
-    public void actor2(State s, IntResult2 r) {
+    @Actor
+    public void actor2(S s, IntResult2 r) {
         s.b = 1;
         r.r2 = s.a;
     }
 
-    @Override
-    public IntResult2 newResult() {
-        return new IntResult2();
+    @State
+    public static class S {
+        volatile int a;
+        volatile int b;
     }
 
-    public static class State {
-        public volatile int a;
-        public volatile int b;
-    }
 }