Skip to content

Commit 48103b1

Browse files
fengxue-ISNathan Henderson
andcommitted
Support using threadStatus field in JVM native
- Update thread status changes to j.l.Thread fields so getState() API can be called without needing to halt the target thread. - Add support of virtual thread state for JDK24+ Co-authored-by: Nathan Henderson <nathan.henderson@ibm.com> Signed-off-by: Jack Lu <Jack.S.Lu@ibm.com>
1 parent f21d6b0 commit 48103b1

File tree

8 files changed

+84
-12
lines changed

8 files changed

+84
-12
lines changed

runtime/oti/VMHelpers.hpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2277,6 +2277,30 @@ class VM_VMHelpers
22772277
targetThread->privateFlags2 |= J9_PRIVATE_FLAGS2_REENTER_INTERPRETER;
22782278
indicateAsyncMessagePending(targetThread);
22792279
}
2280+
2281+
static U_32
2282+
setThreadState(J9VMThread *currentThread, U_32 state)
2283+
{
2284+
U_32 oldState = 0;
2285+
#if JAVA_SPEC_VERSION >= 19
2286+
j9object_t receiverObject = currentThread->carrierThreadObject;
2287+
if (NULL != receiverObject) {
2288+
/* Platform threads must have a non-null FieldHolder object. */
2289+
j9object_t threadHolder = J9VMJAVALANGTHREAD_HOLDER(currentThread, receiverObject);
2290+
if (NULL != threadHolder) {
2291+
oldState = J9VMJAVALANGTHREADFIELDHOLDER_THREADSTATUS(currentThread, threadHolder);
2292+
J9VMJAVALANGTHREADFIELDHOLDER_SET_THREADSTATUS(currentThread, threadHolder, state);
2293+
}
2294+
}
2295+
#else /* JAVA_SPEC_VERSION >= 19 */
2296+
j9object_t receiverObject = currentThread->threadObject;
2297+
if (NULL != receiverObject) {
2298+
oldState = J9VMJAVALANGTHREAD_THREADSTATUS(currentThread, receiverObject);
2299+
J9VMJAVALANGTHREAD_SET_THREADSTATUS(currentThread, receiverObject, state);
2300+
}
2301+
#endif /* JAVA_SPEC_VERSION >= 19 */
2302+
return oldState;
2303+
}
22802304
};
22812305

22822306
#endif /* VMHELPERS_HPP_ */

