xref: /aosp_15_r20/external/cronet/base/at_exit.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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 Worker AtExitManager::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 Worker AtExitManager::~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 Worker void 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 Worker void 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 Worker void 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 Worker void 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 Worker AtExitManager::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