1/*
2 * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24
25#include "precompiled.hpp"
26#include "memory/allocation.hpp"
27#include "runtime/interfaceSupport.inline.hpp"
28#include "runtime/mutexLocker.hpp"
29#include "runtime/thread.hpp"
30#include "runtime/vmOperations.hpp"
31#include "runtime/vmThread.hpp"
32#include "utilities/globalDefinitions.hpp"
33#include "utilities/ostream.hpp"
34#include "unittest.hpp"
35
36struct Threads::Test : public AllStatic {
37 class VM_TestClaimOverflow;
38 class CountThreads;
39 class CheckClaims;
40};
41
42class Threads::Test::CountThreads : public ThreadClosure {
43 uintx _claim_token;
44 uint _java_threads_count;
45 uint _non_java_threads_count;
46 bool _need_claim;
47
48public:
49 CountThreads(uintx claim_token, bool need_claim) :
50 _claim_token(claim_token),
51 _java_threads_count(0),
52 _non_java_threads_count(0),
53 _need_claim(need_claim)
54 {}
55
56 virtual void do_thread(Thread* t) {
57 if (!_need_claim || t->claim_threads_do(true, _claim_token)) {
58 if (t->is_Java_thread()) {
59 ++_java_threads_count;
60 } else {
61 ++_non_java_threads_count;
62 }
63 }
64 }
65
66 uint java_threads_count() const { return _java_threads_count; }
67 uint non_java_threads_count() const { return _non_java_threads_count; }
68 uint count() const { return _java_threads_count + _non_java_threads_count; }
69};
70
71class Threads::Test::CheckClaims : public ThreadClosure {
72 uintx _claim_token;
73 uint _java_threads_claimed;
74 uint _java_threads_unclaimed;
75 uint _non_java_threads_claimed;
76 uint _non_java_threads_unclaimed;
77
78public:
79 CheckClaims(uintx claim_token) :
80 _claim_token(claim_token),
81 _java_threads_claimed(0),
82 _java_threads_unclaimed(0),
83 _non_java_threads_claimed(0),
84 _non_java_threads_unclaimed(0)
85 {}
86
87 virtual void do_thread(Thread* t) {
88 uintx thread_token = t->threads_do_token();
89 if (thread_token == _claim_token) {
90 if (t->is_Java_thread()) {
91 ++_java_threads_claimed;
92 } else {
93 ++_non_java_threads_claimed;
94 }
95 } else {
96 if (t->is_Java_thread()) {
97 ++_java_threads_unclaimed;
98 } else {
99 ++_non_java_threads_unclaimed;
100 }
101 }
102 }
103
104 uint java_threads_claimed() const { return _java_threads_claimed; }
105 uint java_threads_unclaimed() const { return _java_threads_unclaimed; }
106
107 uint non_java_threads_claimed() const { return _non_java_threads_claimed; }
108 uint non_java_threads_unclaimed() const { return _non_java_threads_unclaimed; }
109
110 uint claimed() const {
111 return _java_threads_claimed + _non_java_threads_claimed;
112 }
113
114 uint unclaimed() const {
115 return _java_threads_unclaimed + _non_java_threads_unclaimed;
116 }
117};
118
119class Threads::Test::VM_TestClaimOverflow : public VM_GTestExecuteAtSafepoint {
120public:
121 void doit() {
122 // Prevent changes to the NJT list while we're conducting our test.
123 MutexLocker ml(NonJavaThreadsList_lock, Mutex::_no_safepoint_check_flag);
124
125 _thread_claim_token = max_uintx - 1;
126
127 ASSERT_EQ(max_uintx - 1, thread_claim_token());
128 CountThreads count1(thread_claim_token(), true);
129 threads_do(&count1);
130 tty->print_cr("Testing claim overflow with %u threads", count1.count());
131 // At least the main thread and the VM thread.
132 ASSERT_LE(2u, count1.count());
133 ASSERT_LE(1u, count1.java_threads_count());
134 ASSERT_LE(1u, count1.non_java_threads_count());
135
136 ASSERT_EQ(max_uintx - 1, thread_claim_token());
137 CheckClaims check1(thread_claim_token());
138 threads_do(&check1);
139 ASSERT_EQ(count1.count(), check1.claimed());
140 ASSERT_EQ(count1.java_threads_count(), check1.java_threads_claimed());
141 ASSERT_EQ(0u, check1.java_threads_unclaimed());
142 ASSERT_EQ(count1.non_java_threads_count(), check1.non_java_threads_claimed());
143 ASSERT_EQ(0u, check1.non_java_threads_unclaimed());
144
145 change_thread_claim_token(); // No overflow yet.
146 ASSERT_EQ(max_uintx, thread_claim_token());
147
148 CountThreads count2(thread_claim_token(), false); // Claimed by PPTD below
149 possibly_parallel_threads_do(true, &count2);
150 ASSERT_EQ(count1.java_threads_count(), count2.java_threads_count());
151 ASSERT_EQ(1u, count2.non_java_threads_count()); // Only VM thread
152
153 CheckClaims check2(thread_claim_token());
154 threads_do(&check2);
155 ASSERT_EQ(count2.java_threads_count(), check2.java_threads_claimed());
156 ASSERT_EQ(0u, check2.java_threads_unclaimed());
157 ASSERT_EQ(1u, check2.non_java_threads_claimed()); // Only VM thread
158 ASSERT_EQ(count1.non_java_threads_count(),
159 check2.non_java_threads_claimed() +
160 check2.non_java_threads_unclaimed());
161
162 change_thread_claim_token(); // Expect overflow.
163 ASSERT_EQ(uintx(1), thread_claim_token());
164
165 // Verify all threads have claim value of 0 after change overflow.
166 CheckClaims check3(0);
167 threads_do(&check3);
168 ASSERT_EQ(count1.count(), check3.claimed());
169 ASSERT_EQ(0u, check3.unclaimed());
170 }
171};
172
173// Test overflow handling in Threads::change_thread_claim_token().
174TEST_VM(ThreadsTest, claim_overflow) {
175 Threads::Test::VM_TestClaimOverflow op;
176 ThreadInVMfromNative invm(JavaThread::current());
177 VMThread::execute(&op);
178}
179