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)) {