/* * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. * */ #include "precompiled.hpp" #include "memory/allocation.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/javaThread.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/threads.hpp" #include "runtime/vmOperations.hpp" #include "runtime/vmThread.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/ostream.hpp" #include "unittest.hpp" struct Threads::Test : public AllStatic { class VM_TestClaimOverflow; class CountThreads; class CheckClaims; }; class Threads::Test::CountThreads : public ThreadClosure { uintx _claim_token; uint _java_threads_count; uint _non_java_threads_count; bool _need_claim; public: CountThreads(uintx claim_token, bool need_claim) : _claim_token(claim_token), _java_threads_count(0), _non_java_threads_count(0), _need_claim(need_claim) {} virtual void do_thread(Thread* t) { if (!_need_claim || t->claim_threads_do(true, _claim_token)) { if (t->is_Java_thread()) { ++_java_threads_count; } else { ++_non_java_threads_count; } } } uint java_threads_count() const { return _java_threads_count; } uint non_java_threads_count() const { return _non_java_threads_count; } uint count() const { return _java_threads_count + _non_java_threads_count; } }; class Threads::Test::CheckClaims : public ThreadClosure { uintx _claim_token; uint _java_threads_claimed; uint _java_threads_unclaimed; uint _non_java_threads_claimed; uint _non_java_threads_unclaimed; public: CheckClaims(uintx claim_token) : _claim_token(claim_token), _java_threads_claimed(0), _java_threads_unclaimed(0), _non_java_threads_claimed(0), _non_java_threads_unclaimed(0) {} virtual void do_thread(Thread* t) { uintx thread_token = t->threads_do_token(); if (thread_token == _claim_token) { if (t->is_Java_thread()) { ++_java_threads_claimed; } else { ++_non_java_threads_claimed; } } else { if (t->is_Java_thread()) { ++_java_threads_unclaimed; } else { ++_non_java_threads_unclaimed; } } } uint java_threads_claimed() const { return _java_threads_claimed; } uint java_threads_unclaimed() const { return _java_threads_unclaimed; } uint non_java_threads_claimed() const { return _non_java_threads_claimed; } uint non_java_threads_unclaimed() const { return _non_java_threads_unclaimed; } uint claimed() const { return _java_threads_claimed + _non_java_threads_claimed; } uint unclaimed() const { return _java_threads_unclaimed + _non_java_threads_unclaimed; } }; class Threads::Test::VM_TestClaimOverflow : public VM_GTestExecuteAtSafepoint { public: void doit() { // Prevent changes to the NJT list while we're conducting our test. MutexLocker ml(NonJavaThreadsList_lock, Mutex::_no_safepoint_check_flag); _thread_claim_token = max_uintx - 1; ASSERT_EQ(max_uintx - 1, thread_claim_token()); CountThreads count1(thread_claim_token(), true); threads_do(&count1); tty->print_cr("Testing claim overflow with %u threads", count1.count()); // At least the main thread and the VM thread. ASSERT_LE(2u, count1.count()); ASSERT_LE(1u, count1.java_threads_count()); ASSERT_LE(1u, count1.non_java_threads_count()); ASSERT_EQ(max_uintx - 1, thread_claim_token()); CheckClaims check1(thread_claim_token()); threads_do(&check1); ASSERT_EQ(count1.count(), check1.claimed()); ASSERT_EQ(count1.java_threads_count(), check1.java_threads_claimed()); ASSERT_EQ(0u, check1.java_threads_unclaimed()); ASSERT_EQ(count1.non_java_threads_count(), check1.non_java_threads_claimed()); ASSERT_EQ(0u, check1.non_java_threads_unclaimed()); change_thread_claim_token(); // No overflow yet. ASSERT_EQ(max_uintx, thread_claim_token()); CountThreads count2(thread_claim_token(), false); // Claimed by PPTD below possibly_parallel_threads_do(true /* is_par */, &count2); ASSERT_EQ(count1.java_threads_count(), count2.java_threads_count()); ASSERT_EQ(count1.non_java_threads_count(), count2.non_java_threads_count()); CheckClaims check2(thread_claim_token()); threads_do(&check2); ASSERT_EQ(count2.java_threads_count(), check2.java_threads_claimed()); ASSERT_EQ(0u, check2.java_threads_unclaimed()); ASSERT_EQ(0u, check2.non_java_threads_unclaimed()); ASSERT_EQ(count1.non_java_threads_count(), check2.non_java_threads_claimed()); change_thread_claim_token(); // Expect overflow. ASSERT_EQ(uintx(1), thread_claim_token()); // Verify all threads have claim value of 0 after change overflow. CheckClaims check3(0); threads_do(&check3); ASSERT_EQ(count1.count(), check3.claimed()); ASSERT_EQ(0u, check3.unclaimed()); } }; // Test overflow handling in Threads::change_thread_claim_token(). TEST_VM(ThreadsTest, claim_overflow) { Threads::Test::VM_TestClaimOverflow op; ThreadInVMfromNative invm(JavaThread::current()); VMThread::execute(&op); } TEST_VM(ThreadsTest, fast_jni_in_vm) { JavaThread* current = JavaThread::current(); JNIEnv* env = current->jni_environment(); MACOS_AARCH64_ONLY(ThreadWXEnable wx(WXWrite, current)); // DirectByteBuffer is an easy way to trigger GetIntField, // see JDK-8262896 jlong capacity = 0x10000; jobject buffer = env->NewDirectByteBuffer(nullptr, (jlong)capacity); ASSERT_NE((void*)nullptr, buffer); ASSERT_EQ(capacity, env->GetDirectBufferCapacity(buffer)); }