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 | |
36 | struct Threads::Test : public AllStatic { |
37 | class VM_TestClaimOverflow; |
38 | class CountThreads; |
39 | class CheckClaims; |
40 | }; |
41 | |
42 | class 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 | |
48 | public: |
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 | |
71 | class 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 | |
78 | public: |
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 | |
119 | class Threads::Test::VM_TestClaimOverflow : public VM_GTestExecuteAtSafepoint { |
120 | public: |
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(). |
174 | TEST_VM(ThreadsTest, claim_overflow) { |
175 | Threads::Test::VM_TestClaimOverflow op; |
176 | ThreadInVMfromNative invm(JavaThread::current()); |
177 | VMThread::execute(&op); |
178 | } |
179 | |