runtime/oti/j9nonbuilder.h

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5881,18 +5881,25 @@ typedef struct J9VMThread {
58815881
#endif
58825882
#define J9VMTHREAD_ALIGNMENT 0x100
58835883
#define J9VMTHREAD_RESERVED_C_STACK_FRACTION 8
5884-
#define J9VMTHREAD_STATE_RUNNING 1
5885-
#define J9VMTHREAD_STATE_BLOCKED 2
5886-
#define J9VMTHREAD_STATE_WAITING 4
5887-
#define J9VMTHREAD_STATE_SLEEPING 8
5888-
#define J9VMTHREAD_STATE_SUSPENDED 16
5889-
#define J9VMTHREAD_STATE_DEAD 32
5890-
#define J9VMTHREAD_STATE_WAITING_TIMED 64
5891-
#define J9VMTHREAD_STATE_PARKED 0x80
5884+
5885+
/* J9VMTHREAD_STATE_* bit flags are used to map vmthread state to
5886+
* java.lang.Thread.State in Thread.translateJ9VMThreadStateToThreadState().
5887+
* Any updates to these values must be reflected there.
5888+
*
5889+
* Note: 0 is reserved for uninitialized case and cannot be used.
5890+
*/
5891+
#define J9VMTHREAD_STATE_RUNNING 0x1
5892+
#define J9VMTHREAD_STATE_BLOCKED 0x2
5893+
#define J9VMTHREAD_STATE_WAITING 0x4
5894+
#define J9VMTHREAD_STATE_SLEEPING 0x8
5895+
#define J9VMTHREAD_STATE_SUSPENDED 0x10
5896+
#define J9VMTHREAD_STATE_DEAD 0x20
5897+
#define J9VMTHREAD_STATE_WAITING_TIMED 0x40
5898+
#define J9VMTHREAD_STATE_PARKED 0x80
58925899
#define J9VMTHREAD_STATE_PARKED_TIMED 0x100
5893-
#define J9VMTHREAD_STATE_INTERRUPTED 0x200
5894-
#define J9VMTHREAD_STATE_UNKNOWN 0x400
5895-
#define J9VMTHREAD_STATE_UNREADABLE 0x800
5900+
#define J9VMTHREAD_STATE_INTERRUPTED 0x200
5901+
#define J9VMTHREAD_STATE_UNKNOWN 0x400
5902+
#define J9VMTHREAD_STATE_UNREADABLE 0x800
58965903
#define J9VMSTATE_MAJOR 0xFFFF0000
58975904
#define J9VMSTATE_MINOR 0xFFFF
58985905
#define J9VMSTATE_INTERPRETER 0x10000

runtime/oti/vmconstantpool.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,7 @@ SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0-only WITH Classpath-ex
262262
<fieldref class="java/lang/Thread" name="priority" signature="I" versions="8-18"/>
263263
<fieldref class="java/lang/Thread" name="isDaemon" signature="Z" versions="8-18"/>
264264
<fieldref class="java/lang/Thread" name="group" signature="Ljava/lang/ThreadGroup;" versions="8-18"/>
265+
<fieldref class="java/lang/Thread" name="threadStatus" signature="I" versions="8-18"/>
265266

266267
<fieldref class="java/lang/VirtualThread" name="state" signature="I" versions="19-"/>
267268
<fieldref class="java/lang/VirtualThread" name="carrierThread" signature="Ljava/lang/Thread;" versions="19-"/>

runtime/vm/ObjectMonitor.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ objectMonitorEnterBlocking(J9VMThread *currentThread)
185185

186186
if (J9_EVENT_IS_HOOKED(vm->hookInterface, J9HOOK_VM_MONITOR_CONTENDED_ENTER)) {
187187
bool frameBuilt = saveBlockingEnterObject(currentThread);
188+
VM_VMHelpers::setThreadState(currentThread, J9VMTHREAD_STATE_BLOCKED);
188189
VM_VMAccess::setPublicFlags(currentThread, J9_PUBLIC_FLAGS_THREAD_BLOCKED);
189190
ALWAYS_TRIGGER_J9HOOK_VM_MONITOR_CONTENDED_ENTER(vm->hookInterface, currentThread, monitor);
190191
restoreBlockingEnterObject(currentThread, frameBuilt);
@@ -197,6 +198,7 @@ objectMonitorEnterBlocking(J9VMThread *currentThread)
197198
goto releasedAccess;
198199
}
199200
restart:
201+
VM_VMHelpers::setThreadState(currentThread, J9VMTHREAD_STATE_BLOCKED);
200202
internalReleaseVMAccessSetStatus(currentThread, J9_PUBLIC_FLAGS_THREAD_BLOCKED);
201203
releasedAccess:
202204
omrthread_monitor_enter_using_threadId(monitor, osThread);
@@ -286,6 +288,7 @@ objectMonitorEnterBlocking(J9VMThread *currentThread)
286288
J9_STORE_LOCKWORD(currentThread, lwEA, lock);
287289
goto done;
288290
}
291+
VM_VMHelpers::setThreadState(currentThread, J9VMTHREAD_STATE_BLOCKED);
289292
internalReleaseVMAccessSetStatus(currentThread, J9_PUBLIC_FLAGS_THREAD_BLOCKED);
290293
SET_IGNORE_ENTER(monitor);
291294
omrthread_monitor_wait_timed(monitor, (I_64)waitTime, 0);
@@ -297,6 +300,8 @@ objectMonitorEnterBlocking(J9VMThread *currentThread)
297300
}
298301
done:
299302
clearEventFlag(currentThread, J9_PUBLIC_FLAGS_THREAD_BLOCKED);
303+
VM_VMHelpers::setThreadState(currentThread, J9VMTHREAD_STATE_RUNNING);
304+
300305
/* Clear the SUPPRESS_CONTENDED_EXITS bit in the monitor saying that CONTENDED EXIT can be sent again */
301306
((J9ThreadMonitor*)monitor)->flags &= ~(UDATA)J9THREAD_MONITOR_SUPPRESS_CONTENDED_EXIT;
302307
VM_AtomicSupport::subtract(&monitor->pinCount, 1);

