From c0440f69ebf051ff2ffdc00de51005a040014462 Mon Sep 17 00:00:00 2001 From: Andreas Gampe Date: Thu, 22 Jan 2015 19:48:51 -0800 Subject: [PATCH] ART: On shutdown, only warn on mutex contention Do not abort, as daemon threads may still be active. Bug: 17894429 Change-Id: I7c1d50ff8d4a5e150279e703a69c8f2f1d423e6b --- runtime/base/mutex.cc | 24 ++++++++----- test/132-daemon-locks-shutdown/expected.txt | 0 test/132-daemon-locks-shutdown/info.txt | 1 + test/132-daemon-locks-shutdown/src/Main.java | 53 ++++++++++++++++++++++++++++ 4 files changed, 70 insertions(+), 8 deletions(-) create mode 100644 test/132-daemon-locks-shutdown/expected.txt create mode 100644 test/132-daemon-locks-shutdown/info.txt create mode 100644 test/132-daemon-locks-shutdown/src/Main.java diff --git a/runtime/base/mutex.cc b/runtime/base/mutex.cc index 495ea5c10..3f015de6f 100644 --- a/runtime/base/mutex.cc +++ b/runtime/base/mutex.cc @@ -276,16 +276,26 @@ Mutex::Mutex(const char* name, LockLevel level, bool recursive) exclusive_owner_ = 0; } +// Helper to ignore the lock requirement. +static bool IsShuttingDown() NO_THREAD_SAFETY_ANALYSIS { + Runtime* runtime = Runtime::Current(); + return runtime == nullptr || runtime->IsShuttingDownLocked(); +} + Mutex::~Mutex() { + bool shutting_down = IsShuttingDown(); #if ART_USE_FUTEXES if (state_.LoadRelaxed() != 0) { - Runtime* runtime = Runtime::Current(); - bool shutting_down = runtime == nullptr || runtime->IsShuttingDown(Thread::Current()); - LOG(shutting_down ? WARNING : FATAL) << "destroying mutex with owner: " << exclusive_owner_; + LOG(shutting_down ? WARNING : FATAL) << "destroying mutex with owner: " + << exclusive_owner_; } else { - CHECK_EQ(exclusive_owner_, 0U) << "unexpectedly found an owner on unlocked mutex " << name_; - CHECK_EQ(num_contenders_.LoadSequentiallyConsistent(), 0) - << "unexpectedly found a contender on mutex " << name_; + if (exclusive_owner_ != 0) { + LOG(shutting_down ? WARNING : FATAL) << "unexpectedly found an owner on unlocked mutex " + << name_; + } + if (num_contenders_.LoadSequentiallyConsistent() != 0) { + LOG(shutting_down ? WARNING : FATAL) << "unexpectedly found a contender on mutex " << name_; + } } #else // We can't use CHECK_MUTEX_CALL here because on shutdown a suspended daemon thread @@ -295,8 +305,6 @@ Mutex::~Mutex() { errno = rc; // TODO: should we just not log at all if shutting down? this could be the logging mutex! MutexLock mu(Thread::Current(), *Locks::runtime_shutdown_lock_); - Runtime* runtime = Runtime::Current(); - bool shutting_down = (runtime == NULL) || runtime->IsShuttingDownLocked(); PLOG(shutting_down ? WARNING : FATAL) << "pthread_mutex_destroy failed for " << name_; } #endif diff --git a/test/132-daemon-locks-shutdown/expected.txt b/test/132-daemon-locks-shutdown/expected.txt new file mode 100644 index 000000000..e69de29bb diff --git a/test/132-daemon-locks-shutdown/info.txt b/test/132-daemon-locks-shutdown/info.txt new file mode 100644 index 000000000..f8040643d --- /dev/null +++ b/test/132-daemon-locks-shutdown/info.txt @@ -0,0 +1 @@ +Tests that we can shut down the runtime with daemons still looping over locks. diff --git a/test/132-daemon-locks-shutdown/src/Main.java b/test/132-daemon-locks-shutdown/src/Main.java new file mode 100644 index 000000000..b5bbc8cbe --- /dev/null +++ b/test/132-daemon-locks-shutdown/src/Main.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Test that daemon threads still contending for a lock don't make the runtime abort on shutdown. + */ +public class Main { + + public final static int THREAD_COUNT = 32; + + public static void main(String[] args) throws Exception { + Object sync = new Object(); + + for (int i = 0; i < THREAD_COUNT; i++) { + Thread t = new Thread(new Wait(sync)); + t.setDaemon(true); + t.start(); + } + } + + private static class Wait implements Runnable { + private Object obj; + + public Wait(Object obj) { + this.obj = obj; + } + + public void run() { + for (;;) { + synchronized(obj) { + try { + obj.wait(1); + } catch (Exception exc) { + exc.printStackTrace(System.out); + } + } + } + } + } +} -- 2.11.0