• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
44 namespace 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 
52 class JvmtiMonitor {
53  public:
JvmtiMonitor()54   JvmtiMonitor() : owner_(nullptr), count_(0) {
55   }
56 
Destroy(art::Thread * self,JvmtiMonitor * monitor)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 
MonitorEnter(art::Thread * self)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 
MonitorExit(art::Thread * self)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 
Wait(art::Thread * self)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 
Wait(art::Thread * self,uint64_t timeout_in_ms)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 
Notify(art::Thread * self)117   bool Notify(art::Thread* self) {
118     return Notify(self, [&]() { cond_.notify_one(); });
119   }
120 
NotifyAll(art::Thread * self)121   bool NotifyAll(art::Thread* self) {
122     return Notify(self, [&]() { cond_.notify_all(); });
123   }
124 
125  private:
IsOwner(art::Thread * self)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>
Wait(art::Thread * self,T how_to_wait)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>
Notify(art::Thread * self,T how_to_notify)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 
EncodeMonitor(JvmtiMonitor * monitor)176 static jrawMonitorID EncodeMonitor(JvmtiMonitor* monitor) {
177   return reinterpret_cast<jrawMonitorID>(monitor);
178 }
179 
DecodeMonitor(jrawMonitorID id)180 static JvmtiMonitor* DecodeMonitor(jrawMonitorID id) {
181   return reinterpret_cast<JvmtiMonitor*>(id);
182 }
183 
CreateRawMonitor(jvmtiEnv * env ATTRIBUTE_UNUSED,const char * name,jrawMonitorID * monitor_ptr)184 jvmtiError 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 
DestroyRawMonitor(jvmtiEnv * env ATTRIBUTE_UNUSED,jrawMonitorID id)197 jvmtiError 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 
RawMonitorEnter(jvmtiEnv * env ATTRIBUTE_UNUSED,jrawMonitorID id)212 jvmtiError 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 
RawMonitorExit(jvmtiEnv * env ATTRIBUTE_UNUSED,jrawMonitorID id)225 jvmtiError 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 
RawMonitorWait(jvmtiEnv * env ATTRIBUTE_UNUSED,jrawMonitorID id,jlong millis)240 jvmtiError 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 
RawMonitorNotify(jvmtiEnv * env ATTRIBUTE_UNUSED,jrawMonitorID id)272 jvmtiError 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 
RawMonitorNotifyAll(jvmtiEnv * env ATTRIBUTE_UNUSED,jrawMonitorID id)287 jvmtiError 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