Skip to content

Commit

Permalink
- ItemStackCapInitTask 边界情况异常修复 x4。
Browse files Browse the repository at this point in the history
  • Loading branch information
KasumiNova committed Oct 23, 2024
1 parent b5717e0 commit 69ce7e4
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 42 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,24 @@
import github.kasuminova.stellarcore.mixin.util.StellarItemStack;
import net.minecraft.item.ItemStack;

import java.util.ArrayDeque;
import java.util.Deque;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

@SuppressWarnings("DataFlowIssue")
public class ItemStackCapInitTask {

private static final ThreadLocal<Boolean> CAPABILITY_JOINING = ThreadLocal.withInitial(() -> false);
private static final ThreadLocal<Deque<ItemStackCapInitTask>> JOINING_STACK = ThreadLocal.withInitial(ArrayDeque::new);

private final StellarItemStack target;

private boolean asyncComponentInitialized = false;
private AtomicBoolean done;
private AtomicBoolean joining;

private Lock loadLock;
private Lock joinLock;
private ReentrantLock loadLock;
private ReentrantLock joinLock;

public ItemStackCapInitTask(final ItemStack target) {
this.target = (StellarItemStack) (Object) target;
Expand All @@ -34,15 +35,22 @@ void initAsyncComponents() {
}

public boolean tryRun() {
if (loadLock.tryLock()) {
// Current: JoinLock = locked / unlocked, LoadLock = unlocked
if (acquireLoadLock()) {
// Acquired LoadLock, start running
// Current: JoinLock = locked / unlocked, LoadLock = locked
if (!done.get()) {
run();
done.set(true);
}
loadLock.unlock();

// Unlock LoadLock
// Current: JoinLock = locked / unlocked, LoadLock = unlocked
releaseLoadLock();
return true;
} else {
return false;
}
return false;
}

public void run() {
Expand All @@ -54,48 +62,62 @@ public boolean isDone() {
}

public boolean join() {
final Deque<ItemStackCapInitTask> taskStack = JOINING_STACK.get();
// Recursion check
if (CAPABILITY_JOINING.get()) {
return true;
if (taskStack.peekFirst() == this) {
return false;
}
CAPABILITY_JOINING.set(true);

if (asyncComponentInitialized) {
acquireJoinLock();

// If another thread is currently running.
if (!tryRun()) {
releaseJoinLock();
CAPABILITY_JOINING.set(false);
return false;
taskStack.push(this);

try {
if (asyncComponentInitialized) {
// Current: JoinLock = locked
acquireJoinLock();

if (tryRun()) {
target.stellar_core$joinCapInit();

// Current: JoinLock = unlocked
releaseJoinLock();
} else {
// Current: JoinLock = unlocked
releaseJoinLock();
// If we cannot acquire LoadLock, wait for the another thread to finish load.
awaitLoadComplete();
}
} else {
run();
}
target.stellar_core$joinCapInit();

releaseJoinLock();
} else {
run();
} finally {
taskStack.pop();
}

CAPABILITY_JOINING.set(false);
return true;
}

private void acquireJoinLock() {
while (true) {
// Wait for the another thread finish
while (joining.get()) {
Thread.yield();
}

joinLock.lock();
// Check again
if (!joining.get()) {
// Acquired lock
joining.set(true);
awaitJoinComplete();

if (joinLock.tryLock()) {
// Check again.
if (!joining.get()) {
// Acquired lock.
joining.set(true);
joinLock.unlock();
break;
}
// Acquire failed, unlock and wait for the another thread, then retry.
// Join cannot be interrupted.
joinLock.unlock();
break;
}
joinLock.unlock();
}
}

private void awaitJoinComplete() {
// Wait for the another thread finish
while (joining.get()) {
Thread.yield();
}
}

Expand All @@ -106,4 +128,21 @@ private void releaseJoinLock() {
joinLock.unlock();
}

private boolean acquireLoadLock() {
return loadLock.tryLock();
}

private void releaseLoadLock() {
loadLock.unlock();
}

private void awaitLoadComplete() {
while (true) {
// Wait for the another thread finish
if (!loadLock.isLocked()) {
break;
}
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,13 @@ private void forgeInit() {

@Override
public void stellar_core$joinCapInit() {
if (this.capabilities != null) {
return;
}
if (this.stellar_core$capabilities == null) {
return;
}

this.capabilities = this.stellar_core$capabilities;
this.stellar_core$capabilities = null;
if (this.capNBT != null && this.capabilities != null) {
Expand Down Expand Up @@ -179,12 +186,9 @@ private void injectAreCapsCompatible(final ItemStack other, final CallbackInfoRe
}

try {
while (true) {
if (this.stellar_core$capInitTask.join()) {
break;
}
if (this.stellar_core$capInitTask.join()) {
this.stellar_core$capInitTask = null;
}
this.stellar_core$capInitTask = null;
} catch (NullPointerException ignored) { // If task is already done?
}
}
Expand Down

0 comments on commit 69ce7e4

Please sign in to comment.