runtime/vm/callin.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -589,6 +589,15 @@ initializeAttachedThreadImpl(J9VMThread *currentThread, const char *name, j9obje
589589
currentThread->returnValue = J9_BCLOOP_RUN_METHOD;
590590
currentThread->returnValue2 = (UDATA)J9VMJAVALANGTHREAD_INIT_METHOD(vm);
591591
c_cInterpreter(currentThread);
592+
#if JAVA_SPEC_VERSION >= 19
593+
j9object_t threadHolder = J9VMJAVALANGTHREAD_HOLDER(currentThread, initializee->threadObject);
594+
if (NULL != threadHolder) {
595+
J9VMJAVALANGTHREADFIELDHOLDER_SET_THREADSTATUS(currentThread, threadHolder, J9VMTHREAD_STATE_RUNNING);
596+
}
597+
#else /* JAVA_SPEC_VERSION >= 19 */
598+
J9VMJAVALANGTHREAD_SET_THREADSTATUS(currentThread, initializee->threadObject, J9VMTHREAD_STATE_RUNNING);
599+
#endif /* JAVA_SPEC_VERSION >= 19 */
600+
/* Thread.started must be set after Thread.threadStatus to avoid timing issue in Thread.getState(). */
592601
J9VMJAVALANGTHREAD_SET_STARTED(currentThread, initializee->threadObject, JNI_TRUE);
593602
}
594603
}

