blob: 0fba355698fbebc643fd3225d1323ec64964eb7d [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>
9
apatrick@chromium.org035f4af2011-09-07 08:14:47 +090010#include "base/bind.h"
ajwong@chromium.orge4f3dc32012-01-07 07:12:28 +090011#include "base/callback.h"
mmentovai@google.comaa13be62008-09-03 03:20:34 +090012#include "base/logging.h"
13
14namespace base {
15
16// Keep a stack of registered AtExitManagers. We always operate on the most
rvargas@google.com3e37cca2011-04-23 07:09:35 +090017// recent, and we should never have more than one outside of testing (for a
18// statically linked version of this library). Testing may use the shadow
19// version of the constructor, and if we are building a dynamic library we may
20// end up with multiple AtExitManagers on the same process. We don't protect
21// this for thread-safe access, since it will only be modified in testing.
mmentovai@google.comaa13be62008-09-03 03:20:34 +090022static AtExitManager* g_top_manager = NULL;
23
rvargas@google.com3e37cca2011-04-23 07:09:35 +090024AtExitManager::AtExitManager() : next_manager_(g_top_manager) {
25// If multiple modules instantiate AtExitManagers they'll end up living in this
26// module... they have to coexist.
darin@chromium.org86d9f942011-07-14 05:41:28 +090027#if !defined(COMPONENT_BUILD)
mmentovai@google.comaa13be62008-09-03 03:20:34 +090028 DCHECK(!g_top_manager);
rvargas@google.com3e37cca2011-04-23 07:09:35 +090029#endif
mmentovai@google.comaa13be62008-09-03 03:20:34 +090030 g_top_manager = this;
31}
32
mmentovai@google.comaa13be62008-09-03 03:20:34 +090033AtExitManager::~AtExitManager() {
34 if (!g_top_manager) {
35 NOTREACHED() << "Tried to ~AtExitManager without an AtExitManager";
36 return;
37 }
kushi.p@gmail.com90594e32011-04-29 03:20:09 +090038 DCHECK_EQ(this, g_top_manager);
mmentovai@google.comaa13be62008-09-03 03:20:34 +090039
40 ProcessCallbacksNow();
41 g_top_manager = next_manager_;
42}
43
44// static
deanm@google.comf6299e72008-09-08 18:06:51 +090045void AtExitManager::RegisterCallback(AtExitCallbackType func, void* param) {
apatrick@chromium.org035f4af2011-09-07 08:14:47 +090046 DCHECK(func);
47 RegisterTask(base::Bind(func, param));
48}
49
50// static
51void AtExitManager::RegisterTask(base::Closure task) {
mmentovai@google.comaa13be62008-09-03 03:20:34 +090052 if (!g_top_manager) {
53 NOTREACHED() << "Tried to RegisterCallback without an AtExitManager";
54 return;
55 }
56
57 AutoLock lock(g_top_manager->lock_);
apatrick@chromium.org035f4af2011-09-07 08:14:47 +090058 g_top_manager->stack_.push(task);
mmentovai@google.comaa13be62008-09-03 03:20:34 +090059}
60
61// static
62void AtExitManager::ProcessCallbacksNow() {
63 if (!g_top_manager) {
64 NOTREACHED() << "Tried to ProcessCallbacksNow without an AtExitManager";
65 return;
66 }
67
68 AutoLock lock(g_top_manager->lock_);
69
70 while (!g_top_manager->stack_.empty()) {
apatrick@chromium.org035f4af2011-09-07 08:14:47 +090071 base::Closure task = g_top_manager->stack_.top();
72 task.Run();
mmentovai@google.comaa13be62008-09-03 03:20:34 +090073 g_top_manager->stack_.pop();
mmentovai@google.comaa13be62008-09-03 03:20:34 +090074 }
75}
76
erg@google.com37c078e2011-01-11 09:50:59 +090077AtExitManager::AtExitManager(bool shadow) : next_manager_(g_top_manager) {
78 DCHECK(shadow || !g_top_manager);
79 g_top_manager = this;
80}
81
mmentovai@google.comaa13be62008-09-03 03:20:34 +090082} // namespace base