blob: 52c2151398e310524ee0ceca4caad5e8d3857267 [file] [log] [blame]
scottbyer@chromium.org189aa712012-07-26 05:36:33 +09001// Copyright (c) 2011 The Chromium Authors. All rights reserved.
mmentovai@google.comaa13be62008-09-03 03:20:34 +09002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "base/at_exit.h"
jhawkins@chromium.org8e73d062011-04-05 03:04:37 +09006
7#include <stddef.h>
8#include <ostream>
dcheng7dc91372016-07-06 12:59:26 +09009#include <utility>
jhawkins@chromium.org8e73d062011-04-05 03:04:37 +090010
apatrick@chromium.org035f4af2011-09-07 08:14:47 +090011#include "base/bind.h"
ajwong@chromium.orge4f3dc32012-01-07 07:12:28 +090012#include "base/callback.h"
mmentovai@google.comaa13be62008-09-03 03:20:34 +090013#include "base/logging.h"
14
15namespace base {
16
17// Keep a stack of registered AtExitManagers. We always operate on the most
rvargas@google.com3e37cca2011-04-23 07:09:35 +090018// recent, and we should never have more than one outside of testing (for a
19// statically linked version of this library). Testing may use the shadow
20// version of the constructor, and if we are building a dynamic library we may
21// end up with multiple AtExitManagers on the same process. We don't protect
22// this for thread-safe access, since it will only be modified in testing.
Ivan Kotenkove88f3462017-11-08 21:37:33 +090023static AtExitManager* g_top_manager = nullptr;
mmentovai@google.comaa13be62008-09-03 03:20:34 +090024
harakendf522bd2017-01-12 16:14:04 +090025static bool g_disable_managers = false;
26
amistry11fd6402016-02-10 11:18:33 +090027AtExitManager::AtExitManager()
28 : processing_callbacks_(false), next_manager_(g_top_manager) {
rvargas@google.com3e37cca2011-04-23 07:09:35 +090029// If multiple modules instantiate AtExitManagers they'll end up living in this
30// module... they have to coexist.
darin@chromium.org86d9f942011-07-14 05:41:28 +090031#if !defined(COMPONENT_BUILD)
mmentovai@google.comaa13be62008-09-03 03:20:34 +090032 DCHECK(!g_top_manager);
rvargas@google.com3e37cca2011-04-23 07:09:35 +090033#endif
mmentovai@google.comaa13be62008-09-03 03:20:34 +090034 g_top_manager = this;
35}
36
mmentovai@google.comaa13be62008-09-03 03:20:34 +090037AtExitManager::~AtExitManager() {
38 if (!g_top_manager) {
39 NOTREACHED() << "Tried to ~AtExitManager without an AtExitManager";
40 return;
41 }
kushi.p@gmail.com90594e32011-04-29 03:20:09 +090042 DCHECK_EQ(this, g_top_manager);
mmentovai@google.comaa13be62008-09-03 03:20:34 +090043
harakendf522bd2017-01-12 16:14:04 +090044 if (!g_disable_managers)
45 ProcessCallbacksNow();
mmentovai@google.comaa13be62008-09-03 03:20:34 +090046 g_top_manager = next_manager_;
47}
48
49// static
deanm@google.comf6299e72008-09-08 18:06:51 +090050void AtExitManager::RegisterCallback(AtExitCallbackType func, void* param) {
apatrick@chromium.org035f4af2011-09-07 08:14:47 +090051 DCHECK(func);
52 RegisterTask(base::Bind(func, param));
53}
54
55// static
56void AtExitManager::RegisterTask(base::Closure task) {
mmentovai@google.comaa13be62008-09-03 03:20:34 +090057 if (!g_top_manager) {
58 NOTREACHED() << "Tried to RegisterCallback without an AtExitManager";
59 return;
60 }
61
62 AutoLock lock(g_top_manager->lock_);
amistry11fd6402016-02-10 11:18:33 +090063 DCHECK(!g_top_manager->processing_callbacks_);
dcheng7dc91372016-07-06 12:59:26 +090064 g_top_manager->stack_.push(std::move(task));
mmentovai@google.comaa13be62008-09-03 03:20:34 +090065}
66
67// static
68void AtExitManager::ProcessCallbacksNow() {
69 if (!g_top_manager) {
70 NOTREACHED() << "Tried to ProcessCallbacksNow without an AtExitManager";
71 return;
72 }
73
amistry11fd6402016-02-10 11:18:33 +090074 // Callbacks may try to add new callbacks, so run them without holding
75 // |lock_|. This is an error and caught by the DCHECK in RegisterTask(), but
76 // handle it gracefully in release builds so we don't deadlock.
Brett Wilson19fd2bb2017-10-03 03:55:28 +090077 base::stack<base::Closure> tasks;
amistry11fd6402016-02-10 11:18:33 +090078 {
79 AutoLock lock(g_top_manager->lock_);
80 tasks.swap(g_top_manager->stack_);
81 g_top_manager->processing_callbacks_ = true;
mmentovai@google.comaa13be62008-09-03 03:20:34 +090082 }
amistry11fd6402016-02-10 11:18:33 +090083
tzik8a083482017-04-01 06:31:24 +090084 // Relax the cross-thread access restriction to non-thread-safe RefCount.
85 // It's safe since all other threads should be terminated at this point.
86 ScopedAllowCrossThreadRefCountAccess allow_cross_thread_ref_count_access;
87
amistry11fd6402016-02-10 11:18:33 +090088 while (!tasks.empty()) {
89 base::Closure task = tasks.top();
90 task.Run();
91 tasks.pop();
92 }
93
94 // Expect that all callbacks have been run.
95 DCHECK(g_top_manager->stack_.empty());
mmentovai@google.comaa13be62008-09-03 03:20:34 +090096}
97
harakendf522bd2017-01-12 16:14:04 +090098void AtExitManager::DisableAllAtExitManagers() {
99 AutoLock lock(g_top_manager->lock_);
100 g_disable_managers = true;
101}
102
amistry11fd6402016-02-10 11:18:33 +0900103AtExitManager::AtExitManager(bool shadow)
104 : processing_callbacks_(false), next_manager_(g_top_manager) {
erg@google.com37c078e2011-01-11 09:50:59 +0900105 DCHECK(shadow || !g_top_manager);
106 g_top_manager = this;
107}
108
mmentovai@google.comaa13be62008-09-03 03:20:34 +0900109} // namespace base