blob: 5dcc83cb2f5c390ab8cdbc19ba601ec3fd01ab0b [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.
[email protected]b2e97292008-09-02 18:20:3423static AtExitManager* g_top_manager = NULL;
24
harakenbbfdd9f02017-01-12 07:14:0425static bool g_disable_managers = false;
26
amistryf35088d2016-02-10 02:18:3327AtExitManager::AtExitManager()
28 : processing_callbacks_(false), next_manager_(g_top_manager) {
[email protected]5ceb1b02011-04-22 22:09:3529// If multiple modules instantiate AtExitManagers they'll end up living in this
30// module... they have to coexist.
[email protected]63e39a282011-07-13 20:41:2831#if !defined(COMPONENT_BUILD)
[email protected]b2e97292008-09-02 18:20:3432 DCHECK(!g_top_manager);
[email protected]5ceb1b02011-04-22 22:09:3533#endif
[email protected]b2e97292008-09-02 18:20:3434 g_top_manager = this;
35}
36
[email protected]b2e97292008-09-02 18:20:3437AtExitManager::~AtExitManager() {
38 if (!g_top_manager) {
39 NOTREACHED() << "Tried to ~AtExitManager without an AtExitManager";
40 return;
41 }
[email protected]5e0be642011-04-28 18:20:0942 DCHECK_EQ(this, g_top_manager);
[email protected]b2e97292008-09-02 18:20:3443
harakenbbfdd9f02017-01-12 07:14:0444 if (!g_disable_managers)
45 ProcessCallbacksNow();
[email protected]b2e97292008-09-02 18:20:3446 g_top_manager = next_manager_;
47}
48
49// static
[email protected]9795ec12008-09-08 09:06:5150void AtExitManager::RegisterCallback(AtExitCallbackType func, void* param) {
[email protected]762de912011-09-06 23:14:4751 DCHECK(func);
52 RegisterTask(base::Bind(func, param));
53}
54
55// static
56void AtExitManager::RegisterTask(base::Closure task) {
[email protected]b2e97292008-09-02 18:20:3457 if (!g_top_manager) {
58 NOTREACHED() << "Tried to RegisterCallback without an AtExitManager";
59 return;
60 }
61
62 AutoLock lock(g_top_manager->lock_);
amistryf35088d2016-02-10 02:18:3363 DCHECK(!g_top_manager->processing_callbacks_);
dchengd02ce9c2016-07-06 03:59:2664 g_top_manager->stack_.push(std::move(task));
[email protected]b2e97292008-09-02 18:20:3465}
66
67// static
68void AtExitManager::ProcessCallbacksNow() {
69 if (!g_top_manager) {
70 NOTREACHED() << "Tried to ProcessCallbacksNow without an AtExitManager";
71 return;
72 }
73
amistryf35088d2016-02-10 02:18:3374 // 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.
77 std::stack<base::Closure> tasks;
78 {
79 AutoLock lock(g_top_manager->lock_);
80 tasks.swap(g_top_manager->stack_);
81 g_top_manager->processing_callbacks_ = true;
[email protected]b2e97292008-09-02 18:20:3482 }
amistryf35088d2016-02-10 02:18:3383
84 while (!tasks.empty()) {
85 base::Closure task = tasks.top();
86 task.Run();
87 tasks.pop();
88 }
89
90 // Expect that all callbacks have been run.
91 DCHECK(g_top_manager->stack_.empty());
[email protected]b2e97292008-09-02 18:20:3492}
93
harakenbbfdd9f02017-01-12 07:14:0494void AtExitManager::DisableAllAtExitManagers() {
95 AutoLock lock(g_top_manager->lock_);
96 g_disable_managers = true;
97}
98
amistryf35088d2016-02-10 02:18:3399AtExitManager::AtExitManager(bool shadow)
100 : processing_callbacks_(false), next_manager_(g_top_manager) {
[email protected]eae9c062011-01-11 00:50:59101 DCHECK(shadow || !g_top_manager);
102 g_top_manager = this;
103}
104
[email protected]b2e97292008-09-02 18:20:34105} // namespace base