Skip to content

Commit 1ee805a

Browse files
authored
Merge pull request #21043 from fengxue-IS/threadstate2
Support using threadStatus field in JVM native
2 parents a898441 + 0a58be1 commit 1ee805a

File tree

9 files changed

+139
-35
lines changed

9 files changed

+139
-35
lines changed

jcl/src/java.base/share/classes/java/lang/Thread.java

Lines changed: 55 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -62,26 +62,26 @@ public class Thread implements Runnable {
6262
/**
6363
* The maximum priority value for a Thread.
6464
*/
65-
public final static int MAX_PRIORITY = 10; // Maximum allowed priority for a thread
65+
public final static int MAX_PRIORITY = 10; // Maximum allowed priority for a thread
6666
/**
6767
* The minimum priority value for a Thread.
6868
*/
69-
public final static int MIN_PRIORITY = 1; // Minimum allowed priority for a thread
69+
public final static int MIN_PRIORITY = 1; // Minimum allowed priority for a thread
7070
/**
7171
* The default priority value for a Thread.
7272
*/
73-
public final static int NORM_PRIORITY = 5; // Normal priority for a thread
73+
public final static int NORM_PRIORITY = 5; // Normal priority for a thread
7474
/*[PR 97331] Initial thread name should be Thread-0 */
75-
private static int createCount; // Used internally to compute Thread names that comply with the Java specification
75+
private static int createCount; // Used internally to compute Thread names that comply with the Java specification
7676
/*[PR 122459] LIR646 - Remove use of generic object for synchronization */
7777
private static final class TidLock {
7878
TidLock() {}
7979
}
8080
private static Object tidLock = new TidLock();
8181
private static long tidCount = 1;
82-
private static final int NANOS_MAX = 999999; // Max value for nanoseconds parameter to sleep and join
83-
private static final int INITIAL_LOCAL_STORAGE_CAPACITY = 5; // Initial number of local storages when the Thread is created
84-
static final long NO_REF = 0; // Symbolic constant, no threadRef assigned or already cleaned up
82+
private static final int NANOS_MAX = 999999; // Max value for nanoseconds parameter to sleep and join
83+
private static final int INITIAL_LOCAL_STORAGE_CAPACITY = 5; // Initial number of local storages when the Thread is created
84+
static final long NO_REF = 0; // Symbolic constant, no threadRef assigned or already cleaned up
8585

8686
// Instance variables
8787
private volatile long threadRef; // Used by the VM
@@ -94,14 +94,15 @@ private static final class TidLock {
9494
*/
9595
private volatile boolean deadInterrupt;
9696
/*[ENDIF] JAVA_SPEC_VERSION >= 14 */
97-
private volatile boolean started; // If !isAlive(), tells if Thread died already or hasn't even started
98-
private String name; // The Thread's name
99-
private int priority = NORM_PRIORITY; // The Thread's current priority
100-
private boolean isDaemon; // Tells if the Thread is a daemon thread or not.
101-
102-
ThreadGroup group; // A Thread belongs to exactly one ThreadGroup
103-
private Runnable runnable; // Target (optional) runnable object
104-
private boolean stopCalled = false; // Used by the VM
97+
private volatile boolean started; // If !isAlive(), tells if Thread died already or hasn't even started
98+
private String name; // The Thread's name
99+
private int priority = NORM_PRIORITY; // The Thread's current priority
100+
private boolean isDaemon; // Tells if the Thread is a daemon thread or not.
101+
private volatile int threadStatus; // The Thread's state.
102+
103+
ThreadGroup group; // A Thread belongs to exactly one ThreadGroup
104+
private Runnable runnable; // Target (optional) runnable object
105+
private boolean stopCalled = false; // Used by the VM
105106
/*[PR 1FENTZW]*/
106107
private ClassLoader contextClassLoader; // Used to find classes and resources in this Thread
107108
ThreadLocal.ThreadLocalMap threadLocals;
@@ -124,8 +125,8 @@ private static final class ThreadLock {}
124125

125126
volatile Object parkBlocker;
126127

127-
private static ThreadGroup systemThreadGroup; // Assigned by the vm
128-
private static ThreadGroup mainGroup; // ThreadGroup where the "main" Thread starts
128+
private static ThreadGroup systemThreadGroup; // Assigned by the vm
129+
private static ThreadGroup mainGroup; // ThreadGroup where the "main" Thread starts
129130

130131
/*[PR 113602] Thread fields should be volatile */
131132
private volatile static UncaughtExceptionHandler defaultExceptionHandler;
@@ -1488,6 +1489,39 @@ public static enum State {
14881489
*/
14891490
TERMINATED }
14901491

1492+
/**
1493+
* Returns the translation from a J9VMThread state to a Thread::State.
1494+
*
1495+
* @param status thread status value set by VM.
1496+
* @return this thread's state.
1497+
*
1498+
* @see State
1499+
*/
1500+
private State translateJ9VMThreadStateToThreadState(int status) {
1501+
switch (status) {
1502+
case 0x1: // J9VMTHREAD_STATE_RUNNING
1503+
return State.RUNNABLE;
1504+
case 0x2: // J9VMTHREAD_STATE_BLOCKED
1505+
return State.BLOCKED;
1506+
case 0x4: // J9VMTHREAD_STATE_WAITING
1507+
case 0x80: // J9VMTHREAD_STATE_PARKED
1508+
return State.WAITING;
1509+
case 0x8: // J9VMTHREAD_STATE_SLEEPING
1510+
case 0x40: // J9VMTHREAD_STATE_WAITING_TIMED
1511+
case 0x100: // J9VMTHREAD_STATE_PARKED_TIMED
1512+
return State.TIMED_WAITING;
1513+
case 0x20: // J9VMTHREAD_STATE_DEAD
1514+
return State.TERMINATED;
1515+
default:
1516+
synchronized (lock) {
1517+
if (threadRef == NO_REF) {
1518+
return State.TERMINATED;
1519+
}
1520+
return State.values()[getStateImpl(threadRef)];
1521+
}
1522+
}
1523+
}
1524+
14911525
/**
14921526
* Returns the current Thread state.
14931527
*
@@ -1496,15 +1530,13 @@ public static enum State {
14961530
* @see State
14971531
*/
14981532
public State getState() {
1499-
synchronized(lock) {
1533+
if (started) {
15001534
if (threadRef == NO_REF) {
1501-
if (isDead()) {
1502-
return State.TERMINATED;
1503-
}
1504-
return State.NEW;
1535+
return State.TERMINATED;
15051536
}
1506-
return State.values()[getStateImpl(threadRef)];
1537+
return translateJ9VMThreadStateToThreadState(threadStatus);
15071538
}
1539+
return State.NEW;
15081540
}
15091541

15101542
private native int getStateImpl(long threadRef);

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 java.lang.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)