Skip to content

Commit

Permalink
Added JCStressTests for release/acquire
Browse files Browse the repository at this point in the history
  • Loading branch information
pveentjer committed Jan 16, 2025
1 parent bb70d5d commit 6876fcc
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 4 deletions.
12 changes: 12 additions & 0 deletions agrona-concurrency-tests/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
To run the jcstress concurrency tests directly without Gradle, do the following:

```
./gradlew ./gradlew :agrona-concurrency-tests:shadowJar
```
The above will build the appropriate JCStress binary.

And then:
```
java -jar agrona-concurrency-tests/build/libs/concurrency-tests.jar YourTest -jvmArgsPrepend "--add-exports java.base/jdk.internal.misc=ALL-UNNAMED
```
Make sure to replace the `YourTest` by the appropriate JCStress test.
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,7 @@
import org.openjdk.jcstress.annotations.JCStressTest;
import org.openjdk.jcstress.annotations.Outcome;
import org.openjdk.jcstress.annotations.State;
import org.openjdk.jcstress.infra.results.III_Result;
import org.openjdk.jcstress.infra.results.I_Result;
import org.openjdk.jcstress.infra.results.JJJ_Result;
import org.openjdk.jcstress.infra.results.J_Result;
import org.openjdk.jcstress.infra.results.*;

import static java.nio.ByteBuffer.allocateDirect;

Expand All @@ -38,6 +35,89 @@ public class UnsafeBufferTests
{
}

/**
* Test that verifies that the {@link AtomicBuffer#putLongRelease(int, long)} and
* {@link AtomicBuffer#getLongAcquire(int)} provide causal consistency.
* <p>
* For causal consistency and 2 variables A and B, if first A=1 and then B=1,
* and another thread reads B=1, then it should also read A=1.
*/
@JCStressTest
// first value is B, second value is A.
@Outcome(id = "0, 1", expect = Expect.ACCEPTABLE)
@Outcome(id = "0, 0", expect = Expect.ACCEPTABLE)
@Outcome(id = "1, 1", expect = Expect.ACCEPTABLE)
@Outcome(id = "1, 0", expect = Expect.FORBIDDEN)
@State
public static class ReleaseAcquireLong
{
private final static int A = 0;
private final static int B = 8;
private final UnsafeBuffer buffer = new UnsafeBuffer(BufferUtil.allocateDirectAligned(16, 8));

/**
* Release thread.
*/
@Actor
public void release()
{
buffer.putLong(A, 1);
buffer.putLongRelease(B, 1);
}

/**
* Acquire thread.
*
* @param result object.
*/
@Actor
public void acquire(final JJ_Result result)
{
result.r1 = buffer.getLongAcquire(B);
result.r2 = buffer.getLong(A);
}
}

/**
* Test that verifies that the {@link AtomicBuffer#putIntRelease(int, int)} and
* {@link AtomicBuffer#getIntAcquire(int)} provide causal consistency. For more
* info see {@link ReleaseAcquireLong}.
*/
@JCStressTest
@Outcome(id = "0, 1", expect = Expect.ACCEPTABLE)
@Outcome(id = "0, 0", expect = Expect.ACCEPTABLE)
@Outcome(id = "1, 1", expect = Expect.ACCEPTABLE)
@Outcome(id = "1, 0", expect = Expect.ACCEPTABLE)
@State
public static class ReleaseAcquireInt
{
private final static int A = 0;
private final static int B = 4;
private final UnsafeBuffer buffer = new UnsafeBuffer(BufferUtil.allocateDirectAligned(8, 4));

/**
* Writer thread.
*/
@Actor
public void release()
{
buffer.putInt(A, 1);
buffer.putIntRelease(B, 1);
}

/**
* Reader thread.
*
* @param result object.
*/
@Actor
public void acquire(final JJ_Result result)
{
result.r1 = buffer.getIntAcquire(B);
result.r2 = buffer.getInt(A);
}
}

/**
* Test that verifies the atomicity of the {@link UnsafeBuffer#putLongVolatile(int, long)},
* {@link UnsafeBuffer#putLongRelease(int, long)} (int, long)} and {@link UnsafeBuffer#getLongVolatile(int)}.
Expand Down

0 comments on commit 6876fcc

Please sign in to comment.