JDK-8265240 : runtime/Thread/SuspendAtExit.java needs updating
  • Type: Enhancement
  • Component: hotspot
  • Sub-Component: runtime
  • Affected Version: 17
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2021-04-14
  • Updated: 2021-04-29
  • Resolved: 2021-04-23
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 17
17 b20Fixed
Related Reports
Relates :  
Relates :  
Description
java.lang.Thread.suspend() and java.lang.Thread.resume()
are deprecated for removal:

----------System.err:(13/1091)----------
/System/Volumes/Data/work/shared/bug_hunt/base_for_jdk17.git/open/test/hotspot/jtreg/runtime/Thread/SuspendAtExit.java:70: warning: [removal] suspend() in Thread has been deprecated and marked for removal
                    threads[i].suspend();
                              ^
/System/Volumes/Data/work/shared/bug_hunt/base_for_jdk17.git/open/test/hotspot/jtreg/runtime/Thread/SuspendAtExit.java:77: warning: [removal] resume() in Thread has been deprecated and marked for removal
                    threads[i].resume();
                              ^
/System/Volumes/Data/work/shared/bug_hunt/base_for_jdk17.git/open/test/hotspot/jtreg/runtime/Thread/SuspendAtExit.java:96: warning: [removal] suspend() in Thread has been deprecated and marked for removal
            threads[i].suspend();
                      ^
/System/Volumes/Data/work/shared/bug_hunt/base_for_jdk17.git/open/test/hotspot/jtreg/runtime/Thread/SuspendAtExit.java:97: warning: [removal] resume() in Thread has been deprecated and marked for removal
            threads[i].resume();
                      ^
4 warnings
result: Passed. Compilation successful

Will be switching java.lang.Thread.suspend() to JVM/TI SuspendThread() and
from java.lang.Thread.resume() to JVM/TI ResumeThread().

Also, the test should be switched from a counter based test to a
time based test since time based tests work better for stress kits.
Will also be cleaning up the error handling since the JVM/TI APIs
actually return error codes.
Comments
Changeset: c9b70c80 Author: Daniel D. Daugherty <dcubed@openjdk.org> Date: 2021-04-23 14:20:34 +0000 URL: https://git.openjdk.java.net/jdk/commit/c9b70c80
23-04-2021

