1/* 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) NO_THREAD_SAFETY_ANALYSIS { 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) NO_THREAD_SAFETY_ANALYSIS { 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) NO_THREAD_SAFETY_ANALYSIS { 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 303