1*6777b538SAndroid Build Coastguard Worker // Copyright 2011 The Chromium Authors 2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be 3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file. 4*6777b538SAndroid Build Coastguard Worker 5*6777b538SAndroid Build Coastguard Worker #include "base/at_exit.h" 6*6777b538SAndroid Build Coastguard Worker 7*6777b538SAndroid Build Coastguard Worker #include <stddef.h> 8*6777b538SAndroid Build Coastguard Worker #include <ostream> 9*6777b538SAndroid Build Coastguard Worker #include <utility> 10*6777b538SAndroid Build Coastguard Worker 11*6777b538SAndroid Build Coastguard Worker #include "base/check_op.h" 12*6777b538SAndroid Build Coastguard Worker #include "base/functional/bind.h" 13*6777b538SAndroid Build Coastguard Worker #include "base/functional/callback.h" 14*6777b538SAndroid Build Coastguard Worker #include "base/notreached.h" 15*6777b538SAndroid Build Coastguard Worker 16*6777b538SAndroid Build Coastguard Worker namespace base { 17*6777b538SAndroid Build Coastguard Worker 18*6777b538SAndroid Build Coastguard Worker // Keep a stack of registered AtExitManagers. We always operate on the most 19*6777b538SAndroid Build Coastguard Worker // recent, and we should never have more than one outside of testing (for a 20*6777b538SAndroid Build Coastguard Worker // statically linked version of this library). Testing may use the shadow 21*6777b538SAndroid Build Coastguard Worker // version of the constructor, and if we are building a dynamic library we may 22*6777b538SAndroid Build Coastguard Worker // end up with multiple AtExitManagers on the same process. We don't protect 23*6777b538SAndroid Build Coastguard Worker // this for thread-safe access, since it will only be modified in testing. 24*6777b538SAndroid Build Coastguard Worker static AtExitManager* g_top_manager = nullptr; 25*6777b538SAndroid Build Coastguard Worker 26*6777b538SAndroid Build Coastguard Worker static bool g_disable_managers = false; 27*6777b538SAndroid Build Coastguard Worker AtExitManager()28*6777b538SAndroid Build Coastguard WorkerAtExitManager::AtExitManager() : next_manager_(g_top_manager) { 29*6777b538SAndroid Build Coastguard Worker // If multiple modules instantiate AtExitManagers they'll end up living in this 30*6777b538SAndroid Build Coastguard Worker // module... they have to coexist. 31*6777b538SAndroid Build Coastguard Worker #if !defined(COMPONENT_BUILD) 32*6777b538SAndroid Build Coastguard Worker DCHECK(!g_top_manager); 33*6777b538SAndroid Build Coastguard Worker #endif 34*6777b538SAndroid Build Coastguard Worker g_top_manager = this; 35*6777b538SAndroid Build Coastguard Worker } 36*6777b538SAndroid Build Coastguard Worker ~AtExitManager()37*6777b538SAndroid Build Coastguard WorkerAtExitManager::~AtExitManager() { 38*6777b538SAndroid Build Coastguard Worker if (!g_top_manager) { 39*6777b538SAndroid Build Coastguard Worker NOTREACHED() << "Tried to ~AtExitManager without an AtExitManager"; 40*6777b538SAndroid Build Coastguard Worker return; 41*6777b538SAndroid Build Coastguard Worker } 42*6777b538SAndroid Build Coastguard Worker DCHECK_EQ(this, g_top_manager); 43*6777b538SAndroid Build Coastguard Worker 44*6777b538SAndroid Build Coastguard Worker if (!g_disable_managers) 45*6777b538SAndroid Build Coastguard Worker ProcessCallbacksNow(); 46*6777b538SAndroid Build Coastguard Worker g_top_manager = next_manager_; 47*6777b538SAndroid Build Coastguard Worker } 48*6777b538SAndroid Build Coastguard Worker 49*6777b538SAndroid Build Coastguard Worker // static RegisterCallback(AtExitCallbackType func,void * param)50*6777b538SAndroid Build Coastguard Workervoid AtExitManager::RegisterCallback(AtExitCallbackType func, void* param) { 51*6777b538SAndroid Build Coastguard Worker DCHECK(func); 52*6777b538SAndroid Build Coastguard Worker RegisterTask(base::BindOnce(func, param)); 53*6777b538SAndroid Build Coastguard Worker } 54*6777b538SAndroid Build Coastguard Worker 55*6777b538SAndroid Build Coastguard Worker // static RegisterTask(base::OnceClosure task)56*6777b538SAndroid Build Coastguard Workervoid AtExitManager::RegisterTask(base::OnceClosure task) { 57*6777b538SAndroid Build Coastguard Worker if (!g_top_manager) { 58*6777b538SAndroid Build Coastguard Worker NOTREACHED() << "Tried to RegisterCallback without an AtExitManager"; 59*6777b538SAndroid Build Coastguard Worker return; 60*6777b538SAndroid Build Coastguard Worker } 61*6777b538SAndroid Build Coastguard Worker 62*6777b538SAndroid Build Coastguard Worker AutoLock lock(g_top_manager->lock_); 63*6777b538SAndroid Build Coastguard Worker #if DCHECK_IS_ON() 64*6777b538SAndroid Build Coastguard Worker DCHECK(!g_top_manager->processing_callbacks_); 65*6777b538SAndroid Build Coastguard Worker #endif 66*6777b538SAndroid Build Coastguard Worker g_top_manager->stack_.push(std::move(task)); 67*6777b538SAndroid Build Coastguard Worker } 68*6777b538SAndroid Build Coastguard Worker 69*6777b538SAndroid Build Coastguard Worker // static ProcessCallbacksNow()70*6777b538SAndroid Build Coastguard Workervoid AtExitManager::ProcessCallbacksNow() { 71*6777b538SAndroid Build Coastguard Worker if (!g_top_manager) { 72*6777b538SAndroid Build Coastguard Worker NOTREACHED() << "Tried to ProcessCallbacksNow without an AtExitManager"; 73*6777b538SAndroid Build Coastguard Worker return; 74*6777b538SAndroid Build Coastguard Worker } 75*6777b538SAndroid Build Coastguard Worker 76*6777b538SAndroid Build Coastguard Worker // Callbacks may try to add new callbacks, so run them without holding 77*6777b538SAndroid Build Coastguard Worker // |lock_|. This is an error and caught by the DCHECK in RegisterTask(), but 78*6777b538SAndroid Build Coastguard Worker // handle it gracefully in release builds so we don't deadlock. 79*6777b538SAndroid Build Coastguard Worker base::stack<base::OnceClosure> tasks; 80*6777b538SAndroid Build Coastguard Worker { 81*6777b538SAndroid Build Coastguard Worker AutoLock lock(g_top_manager->lock_); 82*6777b538SAndroid Build Coastguard Worker tasks.swap(g_top_manager->stack_); 83*6777b538SAndroid Build Coastguard Worker #if DCHECK_IS_ON() 84*6777b538SAndroid Build Coastguard Worker g_top_manager->processing_callbacks_ = true; 85*6777b538SAndroid Build Coastguard Worker #endif 86*6777b538SAndroid Build Coastguard Worker } 87*6777b538SAndroid Build Coastguard Worker 88*6777b538SAndroid Build Coastguard Worker // Relax the cross-thread access restriction to non-thread-safe RefCount. 89*6777b538SAndroid Build Coastguard Worker // It's safe since all other threads should be terminated at this point. 90*6777b538SAndroid Build Coastguard Worker ScopedAllowCrossThreadRefCountAccess allow_cross_thread_ref_count_access; 91*6777b538SAndroid Build Coastguard Worker 92*6777b538SAndroid Build Coastguard Worker while (!tasks.empty()) { 93*6777b538SAndroid Build Coastguard Worker std::move(tasks.top()).Run(); 94*6777b538SAndroid Build Coastguard Worker tasks.pop(); 95*6777b538SAndroid Build Coastguard Worker } 96*6777b538SAndroid Build Coastguard Worker 97*6777b538SAndroid Build Coastguard Worker #if DCHECK_IS_ON() 98*6777b538SAndroid Build Coastguard Worker AutoLock lock(g_top_manager->lock_); 99*6777b538SAndroid Build Coastguard Worker // Expect that all callbacks have been run. 100*6777b538SAndroid Build Coastguard Worker DCHECK(g_top_manager->stack_.empty()); 101*6777b538SAndroid Build Coastguard Worker g_top_manager->processing_callbacks_ = false; 102*6777b538SAndroid Build Coastguard Worker #endif 103*6777b538SAndroid Build Coastguard Worker } 104*6777b538SAndroid Build Coastguard Worker DisableAllAtExitManagers()105*6777b538SAndroid Build Coastguard Workervoid AtExitManager::DisableAllAtExitManagers() { 106*6777b538SAndroid Build Coastguard Worker AutoLock lock(g_top_manager->lock_); 107*6777b538SAndroid Build Coastguard Worker g_disable_managers = true; 108*6777b538SAndroid Build Coastguard Worker } 109*6777b538SAndroid Build Coastguard Worker AtExitManager(bool shadow)110*6777b538SAndroid Build Coastguard WorkerAtExitManager::AtExitManager(bool shadow) : next_manager_(g_top_manager) { 111*6777b538SAndroid Build Coastguard Worker DCHECK(shadow || !g_top_manager); 112*6777b538SAndroid Build Coastguard Worker g_top_manager = this; 113*6777b538SAndroid Build Coastguard Worker } 114*6777b538SAndroid Build Coastguard Worker 115*6777b538SAndroid Build Coastguard Worker } // namespace base 116