diff --git a/jcl/src/java.base/share/classes/java/lang/Thread.java b/jcl/src/java.base/share/classes/java/lang/Thread.java
index d54a3c0eb0c..917666c54f2 100644
--- a/jcl/src/java.base/share/classes/java/lang/Thread.java
+++ b/jcl/src/java.base/share/classes/java/lang/Thread.java
@@ -94,14 +94,15 @@ private static final class TidLock {
*/
private volatile boolean deadInterrupt;
/*[ENDIF] JAVA_SPEC_VERSION >= 14 */
- private volatile boolean started; // If !isAlive(), tells if Thread died already or hasn't even started
- private String name; // The Thread's name
- private int priority = NORM_PRIORITY; // The Thread's current priority
+ private volatile boolean started; // If !isAlive(), tells if Thread died already or hasn't even started
+ private String name; // The Thread's name
+ private int priority = NORM_PRIORITY; // The Thread's current priority
private boolean isDaemon; // Tells if the Thread is a daemon thread or not.
+ private volatile int threadStatus; // The Thread's state.
- ThreadGroup group; // A Thread belongs to exactly one ThreadGroup
+ ThreadGroup group; // A Thread belongs to exactly one ThreadGroup
private Runnable runnable; // Target (optional) runnable object
- private boolean stopCalled = false; // Used by the VM
+ private boolean stopCalled = false; // Used by the VM
/*[PR 1FENTZW]*/
private ClassLoader contextClassLoader; // Used to find classes and resources in this Thread
ThreadLocal.ThreadLocalMap threadLocals;
@@ -1488,6 +1489,39 @@ public static enum State {
*/
TERMINATED }
+/**
+ * Returns the translation from a J9VMThread state to a Thread::State.
+ *
+ * @param status thread status value set by VM.
+ * @return this thread's state.
+ *
+ * @see State
+ */
+private State translateJ9VMThreadStateToThreadState(int status) {
+ switch (status) {
+ case 1: // J9VMTHREAD_STATE_RUNNING
+ return State.RUNNABLE;
+ case 2: // J9VMTHREAD_STATE_BLOCKED
+ return State.BLOCKED;
+ case 4: // J9VMTHREAD_STATE_WAITING
+ case 0x80: // J9VMTHREAD_STATE_PARKED
+ return State.WAITING;
+ case 8: // J9VMTHREAD_STATE_SLEEPING
+ case 64: // J9VMTHREAD_STATE_WAITING_TIMED
+ case 0x100: // J9VMTHREAD_STATE_PARKED_TIMED
+ return State.TIMED_WAITING;
+ case 32: // J9VMTHREAD_STATE_DEAD
+ return State.TERMINATED;
+ default:
+ synchronized (lock) {
+ if (threadRef == NO_REF) {
+ return State.TERMINATED;
+ }
+ return State.values()[getStateImpl(threadRef)];
+ }
+ }
+}
+
/**
* Returns the current Thread state.
*
@@ -1496,15 +1530,13 @@ public static enum State {
* @see State
*/
public State getState() {
- synchronized(lock) {
+ if (started) {
if (threadRef == NO_REF) {
- if (isDead()) {
- return State.TERMINATED;
- }
- return State.NEW;
+ return State.TERMINATED;
}
- return State.values()[getStateImpl(threadRef)];
+ return translateJ9VMThreadStateToThreadState(threadStatus);
}
+ return State.NEW;
}
private native int getStateImpl(long threadRef);
diff --git a/runtime/oti/VMHelpers.hpp b/runtime/oti/VMHelpers.hpp
index c3cab71cd0f..19abf008370 100644
--- a/runtime/oti/VMHelpers.hpp
+++ b/runtime/oti/VMHelpers.hpp
@@ -2275,6 +2275,31 @@ class VM_VMHelpers
targetThread->privateFlags2 |= J9_PRIVATE_FLAGS2_REENTER_INTERPRETER;
indicateAsyncMessagePending(targetThread);
}
+
+
+ static U_64
+ setThreadState(J9VMThread *currentThread, U_64 state)
+ {
+ U_64 oldState = 0;
+#if JAVA_SPEC_VERSION >= 19
+ j9object_t receiverObject = currentThread->carrierThreadObject;
+ if (NULL != receiverObject) {
+ /* Platform threads must have a non-null FieldHolder object. */
+ j9object_t threadHolder = J9VMJAVALANGTHREAD_HOLDER(currentThread, receiverObject);
+ if (NULL != threadHolder) {
+ oldState = J9VMJAVALANGTHREADFIELDHOLDER_THREADSTATUS(currentThread, threadHolder);
+ J9VMJAVALANGTHREADFIELDHOLDER_SET_THREADSTATUS(currentThread, threadHolder, state);
+ }
+ }
+#else /* JAVA_SPEC_VERSION >= 19 */
+ j9object_t receiverObject = currentThread->threadObject;
+ if (NULL != receiverObject) {
+ oldState = J9VMJAVALANGTHREAD_THREADSTATUS(currentThread, receiverObject);
+ J9VMJAVALANGTHREAD_SET_THREADSTATUS(currentThread, receiverObject, state);
+ }
+#endif /* JAVA_SPEC_VERSION >= 19 */
+ return oldState;
+ }
};
#endif /* VMHELPERS_HPP_ */
diff --git a/runtime/oti/vmconstantpool.xml b/runtime/oti/vmconstantpool.xml
index a269e864cb6..dec795af9e2 100644
--- a/runtime/oti/vmconstantpool.xml
+++ b/runtime/oti/vmconstantpool.xml
@@ -260,6 +260,7 @@ SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0-only WITH Classpath-ex
+
diff --git a/runtime/vm/ObjectMonitor.cpp b/runtime/vm/ObjectMonitor.cpp
index 2e903c12850..afc64ec3840 100644
--- a/runtime/vm/ObjectMonitor.cpp
+++ b/runtime/vm/ObjectMonitor.cpp
@@ -173,6 +173,8 @@ objectMonitorEnterBlocking(J9VMThread *currentThread)
IDATA waitTime = 1;
if (J9_EVENT_IS_HOOKED(vm->hookInterface, J9HOOK_VM_MONITOR_CONTENDED_ENTER)) {
bool frameBuilt = saveBlockingEnterObject(currentThread);
+ /* Set j.l.Thread status to BLOCKED. */
+ VM_VMHelpers::setThreadState(currentThread, J9VMTHREAD_STATE_BLOCKED);
VM_VMAccess::setPublicFlags(currentThread, J9_PUBLIC_FLAGS_THREAD_BLOCKED);
ALWAYS_TRIGGER_J9HOOK_VM_MONITOR_CONTENDED_ENTER(vm->hookInterface, currentThread, monitor);
restoreBlockingEnterObject(currentThread, frameBuilt);
@@ -185,6 +187,8 @@ objectMonitorEnterBlocking(J9VMThread *currentThread)
goto releasedAccess;
}
restart:
+ /* Set j.l.Thread status to BLOCKED. */
+ VM_VMHelpers::setThreadState(currentThread, J9VMTHREAD_STATE_BLOCKED);
internalReleaseVMAccessSetStatus(currentThread, J9_PUBLIC_FLAGS_THREAD_BLOCKED);
releasedAccess:
omrthread_monitor_enter_using_threadId(monitor, osThread);
@@ -285,6 +289,9 @@ objectMonitorEnterBlocking(J9VMThread *currentThread)
}
done:
clearEventFlag(currentThread, J9_PUBLIC_FLAGS_THREAD_BLOCKED);
+ /* Set j.l.Thread status to RUNNING state. */
+ VM_VMHelpers::setThreadState(currentThread, J9VMTHREAD_STATE_RUNNING);
+
/* Clear the SUPPRESS_CONTENDED_EXITS bit in the monitor saying that CONTENDED EXIT can be sent again */
((J9ThreadMonitor*)monitor)->flags &= ~(UDATA)J9THREAD_MONITOR_SUPPRESS_CONTENDED_EXIT;
VM_AtomicSupport::subtract(&monitor->pinCount, 1);
diff --git a/runtime/vm/callin.cpp b/runtime/vm/callin.cpp
index f466ebad324..08c402203fc 100644
--- a/runtime/vm/callin.cpp
+++ b/runtime/vm/callin.cpp
@@ -590,6 +590,14 @@ initializeAttachedThreadImpl(J9VMThread *currentThread, const char *name, j9obje
currentThread->returnValue2 = (UDATA)J9VMJAVALANGTHREAD_INIT_METHOD(vm);
c_cInterpreter(currentThread);
J9VMJAVALANGTHREAD_SET_STARTED(currentThread, initializee->threadObject, JNI_TRUE);
+#if JAVA_SPEC_VERSION >= 19
+ j9object_t threadHolder = J9VMJAVALANGTHREAD_HOLDER(currentThread, initializee->threadObject);
+ if (NULL != threadHolder) {
+ J9VMJAVALANGTHREADFIELDHOLDER_SET_THREADSTATUS(currentThread, threadHolder, J9VMTHREAD_STATE_RUNNING);
+ }
+#else /* JAVA_SPEC_VERSION >= 19 */
+ J9VMJAVALANGTHREAD_SET_THREADSTATUS(currentThread, initializee->threadObject, J9VMTHREAD_STATE_RUNNING);
+#endif /* JAVA_SPEC_VERSION >= 19 */
}
}
done:
diff --git a/runtime/vm/threadhelp.cpp b/runtime/vm/threadhelp.cpp
index 3adc40da463..d0f3b94f491 100644
--- a/runtime/vm/threadhelp.cpp
+++ b/runtime/vm/threadhelp.cpp
@@ -106,10 +106,16 @@ monitorWaitImpl(J9VMThread *vmThread, j9object_t object, I_64 millis, I_32 nanos
#endif
J9VMTHREAD_SET_BLOCKINGENTEROBJECT(vmThread, vmThread, object);
object = NULL;
+ /* Set j.l.Thread status to WAITING. */
+ U_64 oldState = J9_ARE_ANY_BITS_SET(thrstate, J9_PUBLIC_FLAGS_THREAD_TIMED)
+ ? VM_VMHelpers::setThreadState(vmThread, J9VMTHREAD_STATE_WAITING_TIMED)
+ : VM_VMHelpers::setThreadState(vmThread, J9VMTHREAD_STATE_WAITING);
internalReleaseVMAccessSetStatus(vmThread, thrstate);
rc = timeCompensationHelper(vmThread,
interruptable ? HELPER_TYPE_MONITOR_WAIT_INTERRUPTABLE : HELPER_TYPE_MONITOR_WAIT_TIMED, monitor, millis, nanos);
internalAcquireVMAccessClearStatus(vmThread, thrstate);
+ /* Set j.l.Thread status to oldState. */
+ VM_VMHelpers::setThreadState(vmThread, oldState);
J9VMTHREAD_SET_BLOCKINGENTEROBJECT(vmThread, vmThread, NULL);
omrthread_monitor_unpin(monitor, vmThread->osThread);
TRIGGER_J9HOOK_VM_MONITOR_WAITED(javaVM->hookInterface, vmThread, monitor, millis, nanos, rc, startTicks, (UDATA) monitor, VM_VMHelpers::currentClass(monitorClass));
@@ -179,9 +185,13 @@ threadSleepImpl(J9VMThread *vmThread, I_64 millis, I_32 nanos)
#endif
if (0 == rc) {
TRIGGER_J9HOOK_VM_SLEEP(javaVM->hookInterface, vmThread, millis, nanos);
+ /* Set j.l.Thread status to SLEEPING. */
+ U_64 oldState = VM_VMHelpers::setThreadState(vmThread, J9VMTHREAD_STATE_SLEEPING);
internalReleaseVMAccessSetStatus(vmThread, J9_PUBLIC_FLAGS_THREAD_SLEEPING);
rc = timeCompensationHelper(vmThread, HELPER_TYPE_THREAD_SLEEP, NULL, millis, nanos);
internalAcquireVMAccessClearStatus(vmThread, J9_PUBLIC_FLAGS_THREAD_SLEEPING);
+ /* Set j.l.Thread status to oldState. */
+ VM_VMHelpers::setThreadState(vmThread, oldState);
TRIGGER_J9HOOK_VM_SLEPT(javaVM->hookInterface, vmThread, millis, nanos, startTicks);
}
diff --git a/runtime/vm/threadpark.cpp b/runtime/vm/threadpark.cpp
index 2fba2ebebef..71325fd576e 100644
--- a/runtime/vm/threadpark.cpp
+++ b/runtime/vm/threadpark.cpp
@@ -98,6 +98,10 @@ threadParkImpl(J9VMThread *vmThread, BOOLEAN timeoutIsEpochRelative, I_64 timeou
/* vmThread->threadObject != NULL because vmThread must be the current thread */
J9VMTHREAD_SET_BLOCKINGENTEROBJECT(vmThread, vmThread, J9VMJAVALANGTHREAD_PARKBLOCKER(vmThread, vmThread->threadObject));
TRIGGER_J9HOOK_VM_PARK(vm->hookInterface, vmThread, millis, nanos);
+ /* Set j.l.Thread status to WAITING. */
+ U_64 oldState = J9_ARE_ANY_BITS_SET(thrstate, J9_PUBLIC_FLAGS_THREAD_TIMED)
+ ? VM_VMHelpers::setThreadState(vmThread, J9VMTHREAD_STATE_WAITING_TIMED)
+ : VM_VMHelpers::setThreadState(vmThread, J9VMTHREAD_STATE_WAITING);
internalReleaseVMAccessSetStatus(vmThread, thrstate);
while (1) {
@@ -116,6 +120,8 @@ threadParkImpl(J9VMThread *vmThread, BOOLEAN timeoutIsEpochRelative, I_64 timeou
}
internalAcquireVMAccessClearStatus(vmThread, thrstate);
+ /* Set j.l.Thread status to oldState. */
+ VM_VMHelpers::setThreadState(vmThread, oldState);
TRIGGER_J9HOOK_VM_UNPARKED(vm->hookInterface, vmThread, millis, nanos, startTicks, (UDATA) parkedAddress, VM_VMHelpers::currentClass(parkedClass));
J9VMTHREAD_SET_BLOCKINGENTEROBJECT(vmThread, vmThread, NULL);
}
diff --git a/runtime/vm/vmthread.cpp b/runtime/vm/vmthread.cpp
index 98683f71b59..b0cad18b23b 100644
--- a/runtime/vm/vmthread.cpp
+++ b/runtime/vm/vmthread.cpp
@@ -44,6 +44,7 @@
#include "ut_j9vm.h"
#include "vm_internal.h"
#include "vmaccess.h"
+#include "VMHelpers.hpp"
#include "vmhook_internal.h"
#include "HeapIteratorAPI.h"
@@ -459,6 +460,8 @@ void threadCleanup(J9VMThread * vmThread, UDATA forkedByVM)
/* Safe to call this whether handleUncaughtException clears the exception or not */
internalExceptionDescribe(vmThread);
}
+ /* Set j.l.Thread status to TERMINATED. */
+ VM_VMHelpers::setThreadState(vmThread, J9VMTHREAD_STATE_DEAD);
releaseVMAccess(vmThread);
/* Mark this thread as dead */
@@ -2010,6 +2013,9 @@ startJavaThreadInternal(J9VMThread * currentThread, UDATA privateFlags, UDATA os
}
J9VMJAVALANGTHREAD_SET_THREADREF(currentThread, threadObject, newThread);
+ /* Set j.l.Thread status to RUNNABLE. */
+ VM_VMHelpers::setThreadState(currentThread, J9VMTHREAD_STATE_RUNNING);
+
#if (JAVA_SPEC_VERSION >= 14)
/* If thread was interrupted before start, make sure interrupt flag is set for running thread. */
if (J9VMJAVALANGTHREAD_DEADINTERRUPT(currentThread, threadObject)) {