Coverage Report

Created: 2025-08-05 06:45

/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