A single run of the latest version of runtime/Thread/SuspendAtExit.java failed in Tier6 on Win-X64 by hanging: - the test timed out at just over 8 minutes (which matches the default timeout value of 2 minutes/120 seconds with a default timeoutFactor of 4) - there were no special JVM args for the test task The timeout handler captured 6 jstack outputs for the test: - iteration 0: "MainThread" #16 prio=5 os_prio=0 cpu=81921.88ms elapsed=487.90s allocated=256K defined_classes=15 tid=0x000002856e637890 nid=0x8028 runnable _threads_hazard_ptr=0x000002856e581fd0, _nested_threads_hazard_ptr=0x000002856e581fd0 [0x000000e69fdfe000] java.lang.Thread.State: RUNNABLE at SuspendAtExit.suspendThread(Native Method) at SuspendAtExit.main(SuspendAtExit.java:105) at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(java.base@17-internal/Native Method) at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(java.base@17-internal/NativeMethodAccessorImpl.java:78) at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(java.base@17-internal/DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(java.base@17-internal/Method.java:568) at com.sun.javatest.regtest.agent.MainWrapper$MainThread.run(MainWrapper.java:127) at java.lang.Thread.run(java.base@17-internal/Thread.java:831) Locked ownable synchronizers: - None "Thread-23" #39 prio=5 os_prio=0 cpu=31.25ms elapsed=0.54s allocated=64B defined_classes=0 tid=0x000002856e670320 nid=0x5f0 runnable [0x000000e6a39ff000] java.lang.Thread.State: RUNNABLE at jdk.internal.misc.Unsafe.park(java.base@17-internal/Native Method) - parking to wait for <0x0000000087700280> (a java.util.concurrent.CountDownLatch$Sync) at java.util.concurrent.locks.LockSupport.park(java.base@17-internal/LockSupport.java:211) at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(java.base@17-internal/AbstractQueuedSynchronizer.java:715) at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(java.base@17-internal/AbstractQueuedSynchronizer.java:1047) at java.util.concurrent.CountDownLatch.await(java.base@17-internal/CountDownLatch.java:230) at SuspendAtExit.run(SuspendAtExit.java:56) Locked ownable synchronizers: - None - iteration 1: "MainThread" #16 prio=5 os_prio=0 cpu=82093.75ms elapsed=488.65s allocated=256K defined_classes=15 tid=0x000002856e637890 nid=0x8028 waiting on condition _threads_hazard_ptr=0x000002856e581fd0, _nested_threads_hazard_ptr=0x000002856e581fd0 [0x000000e69fdfe000] java.lang.Thread.State: RUNNABLE at SuspendAtExit.suspendThread(Native Method) at SuspendAtExit.main(SuspendAtExit.java:105) at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(java.base@17-internal/Native Method) at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(java.base@17-internal/NativeMethodAccessorImpl.java:78) at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(java.base@17-internal/DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(java.base@17-internal/Method.java:568) at com.sun.javatest.regtest.agent.MainWrapper$MainThread.run(MainWrapper.java:127) at java.lang.Thread.run(java.base@17-internal/Thread.java:831) Locked ownable synchronizers: - None "Thread-23" #39 prio=5 os_prio=0 cpu=140.63ms elapsed=1.29s allocated=64B defined_classes=0 tid=0x000002856e670320 nid=0x5f0 runnable [0x000000e6a39ff000] java.lang.Thread.State: RUNNABLE at jdk.internal.misc.Unsafe.park(java.base@17-internal/Native Method) - parking to wait for <0x0000000087700280> (a java.util.concurrent.CountDownLatch$Sync) at java.util.concurrent.locks.LockSupport.park(java.base@17-internal/LockSupport.java:211) at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(java.base@17-internal/AbstractQueuedSynchronizer.java:715) at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(java.base@17-internal/AbstractQueuedSynchronizer.java:1047) at java.util.concurrent.CountDownLatch.await(java.base@17-internal/CountDownLatch.java:230) at SuspendAtExit.run(SuspendAtExit.java:56) Locked ownable synchronizers: - None - iteration 2: "MainThread" #16 prio=5 os_prio=0 cpu=82281.25ms elapsed=489.41s allocated=256K defined_classes=15 tid=0x000002856e637890 nid=0x8028 runnable _threads_hazard_ptr=0x000002856e581fd0 [0x000000e69fdfe000] java.lang.Thread.State: RUNNABLE at SuspendAtExit.resumeThread(Native Method) at SuspendAtExit.main(SuspendAtExit.java:124) at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(java.base@17-internal/Native Method) at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(java.base@17-internal/NativeMethodAccessorImpl.java:78) at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(java.base@17-internal/DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(java.base@17-internal/Method.java:568) at com.sun.javatest.regtest.agent.MainWrapper$MainThread.run(MainWrapper.java:127) at java.lang.Thread.run(java.base@17-internal/Thread.java:831) Locked ownable synchronizers: - None "Thread-23" #39 prio=5 os_prio=0 cpu=234.38ms elapsed=2.05s allocated=64B defined_classes=0 tid=0x000002856e670320 nid=0x5f0 runnable [0x000000e6a39ff000] java.lang.Thread.State: RUNNABLE at jdk.internal.misc.Unsafe.putReferenceVolatile(java.base@17-internal/Native Method) - parking to wait for <0x0000000087700280> (a java.util.concurrent.CountDownLatch$Sync) at jdk.internal.misc.Unsafe.putReferenceOpaque(java.base@17-internal/Unsafe.java:2350) at java.util.concurrent.locks.LockSupport.setBlocker(java.base@17-internal/LockSupport.java:143) at java.util.concurrent.locks.LockSupport.park(java.base@17-internal/LockSupport.java:212) at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(java.base@17-internal/AbstractQueuedSynchronizer.java:715) at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(java.base@17-internal/AbstractQueuedSynchronizer.java:1047) at java.util.concurrent.CountDownLatch.await(java.base@17-internal/CountDownLatch.java:230) at SuspendAtExit.run(SuspendAtExit.java:56) Locked ownable synchronizers: - None - iteration 3: "MainThread" #16 prio=5 os_prio=0 cpu=82328.13ms elapsed=490.16s allocated=256K defined_classes=15 tid=0x000002856e637890 nid=0x8028 waiting on condition _threads_hazard_ptr=0x000002856e581fd0, _nested_threads_hazard_ptr=0x000002856e581fd0 [0x000000e69fdfe000] java.lang.Thread.State: RUNNABLE at SuspendAtExit.suspendThread(Native Method) at SuspendAtExit.main(SuspendAtExit.java:105) at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(java.base@17-internal/Native Method) at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(java.base@17-internal/NativeMethodAccessorImpl.java:78) at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(java.base@17-internal/DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(java.base@17-internal/Method.java:568) at com.sun.javatest.regtest.agent.MainWrapper$MainThread.run(MainWrapper.java:127) at java.lang.Thread.run(java.base@17-internal/Thread.java:831) Locked ownable synchronizers: - None "Thread-23" #39 prio=5 os_prio=0 cpu=265.63ms elapsed=2.80s allocated=64B defined_classes=0 tid=0x000002856e670320 nid=0x5f0 runnable [0x000000e6a39ff000] java.lang.Thread.State: RUNNABLE at jdk.internal.misc.Unsafe.putReferenceVolatile(java.base@17-internal/Native Method) - parking to wait for <0x0000000087700280> (a java.util.concurrent.CountDownLatch$Sync) at jdk.internal.misc.Unsafe.putReferenceOpaque(java.base@17-internal/Unsafe.java:2350) at java.util.concurrent.locks.LockSupport.setBlocker(java.base@17-internal/LockSupport.java:143) at java.util.concurrent.locks.LockSupport.park(java.base@17-internal/LockSupport.java:212) at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(java.base@17-internal/AbstractQueuedSynchronizer.java:715) at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(java.base@17-internal/AbstractQueuedSynchronizer.java:1047) at java.util.concurrent.CountDownLatch.await(java.base@17-internal/CountDownLatch.java:230) at SuspendAtExit.run(SuspendAtExit.java:56) Locked ownable synchronizers: - None - iteration 4: "MainThread" #16 prio=5 os_prio=0 cpu=82453.13ms elapsed=490.92s allocated=256K defined_classes=15 tid=0x000002856e637890 nid=0x8028 waiting on condition _threads_hazard_ptr=0x000002856e581fd0, _nested_threads_hazard_ptr=0x000002856e581fd0 [0x000000e69fdfe000] java.lang.Thread.State: RUNNABLE at SuspendAtExit.suspendThread(Native Method) at SuspendAtExit.main(SuspendAtExit.java:105) at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(java.base@17-internal/Native Method) at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(java.base@17-internal/NativeMethodAccessorImpl.java:78) at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(java.base@17-internal/DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(java.base@17-internal/Method.java:568) at com.sun.javatest.regtest.agent.MainWrapper$MainThread.run(MainWrapper.java:127) at java.lang.Thread.run(java.base@17-internal/Thread.java:831) Locked ownable synchronizers: - None "Thread-23" #39 prio=5 os_prio=0 cpu=375.00ms elapsed=3.56s allocated=64B defined_classes=0 tid=0x000002856e670320 nid=0x5f0 runnable [0x000000e6a39ff000] java.lang.Thread.State: RUNNABLE at jdk.internal.misc.Unsafe.putReferenceVolatile(java.base@17-internal/Native Method) - parking to wait for <0x0000000087700280> (a java.util.concurrent.CountDownLatch$Sync) at jdk.internal.misc.Unsafe.putReferenceOpaque(java.base@17-internal/Unsafe.java:2350) at java.util.concurrent.locks.LockSupport.setBlocker(java.base@17-internal/LockSupport.java:143) at java.util.concurrent.locks.LockSupport.park(java.base@17-internal/LockSupport.java:212) at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(java.base@17-internal/AbstractQueuedSynchronizer.java:715) at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(java.base@17-internal/AbstractQueuedSynchronizer.java:1047) at java.util.concurrent.CountDownLatch.await(java.base@17-internal/CountDownLatch.java:230) at SuspendAtExit.run(SuspendAtExit.java:56) Locked ownable synchronizers: - None - iteration 5: "MainThread" #16 prio=5 os_prio=0 cpu=82578.13ms elapsed=491.69s allocated=256K defined_classes=15 tid=0x000002856e637890 nid=0x8028 waiting on condition _threads_hazard_ptr=0x000002856e581fd0, _nested_threads_hazard_ptr=0x000002856e581fd0 [0x000000e69fdfe000] java.lang.Thread.State: RUNNABLE at SuspendAtExit.suspendThread(Native Method) at SuspendAtExit.main(SuspendAtExit.java:105) at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(java.base@17-internal/Native Method) at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(java.base@17-internal/NativeMethodAccessorImpl.java:78) at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(java.base@17-internal/DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(java.base@17-internal/Method.java:568) at com.sun.javatest.regtest.agent.MainWrapper$MainThread.run(MainWrapper.java:127) at java.lang.Thread.run(java.base@17-internal/Thread.java:831) Locked ownable synchronizers: - None "Thread-23" #39 prio=5 os_prio=0 cpu=437.50ms elapsed=4.33s allocated=64B defined_classes=0 tid=0x000002856e670320 nid=0x5f0 runnable [0x000000e6a39ff000] java.lang.Thread.State: RUNNABLE at jdk.internal.misc.Unsafe.putReferenceVolatile(java.base@17-internal/Native Method) - parking to wait for <0x0000000087700280> (a java.util.concurrent.CountDownLatch$Sync) at jdk.internal.misc.Unsafe.putReferenceOpaque(java.base@17-internal/Unsafe.java:2350) at java.util.concurrent.locks.LockSupport.setBlocker(java.base@17-internal/LockSupport.java:143) at java.util.concurrent.locks.LockSupport.park(java.base@17-internal/LockSupport.java:212) at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(java.base@17-internal/AbstractQueuedSynchronizer.java:715) at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(java.base@17-internal/AbstractQueuedSynchronizer.java:1047) at java.util.concurrent.CountDownLatch.await(java.base@17-internal/CountDownLatch.java:230) at SuspendAtExit.run(SuspendAtExit.java:56) Locked ownable synchronizers: - None In each of the samples, the worker thread ("Thread-23") is in this code block: public void run() { // Tell main thread we have started. startSyncObj.countDown(); try { // Wait for main thread to interrupt us so we // can race to exit. exitSyncObj.await(); <<<=== "Thread-23" is here } catch (InterruptedException e) { // ignore because we expect one } } and the "MainThread" is here: // This interrupt() call will break the worker out of // the exitSyncObj.await() call and the SuspendThread() // calls will come in during thread exit. threads[i].interrupt(); while (true) { retCode = suspendThread(threads[i]); <<<=== "MainThread" here (5 times) if (retCode == JVMTI_ERROR_THREAD_NOT_ALIVE) { // Done with SuspendThread() calls since // thread is not alive. break; } else if (retCode != 0) { throw new RuntimeException("thread #" + i + ": suspendThread() " + "retCode=" + retCode + ": unexpected value."); } if (!threads[i].isAlive()) { throw new RuntimeException("thread #" + i + ": is not alive " + "after successful " + "suspendThread()."); } retCode = resumeThread(threads[i]); <<<=== "MainThread" here (1 time) if (retCode != 0) { throw new RuntimeException("thread #" + i + ": resumeThread() " + "retCode=" + retCode + ": unexpected value."); } } I believe that the "threads[i].interrupt()" call by the "MainThread" got lost and never interrupted "Thread-23" in its "exitSyncObj.await()" call. We have had lost Thread.interrupt() calls in the past.
19-04-2021

