From 1ab5b3494263d2f641ba30ab9d0a361fe74749f9 Mon Sep 17 00:00:00 2001 From: Serguei Spitsyn Date: Wed, 14 Feb 2024 15:19:52 +0000 Subject: [PATCH] review: added assert to get_pending_threads; added suggested coverage to test objmonusage003 --- src/hotspot/share/runtime/threads.cpp | 1 + .../GetObjectMonitorUsage/objmonusage003.java | 157 +++++++++++++++--- 2 files changed, 132 insertions(+), 26 deletions(-) diff --git a/src/hotspot/share/runtime/threads.cpp b/src/hotspot/share/runtime/threads.cpp index 083109eac31eb..3b206e0525486 100644 --- a/src/hotspot/share/runtime/threads.cpp +++ b/src/hotspot/share/runtime/threads.cpp @@ -1185,6 +1185,7 @@ void Threads::metadata_handles_do(void f(Metadata*)) { GrowableArray* Threads::get_pending_threads(ThreadsList * t_list, int count, address monitor) { + assert(Thread::current()->is_VM_thread(), "Must be the VM thread"); GrowableArray* result = new GrowableArray(count); int i = 0; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage003.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage003.java index 44800cddd4439..ce1f1b725d042 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage003.java @@ -28,9 +28,9 @@ public class objmonusage003 { final static int JCK_STATUS_BASE = 95; - final static int NUMBER_OF_ENTERER_THREADS = 4; - final static int NUMBER_OF_WAITER_THREADS = 4; - final static int NUMBER_OF_THREADS = NUMBER_OF_ENTERER_THREADS + NUMBER_OF_WAITER_THREADS; + final static int NUMBER_OF_ENTERING_THREADS = 4; + final static int NUMBER_OF_WAITING_THREADS = 4; + final static int NUMBER_OF_THREADS = NUMBER_OF_ENTERING_THREADS + NUMBER_OF_WAITING_THREADS; static { try { @@ -44,48 +44,137 @@ public class objmonusage003 { } static Object lockCheck = new Object(); + static TestThread thr[] = new TestThread[NUMBER_OF_THREADS]; native static int getRes(); native static void check(Object obj, Thread owner, int entryCount, int waiterCount, int notifyWaiterCount); - public static void main(String args[]) { - args = nsk.share.jvmti.JVMTITest.commonInit(args); + /* Scenario #1: + * - non-zero entering threads + * - zero re-entering threads + * - zero threads waiting to be notified + */ + static void test1() throws Error { + synchronized (lockCheck) { + // entry count: 1 + // count of threads waiting to enter: 0 + // count of threads waiting to re-enter: 0 + // count of threads waiting to be notified: 0 + check(lockCheck, Thread.currentThread(), 1, 0, 0); - // produce JCK-like exit status. - System.exit(run(args, System.out) + JCK_STATUS_BASE); + for (int i = 0; i < NUMBER_OF_ENTERING_THREADS; i++) { + thr[i] = new EnteringThread(); + thr[i].start(); + // this EnteringThread has to be blocked on the lockCheck enter + thr[i].waitReady(); + } + // entry count: 1 + // count of threads waiting to enter: NUMBER_OF_ENTERING_THREADS + // count of threads waiting to re-enter: 0 + // count of threads waiting to be notified: 0 + check(lockCheck, Thread.currentThread(), 1, + NUMBER_OF_ENTERING_THREADS, + 0 /* count of threads waiting to be notified: 0 */); + } + for (int i = 0; i < NUMBER_OF_ENTERING_THREADS; i++) { + try { + thr[i].join(); + } catch (InterruptedException e) { + throw new Error("Unexpected " + e); + } + } } - public static int run(String args[], PrintStream out) { - check(lockCheck, null, 0, 0, 0); - + /* Scenario #2: + * - non-zero entering threads + * - zero re-entering threads + * - non-zero waiting to be notified + */ + static void test2() throws Error { + for (int i = NUMBER_OF_ENTERING_THREADS; i < NUMBER_OF_THREADS; i++) { + thr[i] = new WaitingThread(); + thr[i].start(); + thr[i].waitReady(); // the WaitingThread has to wait to be notified in a lockCheck.wait() + } synchronized (lockCheck) { - check(lockCheck, Thread.currentThread(), 1, 0, 0); + for (int i = 0; i < NUMBER_OF_ENTERING_THREADS; i++) { + thr[i] = new EnteringThread(); + thr[i].start(); + thr[i].waitReady(); // the EnteringThread has to block on monitor enter + } + // entry count: 1 + // count of threads waiting to enter: NUMBER_OF_ENTERING_THREADS + // count of threads waiting to re-enter: 0 + // count of threads waiting to be notified: NUMBER_OF_WAITING_THREADS + check(lockCheck, Thread.currentThread(), 1, + NUMBER_OF_ENTERING_THREADS, + NUMBER_OF_WAITING_THREADS); + + lockCheck.notifyAll(); } + for (int i = 0; i < NUMBER_OF_THREADS; i++) { + try { + thr[i].join(); + } catch (InterruptedException e) { + throw new Error("Unexpected " + e); + } + } + } - TestThread thr[] = new TestThread[NUMBER_OF_THREADS]; - for (int i = NUMBER_OF_ENTERER_THREADS; i < NUMBER_OF_THREADS; i++) { - thr[i] = new WaiterThread(); + /* Scenario #3: + * Initially we have: + * - zero entering threads + * - zero re-entering threads + * - non-zero threads waiting to be notified + * + * The threads waiting to be notified are being notified one-by-one + * until all threads are blocked on re-entering the monitor. + * The numbers of entering/re-entering and waiting threads are checked + * for correctness after each notification. + */ + static void test3() throws Error { + for (int i = NUMBER_OF_ENTERING_THREADS; i < NUMBER_OF_THREADS; i++) { + thr[i] = new WaitingThread(); thr[i].start(); - // the WaiterThread has to wait to be notified in a lockCheck.wait() + // the WaitingThread has to wait to be notified in a lockCheck.wait() thr[i].waitReady(); } synchronized (lockCheck) { - for (int i = 0; i < NUMBER_OF_ENTERER_THREADS; i++) { - thr[i] = new EntererThread(); + // entry count: 1 + // count of threads waiting to enter: 0 + // count of threads waiting to re-enter: 0 + // count of threads waiting to be notified: NUMBER_OF_WAITING_THREADS + check(lockCheck, Thread.currentThread(), 1, + 0, // number of threads waiting to enter or re-enter + NUMBER_OF_WAITING_THREADS); + + for (int i = 0; i < NUMBER_OF_ENTERING_THREADS; i++) { + thr[i] = new EnteringThread(); thr[i].start(); - // the EntererThread has to be blocked on the lockCheck enter + // this EnteringThread has to be blocked on the lockCheck enter thr[i].waitReady(); } + + // entry count: 1 + // count of threads waiting to enter: NUMBER_OF_ENTERING_THREADS + // count of threads waiting to re-enter: 0 + // count of threads waiting to be notified: NUMBER_OF_WAITING_THREADS check(lockCheck, Thread.currentThread(), 1, - NUMBER_OF_ENTERER_THREADS, - NUMBER_OF_WAITER_THREADS); - for (int i = 0; i < NUMBER_OF_WAITER_THREADS; i++) { + NUMBER_OF_ENTERING_THREADS, + NUMBER_OF_WAITING_THREADS); + + for (int i = 0; i < NUMBER_OF_WAITING_THREADS; i++) { lockCheck.notify(); - // now the notified WaiterThread has to be blocked on the lockCheck re-enter + // now the notified WaitingThread has to be blocked on the lockCheck re-enter + + // entry count: 1 + // count of threads waiting to enter: NUMBER_OF_ENTERING_THREADS + // count of threads waiting to re-enter: i + 1 + // count of threads waiting to be notified: NUMBER_OF_WAITING_THREADS - i - 1 check(lockCheck, Thread.currentThread(), 1, - NUMBER_OF_ENTERER_THREADS + i + 1, - NUMBER_OF_WAITER_THREADS - i - 1); + NUMBER_OF_ENTERING_THREADS + i + 1, + NUMBER_OF_WAITING_THREADS - i - 1); } } for (int i = 0; i < NUMBER_OF_THREADS; i++) { @@ -95,6 +184,22 @@ public static int run(String args[], PrintStream out) { throw new Error("Unexpected " + e); } } + } + + public static void main(String args[]) { + args = nsk.share.jvmti.JVMTITest.commonInit(args); + + // produce JCK-like exit status. + System.exit(run(args, System.out) + JCK_STATUS_BASE); + } + + public static int run(String args[], PrintStream out) { + check(lockCheck, null, 0, 0, 0); + + test1(); + test2(); + test3(); + check(lockCheck, null, 0, 0, 0); return getRes(); } @@ -112,7 +217,7 @@ public void waitReady() { } } - static class EntererThread extends TestThread { + static class EnteringThread extends TestThread { public void run() { ready = true; synchronized (lockCheck) { @@ -120,7 +225,7 @@ public void run() { } } - static class WaiterThread extends TestThread { + static class WaitingThread extends TestThread { public void run() { synchronized (lockCheck) { try {