Skip to content

Commit a256c2a

Browse files
[GR-53685] Implement JVM_GetThreadInterruptEvent
1 parent 5e40f5a commit a256c2a

File tree

10 files changed

+121
-22
lines changed

10 files changed

+121
-22
lines changed

espresso/src/com.oracle.truffle.espresso.mokapot/include/mokapot.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,13 @@ typedef uint64_t julong;
380380
V(JVM_IsStaticallyLinked) \
381381
V(JVM_CreateThreadSnapshot)
382382

383+
#if defined(_WIN32)
384+
#define PD_VM_METHOD_LIST(V) \
385+
V(JVM_GetThreadInterruptEvent)
386+
#else
387+
#define PD_VM_METHOD_LIST(V)
388+
#endif
389+
383390
#ifdef __cplusplus
384391
extern "C" {
385392
#endif
@@ -398,6 +405,8 @@ JNIEXPORT OS_DL_HANDLE JNICALL mokapotGetProcessHandle(void);
398405

399406
JNIEXPORT const char* JNICALL getPackageAt(const char* const* packages, int at);
400407

408+
MokapotEnv* getEnv(void);
409+
401410
#ifdef __cplusplus
402411
} // extern "C"
403412
#endif
@@ -1018,6 +1027,8 @@ jobject (*JVM_TakeVirtualThreadListToUnblock)(JNIEnv* env, jclass ignored);
10181027
jboolean(*JVM_IsStaticallyLinked)(void);
10191028

10201029
jobject(*JVM_CreateThreadSnapshot)(JNIEnv* env, jobject thread);
1030+
1031+
void * (*JVM_GetThreadInterruptEvent)(void);
10211032
};
10221033