Actually I'm not planning on keeping the calls to Thread.suspend() or Thread.resume() since neither of those APIs have error codes. Since those two APIs are terminally deprecated, I think it's time to move on and we'll get the testing we want at thread exit time by using the JVM/TI SuspendThread() and ResumeThread() APIs. I'm running the revised test on [~rehn]'s changes for JDK-8257831 in 3 parallel configs {fastdebug,release,slowdebug) for 9 hours without any extra options. I'm following that with another run with 3 parallel configs {fastdebug,release,slowdebug) for 9 hours with these options: -XX:+UnlockDiagnosticVMOptions -XX:GuaranteedSafepointInterval=1 -XX:+HandshakeALot
15-04-2021

Something like: s/threads[i].suspend()/doSuspend(threads[i]) static void doSuspend(Thread t) { if (useJava) t.suspend(); else doJVMTISuspend(t); } static native void doJVMTISuspend(Thread t); ?
14-04-2021

I've updated the description note to hopefully be more clear. I'm using the revamped test to stress test [~rehn]'s fix for: JDK-8257831 Suspend with handshakes since the SuspendThread at thread exit logic has been changed.
14-04-2021

I'm not sure what is being suggested. When these deprecated suspend/resume methods are actually removed then the test can be deleted. Given that, any updates to the test would seem a waste of resources (unless causing intermittent failures).
14-04-2021