Skip to content

Commit 03d17aa

Browse files
committed
[GR-43078] Add more actions to Isolate teardown.
PullRequest: graal/13435
2 parents e10b2cc + 9b5155f commit 03d17aa

File tree

7 files changed

+83
-29
lines changed

7 files changed

+83
-29
lines changed

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/c/function/CEntryPointActions.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,9 @@ private CEntryPointActions() {
6262
* context. If the thread has already been attached, this does not cause the operation to fail.
6363
*
6464
* @param isolate an existing isolate.
65-
* @param startedByIsolate Whether the current thread has been launched directly by the isolate,
66-
* which makes the isolate responsible for cleanups when the thread detaches.
65+
* @param startedByIsolate Whether the current thread has been launched directly by the isolate
66+
* (as opposed to being an externally started thread), which makes the isolate
67+
* responsible for cleanups when the thread detaches.
6768
* @param ensureJavaThread when set to true, the method ensures that the {@link Thread} object
6869
* for the newly attached thread is created. If the parameter is set to false, a
6970
* later call to one of the {@link PlatformThreads#ensureCurrentAssigned} methods

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/CEntryPointSnippets.java

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -471,21 +471,34 @@ public static int tearDownIsolateSnippet() {
471471
}
472472

473473
@SubstrateForeignCallTarget(stubCallingConvention = false)
474+
@Uninterruptible(reason = "All code executed after VMThreads#tearDown must be uninterruptible")
474475
private static int tearDownIsolate() {
475476
try {
476-
RuntimeSupport.executeTearDownHooks();
477-
if (!PlatformThreads.singleton().tearDown()) {
477+
if (!initiateTearDownIsolateInterruptibly()) {
478478
return CEntryPointErrors.UNSPECIFIED;
479479
}
480480

481481
VMThreads.singleton().tearDown();
482-
return Isolates.tearDownCurrent();
482+
IsolateThread finalThread = CurrentIsolate.getCurrentThread();
483+
int result = Isolates.tearDownCurrent();
484+
// release the heap memory associated with final isolate thread
485+
VMThreads.singleton().freeIsolateThread(finalThread);
486+
return result;
483487
} catch (Throwable t) {
484-
logException(t);
485-
return CEntryPointErrors.UNCAUGHT_EXCEPTION;
488+
return reportException(t);
486489
}
487490
}
488491

492+
@Uninterruptible(reason = "Used as a transition between uninterruptible and interruptible code", calleeMustBe = false)
493+
private static boolean initiateTearDownIsolateInterruptibly() {
494+
return initiateTearDownIsolateInterruptibly0();
495+
}
496+
497+
private static boolean initiateTearDownIsolateInterruptibly0() {
498+
RuntimeSupport.executeTearDownHooks();
499+
return PlatformThreads.singleton().tearDown();
500+
}
501+
489502
@Snippet(allowMissingProbabilities = true)
490503
public static int enterByIsolateSnippet(Isolate isolate) {
491504
int result;

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/TimeZoneSubstitutions.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import org.graalvm.nativeimage.ImageSingletons;
3838
import org.graalvm.nativeimage.PinnedObject;
3939
import org.graalvm.nativeimage.Platforms;
40+
import org.graalvm.nativeimage.UnmanagedMemory;
4041
import org.graalvm.nativeimage.c.type.CCharPointer;
4142
import org.graalvm.nativeimage.c.type.CTypeConversion;
4243
import org.graalvm.nativeimage.impl.InternalPlatform;
@@ -97,7 +98,10 @@ private static String getSystemTimeZoneID(String javaHome) {
9798
tzMappingsPtr = pinnedContent.addressOfArrayElement(0);
9899
}
99100
CCharPointer tzId = LibCHelper.SVM_FindJavaTZmd(tzMappingsPtr, contentLen);
100-
return CTypeConversion.toJavaString(tzId);
101+
String result = CTypeConversion.toJavaString(tzId);
102+
// SVM_FindJavaTZmd returns a newly allocated string
103+
UnmanagedMemory.free(tzId);
104+
return result;
101105
} finally {
102106
if (pinnedContent != null) {
103107
pinnedContent.close();

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmstat/PerfMemory.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,9 @@ private void addOverflowMemory(Word result) {
163163
if (overflowMemory == null) {
164164
overflowMemory = new Word[8];
165165
} else if (overflowMemory.length == overflowMemoryPos) {
166-
overflowMemory = new Word[overflowMemory.length * 2];
166+
Word[] expandedOverflowMemory = new Word[overflowMemory.length * 2];
167+
System.arraycopy(overflowMemory, 0, expandedOverflowMemory, 0, overflowMemoryPos);
168+
overflowMemory = expandedOverflowMemory;
167169
}
168170
overflowMemory[overflowMemoryPos] = result;
169171
overflowMemoryPos++;

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/PlatformThreads.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -523,7 +523,14 @@ public boolean tearDown() {
523523
return true;
524524
}
525525
/* Tell all the threads that the VM is being torn down. */
526-
return tearDownPlatformThreads();
526+
boolean result = tearDownPlatformThreads();
527+
528+
// Detach last thread data
529+
Thread thread = currentThread.get(CurrentIsolate.getCurrentThread());
530+
if (thread != null) {
531+
toTarget(thread).threadData.detach();
532+
}
533+
return result;
527534
}
528535

529536
@Uninterruptible(reason = "Thread is detaching and holds the THREAD_MUTEX.")

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMOperationControl.java

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -33,17 +33,20 @@
3333
import org.graalvm.nativeimage.IsolateThread;
3434
import org.graalvm.nativeimage.Platform;
3535
import org.graalvm.nativeimage.Platforms;
36+
import org.graalvm.nativeimage.StackValue;
37+
import org.graalvm.nativeimage.c.struct.SizeOf;
38+
import org.graalvm.word.Pointer;
3639
import org.graalvm.word.UnsignedWord;
3740
import org.graalvm.word.WordFactory;
3841

3942
import com.oracle.svm.core.NeverInline;
4043
import com.oracle.svm.core.SubstrateOptions;
4144
import com.oracle.svm.core.SubstrateOptions.ConcealedOptions;
4245
import com.oracle.svm.core.Uninterruptible;
46+
import com.oracle.svm.core.UnmanagedMemoryUtil;
4347
import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton;
4448
import com.oracle.svm.core.heap.Heap;
4549
import com.oracle.svm.core.heap.RestrictHeapAccess;
46-
import com.oracle.svm.core.heap.RestrictHeapAccess.Access;
4750
import com.oracle.svm.core.heap.VMOperationInfos;
4851
import com.oracle.svm.core.locks.VMCondition;
4952
import com.oracle.svm.core.locks.VMMutex;
@@ -135,29 +138,41 @@ public static void startVMOperationThread() {
135138
control.dedicatedVMOperationThread.waitUntilStarted();
136139
}
137140

141+
@Uninterruptible(reason = "Executed during teardown after VMThreads#threadExit")
138142
public static void shutdownAndDetachVMOperationThread() {
139143
assert useDedicatedVMOperationThread();
140144

141-
StopVMOperationThread vmOp = new StopVMOperationThread();
142-
vmOp.enqueue();
145+
int size = SizeOf.get(NativeVMOperationData.class);
146+
NativeVMOperationData data = StackValue.get(size);
147+
UnmanagedMemoryUtil.fill((Pointer) data, WordFactory.unsigned(size), (byte) 0);
148+
NativeStopVMOperationThread operation = get().stopVMOperationThreadOperation;
149+
data.setNativeVMOperation(operation);
150+
/*
151+
* Note we don't call enqueueFromNonJavaThread b/c this thread still has characteristics of
152+
* a Java thread even though VMTheads#threadExit has already been called.
153+
*/
154+
get().mainQueues.enqueueUninterruptibly(operation, data);
143155

144156
waitUntilVMOperationThreadDetached();
145157
assert get().mainQueues.isEmpty();
146158
}
147159

148-
private static class StopVMOperationThread extends JavaVMOperation {
149-
StopVMOperationThread() {
150-
super(VMOperationInfos.get(StopVMOperationThread.class, "Stop VM operation thread", VMOperation.SystemEffect.NONE));
160+
private final NativeStopVMOperationThread stopVMOperationThreadOperation = new NativeStopVMOperationThread();
161+
162+
private static class NativeStopVMOperationThread extends NativeVMOperation {
163+
NativeStopVMOperationThread() {
164+
super(VMOperationInfos.get(NativeStopVMOperationThread.class, "Stop VM operation thread", VMOperation.SystemEffect.NONE));
151165
}
152166

153167
@Override
154-
protected void operate() {
155-
VMOperationControl.get().dedicatedVMOperationThread.shutdown();
168+
@Uninterruptible(reason = "Executed during teardown after VMThreads#exit")
169+
protected void operate(NativeVMOperationData data) {
170+
VMOperationControl.get().dedicatedVMOperationThread.stopped = true;
156171
}
157172
}
158173

159-
@RestrictHeapAccess(access = Access.NO_ALLOCATION, reason = "Called during teardown")
160174
@NeverInline("Must not be inlined in a caller that has an exception handler: We only support InvokeNode and not InvokeWithExceptionNode between a CFunctionPrologueNode and CFunctionEpilogueNode.")
175+
@Uninterruptible(reason = "Executed during teardown after VMThreads#threadExit")
161176
private static void waitUntilVMOperationThreadDetached() {
162177
CFunctionPrologueNode.cFunctionPrologue(StatusSupport.STATUS_IN_NATIVE);
163178
waitUntilVMOperationThreadDetachedInNative();
@@ -433,11 +448,6 @@ public IsolateThread getIsolateThread() {
433448
public boolean isRunning() {
434449
return isolateThread.isNonNull() && !stopped;
435450
}
436-
437-
void shutdown() {
438-
VMOperation.guaranteeInProgress("must only be called from a VM operation");
439-
this.stopped = true;
440-
}
441451
}
442452

443453
private static final class WorkQueues {
@@ -468,6 +478,7 @@ private static final class WorkQueues {
468478
this.operationFinished = createCondition();
469479
}
470480

481+
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
471482
boolean isEmpty() {
472483
return nativeNonSafepointOperations.isEmpty() && nativeSafepointOperations.isEmpty() && javaNonSafepointOperations.isEmpty() && javaSafepointOperations.isEmpty();
473484
}
@@ -721,6 +732,7 @@ protected abstract static class AllocationFreeQueue<T> {
721732
this.name = name;
722733
}
723734

735+
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
724736
abstract boolean isEmpty();
725737

726738
abstract void push(T element);
@@ -745,6 +757,7 @@ protected abstract static class JavaAllocationFreeQueue<T extends JavaAllocation
745757
}
746758

747759
@Override
760+
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
748761
public boolean isEmpty() {
749762
return head == null;
750763
}
@@ -815,6 +828,7 @@ protected static class NativeVMOperationQueue extends AllocationFreeQueue<Native
815828
}
816829

817830
@Override
831+
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
818832
public boolean isEmpty() {
819833
return head.isNull();
820834
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMThreads.java

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,11 @@ public static VMThreads singleton() {
153153
* used for the stack overflow check.
154154
*/
155155
public static final FastThreadLocalWord<UnsignedWord> StackEnd = FastThreadLocalFactory.createWord("VMThreads.StackEnd");
156+
/**
157+
* Tracks whether this thread was started by the current isolate or if it was an externally
158+
* started thread which was attached to the isolate. This distinction determines the teardown
159+
* process for the thread.
160+
*/
156161
private static final FastThreadLocalBytes<Pointer> StartedByCurrentIsolate = FastThreadLocalFactory.createBytes(() -> 1, "VMThreads.StartedByCurrentIsolate");
157162

158163
private static final int STATE_UNINITIALIZED = 1;
@@ -448,12 +453,20 @@ private static void removeFromThreadList(IsolateThread thread) {
448453
}
449454
}
450455

456+
@Uninterruptible(reason = "Only uninterruptible code may be executed after VMThreads#threadExit.")
451457
public void tearDown() {
452458
ThreadingSupportImpl.pauseRecurringCallback("Execution of arbitrary code is prohibited during the last teardown steps.");
459+
460+
IsolateThread curThread = CurrentIsolate.getCurrentThread();
461+
VMThreads.threadExit(curThread);
462+
/* Only uninterruptible code may be executed from now on. */
463+
PlatformThreads.afterThreadExit(curThread);
464+
453465
if (VMOperationControl.useDedicatedVMOperationThread()) {
454466
VMOperationControl.shutdownAndDetachVMOperationThread();
455467
}
456-
// At this point, it is guaranteed that all other threads were detached.
468+
469+
/* At this point, it is guaranteed that all other threads were detached. */
457470
IsolateListenerSupport.singleton().onIsolateTeardown();
458471
waitUntilLastOsThreadExited();
459472
}
@@ -486,7 +499,7 @@ private static void threadExit(IsolateThread thread) {
486499
* following tear-down.
487500
*/
488501
public static void detachAllThreadsExceptCurrentWithoutCleanupForTearDown() {
489-
DetachAllThreadsExceptCurrentOperation vmOp = new DetachAllThreadsExceptCurrentOperation();
502+
DetachAllExternallyStartedThreadsExceptCurrentOperation vmOp = new DetachAllExternallyStartedThreadsExceptCurrentOperation();
490503
vmOp.enqueue();
491504
}
492505

@@ -622,9 +635,9 @@ public static boolean printLocationInfo(Log log, UnsignedWord value, boolean all
622635
return false;
623636
}
624637

625-
private static class DetachAllThreadsExceptCurrentOperation extends JavaVMOperation {
626-
DetachAllThreadsExceptCurrentOperation() {
627-
super(VMOperationInfos.get(DetachAllThreadsExceptCurrentOperation.class, "Detach all threads except current", SystemEffect.SAFEPOINT));
638+
private static class DetachAllExternallyStartedThreadsExceptCurrentOperation extends JavaVMOperation {
639+
DetachAllExternallyStartedThreadsExceptCurrentOperation() {
640+
super(VMOperationInfos.get(DetachAllExternallyStartedThreadsExceptCurrentOperation.class, "Detach all externally started threads except current", SystemEffect.SAFEPOINT));
628641
}
629642

630643
@Override

0 commit comments

Comments
 (0)