runtime/vm/threadhelp.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,10 +121,17 @@ monitorWaitImpl(J9VMThread *vmThread, j9object_t object, I_64 millis, I_32 nanos
121121
#if JAVA_SPEC_VERSION >= 24
122122
J9VM_SEND_VIRTUAL_UNBLOCKER_THREAD_SIGNAL(javaVM);
123123
#endif /* JAVA_SPEC_VERSION >= 24 */
124+
/* Set j.l.Thread status to UNKNOWN since the wait can be notified/interrupted
125+
* but blocked on re-acquiring the monitor.
126+
* In this case, the thread state will have to be determined by looking at
127+
* the vmThread->publicFlags field.
128+
*/
129+
U_32 oldState = VM_VMHelpers::setThreadState(vmThread, J9VMTHREAD_STATE_UNKNOWN);
124130
internalReleaseVMAccessSetStatus(vmThread, thrstate);
125131
rc = timeCompensationHelper(vmThread,
126132
interruptable ? HELPER_TYPE_MONITOR_WAIT_INTERRUPTABLE : HELPER_TYPE_MONITOR_WAIT_TIMED, monitor, millis, nanos);
127133
internalAcquireVMAccessClearStatus(vmThread, thrstate);
134+
VM_VMHelpers::setThreadState(vmThread, oldState);
128135
J9VMTHREAD_SET_BLOCKINGENTEROBJECT(vmThread, vmThread, NULL);
129136
omrthread_monitor_unpin(monitor, vmThread->osThread);
130137
#if JAVA_SPEC_VERSION >= 24
@@ -197,9 +204,11 @@ threadSleepImpl(J9VMThread *vmThread, I_64 millis, I_32 nanos)
197204
#endif
198205
if (0 == rc) {
199206
TRIGGER_J9HOOK_VM_SLEEP(javaVM->hookInterface, vmThread, millis, nanos);
207+
U_32 oldState = VM_VMHelpers::setThreadState(vmThread, J9VMTHREAD_STATE_SLEEPING);
200208
internalReleaseVMAccessSetStatus(vmThread, J9_PUBLIC_FLAGS_THREAD_SLEEPING);
201209
rc = timeCompensationHelper(vmThread, HELPER_TYPE_THREAD_SLEEP, NULL, millis, nanos);
202210
internalAcquireVMAccessClearStatus(vmThread, J9_PUBLIC_FLAGS_THREAD_SLEEPING);
211+
VM_VMHelpers::setThreadState(vmThread, oldState);
203212
TRIGGER_J9HOOK_VM_SLEPT(javaVM->hookInterface, vmThread, millis, nanos, startTicks);
204213
}
205214

runtime/vm/threadpark.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,9 @@ threadParkImpl(J9VMThread *vmThread, BOOLEAN timeoutIsEpochRelative, I_64 timeou
9898
/* vmThread->threadObject != NULL because vmThread must be the current thread */
9999
J9VMTHREAD_SET_BLOCKINGENTEROBJECT(vmThread, vmThread, J9VMJAVALANGTHREAD_PARKBLOCKER(vmThread, vmThread->threadObject));
100100
TRIGGER_J9HOOK_VM_PARK(vm->hookInterface, vmThread, millis, nanos);
101+
U_32 oldState = J9_ARE_ANY_BITS_SET(thrstate, J9_PUBLIC_FLAGS_THREAD_TIMED)
102+
? VM_VMHelpers::setThreadState(vmThread, J9VMTHREAD_STATE_PARKED_TIMED)
103+
: VM_VMHelpers::setThreadState(vmThread, J9VMTHREAD_STATE_PARKED);
101104
internalReleaseVMAccessSetStatus(vmThread, thrstate);
102105

103106
while (1) {
@@ -116,6 +119,7 @@ threadParkImpl(J9VMThread *vmThread, BOOLEAN timeoutIsEpochRelative, I_64 timeou
116119
}
117120

118121
internalAcquireVMAccessClearStatus(vmThread, thrstate);
122+
VM_VMHelpers::setThreadState(vmThread, oldState);
119123
TRIGGER_J9HOOK_VM_UNPARKED(vm->hookInterface, vmThread, millis, nanos, startTicks, (UDATA) parkedAddress, VM_VMHelpers::currentClass(parkedClass));
120124
J9VMTHREAD_SET_BLOCKINGENTEROBJECT(vmThread, vmThread, NULL);
121125
}

runtime/vm/vmthread.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
#include "ut_j9vm.h"
4545
#include "vm_internal.h"
4646
#include "vmaccess.h"
47+
#include "VMHelpers.hpp"
4748
#include "vmhook_internal.h"
4849

4950
#include "HeapIteratorAPI.h"
@@ -459,6 +460,7 @@ void threadCleanup(J9VMThread * vmThread, UDATA forkedByVM)
459460
/* Safe to call this whether handleUncaughtException clears the exception or not */
460461
internalExceptionDescribe(vmThread);
461462
}
463+
VM_VMHelpers::setThreadState(vmThread, J9VMTHREAD_STATE_DEAD);
462464
releaseVMAccess(vmThread);
463465

464466
/* Mark this thread as dead */
@@ -1921,8 +1923,19 @@ startJavaThread(J9VMThread * currentThread, j9object_t threadObject, UDATA priva
19211923
privateFlags &= ~J9_PRIVATE_FLAGS_NO_EXCEPTION_IN_START_JAVA_THREAD;
19221924

19231925
#ifndef J9VM_IVE_RAW_BUILD /* J9VM_IVE_RAW_BUILD is not enabled by default */
1926+
#if JAVA_SPEC_VERSION >= 19
1927+
j9object_t threadHolder = J9VMJAVALANGTHREAD_HOLDER(currentThread, threadObject);
1928+
if (NULL != threadHolder) {
1929+
J9VMJAVALANGTHREADFIELDHOLDER_SET_THREADSTATUS(currentThread, threadHolder, J9VMTHREAD_STATE_RUNNING);
1930+
}
1931+
#else /* JAVA_SPEC_VERSION >= 19 */
1932+
J9VMJAVALANGTHREAD_SET_THREADSTATUS(currentThread, threadObject, J9VMTHREAD_STATE_RUNNING);
1933+
#endif /* JAVA_SPEC_VERSION >= 19 */
19241934
/* Any attempt to start a Thread makes it illegal to attempt to start it again.
1925-
* Oracle class libraries don't have the 'started' field */
1935+
* Oracle class libraries don't have the 'started' field.
1936+
*
1937+
* Thread.started must be set after Thread.threadStatus to avoid timing issue in Thread.getState().
1938+
*/
19261939
J9VMJAVALANGTHREAD_SET_STARTED(currentThread, threadObject, TRUE);
19271940
#endif /* !J9VM_IVE_RAW_BUILD */
19281941

0 commit comments

Comments
 (0)