mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-26 14:24:46 +02:00
8343394: Make MemorySessionImpl.state a stable field
Co-authored-by: Maurizio Cimadamore <mcimadamore@openjdk.org> Reviewed-by: mcimadamore, jvernee
This commit is contained in:
parent
d2b681d455
commit
1d117f65f0
7 changed files with 250 additions and 43 deletions
|
@ -41,8 +41,7 @@ final class ConfinedSession extends MemorySessionImpl {
|
|||
|
||||
private int asyncReleaseCount = 0;
|
||||
|
||||
static final VarHandle ASYNC_RELEASE_COUNT= MhUtil.findVarHandle(
|
||||
MethodHandles.lookup(), "asyncReleaseCount", int.class);
|
||||
static final VarHandle ASYNC_RELEASE_COUNT= MhUtil.findVarHandle(MethodHandles.lookup(), "asyncReleaseCount", int.class);
|
||||
|
||||
public ConfinedSession(Thread owner) {
|
||||
super(owner, new ConfinedResourceList());
|
||||
|
@ -52,17 +51,17 @@ final class ConfinedSession extends MemorySessionImpl {
|
|||
@ForceInline
|
||||
public void acquire0() {
|
||||
checkValidState();
|
||||
if (state == MAX_FORKS) {
|
||||
if (acquireCount == MAX_FORKS) {
|
||||
throw tooManyAcquires();
|
||||
}
|
||||
state++;
|
||||
acquireCount++;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public void release0() {
|
||||
if (Thread.currentThread() == owner) {
|
||||
state--;
|
||||
acquireCount--;
|
||||
} else {
|
||||
// It is possible to end up here in two cases: this session was kept alive by some other confined session
|
||||
// which is implicitly released (in which case the release call comes from the cleaner thread). Or,
|
||||
|
@ -75,11 +74,11 @@ final class ConfinedSession extends MemorySessionImpl {
|
|||
void justClose() {
|
||||
checkValidState();
|
||||
int asyncCount = (int)ASYNC_RELEASE_COUNT.getVolatile(this);
|
||||
if ((state == 0 && asyncCount == 0)
|
||||
|| ((state - asyncCount) == 0)) {
|
||||
int acquire = acquireCount - asyncCount;
|
||||
if (acquire == 0) {
|
||||
state = CLOSED;
|
||||
} else {
|
||||
throw alreadyAcquired(state - asyncCount);
|
||||
throw alreadyAcquired(acquire);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -42,6 +42,7 @@ non-sealed class GlobalSession extends MemorySessionImpl {
|
|||
|
||||
public GlobalSession() {
|
||||
super(null, null);
|
||||
this.state = NONCLOSEABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -50,11 +51,6 @@ non-sealed class GlobalSession extends MemorySessionImpl {
|
|||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCloseable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public void acquire0() {
|
||||
|
|
|
@ -42,6 +42,7 @@ final class ImplicitSession extends SharedSession {
|
|||
|
||||
public ImplicitSession(Cleaner cleaner) {
|
||||
super();
|
||||
this.state = NONCLOSEABLE;
|
||||
cleaner.register(this, resourceList);
|
||||
}
|
||||
|
||||
|
@ -55,11 +56,6 @@ final class ImplicitSession extends SharedSession {
|
|||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCloseable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void justClose() {
|
||||
throw nonCloseable();
|
||||
|
|
|
@ -38,6 +38,7 @@ import jdk.internal.foreign.GlobalSession.HeapSession;
|
|||
import jdk.internal.misc.ScopedMemoryAccess;
|
||||
import jdk.internal.invoke.MhUtil;
|
||||
import jdk.internal.vm.annotation.ForceInline;
|
||||
import jdk.internal.vm.annotation.Stable;
|
||||
|
||||
/**
|
||||
* This class manages the temporal bounds associated with a memory segment as well
|
||||
|
@ -55,11 +56,19 @@ import jdk.internal.vm.annotation.ForceInline;
|
|||
public abstract sealed class MemorySessionImpl
|
||||
implements Scope
|
||||
permits ConfinedSession, GlobalSession, SharedSession {
|
||||
|
||||
/**
|
||||
* The value of the {@code state} of a {@code MemorySessionImpl}. The only possible transition
|
||||
* is OPEN -> CLOSED. As a result, the states CLOSED and NONCLOSEABLE are stable. This allows
|
||||
* us to annotate {@code state} with {@link Stable} and elide liveness check on non-closeable
|
||||
* constant scopes, such as {@code GLOBAL_SESSION}.
|
||||
*/
|
||||
static final int OPEN = 0;
|
||||
static final int CLOSED = -1;
|
||||
static final int NONCLOSEABLE = 1;
|
||||
|
||||
static final VarHandle STATE = MhUtil.findVarHandle(
|
||||
MethodHandles.lookup(), "state", int.class);
|
||||
static final VarHandle STATE = MhUtil.findVarHandle(MethodHandles.lookup(), "state", int.class);
|
||||
static final VarHandle ACQUIRE_COUNT = MhUtil.findVarHandle(MethodHandles.lookup(), "acquireCount", int.class);
|
||||
|
||||
static final int MAX_FORKS = Integer.MAX_VALUE;
|
||||
|
||||
|
@ -70,7 +79,11 @@ public abstract sealed class MemorySessionImpl
|
|||
|
||||
final ResourceList resourceList;
|
||||
final Thread owner;
|
||||
int state = OPEN;
|
||||
|
||||
@Stable
|
||||
int state;
|
||||
|
||||
int acquireCount;
|
||||
|
||||
public Arena asArena() {
|
||||
return new ArenaImpl(this);
|
||||
|
@ -214,8 +227,8 @@ public abstract sealed class MemorySessionImpl
|
|||
throw new CloneNotSupportedException();
|
||||
}
|
||||
|
||||
public boolean isCloseable() {
|
||||
return true;
|
||||
public final boolean isCloseable() {
|
||||
return state <= OPEN;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -44,6 +44,8 @@ sealed class SharedSession extends MemorySessionImpl permits ImplicitSession {
|
|||
|
||||
private static final ScopedMemoryAccess SCOPED_MEMORY_ACCESS = ScopedMemoryAccess.getScopedMemoryAccess();
|
||||
|
||||
private static final int CLOSED_ACQUIRE_COUNT = -1;
|
||||
|
||||
SharedSession() {
|
||||
super(null, new SharedResourceList());
|
||||
}
|
||||
|
@ -53,15 +55,15 @@ sealed class SharedSession extends MemorySessionImpl permits ImplicitSession {
|
|||
public void acquire0() {
|
||||
int value;
|
||||
do {
|
||||
value = (int) STATE.getVolatile(this);
|
||||
if (value < OPEN) {
|
||||
value = (int) ACQUIRE_COUNT.getVolatile(this);
|
||||
if (value < 0) {
|
||||
//segment is not open!
|
||||
throw alreadyClosed();
|
||||
throw sharedSessionAlreadyClosed();
|
||||
} else if (value == MAX_FORKS) {
|
||||
//overflow
|
||||
throw tooManyAcquires();
|
||||
}
|
||||
} while (!STATE.compareAndSet(this, value, value + 1));
|
||||
} while (!ACQUIRE_COUNT.compareAndSet(this, value, value + 1));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -69,24 +71,35 @@ sealed class SharedSession extends MemorySessionImpl permits ImplicitSession {
|
|||
public void release0() {
|
||||
int value;
|
||||
do {
|
||||
value = (int) STATE.getVolatile(this);
|
||||
if (value <= OPEN) {
|
||||
value = (int) ACQUIRE_COUNT.getVolatile(this);
|
||||
if (value <= 0) {
|
||||
//cannot get here - we can't close segment twice
|
||||
throw alreadyClosed();
|
||||
throw sharedSessionAlreadyClosed();
|
||||
}
|
||||
} while (!STATE.compareAndSet(this, value, value - 1));
|
||||
} while (!ACQUIRE_COUNT.compareAndSet(this, value, value - 1));
|
||||
}
|
||||
|
||||
void justClose() {
|
||||
int prevState = (int) STATE.compareAndExchange(this, OPEN, CLOSED);
|
||||
if (prevState < 0) {
|
||||
throw alreadyClosed();
|
||||
} else if (prevState != OPEN) {
|
||||
throw alreadyAcquired(prevState);
|
||||
int acquireCount = (int) ACQUIRE_COUNT.compareAndExchange(this, 0, CLOSED_ACQUIRE_COUNT);
|
||||
if (acquireCount < 0) {
|
||||
throw sharedSessionAlreadyClosed();
|
||||
} else if (acquireCount > 0) {
|
||||
throw alreadyAcquired(acquireCount);
|
||||
}
|
||||
|
||||
STATE.setVolatile(this, CLOSED);
|
||||
SCOPED_MEMORY_ACCESS.closeScope(this, ALREADY_CLOSED);
|
||||
}
|
||||
|
||||
private IllegalStateException sharedSessionAlreadyClosed() {
|
||||
// To avoid the situation where a scope fails to be acquired or closed but still reports as
|
||||
// alive afterward, we wait for the state to change before throwing the exception
|
||||
while ((int) STATE.getVolatile(this) == OPEN) {
|
||||
Thread.onSpinWait();
|
||||
}
|
||||
return alreadyClosed();
|
||||
}
|
||||
|
||||
/**
|
||||
* A shared resource list; this implementation has to handle add vs. add races, as well as add vs. cleanup races.
|
||||
*/
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue