1 /* |
|
2 * Copyright (c) 2016, 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 "classfile/javaClasses.hpp" |
|
27 #include "classfile/systemDictionary.hpp" |
|
28 #include "gc/shared/collectedHeap.hpp" |
|
29 #include "gc/shared/referencePendingListLocker.hpp" |
|
30 #include "memory/universe.hpp" |
|
31 #include "runtime/javaCalls.hpp" |
|
32 #include "utilities/preserveException.hpp" |
|
33 |
|
34 ReferencePendingListLockerThread::ReferencePendingListLockerThread() : |
|
35 JavaThread(&start), |
|
36 _monitor(Monitor::nonleaf, "ReferencePendingListLocker", false, Monitor::_safepoint_check_sometimes), |
|
37 _message(NONE) {} |
|
38 |
|
39 ReferencePendingListLockerThread* ReferencePendingListLockerThread::create(TRAPS) { |
|
40 // Create Java thread objects |
|
41 instanceKlassHandle thread_klass = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_Thread(), true, CHECK_NULL); |
|
42 instanceHandle thread_object = thread_klass->allocate_instance_handle(CHECK_NULL); |
|
43 Handle thread_name = java_lang_String::create_from_str("Reference Pending List Locker", CHECK_NULL); |
|
44 Handle thread_group = Universe::system_thread_group(); |
|
45 JavaValue result(T_VOID); |
|
46 JavaCalls::call_special(&result, |
|
47 thread_object, |
|
48 thread_klass, |
|
49 vmSymbols::object_initializer_name(), |
|
50 vmSymbols::threadgroup_string_void_signature(), |
|
51 thread_group, |
|
52 thread_name, |
|
53 CHECK_NULL); |
|
54 |
|
55 { |
|
56 MutexLocker ml(Threads_lock); |
|
57 |
|
58 // Allocate thread |
|
59 ReferencePendingListLockerThread* thread = new ReferencePendingListLockerThread(); |
|
60 if (thread == NULL || thread->osthread() == NULL) { |
|
61 vm_exit_during_initialization("java.lang.OutOfMemoryError", |
|
62 os::native_thread_creation_failed_msg()); |
|
63 } |
|
64 |
|
65 // Initialize thread |
|
66 java_lang_Thread::set_thread(thread_object(), thread); |
|
67 java_lang_Thread::set_priority(thread_object(), NearMaxPriority); |
|
68 java_lang_Thread::set_daemon(thread_object()); |
|
69 thread->set_threadObj(thread_object()); |
|
70 |
|
71 // Start thread |
|
72 Threads::add(thread); |
|
73 Thread::start(thread); |
|
74 |
|
75 return thread; |
|
76 } |
|
77 } |
|
78 |
|
79 void ReferencePendingListLockerThread::start(JavaThread* thread, TRAPS) { |
|
80 ReferencePendingListLockerThread* locker_thread = static_cast<ReferencePendingListLockerThread*>(thread); |
|
81 locker_thread->receive_and_handle_messages(); |
|
82 } |
|
83 |
|
84 bool ReferencePendingListLockerThread::is_hidden_from_external_view() const { |
|
85 return true; |
|
86 } |
|
87 |
|
88 void ReferencePendingListLockerThread::send_message(Message message) { |
|
89 assert(message != NONE, "Should not be none"); |
|
90 MonitorLockerEx ml(&_monitor, Monitor::_no_safepoint_check_flag); |
|
91 |
|
92 // Wait for completion of current message |
|
93 while (_message != NONE) { |
|
94 ml.wait(Monitor::_no_safepoint_check_flag); |
|
95 } |
|
96 |
|
97 // Send new message |
|
98 _message = message; |
|
99 ml.notify_all(); |
|
100 |
|
101 // Wait for completion of new message |
|
102 while (_message != NONE) { |
|
103 ml.wait(Monitor::_no_safepoint_check_flag); |
|
104 } |
|
105 } |
|
106 |
|
107 void ReferencePendingListLockerThread::receive_and_handle_messages() { |
|
108 ReferencePendingListLocker pending_list_locker; |
|
109 MonitorLockerEx ml(&_monitor); |
|
110 |
|
111 // Main loop, never terminates |
|
112 for (;;) { |
|
113 // Wait for message |
|
114 while (_message == NONE) { |
|
115 ml.wait(); |
|
116 } |
|
117 |
|
118 // Handle message |
|
119 if (_message == LOCK) { |
|
120 pending_list_locker.lock(); |
|
121 } else if (_message == UNLOCK) { |
|
122 pending_list_locker.unlock(); |
|
123 } else { |
|
124 ShouldNotReachHere(); |
|
125 } |
|
126 |
|
127 // Clear message |
|
128 _message = NONE; |
|
129 ml.notify_all(); |
|
130 } |
|
131 } |
|
132 |
|
133 void ReferencePendingListLockerThread::lock() { |
|
134 send_message(LOCK); |
|
135 } |
|
136 |
|
137 void ReferencePendingListLockerThread::unlock() { |
|
138 send_message(UNLOCK); |
|
139 } |
|
140 |
|
141 bool ReferencePendingListLocker::_is_initialized = false; |
|
142 ReferencePendingListLockerThread* ReferencePendingListLocker::_locker_thread = NULL; |
|
143 |
|
144 void ReferencePendingListLocker::initialize(bool needs_locker_thread, TRAPS) { |
|
145 if (needs_locker_thread) { |
|
146 _locker_thread = ReferencePendingListLockerThread::create(CHECK); |
|
147 } |
|
148 |
|
149 _is_initialized = true; |
|
150 } |
|
151 |
|
152 bool ReferencePendingListLocker::is_initialized() { |
|
153 return _is_initialized; |
|
154 } |
|
155 |
|
156 bool ReferencePendingListLocker::is_locked_by_self() { |
|
157 oop pending_list_lock = java_lang_ref_Reference::pending_list_lock(); |
|
158 if (pending_list_lock == NULL) { |
|
159 return false; |
|
160 } |
|
161 |
|
162 JavaThread* thread = JavaThread::current(); |
|
163 Handle handle(thread, pending_list_lock); |
|
164 return ObjectSynchronizer::current_thread_holds_lock(thread, handle); |
|
165 } |
|
166 |
|
167 void ReferencePendingListLocker::lock() { |
|
168 assert(!Heap_lock->owned_by_self(), "Heap_lock must not be owned by requesting thread"); |
|
169 |
|
170 if (Thread::current()->is_Java_thread()) { |
|
171 assert(java_lang_ref_Reference::pending_list_lock() != NULL, "Not initialized"); |
|
172 |
|
173 // We may enter this with a pending exception |
|
174 PRESERVE_EXCEPTION_MARK; |
|
175 |
|
176 HandleMark hm; |
|
177 Handle handle(THREAD, java_lang_ref_Reference::pending_list_lock()); |
|
178 |
|
179 // Lock |
|
180 ObjectSynchronizer::fast_enter(handle, &_basic_lock, false, THREAD); |
|
181 |
|
182 assert(is_locked_by_self(), "Locking failed"); |
|
183 |
|
184 if (HAS_PENDING_EXCEPTION) { |
|
185 CLEAR_PENDING_EXCEPTION; |
|
186 } |
|
187 } else { |
|
188 // Delegate operation to locker thread |
|
189 assert(_locker_thread != NULL, "Locker thread not created"); |
|
190 _locker_thread->lock(); |
|
191 } |
|
192 } |
|
193 |
|
194 void ReferencePendingListLocker::unlock() { |
|
195 if (Thread::current()->is_Java_thread()) { |
|
196 assert(java_lang_ref_Reference::pending_list_lock() != NULL, "Not initialized"); |
|
197 |
|
198 // We may enter this with a pending exception |
|
199 PRESERVE_EXCEPTION_MARK; |
|
200 |
|
201 HandleMark hm; |
|
202 Handle handle(THREAD, java_lang_ref_Reference::pending_list_lock()); |
|
203 |
|
204 assert(is_locked_by_self(), "Should be locked by self"); |
|
205 |
|
206 // Notify waiters if the pending list is non-empty |
|
207 if (java_lang_ref_Reference::pending_list() != NULL) { |
|
208 ObjectSynchronizer::notifyall(handle, THREAD); |
|
209 } |
|
210 |
|
211 // Unlock |
|
212 ObjectSynchronizer::fast_exit(handle(), &_basic_lock, THREAD); |
|
213 |
|
214 if (HAS_PENDING_EXCEPTION) { |
|
215 CLEAR_PENDING_EXCEPTION; |
|
216 } |
|
217 } else { |
|
218 // Delegate operation to locker thread |
|
219 assert(_locker_thread != NULL, "Locker thread not created"); |
|
220 _locker_thread->unlock(); |
|
221 } |
|
222 } |
|