Skip to content

Commit

Permalink
Adding Atomic Unpadded queues
Browse files Browse the repository at this point in the history
  • Loading branch information
franz1981 committed Feb 7, 2024
1 parent 0dae71c commit 4b295bb
Show file tree
Hide file tree
Showing 53 changed files with 4,655 additions and 129 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,23 @@
import com.github.javaparser.ast.type.PrimitiveType;
import com.github.javaparser.ast.type.Type;

import static org.jctools.queues.util.GeneratorUtils.formatMultilineJavadoc;
import static org.jctools.queues.util.GeneratorUtils.runJCToolsGenerator;

/**
* This generator takes in an JCTools 'ArrayQueue' Java source file and patches {@link sun.misc.Unsafe} accesses into
* atomic {@link java.util.concurrent.atomic.AtomicLongFieldUpdater}. It outputs a Java source file with these patches.
* <p>
* An 'ArrayQueue' is one that is backed by a circular array and use a <code>producerLimit</code> and a
* <code>consumerLimit</code> field to track the positions of each.
*/
public final class JavaParsingAtomicArrayQueueGenerator extends JavaParsingAtomicQueueGenerator {
public class JavaParsingAtomicArrayQueueGenerator extends JavaParsingAtomicQueueGenerator {

public static void main(String[] args) throws Exception {
main(JavaParsingAtomicArrayQueueGenerator.class, args);
runJCToolsGenerator(JavaParsingAtomicArrayQueueGenerator.class, args);
}

JavaParsingAtomicArrayQueueGenerator(String sourceFileName) {
public JavaParsingAtomicArrayQueueGenerator(String sourceFileName) {
super(sourceFileName);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,27 @@
import com.github.javaparser.ast.type.PrimitiveType;
import com.github.javaparser.ast.type.Type;

import static org.jctools.queues.util.GeneratorUtils.formatMultilineJavadoc;
import static org.jctools.queues.util.GeneratorUtils.runJCToolsGenerator;

/**
* This generator takes in an JCTools 'LinkedQueue' Java source file and patches {@link sun.misc.Unsafe} accesses into
* atomic {@link java.util.concurrent.atomic.AtomicLongFieldUpdater}. It outputs a Java source file with these patches.
* <p>
* An 'LinkedQueue' is one that is backed by a linked list and use a <code>producerNode</code> and a
* <code>consumerNode</code> field to track the positions of each.
*/
public final class JavaParsingAtomicLinkedQueueGenerator extends JavaParsingAtomicQueueGenerator {
private static final String MPSC_LINKED_ATOMIC_QUEUE_NAME = "MpscLinkedAtomicQueue";
public class JavaParsingAtomicLinkedQueueGenerator extends JavaParsingAtomicQueueGenerator {

private final String mpscLinkedQueueName;

public static void main(String[] args) throws Exception {
main(JavaParsingAtomicLinkedQueueGenerator.class, args);
runJCToolsGenerator(JavaParsingAtomicLinkedQueueGenerator.class, args);
}

JavaParsingAtomicLinkedQueueGenerator(String sourceFileName) {
public JavaParsingAtomicLinkedQueueGenerator(String sourceFileName) {
super(sourceFileName);
this.mpscLinkedQueueName = atomicQueueName();
}

@Override
Expand All @@ -40,13 +45,17 @@ public void visit(ConstructorDeclaration n, Void arg) {
if (nameAsString.equals("WeakIterator"))
return;
n.setName(translateQueueName(nameAsString));
if (MPSC_LINKED_ATOMIC_QUEUE_NAME.equals(nameAsString)) {
if (mpscLinkedQueueName.equals(nameAsString)) {
// Special case for MPSC because the Unsafe variant has a static factory method and a protected constructor.
n.setModifier(Keyword.PROTECTED, false);
n.setModifier(Keyword.PUBLIC, true);
}
}

private String atomicQueueName() {
return "MpscLinked" + queueClassNamePrefix() + "Queue";
}

@Override
public void visit(ClassOrInterfaceDeclaration node, Void arg) {
super.visit(node, arg);
Expand All @@ -56,7 +65,7 @@ public void visit(ClassOrInterfaceDeclaration node, Void arg) {
String nameAsString = node.getNameAsString();
if (nameAsString.contains("Queue"))
node.setName(translateQueueName(nameAsString));
if (MPSC_LINKED_ATOMIC_QUEUE_NAME.equals(nameAsString)) {
if (mpscLinkedQueueName.equals(nameAsString)) {
/*
* Special case for MPSC
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import com.github.javaparser.ast.type.ClassOrInterfaceType;
import com.github.javaparser.ast.type.Type;
import com.github.javaparser.ast.visitor.VoidVisitorAdapter;
import org.jctools.queues.util.JCToolsGenerator;

/**
* Base class of the atomic queue generators. These generators work by parsing a Java source file using
Expand All @@ -44,7 +45,7 @@
* These generators are coupled with the structure and naming of fields, variables and methods and are not suitable for
* general purpose use.
*/
abstract class JavaParsingAtomicQueueGenerator extends VoidVisitorAdapter<Void> {
public abstract class JavaParsingAtomicQueueGenerator extends VoidVisitorAdapter<Void> implements JCToolsGenerator {

/**
* When set on a class using a single line comment, the class has fields that have unsafe 'ordered' reads and
Expand All @@ -57,34 +58,14 @@ abstract class JavaParsingAtomicQueueGenerator extends VoidVisitorAdapter<Void>
*/
protected static final String GEN_DIRECTIVE_METHOD_IGNORE = "$gen:ignore";

protected static final String INDENT_LEVEL = " ";
protected final String sourceFileName;

static void main(Class<? extends JavaParsingAtomicQueueGenerator> generatorClass, String[] args) throws Exception {

if (args.length < 2) {
throw new IllegalArgumentException("Usage: outputDirectory inputSourceFiles");
}

File outputDirectory = new File(args[0]);

for (int i = 1; i < args.length; i++) {
File file = new File(args[i]);
System.out.println("Processing " + file);
CompilationUnit cu = new JavaParser().parse(file).getResult().get();
JavaParsingAtomicQueueGenerator generator = buildGenerator(generatorClass, file.getName());
generator.visit(cu, null);

generator.organiseImports(cu);

String outputFileName = generator.translateQueueName(file.getName().replace(".java", "")) + ".java";

try (FileWriter writer = new FileWriter(new File(outputDirectory, outputFileName))) {
writer.write(cu.toString());
}
protected String outoutPackage() {
return "org.jctools.queues.atomic";
}

System.out.println("Saved to " + outputFileName);
}
protected String queueClassNamePrefix() {
return "Atomic";
}

JavaParsingAtomicQueueGenerator(String sourceFileName) {
Expand All @@ -98,7 +79,7 @@ static void main(Class<? extends JavaParsingAtomicQueueGenerator> generatorClass
public void visit(PackageDeclaration n, Void arg) {
super.visit(n, arg);
// Change the package of the output
n.setName("org.jctools.queues.atomic");
n.setName(outoutPackage());
}

@Override
Expand Down Expand Up @@ -149,13 +130,14 @@ protected void removeStaticFieldsAndInitialisers(ClassOrInterfaceDeclaration nod
}
}

protected String translateQueueName(String qName) {
@Override
public String translateQueueName(String qName) {
if (qName.contains("LinkedQueue") || qName.contains("LinkedArrayQueue")) {
return qName.replace("Linked", "LinkedAtomic");
return qName.replace("Linked", "Linked" + queueClassNamePrefix());
}

if (qName.contains("ArrayQueue")) {
return qName.replace("ArrayQueue", "AtomicArrayQueue");
return qName.replace("ArrayQueue", queueClassNamePrefix() + "ArrayQueue");
}

throw new IllegalArgumentException("Unexpected queue name: " + qName);
Expand Down Expand Up @@ -219,7 +201,7 @@ protected void replaceParentClassesForAtomics(ClassOrInterfaceDeclaration n) {
// ignore the JDK parent
break;
case "BaseLinkedQueue":
parent.setName("BaseLinkedAtomicQueue");
parent.setName("BaseLinked" + queueClassNamePrefix() + "Queue");
break;
case "ConcurrentCircularArrayQueue":
parent.setName("AtomicReferenceArrayQueue");
Expand All @@ -234,7 +216,14 @@ protected void replaceParentClassesForAtomics(ClassOrInterfaceDeclaration n) {
}
}
}
protected void organiseImports(CompilationUnit cu) {

@Override
public void cleanupComments(CompilationUnit cu) {
// nop
}

@Override
public void organiseImports(CompilationUnit cu) {
List<ImportDeclaration> importDecls = new ArrayList<>();

// remove irrelevant imports
Expand All @@ -258,27 +247,13 @@ protected void organiseImports(CompilationUnit cu) {
cu.addImport(new ImportDeclaration("java.util.concurrent.atomic", false, true));

cu.addImport(new ImportDeclaration("org.jctools.queues", false, true));
cu.addImport(staticImportDeclaration("org.jctools.queues.atomic.AtomicQueueUtil"));
cu.addImport(staticImportDeclaration(outoutPackage() + ".AtomicQueueUtil"));
}

protected String capitalise(String s) {
return s.substring(0, 1).toUpperCase() + s.substring(1);
}

protected String formatMultilineJavadoc(int indent, String... lines) {
String indentation = "";
for (int i = 0; i < indent; i++) {
indentation += INDENT_LEVEL;
}

String out = "\n";
for (String line : lines) {
out += indentation + " * " + line + "\n";
}
out += indentation + " ";
return out;
}

/**
* Generates something like
* <code>P_INDEX_UPDATER.lazySet(this, newValue)</code>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package org.jctools.queues.atomic.unpadded;

import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import org.jctools.queues.atomic.JavaParsingAtomicArrayQueueGenerator;

import static org.jctools.queues.util.GeneratorUtils.cleanupPaddingComments;
import static org.jctools.queues.util.GeneratorUtils.removePaddingFields;
import static org.jctools.queues.util.GeneratorUtils.runJCToolsGenerator;

public class JavaParsingAtomicUnpaddedArrayQueueGenerator extends JavaParsingAtomicArrayQueueGenerator {
public static void main(String[] args) throws Exception {
runJCToolsGenerator(JavaParsingAtomicUnpaddedArrayQueueGenerator.class, args);
}

public JavaParsingAtomicUnpaddedArrayQueueGenerator(String sourceFileName) {
super(sourceFileName);
}

@Override
public void cleanupComments(CompilationUnit cu) {
super.cleanupComments(cu);
cleanupPaddingComments(cu);
}

@Override
public void visit(ClassOrInterfaceDeclaration node, Void arg) {
super.visit(node, arg);
removePaddingFields(node);
}

@Override
protected String outoutPackage() {
return "org.jctools.queues.atomic.unpadded";
}

@Override
protected String queueClassNamePrefix() {
return "AtomicUnpadded";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package org.jctools.queues.atomic.unpadded;

import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import org.jctools.queues.atomic.JavaParsingAtomicLinkedQueueGenerator;

import static org.jctools.queues.util.GeneratorUtils.cleanupPaddingComments;
import static org.jctools.queues.util.GeneratorUtils.removePaddingFields;
import static org.jctools.queues.util.GeneratorUtils.runJCToolsGenerator;

public class JavaParsingAtomicUnpaddedLinkedQueueGenerator extends JavaParsingAtomicLinkedQueueGenerator {
public static void main(String[] args) throws Exception {
runJCToolsGenerator(JavaParsingAtomicUnpaddedLinkedQueueGenerator.class, args);
}

public JavaParsingAtomicUnpaddedLinkedQueueGenerator(String sourceFileName) {
super(sourceFileName);
}

@Override
public void cleanupComments(CompilationUnit cu) {
super.cleanupComments(cu);
cleanupPaddingComments(cu);
}

@Override
public void visit(ClassOrInterfaceDeclaration node, Void arg) {
super.visit(node, arg);
removePaddingFields(node);
}

@Override
protected String outoutPackage() {
return "org.jctools.queues.atomic.unpadded";
}

@Override
protected String queueClassNamePrefix() {
return "AtomicUnpadded";
}
}
Loading

0 comments on commit 4b295bb

Please sign in to comment.