blob: eb7d26cdc7c137cdcd5897ddabb4b0960c52ca17 [file] [log] [blame]
[email protected]fe992bf02012-07-25 20:36:331// Copyright (c) 2011 The Chromium Authors. All rights reserved.
[email protected]b2e97292008-09-02 18:20:342// 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"
[email protected]2edc2862011-04-04 18:04:376
7#include <stddef.h>
8#include <ostream>
dchengd02ce9c2016-07-06 03:59:269#include <utility>
[email protected]2edc2862011-04-04 18:04:3710
[email protected]762de912011-09-06 23:14:4711#include "base/bind.h"
[email protected]c6944272012-01-06 22:12:2812#include "base/callback.h"
[email protected]b2e97292008-09-02 18:20:3413#include "base/logging.h"
14
15namespace base {
16
17// Keep a stack of registered AtExitManagers. We always operate on the most
[email protected]5ceb1b02011-04-22 22:09:3518// 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 Kotenkova16212a52017-11-08 12:37:3323static AtExitManager* g_top_manager = nullptr;
[email protected]b2e97292008-09-02 18:20:3424
harakenbbfdd9f02017-01-12 07:14:0425static bool g_disable_managers = false;
26
Gabriel Charette24e83392018-10-30 23:09:0327AtExitManager::AtExitManager() : next_manager_(g_top_manager) {
[email protected]5ceb1b02011-04-22 22:09:3528// If multiple modules instantiate AtExitManagers they'll end up living in this
29// module... they have to coexist.
[email protected]63e39a282011-07-13 20:41:2830#if !defined(COMPONENT_BUILD)
[email protected]b2e97292008-09-02 18:20:3431 DCHECK(!g_top_manager);
[email protected]5ceb1b02011-04-22 22:09:3532#endif
[email protected]b2e97292008-09-02 18:20:3433 g_top_manager = this;
34}
35
[email protected]b2e97292008-09-02 18:20:3436AtExitManager::~AtExitManager() {
37 if (!g_top_manager) {
38 NOTREACHED() << "Tried to ~AtExitManager without an AtExitManager";
39 return;
40 }
[email protected]5e0be642011-04-28 18:20:0941 DCHECK_EQ(this, g_top_manager);
[email protected]b2e97292008-09-02 18:20:3442
harakenbbfdd9f02017-01-12 07:14:0443 if (!g_disable_managers)
44 ProcessCallbacksNow();
[email protected]b2e97292008-09-02 18:20:3445 g_top_manager = next_manager_;
46}
47
48// static
[email protected]9795ec12008-09-08 09:06:5149void AtExitManager::RegisterCallback(AtExitCallbackType func, void* param) {
[email protected]762de912011-09-06 23:14:4750 DCHECK(func);
kylecharb2695fc2019-04-24 14:51:2051 RegisterTask(base::BindOnce(func, param));
[email protected]762de912011-09-06 23:14:4752}
53
54// static
kylecharb2695fc2019-04-24 14:51:2055void AtExitManager::RegisterTask(base::OnceClosure task) {
[email protected]b2e97292008-09-02 18:20:3456 if (!g_top_manager) {
57 NOTREACHED() << "Tried to RegisterCallback without an AtExitManager";
58 return;
59 }
60
61 AutoLock lock(g_top_manager->lock_);
Gabriel Charette24e83392018-10-30 23:09:0362#if DCHECK_IS_ON()
amistryf35088d2016-02-10 02:18:3363 DCHECK(!g_top_manager->processing_callbacks_);
Gabriel Charette24e83392018-10-30 23:09:0364#endif
dchengd02ce9c2016-07-06 03:59:2665 g_top_manager->stack_.push(std::move(task));
[email protected]b2e97292008-09-02 18:20:3466}
67
68// static
69void AtExitManager::ProcessCallbacksNow() {
70 if (!g_top_manager) {
71 NOTREACHED() << "Tried to ProcessCallbacksNow without an AtExitManager";
72 return;
73 }
74
amistryf35088d2016-02-10 02:18:3375 // Callbacks may try to add new callbacks, so run them without holding
76 // |lock_|. This is an error and caught by the DCHECK in RegisterTask(), but
77 // handle it gracefully in release builds so we don't deadlock.
kylecharb2695fc2019-04-24 14:51:2078 base::stack<base::OnceClosure> tasks;
amistryf35088d2016-02-10 02:18:3379 {
80 AutoLock lock(g_top_manager->lock_);
81 tasks.swap(g_top_manager->stack_);
Gabriel Charette24e83392018-10-30 23:09:0382#if DCHECK_IS_ON()
amistryf35088d2016-02-10 02:18:3383 g_top_manager->processing_callbacks_ = true;
Gabriel Charette24e83392018-10-30 23:09:0384#endif
[email protected]b2e97292008-09-02 18:20:3485 }
amistryf35088d2016-02-10 02:18:3386
tzik3f4231f2017-03-31 21:31:2487 // Relax the cross-thread access restriction to non-thread-safe RefCount.
88 // It's safe since all other threads should be terminated at this point.
89 ScopedAllowCrossThreadRefCountAccess allow_cross_thread_ref_count_access;
90
amistryf35088d2016-02-10 02:18:3391 while (!tasks.empty()) {
kylecharb2695fc2019-04-24 14:51:2092 std::move(tasks.top()).Run();
amistryf35088d2016-02-10 02:18:3393 tasks.pop();
94 }
95
Gabriel Charette24e83392018-10-30 23:09:0396#if DCHECK_IS_ON()
97 AutoLock lock(g_top_manager->lock_);
amistryf35088d2016-02-10 02:18:3398 // Expect that all callbacks have been run.
99 DCHECK(g_top_manager->stack_.empty());
Gabriel Charette24e83392018-10-30 23:09:03100 g_top_manager->processing_callbacks_ = false;
101#endif
[email protected]b2e97292008-09-02 18:20:34102}
103
harakenbbfdd9f02017-01-12 07:14:04104void AtExitManager::DisableAllAtExitManagers() {
105 AutoLock lock(g_top_manager->lock_);
106 g_disable_managers = true;
107}
108
Gabriel Charette24e83392018-10-30 23:09:03109AtExitManager::AtExitManager(bool shadow) : next_manager_(g_top_manager) {
[email protected]eae9c062011-01-11 00:50:59110 DCHECK(shadow || !g_top_manager);
111 g_top_manager = this;
112}
113
[email protected]b2e97292008-09-02 18:20:34114} // namespace base