blob: b82768397be84195601e884f15047555de2942eb [file] [log] [blame]
Andreas Gampe319dbe82017-01-09 16:42:21 -08001/* Copyright (C) 2017 The Android Open Source Project
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3 *
4 * This file implements interfaces from the file jvmti.h. This implementation
5 * is licensed under the same terms as the file jvmti.h. The
6 * copyright and license information for the file jvmti.h follows.
7 *
8 * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
9 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
10 *
11 * This code is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License version 2 only, as
13 * published by the Free Software Foundation. Oracle designates this
14 * particular file as subject to the "Classpath" exception as provided
15 * by Oracle in the LICENSE file that accompanied this code.
16 *
17 * This code is distributed in the hope that it will be useful, but WITHOUT
18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * version 2 for more details (a copy is included in the LICENSE file that
21 * accompanied this code).
22 *
23 * You should have received a copy of the GNU General Public License version
24 * 2 along with this work; if not, write to the Free Software Foundation,
25 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
26 *
27 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
28 * or visit www.oracle.com if you need additional information or have any
29 * questions.
30 */
31
32#include "ti_monitor.h"
33
34#include <atomic>
35#include <chrono>
36#include <condition_variable>
37#include <mutex>
38
39#include "art_jvmti.h"
40#include "runtime.h"
41#include "scoped_thread_state_change-inl.h"
42#include "thread-inl.h"
43
44namespace openjdkjvmti {
45
46// We cannot use ART monitors, as they require the mutator lock for contention locking. We
47// also cannot use pthread mutexes and condition variables (or C++11 abstractions) directly,
48// as the do not have the right semantics for recursive mutexes and waiting (wait only unlocks
49// the mutex once).
50// So go ahead and use a wrapper that does the counting explicitly.
51
52class JvmtiMonitor {
53 public:
54 JvmtiMonitor() : owner_(nullptr), count_(0) {
55 }
56
57 static bool Destroy(art::Thread* self, JvmtiMonitor* monitor) {
58 // Check whether this thread holds the monitor, or nobody does.
59 art::Thread* owner_thread = monitor->owner_.load(std::memory_order_relaxed);
60 if (owner_thread != nullptr && self != owner_thread) {
61 return false;
62 }
63
64 if (monitor->count_ > 0) {
65 monitor->count_ = 0;
66 monitor->owner_.store(nullptr, std::memory_order_relaxed);
67 monitor->mutex_.unlock();
68 }
69
70 delete monitor;
71 return true;
72 }
73
74 void MonitorEnter(art::Thread* self) {
75 // Check for recursive enter.
76 if (IsOwner(self)) {
77 count_++;
78 return;
79 }
80
81 mutex_.lock();
82
83 DCHECK(owner_.load(std::memory_order_relaxed) == nullptr);
84 owner_.store(self, std::memory_order_relaxed);
85 DCHECK_EQ(0u, count_);
86 count_ = 1;
87 }
88
89 bool MonitorExit(art::Thread* self) {
90 if (!IsOwner(self)) {
91 return false;
92 }
93
94 --count_;
95 if (count_ == 0u) {
96 owner_.store(nullptr, std::memory_order_relaxed);
97 mutex_.unlock();
98 }
99
100 return true;
101 }
102
103 bool Wait(art::Thread* self) {
104 auto wait_without_timeout = [&](std::unique_lock<std::mutex>& lk) {
105 cond_.wait(lk);
106 };
107 return Wait(self, wait_without_timeout);
108 }
109
110 bool Wait(art::Thread* self, uint64_t timeout_in_ms) {
111 auto wait_with_timeout = [&](std::unique_lock<std::mutex>& lk) {
112 cond_.wait_for(lk, std::chrono::milliseconds(timeout_in_ms));
113 };
114 return Wait(self, wait_with_timeout);
115 }
116
117 bool Notify(art::Thread* self) {
118 return Notify(self, [&]() { cond_.notify_one(); });
119 }
120
121 bool NotifyAll(art::Thread* self) {
122 return Notify(self, [&]() { cond_.notify_all(); });
123 }
124
125 private:
126 bool IsOwner(art::Thread* self) {
127 // There's a subtle correctness argument here for a relaxed load outside the critical section.
128 // A thread is guaranteed to see either its own latest store or another thread's store. If a
129 // thread sees another thread's store than it cannot be holding the lock.
130 art::Thread* owner_thread = owner_.load(std::memory_order_relaxed);
131 return self == owner_thread;
132 }
133
134 template <typename T>
135 bool Wait(art::Thread* self, T how_to_wait) {
136 if (!IsOwner(self)) {
137 return false;
138 }
139
140 size_t old_count = count_;
141
142 count_ = 0;
143 owner_.store(nullptr, std::memory_order_relaxed);
144
145 {
146 std::unique_lock<std::mutex> lk(mutex_, std::adopt_lock);
147 how_to_wait(lk);
148 lk.release(); // Do not unlock the mutex.
149 }
150
151 DCHECK(owner_.load(std::memory_order_relaxed) == nullptr);
152 owner_.store(self, std::memory_order_relaxed);
153 DCHECK_EQ(0u, count_);
154 count_ = old_count;
155
156 return true;
157 }
158
159 template <typename T>
160 bool Notify(art::Thread* self, T how_to_notify) {
161 if (!IsOwner(self)) {
162 return false;
163 }
164
165 how_to_notify();
166
167 return true;
168 }
169
170 std::mutex mutex_;
171 std::condition_variable cond_;
172 std::atomic<art::Thread*> owner_;
173 size_t count_;
174};
175
176static jrawMonitorID EncodeMonitor(JvmtiMonitor* monitor) {
177 return reinterpret_cast<jrawMonitorID>(monitor);
178}
179
180static JvmtiMonitor* DecodeMonitor(jrawMonitorID id) {
181 return reinterpret_cast<JvmtiMonitor*>(id);
182}
183
184jvmtiError MonitorUtil::CreateRawMonitor(jvmtiEnv* env ATTRIBUTE_UNUSED,
185 const char* name,
186 jrawMonitorID* monitor_ptr) {
187 if (name == nullptr || monitor_ptr == nullptr) {
188 return ERR(NULL_POINTER);
189 }
190
191 JvmtiMonitor* monitor = new JvmtiMonitor();
192 *monitor_ptr = EncodeMonitor(monitor);
193
194 return ERR(NONE);
195}
196
197jvmtiError MonitorUtil::DestroyRawMonitor(jvmtiEnv* env ATTRIBUTE_UNUSED, jrawMonitorID id) {
198 if (id == nullptr) {
199 return ERR(INVALID_MONITOR);
200 }
201
202 JvmtiMonitor* monitor = DecodeMonitor(id);
203 art::Thread* self = art::Thread::Current();
204
205 if (!JvmtiMonitor::Destroy(self, monitor)) {
206 return ERR(NOT_MONITOR_OWNER);
207 }
208
209 return ERR(NONE);
210}
211
212jvmtiError MonitorUtil::RawMonitorEnter(jvmtiEnv* env ATTRIBUTE_UNUSED, jrawMonitorID id) {
213 if (id == nullptr) {
214 return ERR(INVALID_MONITOR);
215 }
216
217 JvmtiMonitor* monitor = DecodeMonitor(id);
218 art::Thread* self = art::Thread::Current();
219
220 monitor->MonitorEnter(self);
221
222 return ERR(NONE);
223}
224
225jvmtiError MonitorUtil::RawMonitorExit(jvmtiEnv* env ATTRIBUTE_UNUSED, jrawMonitorID id) {
226 if (id == nullptr) {
227 return ERR(INVALID_MONITOR);
228 }
229
230 JvmtiMonitor* monitor = DecodeMonitor(id);
231 art::Thread* self = art::Thread::Current();
232
233 if (!monitor->MonitorExit(self)) {
234 return ERR(NOT_MONITOR_OWNER);
235 }
236
237 return ERR(NONE);
238}
239
240jvmtiError MonitorUtil::RawMonitorWait(jvmtiEnv* env ATTRIBUTE_UNUSED,
241 jrawMonitorID id,
242 jlong millis) {
243 if (id == nullptr) {
244 return ERR(INVALID_MONITOR);
245 }
246
247 JvmtiMonitor* monitor = DecodeMonitor(id);
248 art::Thread* self = art::Thread::Current();
249
250 // This is not in the spec, but it's the only thing that makes sense (and agrees with
251 // Object.wait).
252 if (millis < 0) {
253 return ERR(ILLEGAL_ARGUMENT);
254 }
255
256 bool result = (millis > 0)
257 ? monitor->Wait(self, static_cast<uint64_t>(millis))
258 : monitor->Wait(self);
259
260 if (!result) {
261 return ERR(NOT_MONITOR_OWNER);
262 }
263
264 // TODO: Make sure that is really what we should be checking here.
265 if (self->IsInterrupted()) {
266 return ERR(INTERRUPT);
267 }
268
269 return ERR(NONE);
270}
271
272jvmtiError MonitorUtil::RawMonitorNotify(jvmtiEnv* env ATTRIBUTE_UNUSED, jrawMonitorID id) {
273 if (id == nullptr) {
274 return ERR(INVALID_MONITOR);
275 }
276
277 JvmtiMonitor* monitor = DecodeMonitor(id);
278 art::Thread* self = art::Thread::Current();
279
280 if (!monitor->Notify(self)) {
281 return ERR(NOT_MONITOR_OWNER);
282 }
283
284 return ERR(NONE);
285}
286
287jvmtiError MonitorUtil::RawMonitorNotifyAll(jvmtiEnv* env ATTRIBUTE_UNUSED, jrawMonitorID id) {
288 if (id == nullptr) {
289 return ERR(INVALID_MONITOR);
290 }
291
292 JvmtiMonitor* monitor = DecodeMonitor(id);
293 art::Thread* self = art::Thread::Current();
294
295 if (!monitor->NotifyAll(self)) {
296 return ERR(NOT_MONITOR_OWNER);
297 }
298
299 return ERR(NONE);
300}
301
302} // namespace openjdkjvmti