blob: 0d419617553cd1ad2759f763cc66b77dc2643966 [file] [log] [blame]
Avi Drissmane4622aa2022-09-08 20:36:061// Copyright 2011 The Chromium Authors
[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>
Peter Kasting134ef9af2024-12-28 02:30:098
[email protected]2edc2862011-04-04 18:04:379#include <ostream>
dchengd02ce9c2016-07-06 03:59:2610#include <utility>
[email protected]2edc2862011-04-04 18:04:3711
Hans Wennborgc3cffa62020-04-27 10:09:1212#include "base/check_op.h"
Avi Drissman63e1f992023-01-13 18:54:4313#include "base/functional/bind.h"
14#include "base/functional/callback.h"
Hans Wennborgc3cffa62020-04-27 10:09:1215#include "base/notreached.h"
[email protected]b2e97292008-09-02 18:20:3416
17namespace base {
18
19// Keep a stack of registered AtExitManagers. We always operate on the most
[email protected]5ceb1b02011-04-22 22:09:3520// recent, and we should never have more than one outside of testing (for a
21// statically linked version of this library). Testing may use the shadow
22// version of the constructor, and if we are building a dynamic library we may
23// end up with multiple AtExitManagers on the same process. We don't protect
24// this for thread-safe access, since it will only be modified in testing.
Ivan Kotenkova16212a52017-11-08 12:37:3325static AtExitManager* g_top_manager = nullptr;
[email protected]b2e97292008-09-02 18:20:3426
harakenbbfdd9f02017-01-12 07:14:0427static bool g_disable_managers = false;
28
Gabriel Charette24e83392018-10-30 23:09:0329AtExitManager::AtExitManager() : next_manager_(g_top_manager) {
[email protected]5ceb1b02011-04-22 22:09:3530// If multiple modules instantiate AtExitManagers they'll end up living in this
31// module... they have to coexist.
[email protected]63e39a282011-07-13 20:41:2832#if !defined(COMPONENT_BUILD)
[email protected]b2e97292008-09-02 18:20:3433 DCHECK(!g_top_manager);
[email protected]5ceb1b02011-04-22 22:09:3534#endif
[email protected]b2e97292008-09-02 18:20:3435 g_top_manager = this;
36}
37
[email protected]b2e97292008-09-02 18:20:3438AtExitManager::~AtExitManager() {
39 if (!g_top_manager) {
Peter Boströmde573332024-08-26 20:42:4540 NOTREACHED() << "Tried to ~AtExitManager without an AtExitManager";
[email protected]b2e97292008-09-02 18:20:3441 }
[email protected]5e0be642011-04-28 18:20:0942 DCHECK_EQ(this, g_top_manager);
[email protected]b2e97292008-09-02 18:20:3443
Peter Kasting134ef9af2024-12-28 02:30:0944 if (!g_disable_managers) {
harakenbbfdd9f02017-01-12 07:14:0445 ProcessCallbacksNow();
Peter Kasting134ef9af2024-12-28 02:30:0946 }
[email protected]b2e97292008-09-02 18:20:3447 g_top_manager = next_manager_;
48}
49
50// static
[email protected]9795ec12008-09-08 09:06:5151void AtExitManager::RegisterCallback(AtExitCallbackType func, void* param) {
[email protected]762de912011-09-06 23:14:4752 DCHECK(func);
kylecharb2695fc2019-04-24 14:51:2053 RegisterTask(base::BindOnce(func, param));
[email protected]762de912011-09-06 23:14:4754}
55
56// static
kylecharb2695fc2019-04-24 14:51:2057void AtExitManager::RegisterTask(base::OnceClosure task) {
[email protected]b2e97292008-09-02 18:20:3458 if (!g_top_manager) {
Peter Boströmde573332024-08-26 20:42:4559 NOTREACHED() << "Tried to RegisterCallback without an AtExitManager";
[email protected]b2e97292008-09-02 18:20:3460 }
61
62 AutoLock lock(g_top_manager->lock_);
Gabriel Charette24e83392018-10-30 23:09:0363#if DCHECK_IS_ON()
amistryf35088d2016-02-10 02:18:3364 DCHECK(!g_top_manager->processing_callbacks_);
Gabriel Charette24e83392018-10-30 23:09:0365#endif
dchengd02ce9c2016-07-06 03:59:2666 g_top_manager->stack_.push(std::move(task));
[email protected]b2e97292008-09-02 18:20:3467}
68
69// static
70void AtExitManager::ProcessCallbacksNow() {
71 if (!g_top_manager) {
Peter Boströmde573332024-08-26 20:42:4572 NOTREACHED() << "Tried to ProcessCallbacksNow without an AtExitManager";
[email protected]b2e97292008-09-02 18:20:3473 }
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