blob: aaedb23e4504212ae8ed8dc9091cca1bfcf7bd5c [file] [log] [blame]
Andreas Gampe04bbb5b2017-01-19 17:49:03 +00001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "runtime_callbacks.h"
18
Andreas Gampea5814f92017-01-18 21:43:16 -080019#include <signal.h>
20#include <sys/types.h>
21#include <unistd.h>
Andreas Gampe0f01b582017-01-18 15:22:37 -080022
23#include <initializer_list>
Andreas Gampe04bbb5b2017-01-19 17:49:03 +000024#include <memory>
Igor Murashkin5573c372017-11-16 13:34:30 -080025#include <mutex>
Andreas Gampe04bbb5b2017-01-19 17:49:03 +000026#include <string>
27
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070028#include "jni.h"
29
Andreas Gampe04bbb5b2017-01-19 17:49:03 +000030#include "art_method-inl.h"
David Sehr79e26072018-04-06 17:58:50 -070031#include "base/mem_map.h"
Andreas Gampe04bbb5b2017-01-19 17:49:03 +000032#include "base/mutex.h"
Andreas Gampe0f01b582017-01-18 15:22:37 -080033#include "class_linker.h"
Andreas Gampe04bbb5b2017-01-19 17:49:03 +000034#include "common_runtime_test.h"
David Sehr312f3b22018-03-19 08:39:26 -070035#include "dex/class_reference.h"
Andreas Gampe0f01b582017-01-18 15:22:37 -080036#include "handle.h"
37#include "handle_scope-inl.h"
Andreas Gampe0f01b582017-01-18 15:22:37 -080038#include "mirror/class-inl.h"
39#include "mirror/class_loader.h"
Alex Light77fee872017-09-05 14:51:49 -070040#include "monitor.h"
Andreas Gampe373a9b52017-10-18 09:01:57 -070041#include "nativehelper/scoped_local_ref.h"
Andreas Gampe04bbb5b2017-01-19 17:49:03 +000042#include "obj_ptr.h"
43#include "runtime.h"
44#include "scoped_thread_state_change-inl.h"
Andreas Gampe04bbb5b2017-01-19 17:49:03 +000045#include "thread-inl.h"
46#include "thread_list.h"
47#include "well_known_classes.h"
48
49namespace art {
50
51class RuntimeCallbacksTest : public CommonRuntimeTest {
52 protected:
Roland Levillainbbc6e7e2018-08-24 16:58:47 +010053 void SetUp() override {
Andreas Gampe04bbb5b2017-01-19 17:49:03 +000054 CommonRuntimeTest::SetUp();
55
56 Thread* self = Thread::Current();
57 ScopedObjectAccess soa(self);
58 ScopedThreadSuspension sts(self, kWaitingForDebuggerToAttach);
59 ScopedSuspendAll ssa("RuntimeCallbacksTest SetUp");
60 AddListener();
61 }
62
Roland Levillainbbc6e7e2018-08-24 16:58:47 +010063 void TearDown() override {
Andreas Gampe04bbb5b2017-01-19 17:49:03 +000064 {
65 Thread* self = Thread::Current();
66 ScopedObjectAccess soa(self);
67 ScopedThreadSuspension sts(self, kWaitingForDebuggerToAttach);
68 ScopedSuspendAll ssa("RuntimeCallbacksTest TearDown");
Andreas Gampe04bbb5b2017-01-19 17:49:03 +000069 RemoveListener();
70 }
71
72 CommonRuntimeTest::TearDown();
73 }
74
75 virtual void AddListener() REQUIRES(Locks::mutator_lock_) = 0;
76 virtual void RemoveListener() REQUIRES(Locks::mutator_lock_) = 0;
77
78 void MakeExecutable(ObjPtr<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_) {
79 CHECK(klass != nullptr);
80 PointerSize pointer_size = class_linker_->GetImagePointerSize();
81 for (auto& m : klass->GetMethods(pointer_size)) {
82 if (!m.IsAbstract()) {
83 class_linker_->SetEntryPointsToInterpreter(&m);
84 }
85 }
86 }
87};
88
89class ThreadLifecycleCallbackRuntimeCallbacksTest : public RuntimeCallbacksTest {
90 public:
91 static void* PthreadsCallback(void* arg ATTRIBUTE_UNUSED) {
92 // Attach.
93 Runtime* runtime = Runtime::Current();
94 CHECK(runtime->AttachCurrentThread("ThreadLifecycle test thread", true, nullptr, false));
95
96 // Detach.
97 runtime->DetachCurrentThread();
98
99 // Die...
100 return nullptr;
101 }
102
103 protected:
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100104 void AddListener() override REQUIRES(Locks::mutator_lock_) {
Andreas Gampeac30fa22017-01-18 21:02:36 -0800105 Runtime::Current()->GetRuntimeCallbacks()->AddThreadLifecycleCallback(&cb_);
Andreas Gampe04bbb5b2017-01-19 17:49:03 +0000106 }
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100107 void RemoveListener() override REQUIRES(Locks::mutator_lock_) {
Andreas Gampeac30fa22017-01-18 21:02:36 -0800108 Runtime::Current()->GetRuntimeCallbacks()->RemoveThreadLifecycleCallback(&cb_);
Andreas Gampe04bbb5b2017-01-19 17:49:03 +0000109 }
110
111 enum CallbackState {
112 kBase,
113 kStarted,
114 kDied,
115 kWrongStart,
116 kWrongDeath,
117 };
118
119 struct Callback : public ThreadLifecycleCallback {
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100120 void ThreadStart(Thread* self) override {
Andreas Gampe04bbb5b2017-01-19 17:49:03 +0000121 if (state == CallbackState::kBase) {
122 state = CallbackState::kStarted;
123 stored_self = self;
124 } else {
125 state = CallbackState::kWrongStart;
126 }
127 }
128
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100129 void ThreadDeath(Thread* self) override {
Andreas Gampe04bbb5b2017-01-19 17:49:03 +0000130 if (state == CallbackState::kStarted && self == stored_self) {
131 state = CallbackState::kDied;
132 } else {
133 state = CallbackState::kWrongDeath;
134 }
135 }
136
137 Thread* stored_self;
138 CallbackState state = CallbackState::kBase;
139 };
140
141 Callback cb_;
142};
143
Andreas Gampe04bbb5b2017-01-19 17:49:03 +0000144TEST_F(ThreadLifecycleCallbackRuntimeCallbacksTest, ThreadLifecycleCallbackJava) {
145 Thread* self = Thread::Current();
146
147 self->TransitionFromSuspendedToRunnable();
148 bool started = runtime_->Start();
149 ASSERT_TRUE(started);
150
151 cb_.state = CallbackState::kBase; // Ignore main thread attach.
152
153 {
154 ScopedObjectAccess soa(self);
155 MakeExecutable(soa.Decode<mirror::Class>(WellKnownClasses::java_lang_Thread));
156 }
157
158 JNIEnv* env = self->GetJniEnv();
159
160 ScopedLocalRef<jobject> thread_name(env,
161 env->NewStringUTF("ThreadLifecycleCallback test thread"));
162 ASSERT_TRUE(thread_name.get() != nullptr);
163
164 ScopedLocalRef<jobject> thread(env, env->AllocObject(WellKnownClasses::java_lang_Thread));
165 ASSERT_TRUE(thread.get() != nullptr);
166
167 env->CallNonvirtualVoidMethod(thread.get(),
168 WellKnownClasses::java_lang_Thread,
169 WellKnownClasses::java_lang_Thread_init,
170 runtime_->GetMainThreadGroup(),
171 thread_name.get(),
172 kMinThreadPriority,
173 JNI_FALSE);
174 ASSERT_FALSE(env->ExceptionCheck());
175
176 jmethodID start_id = env->GetMethodID(WellKnownClasses::java_lang_Thread, "start", "()V");
177 ASSERT_TRUE(start_id != nullptr);
178
179 env->CallVoidMethod(thread.get(), start_id);
180 ASSERT_FALSE(env->ExceptionCheck());
181
182 jmethodID join_id = env->GetMethodID(WellKnownClasses::java_lang_Thread, "join", "()V");
183 ASSERT_TRUE(join_id != nullptr);
184
185 env->CallVoidMethod(thread.get(), join_id);
186 ASSERT_FALSE(env->ExceptionCheck());
187
188 EXPECT_TRUE(cb_.state == CallbackState::kDied) << static_cast<int>(cb_.state);
189}
190
191TEST_F(ThreadLifecycleCallbackRuntimeCallbacksTest, ThreadLifecycleCallbackAttach) {
192 std::string error_msg;
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100193 MemMap stack = MemMap::MapAnonymous("ThreadLifecycleCallback Thread",
194 /* addr */ nullptr,
195 128 * kPageSize, // Just some small stack.
196 PROT_READ | PROT_WRITE,
Vladimir Markof6985bd2018-08-24 09:02:28 +0100197 /* low_4gb */ false,
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100198 &error_msg);
199 ASSERT_TRUE(stack.IsValid()) << error_msg;
Andreas Gampe04bbb5b2017-01-19 17:49:03 +0000200
201 const char* reason = "ThreadLifecycleCallback test thread";
202 pthread_attr_t attr;
203 CHECK_PTHREAD_CALL(pthread_attr_init, (&attr), reason);
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100204 CHECK_PTHREAD_CALL(pthread_attr_setstack, (&attr, stack.Begin(), stack.Size()), reason);
Andreas Gampe04bbb5b2017-01-19 17:49:03 +0000205 pthread_t pthread;
206 CHECK_PTHREAD_CALL(pthread_create,
207 (&pthread,
208 &attr,
209 &ThreadLifecycleCallbackRuntimeCallbacksTest::PthreadsCallback,
210 this),
211 reason);
212 CHECK_PTHREAD_CALL(pthread_attr_destroy, (&attr), reason);
213
214 CHECK_PTHREAD_CALL(pthread_join, (pthread, nullptr), "ThreadLifecycleCallback test shutdown");
215
216 // Detach is not a ThreadDeath event, so we expect to be in state Started.
217 EXPECT_TRUE(cb_.state == CallbackState::kStarted) << static_cast<int>(cb_.state);
218}
219
Andreas Gampe0f01b582017-01-18 15:22:37 -0800220class ClassLoadCallbackRuntimeCallbacksTest : public RuntimeCallbacksTest {
221 protected:
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100222 void AddListener() override REQUIRES(Locks::mutator_lock_) {
Andreas Gampeac30fa22017-01-18 21:02:36 -0800223 Runtime::Current()->GetRuntimeCallbacks()->AddClassLoadCallback(&cb_);
Andreas Gampe0f01b582017-01-18 15:22:37 -0800224 }
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100225 void RemoveListener() override REQUIRES(Locks::mutator_lock_) {
Andreas Gampeac30fa22017-01-18 21:02:36 -0800226 Runtime::Current()->GetRuntimeCallbacks()->RemoveClassLoadCallback(&cb_);
Andreas Gampe0f01b582017-01-18 15:22:37 -0800227 }
228
229 bool Expect(std::initializer_list<const char*> list) {
230 if (cb_.data.size() != list.size()) {
231 PrintError(list);
232 return false;
233 }
234
235 if (!std::equal(cb_.data.begin(), cb_.data.end(), list.begin())) {
236 PrintError(list);
237 return false;
238 }
239
240 return true;
241 }
242
243 void PrintError(std::initializer_list<const char*> list) {
244 LOG(ERROR) << "Expected:";
245 for (const char* expected : list) {
246 LOG(ERROR) << " " << expected;
247 }
248 LOG(ERROR) << "Found:";
249 for (const auto& s : cb_.data) {
250 LOG(ERROR) << " " << s;
251 }
252 }
253
254 struct Callback : public ClassLoadCallback {
Roland Levillainf73caca2018-08-24 17:19:07 +0100255 void ClassPreDefine(const char* descriptor,
256 Handle<mirror::Class> klass ATTRIBUTE_UNUSED,
257 Handle<mirror::ClassLoader> class_loader ATTRIBUTE_UNUSED,
258 const DexFile& initial_dex_file,
259 const DexFile::ClassDef& initial_class_def ATTRIBUTE_UNUSED,
260 /*out*/DexFile const** final_dex_file ATTRIBUTE_UNUSED,
261 /*out*/DexFile::ClassDef const** final_class_def ATTRIBUTE_UNUSED) override
262 REQUIRES_SHARED(Locks::mutator_lock_) {
Andreas Gampe641a4732017-08-24 13:21:35 -0700263 const std::string& location = initial_dex_file.GetLocation();
Alex Lightb0f11922017-01-23 14:25:17 -0800264 std::string event =
265 std::string("PreDefine:") + descriptor + " <" +
Andreas Gampe5555dd12017-08-24 13:50:21 -0700266 location.substr(location.rfind('/') + 1, location.size()) + ">";
Alex Lightb0f11922017-01-23 14:25:17 -0800267 data.push_back(event);
268 }
269
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100270 void ClassLoad(Handle<mirror::Class> klass) override REQUIRES_SHARED(Locks::mutator_lock_) {
Andreas Gampe0f01b582017-01-18 15:22:37 -0800271 std::string tmp;
272 std::string event = std::string("Load:") + klass->GetDescriptor(&tmp);
273 data.push_back(event);
274 }
275
276 void ClassPrepare(Handle<mirror::Class> temp_klass,
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100277 Handle<mirror::Class> klass) override REQUIRES_SHARED(Locks::mutator_lock_) {
Andreas Gampe0f01b582017-01-18 15:22:37 -0800278 std::string tmp, tmp2;
279 std::string event = std::string("Prepare:") + klass->GetDescriptor(&tmp)
280 + "[" + temp_klass->GetDescriptor(&tmp2) + "]";
281 data.push_back(event);
282 }
283
284 std::vector<std::string> data;
285 };
286
287 Callback cb_;
288};
289
290TEST_F(ClassLoadCallbackRuntimeCallbacksTest, ClassLoadCallback) {
291 ScopedObjectAccess soa(Thread::Current());
292 jobject jclass_loader = LoadDex("XandY");
293 VariableSizedHandleScope hs(soa.Self());
294 Handle<mirror::ClassLoader> class_loader(hs.NewHandle(
295 soa.Decode<mirror::ClassLoader>(jclass_loader)));
296
297 const char* descriptor_y = "LY;";
298 Handle<mirror::Class> h_Y(
299 hs.NewHandle(class_linker_->FindClass(soa.Self(), descriptor_y, class_loader)));
Andreas Gampefa4333d2017-02-14 11:10:34 -0800300 ASSERT_TRUE(h_Y != nullptr);
Andreas Gampe0f01b582017-01-18 15:22:37 -0800301
Alex Lightb0f11922017-01-23 14:25:17 -0800302 bool expect1 = Expect({ "PreDefine:LY; <art-gtest-XandY.jar>",
303 "PreDefine:LX; <art-gtest-XandY.jar>",
304 "Load:LX;",
305 "Prepare:LX;[LX;]",
306 "Load:LY;",
307 "Prepare:LY;[LY;]" });
Andreas Gampe0f01b582017-01-18 15:22:37 -0800308 EXPECT_TRUE(expect1);
309
310 cb_.data.clear();
311
312 ASSERT_TRUE(class_linker_->EnsureInitialized(Thread::Current(), h_Y, true, true));
313
Alex Lightb0f11922017-01-23 14:25:17 -0800314 bool expect2 = Expect({ "PreDefine:LY$Z; <art-gtest-XandY.jar>",
315 "Load:LY$Z;",
316 "Prepare:LY$Z;[LY$Z;]" });
Andreas Gampe0f01b582017-01-18 15:22:37 -0800317 EXPECT_TRUE(expect2);
318}
319
Andreas Gampea5814f92017-01-18 21:43:16 -0800320class RuntimeSigQuitCallbackRuntimeCallbacksTest : public RuntimeCallbacksTest {
321 protected:
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100322 void AddListener() override REQUIRES(Locks::mutator_lock_) {
Andreas Gampea5814f92017-01-18 21:43:16 -0800323 Runtime::Current()->GetRuntimeCallbacks()->AddRuntimeSigQuitCallback(&cb_);
324 }
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100325 void RemoveListener() override REQUIRES(Locks::mutator_lock_) {
Andreas Gampea5814f92017-01-18 21:43:16 -0800326 Runtime::Current()->GetRuntimeCallbacks()->RemoveRuntimeSigQuitCallback(&cb_);
327 }
328
329 struct Callback : public RuntimeSigQuitCallback {
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100330 void SigQuit() override {
Andreas Gampea5814f92017-01-18 21:43:16 -0800331 ++sigquit_count;
332 }
333
334 size_t sigquit_count = 0;
335 };
336
337 Callback cb_;
338};
339
340TEST_F(RuntimeSigQuitCallbackRuntimeCallbacksTest, SigQuit) {
341 // The runtime needs to be started for the signal handler.
342 Thread* self = Thread::Current();
343
344 self->TransitionFromSuspendedToRunnable();
345 bool started = runtime_->Start();
346 ASSERT_TRUE(started);
347
348 EXPECT_EQ(0u, cb_.sigquit_count);
349
350 kill(getpid(), SIGQUIT);
351
352 // Try a few times.
353 for (size_t i = 0; i != 30; ++i) {
354 if (cb_.sigquit_count == 0) {
355 sleep(1);
356 } else {
357 break;
358 }
359 }
360 EXPECT_EQ(1u, cb_.sigquit_count);
361}
362
Andreas Gampe48864112017-01-19 17:23:17 -0800363class RuntimePhaseCallbackRuntimeCallbacksTest : public RuntimeCallbacksTest {
364 protected:
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100365 void AddListener() override REQUIRES(Locks::mutator_lock_) {
Andreas Gampe48864112017-01-19 17:23:17 -0800366 Runtime::Current()->GetRuntimeCallbacks()->AddRuntimePhaseCallback(&cb_);
367 }
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100368 void RemoveListener() override REQUIRES(Locks::mutator_lock_) {
Andreas Gampe48864112017-01-19 17:23:17 -0800369 Runtime::Current()->GetRuntimeCallbacks()->RemoveRuntimePhaseCallback(&cb_);
370 }
371
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100372 void TearDown() override {
Andreas Gampe48864112017-01-19 17:23:17 -0800373 // Bypass RuntimeCallbacksTest::TearDown, as the runtime is already gone.
374 CommonRuntimeTest::TearDown();
375 }
376
377 struct Callback : public RuntimePhaseCallback {
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100378 void NextRuntimePhase(RuntimePhaseCallback::RuntimePhase p) override {
Andreas Gampe96eca782017-01-19 19:45:30 -0800379 if (p == RuntimePhaseCallback::RuntimePhase::kInitialAgents) {
380 if (start_seen > 0 || init_seen > 0 || death_seen > 0) {
381 LOG(FATAL) << "Unexpected order";
382 }
383 ++initial_agents_seen;
384 } else if (p == RuntimePhaseCallback::RuntimePhase::kStart) {
385 if (init_seen > 0 || death_seen > 0) {
Andreas Gampe48864112017-01-19 17:23:17 -0800386 LOG(FATAL) << "Init seen before start.";
387 }
388 ++start_seen;
389 } else if (p == RuntimePhaseCallback::RuntimePhase::kInit) {
390 ++init_seen;
391 } else if (p == RuntimePhaseCallback::RuntimePhase::kDeath) {
392 ++death_seen;
393 } else {
394 LOG(FATAL) << "Unknown phase " << static_cast<uint32_t>(p);
395 }
396 }
397
Andreas Gampe96eca782017-01-19 19:45:30 -0800398 size_t initial_agents_seen = 0;
Andreas Gampe48864112017-01-19 17:23:17 -0800399 size_t start_seen = 0;
400 size_t init_seen = 0;
401 size_t death_seen = 0;
402 };
403
404 Callback cb_;
405};
406
407TEST_F(RuntimePhaseCallbackRuntimeCallbacksTest, Phases) {
Andreas Gampe96eca782017-01-19 19:45:30 -0800408 ASSERT_EQ(0u, cb_.initial_agents_seen);
Andreas Gampe48864112017-01-19 17:23:17 -0800409 ASSERT_EQ(0u, cb_.start_seen);
410 ASSERT_EQ(0u, cb_.init_seen);
411 ASSERT_EQ(0u, cb_.death_seen);
412
413 // Start the runtime.
414 {
415 Thread* self = Thread::Current();
416 self->TransitionFromSuspendedToRunnable();
417 bool started = runtime_->Start();
418 ASSERT_TRUE(started);
419 }
420
Andreas Gampe96eca782017-01-19 19:45:30 -0800421 ASSERT_EQ(0u, cb_.initial_agents_seen);
Andreas Gampe48864112017-01-19 17:23:17 -0800422 ASSERT_EQ(1u, cb_.start_seen);
423 ASSERT_EQ(1u, cb_.init_seen);
424 ASSERT_EQ(0u, cb_.death_seen);
425
426 // Delete the runtime.
427 runtime_.reset();
428
Andreas Gampe96eca782017-01-19 19:45:30 -0800429 ASSERT_EQ(0u, cb_.initial_agents_seen);
Andreas Gampe48864112017-01-19 17:23:17 -0800430 ASSERT_EQ(1u, cb_.start_seen);
431 ASSERT_EQ(1u, cb_.init_seen);
432 ASSERT_EQ(1u, cb_.death_seen);
433}
434
Alex Light77fee872017-09-05 14:51:49 -0700435class MonitorWaitCallbacksTest : public RuntimeCallbacksTest {
436 protected:
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100437 void AddListener() override REQUIRES(Locks::mutator_lock_) {
Alex Light77fee872017-09-05 14:51:49 -0700438 Runtime::Current()->GetRuntimeCallbacks()->AddMonitorCallback(&cb_);
439 }
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100440 void RemoveListener() override REQUIRES(Locks::mutator_lock_) {
Alex Light77fee872017-09-05 14:51:49 -0700441 Runtime::Current()->GetRuntimeCallbacks()->RemoveMonitorCallback(&cb_);
442 }
443
444 struct Callback : public MonitorCallback {
445 bool IsInterestingObject(mirror::Object* obj) REQUIRES_SHARED(art::Locks::mutator_lock_) {
446 if (!obj->IsClass()) {
447 return false;
448 }
449 std::lock_guard<std::mutex> lock(ref_guard_);
450 mirror::Class* k = obj->AsClass();
451 ClassReference test = { &k->GetDexFile(), k->GetDexClassDefIndex() };
452 return ref_ == test;
453 }
454
455 void SetInterestingObject(mirror::Object* obj) REQUIRES_SHARED(art::Locks::mutator_lock_) {
456 std::lock_guard<std::mutex> lock(ref_guard_);
457 mirror::Class* k = obj->AsClass();
458 ref_ = { &k->GetDexFile(), k->GetDexClassDefIndex() };
459 }
460
461 void MonitorContendedLocking(Monitor* mon ATTRIBUTE_UNUSED)
462 REQUIRES_SHARED(Locks::mutator_lock_) { }
463
464 void MonitorContendedLocked(Monitor* mon ATTRIBUTE_UNUSED)
465 REQUIRES_SHARED(Locks::mutator_lock_) { }
466
467 void ObjectWaitStart(Handle<mirror::Object> obj, int64_t millis ATTRIBUTE_UNUSED)
468 REQUIRES_SHARED(Locks::mutator_lock_) {
469 if (IsInterestingObject(obj.Get())) {
470 saw_wait_start_ = true;
471 }
472 }
473
474 void MonitorWaitFinished(Monitor* m, bool timed_out ATTRIBUTE_UNUSED)
475 REQUIRES_SHARED(Locks::mutator_lock_) {
476 if (IsInterestingObject(m->GetObject())) {
477 saw_wait_finished_ = true;
478 }
479 }
480
481 std::mutex ref_guard_;
482 ClassReference ref_ = {nullptr, 0};
483 bool saw_wait_start_ = false;
484 bool saw_wait_finished_ = false;
485 };
486
487 Callback cb_;
488};
489
490// TODO It would be good to have more tests for this but due to the multi-threaded nature of the
491// callbacks this is difficult. For now the run-tests 1931 & 1932 should be sufficient.
492TEST_F(MonitorWaitCallbacksTest, WaitUnlocked) {
493 ASSERT_FALSE(cb_.saw_wait_finished_);
494 ASSERT_FALSE(cb_.saw_wait_start_);
495 {
496 Thread* self = Thread::Current();
497 self->TransitionFromSuspendedToRunnable();
498 bool started = runtime_->Start();
499 ASSERT_TRUE(started);
500 {
501 ScopedObjectAccess soa(self);
502 cb_.SetInterestingObject(
503 soa.Decode<mirror::Class>(WellKnownClasses::java_util_Collections).Ptr());
504 Monitor::Wait(
505 self,
506 // Just a random class
507 soa.Decode<mirror::Class>(WellKnownClasses::java_util_Collections).Ptr(),
508 /*ms*/0,
509 /*ns*/0,
510 /*interruptShouldThrow*/false,
511 /*why*/kWaiting);
512 }
513 }
514 ASSERT_TRUE(cb_.saw_wait_start_);
515 ASSERT_FALSE(cb_.saw_wait_finished_);
516}
517
Andreas Gampe04bbb5b2017-01-19 17:49:03 +0000518} // namespace art