10231034
struct MokapotEnv_ {

espresso/src/com.oracle.truffle.espresso.mokapot/src/mokapot.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ JNIEXPORT MokapotEnv* JNICALL initializeMokapotContext(JNIEnv* env, void* (*fetc
103103
#define INIT__(name) \
104104
functions->name = fetch_by_name(#name, (void*)&name);
105105
VM_METHOD_LIST(INIT__)
106+
PD_VM_METHOD_LIST(INIT__)
106107
#undef INIT_
107108

108109
// Persist Moka env in TLS.

espresso/src/com.oracle.truffle.espresso.mokapot/src/mokapot_windows.c

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,27 @@
2525
#include "jvm_windows.h"
2626
#include "mokapot.h"
2727

28-
JNIEXPORT void * JNICALL JVM_GetThreadInterruptEvent(void) {
29-
UNIMPLEMENTED(JVM_GetThreadInterruptEvent);
30-
return NULL;
28+
JNIEXPORT void JNICALL mokapotSetThreadInterrupted(void* interrupt_event_ptr, jboolean interrupted) {
29+
HANDLE interrupt_event = (HANDLE) interrupt_event_ptr;
30+
if (interrupted) {
31+
SetEvent(interrupt_event);
32+
} else {
33+
ResetEvent(interrupt_event);
34+
}
35+
}
36+
37+
JNIEXPORT void* JNICALL mokapotCreateInterruptedEvent(void) {
38+
return CreateEvent(NULL, TRUE, FALSE, NULL);
39+
}
40+
41+
JNIEXPORT void JNICALL mokapotDestroyInterruptedEvent(void* interrupt_event_ptr) {
42+
HANDLE interrupt_event = (HANDLE) interrupt_event_ptr;
43+
CloseHandle(interrupt_event);
44+
}
45+
46+
JNIEXPORT void* JNICALL JVM_GetThreadInterruptEvent(void) {
47+
IMPLEMENTED(JVM_GetThreadInterruptEvent);
48+
return (*getEnv())->JVM_GetThreadInterruptEvent();
3149
}
3250

3351
#endif /* defined(_WIN32) */

espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/EspressoLanguage.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -801,6 +801,11 @@ public int getMaxStackTraceDepth() {
801801
return maxStackTraceDepth;
802802
}
803803

804+
@SuppressWarnings("static-method")
805+
public boolean needsInterruptedEvent() {
806+
return OS.getCurrent() == OS.Windows;
807+
}
808+
804809
public final class DisableSingleStepping implements AutoCloseable {
805810

806811
private final boolean steppingDisabled;

espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/EspressoSymbols.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1077,6 +1077,7 @@ public static class Names {
10771077
public static final Symbol<Name> HIDDEN_ESPRESSO_MANAGED = SYMBOLS.putName("0HIDDEN_ESPRESSO_MANAGED");
10781078
public static final Symbol<Name> HIDDEN_TO_NATIVE_LOCK = SYMBOLS.putName("0HIDDEN_TO_NATIVE_LOCK");
10791079
public static final Symbol<Name> HIDDEN_INTERRUPTED = SYMBOLS.putName("0HIDDEN_INTERRUPTED");
1080+
public static final Symbol<Name> HIDDEN_INTERRUPTED_EVENT = SYMBOLS.putName("0HIDDEN_INTERRUPTED_EVENT");
10801081
public static final Symbol<Name> HIDDEN_THREAD_PENDING_MONITOR = SYMBOLS.putName("0HIDDEN_THREAD_PENDING_MONITOR");
10811082
public static final Symbol<Name> HIDDEN_THREAD_WAITING_MONITOR = SYMBOLS.putName("0HIDDEN_THREAD_WAITING_MONITOR");
10821083
public static final Symbol<Name> HIDDEN_THREAD_BLOCKED_COUNT = SYMBOLS.putName("0HIDDEN_THREAD_BLOCKED_COUNT");

espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/LinkedKlassFieldLayout.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,7 @@ private static class HiddenField {
217217
}),
218218
entry(Types.java_lang_Thread, new HiddenField[]{
219219
new HiddenField(Names.HIDDEN_INTERRUPTED, Types._boolean, VersionRange.lower(13), NO_ADDITIONAL_FLAGS),
220+
new HiddenField(Names.HIDDEN_INTERRUPTED_EVENT, Types.java_lang_Object, EspressoLanguage::needsInterruptedEvent, NO_ADDITIONAL_FLAGS),
220221
new HiddenField(Names.HIDDEN_HOST_THREAD),
221222
new HiddenField(Names.HIDDEN_ESPRESSO_MANAGED, Types._boolean, VersionRange.ALL, NO_ADDITIONAL_FLAGS),
222223
new HiddenField(Names.HIDDEN_TO_NATIVE_LOCK, Types.java_lang_Object, VersionRange.ALL, Constants.ACC_FINAL),

espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/Meta.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,11 @@ public Meta(EspressoContext context) {
543543
} else {
544544
HIDDEN_THREAD_SCOPED_VALUE_CACHE = null;
545545
}
546+
if (getLanguage().needsInterruptedEvent()) {
547+
HIDDEN_INTERRUPTED_EVENT = java_lang_Thread.requireHiddenField(Names.HIDDEN_INTERRUPTED_EVENT);
548+
} else {
549+
HIDDEN_INTERRUPTED_EVENT = null;
550+
}
546551

547552
if (context.getEspressoEnv().EnableManagement) {
548553
HIDDEN_THREAD_PENDING_MONITOR = java_lang_Thread.requireHiddenField(Names.HIDDEN_THREAD_PENDING_MONITOR);
@@ -1707,6 +1712,7 @@ private DiffVersionLoadHelper diff() {
17071712
public final Field HIDDEN_ESPRESSO_MANAGED;
17081713
public final Field HIDDEN_TO_NATIVE_LOCK;
17091714
public final Field HIDDEN_INTERRUPTED;
1715+
public final Field HIDDEN_INTERRUPTED_EVENT;
17101716
public final Field HIDDEN_THREAD_UNPARK_SIGNALS;
17111717
public final Field HIDDEN_THREAD_PARK_LOCK;
17121718
public final Field HIDDEN_DEPRECATION_SUPPORT;

espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/standard/Target_java_lang_Thread.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ public static void interrupt0(@JavaType(Object.class) StaticObject self,
272272

273273
@Substitution
274274
public static void clearInterruptEvent(@Inject EspressoContext context) {
275-
context.getThreadAccess().clearInterruptEvent();
275+
context.getThreadAccess().clearInterruptEvent(context.getCurrentPlatformThread());
276276
}
277277

278278
@TruffleBoundary

espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/threads/ThreadAccess.java

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import com.oracle.truffle.espresso.nodes.EspressoNode;
4242
import com.oracle.truffle.espresso.runtime.EspressoExitException;
4343
import com.oracle.truffle.espresso.runtime.staticobject.StaticObject;
44+
import com.oracle.truffle.espresso.vm.VM;
4445

4546
/**
4647
* Provides bridges to guest world thread implementation.
@@ -361,13 +362,11 @@ public boolean isInterrupted(StaticObject guest, boolean clear) {
361362
return false;
362363
}
363364
boolean isInterrupted = meta.HIDDEN_INTERRUPTED.getBoolean(guest, true);
364-
if (clear) {
365+
if (clear && isInterrupted) {
365366
Thread host = getHost(guest);
366367
EspressoError.guarantee(host == Thread.currentThread(), "Thread#isInterrupted(true) is only supported for the current thread.");
367-
if (host != null && host.isInterrupted()) {
368-
Thread.interrupted();
369-
}
370-
clearInterruptStatus(guest);
368+
clearInterruptEvent(guest);
369+
meta.HIDDEN_INTERRUPTED.setBoolean(guest, false, true);
371370
}
372371
return isInterrupted;
373372
}
@@ -390,25 +389,22 @@ public void interrupt(StaticObject guest) {
390389
}
391390

392391
private void doInterrupt(StaticObject guest) {
393-
if (getContext().getJavaVersion().java13OrEarlier() && isAlive(guest)) {
392+
if (getJavaVersion().java13OrEarlier() && isAlive(guest)) {
394393
// In JDK 13+, the interrupted status is set in java code.
395394
meta.HIDDEN_INTERRUPTED.setBoolean(guest, true, true);
396395
}
396+
VM vm = getVM();
397+
if (vm.needsThreadInterruptedNotification() && isAlive(guest)) {
398+
vm.notifyThreadInterrupted(guest, true);
399+
}
397400
}
398401

399-
/**
400-
* Implementation of {@code Thread.clearInterruptEvent} (JDK 13+).
401-
*/
402-
public void clearInterruptEvent() {
403-
assert !getContext().getJavaVersion().java13OrEarlier();
402+
public void clearInterruptEvent(StaticObject guest) {
404403
Thread.interrupted();
405-
}
406-
407-
/**
408-
* Sets the interrupted field of the given thread to {@code false}.
409-
*/
410-
public void clearInterruptStatus(StaticObject guest) {
411-
meta.HIDDEN_INTERRUPTED.setBoolean(guest, false, true);
404+
VM vm = getVM();
405+
if (vm.needsThreadInterruptedNotification()) {
406+
vm.notifyThreadInterrupted(guest, false);
407+
}
412408
}
413409

414410
/**
@@ -474,6 +470,9 @@ public void initializeHiddenFields(StaticObject guest, Thread host, boolean isMa
474470
meta.HIDDEN_ESPRESSO_MANAGED.setBoolean(guest, isManaged);
475471
meta.HIDDEN_THREAD_PARK_LOCK.setHiddenObject(guest, EspressoLock.create(getContext().getBlockingSupport()));
476472
meta.HIDDEN_TO_NATIVE_LOCK.setHiddenObject(guest, EspressoLock.create(getContext().getBlockingSupport()));
473+
if (meta.HIDDEN_INTERRUPTED_EVENT != null) {
474+
meta.HIDDEN_INTERRUPTED_EVENT.setHiddenObject(guest, getVM().createInterruptedEvent());
475+
}
477476
}
478477

479478
// endregion thread control

espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/VM.java

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,9 @@ public final class VM extends NativeEnv {
196196

197197
private final @Pointer TruffleObject getJavaVM;
198198
private final @Pointer TruffleObject mokapotAttachThread;
199+
private final @Pointer TruffleObject mokapotSetThreadInterrupted;
200+
private final @Pointer TruffleObject mokapotCreateInterruptedEvent;
201+
private final @Pointer TruffleObject mokapotDestroyInterruptedEvent;
199202
private final @Pointer TruffleObject mokapotCaptureState;
200203
private final @Pointer TruffleObject getPackageAt;
201204

@@ -234,6 +237,22 @@ public void attachThread(Thread hostThread) {
234237
}
235238
}
236239

240+
public boolean needsThreadInterruptedNotification() {
241+
return mokapotSetThreadInterrupted != null;
242+
}
243+
244+
@TruffleBoundary
245+
public void notifyThreadInterrupted(StaticObject guestThread, boolean interrupted) {
246+
assert needsThreadInterruptedNotification();
247+
try {
248+
TruffleObject event = (TruffleObject) getMeta().HIDDEN_INTERRUPTED_EVENT.getHiddenObject(guestThread);
249+
assert event != null;
250+
getUncached().execute(mokapotSetThreadInterrupted, event, interrupted);
251+
} catch (UnsupportedTypeException | ArityException | UnsupportedMessageException e) {
252+
throw EspressoError.shouldNotReachHere("setThreadInterrupted failed", e);
253+
}
254+
}
255+
237256
public Management getManagement() {
238257
return management;
239258
}
@@ -242,6 +261,16 @@ public Management getManagement() {
242261
return javaLibrary;
243262
}
244263

264+
public Object createInterruptedEvent() {
265+
try {
266+
TruffleObject ptr = (TruffleObject) getUncached().execute(mokapotCreateInterruptedEvent);
267+
assert getUncached().isPointer(ptr);
268+
return ptr;
269+
} catch (UnsupportedTypeException | ArityException | UnsupportedMessageException e) {
270+
throw EspressoError.shouldNotReachHere("mokapotAttachThread failed", e);
271+
}
272+
}
273+
245274
public static final class GlobalFrameIDs {
246275
private static final AtomicLong id = new AtomicLong();
247276

@@ -329,6 +358,18 @@ private VM(JniEnv jniEnv) {
329358
"mokapotAttachThread",
330359
NativeSignature.create(NativeType.VOID, NativeType.POINTER));
331360

361+
mokapotSetThreadInterrupted = getNativeAccess().lookupAndBindSymbol(mokapotLibrary,
362+
"mokapotSetThreadInterrupted",
363+
NativeSignature.create(NativeType.VOID, NativeType.POINTER, NativeType.BOOLEAN), false, true);
364+
365+
mokapotCreateInterruptedEvent = getNativeAccess().lookupAndBindSymbol(mokapotLibrary,
366+
"mokapotCreateInterruptedEvent",
367+
NativeSignature.create(NativeType.POINTER), false, true);
368+
369+
mokapotDestroyInterruptedEvent = getNativeAccess().lookupAndBindSymbol(mokapotLibrary,
370+
"mokapotDestroyInterruptedEvent",
371+
NativeSignature.create(NativeType.VOID, NativeType.POINTER), false, true);
372+
332373
mokapotCaptureState = getNativeAccess().lookupAndBindSymbol(mokapotLibrary,
333374
"mokapotCaptureState",
334375
NativeSignature.create(NativeType.VOID, NativeType.POINTER, NativeType.INT));
@@ -1579,6 +1620,16 @@ public Method visitFrame(FrameInstance frameInstance) {
15791620
} finally {
15801621
context.unregisterThread(currentThread);
15811622
}
1623+
if (mokapotDestroyInterruptedEvent != null) {
1624+
TruffleObject event = (TruffleObject) getMeta().HIDDEN_INTERRUPTED_EVENT.getHiddenObject(currentThread);
1625+
if (event != null) {
1626+
try {
1627+
getUncached().execute(mokapotDestroyInterruptedEvent, event);
1628+
} catch (UnsupportedTypeException | ArityException | UnsupportedMessageException e) {
1629+
throw EspressoError.shouldNotReachHere("mokapotDetachThread failed", e);
1630+
}
1631+
}
1632+
}
15821633

15831634
return JNI_OK;
15841635
}
@@ -3525,6 +3576,12 @@ public int JNI_GetCreatedJavaVMs(@Pointer TruffleObject vmBufPtr, int bufLen, @P
35253576
throw meta.throwException(meta.java_lang_UnsupportedOperationException);
35263577
}
35273578

3579+
@VmImpl
3580+
public static @Pointer TruffleObject JVM_GetThreadInterruptEvent(@Inject EspressoContext context, @Inject Meta meta) {
3581+
StaticObject currentThread = context.getCurrentPlatformThread();
3582+
return (TruffleObject) meta.HIDDEN_INTERRUPTED_EVENT.getHiddenObject(currentThread);
3583+
}
3584+
35283585
// endregion threads
35293586

35303587
// region Management

0 commit comments

Comments
 (0)