/src/brpc/src/butil/at_exit.cc
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 | | // Use of this source code is governed by a BSD-style license that can be |
3 | | // found in the LICENSE file. |
4 | | |
5 | | #include "butil/at_exit.h" |
6 | | |
7 | | #include <stddef.h> |
8 | | #include <ostream> |
9 | | |
10 | | #include "butil/logging.h" |
11 | | |
12 | | namespace butil { |
13 | | |
14 | | // Keep a stack of registered AtExitManagers. We always operate on the most |
15 | | // recent, and we should never have more than one outside of testing (for a |
16 | | // statically linked version of this library). Testing may use the shadow |
17 | | // version of the constructor, and if we are building a dynamic library we may |
18 | | // end up with multiple AtExitManagers on the same process. We don't protect |
19 | | // this for thread-safe access, since it will only be modified in testing. |
20 | | static AtExitManager* g_top_manager = NULL; |
21 | | |
22 | 0 | AtExitManager::AtExitManager() : next_manager_(g_top_manager) { |
23 | | // If multiple modules instantiate AtExitManagers they'll end up living in this |
24 | | // module... they have to coexist. |
25 | 0 | #if !defined(COMPONENT_BUILD) |
26 | 0 | DCHECK(!g_top_manager); |
27 | 0 | #endif |
28 | 0 | g_top_manager = this; |
29 | 0 | } |
30 | | |
31 | 0 | AtExitManager::~AtExitManager() { |
32 | 0 | if (!g_top_manager) { |
33 | 0 | NOTREACHED() << "Tried to ~AtExitManager without an AtExitManager"; |
34 | 0 | return; |
35 | 0 | } |
36 | 0 | DCHECK_EQ(this, g_top_manager); |
37 | |
|
38 | 0 | ProcessCallbacksNow(); |
39 | 0 | g_top_manager = next_manager_; |
40 | 0 | } |
41 | | |
42 | | // static |
43 | 0 | void AtExitManager::RegisterCallback(AtExitCallbackType func, void* param) { |
44 | 0 | DCHECK(func); |
45 | 0 | if (!g_top_manager) { |
46 | 0 | NOTREACHED() << "Tried to RegisterCallback without an AtExitManager"; |
47 | 0 | return; |
48 | 0 | } |
49 | | |
50 | 0 | AutoLock lock(g_top_manager->lock_); |
51 | 0 | g_top_manager->stack_.push({func, param}); |
52 | 0 | } |
53 | | |
54 | | // static |
55 | 0 | void AtExitManager::ProcessCallbacksNow() { |
56 | 0 | if (!g_top_manager) { |
57 | 0 | NOTREACHED() << "Tried to ProcessCallbacksNow without an AtExitManager"; |
58 | 0 | return; |
59 | 0 | } |
60 | | |
61 | 0 | AutoLock lock(g_top_manager->lock_); |
62 | |
|
63 | 0 | while (!g_top_manager->stack_.empty()) { |
64 | 0 | Callback task = g_top_manager->stack_.top(); |
65 | 0 | task.func(task.param); |
66 | 0 | g_top_manager->stack_.pop(); |
67 | 0 | } |
68 | 0 | } |
69 | | |
70 | 0 | AtExitManager::AtExitManager(bool shadow) : next_manager_(g_top_manager) { |
71 | 0 | DCHECK(shadow || !g_top_manager); |
72 | 0 | g_top_manager = this; |
73 | 0 | } |
74 | | |
75 | | } // namespace butil |