1b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// Use of this source code is governed by a BSD-style license that can be 3b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// found in the LICENSE file. 4b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 5b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/at_exit.h" 6b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 7b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include <stddef.h> 8b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include <ostream> 90c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez#include <utility> 10b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 11b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/bind.h" 12b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/callback.h" 13b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/logging.h" 14b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 15b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratnamespace base { 16b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 17b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// Keep a stack of registered AtExitManagers. We always operate on the most 18b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// recent, and we should never have more than one outside of testing (for a 19b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// statically linked version of this library). Testing may use the shadow 20b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// version of the constructor, and if we are building a dynamic library we may 21b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// end up with multiple AtExitManagers on the same process. We don't protect 22b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// this for thread-safe access, since it will only be modified in testing. 23b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratstatic AtExitManager* g_top_manager = NULL; 24b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 2545779228f8c9e40851cfd23f727e2bd8ffdd4714Alex VakulenkoAtExitManager::AtExitManager() 2645779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko : processing_callbacks_(false), next_manager_(g_top_manager) { 27b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// If multiple modules instantiate AtExitManagers they'll end up living in this 28b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// module... they have to coexist. 29b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#if !defined(COMPONENT_BUILD) 30b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat DCHECK(!g_top_manager); 31b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#endif 32b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat g_top_manager = this; 33b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 34b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 35b8cf94937c52feb53b55c39e3f82094d27de464cDaniel EratAtExitManager::~AtExitManager() { 36b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (!g_top_manager) { 37b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat NOTREACHED() << "Tried to ~AtExitManager without an AtExitManager"; 38b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat return; 39b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 40b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat DCHECK_EQ(this, g_top_manager); 41b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 42b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat ProcessCallbacksNow(); 43b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat g_top_manager = next_manager_; 44b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 45b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 46b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// static 47b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid AtExitManager::RegisterCallback(AtExitCallbackType func, void* param) { 48b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat DCHECK(func); 49b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat RegisterTask(base::Bind(func, param)); 50b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 51b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 52b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// static 53b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid AtExitManager::RegisterTask(base::Closure task) { 54b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (!g_top_manager) { 55b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat NOTREACHED() << "Tried to RegisterCallback without an AtExitManager"; 56b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat return; 57b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 58b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 59b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat AutoLock lock(g_top_manager->lock_); 6045779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko DCHECK(!g_top_manager->processing_callbacks_); 610c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez g_top_manager->stack_.push(std::move(task)); 62b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 63b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 64b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// static 65b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid AtExitManager::ProcessCallbacksNow() { 66b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (!g_top_manager) { 67b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat NOTREACHED() << "Tried to ProcessCallbacksNow without an AtExitManager"; 68b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat return; 69b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 70b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 7145779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko // Callbacks may try to add new callbacks, so run them without holding 7245779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko // |lock_|. This is an error and caught by the DCHECK in RegisterTask(), but 7345779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko // handle it gracefully in release builds so we don't deadlock. 7445779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko std::stack<base::Closure> tasks; 7545779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko { 7645779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko AutoLock lock(g_top_manager->lock_); 7745779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko tasks.swap(g_top_manager->stack_); 7845779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko g_top_manager->processing_callbacks_ = true; 7945779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko } 80b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 8145779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko while (!tasks.empty()) { 8245779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko base::Closure task = tasks.top(); 83b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat task.Run(); 8445779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko tasks.pop(); 85b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 8645779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko 8745779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko // Expect that all callbacks have been run. 8845779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko DCHECK(g_top_manager->stack_.empty()); 89b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 90b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 9145779228f8c9e40851cfd23f727e2bd8ffdd4714Alex VakulenkoAtExitManager::AtExitManager(bool shadow) 9245779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko : processing_callbacks_(false), next_manager_(g_top_manager) { 93b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat DCHECK(shadow || !g_top_manager); 94b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat g_top_manager = this; 95b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 96b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 97b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} // namespace base 98