c1281e6b45
Reviewed-by: kbarrett, dholmes, jwaters
192 lines
6.4 KiB
C++
192 lines
6.4 KiB
C++
/*
|
|
* 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));
|
|
}
|