Coverage Report

Created: 2024-09-19 09:45

/proc/self/cwd/source/common/singleton/threadsafe_singleton.h
Line
Count
Source (jump to first uncovered line)
1
#pragma once
2
3
#include <memory>
4
5
#include "source/common/common/assert.h"
6
7
#include "absl/base/call_once.h"
8
9
namespace Envoy {
10
11
/**
12
 * ThreadSafeSingleton allows easy global cross-thread access to a non-const object.
13
 *
14
 * This singleton class should be used for singletons which must be globally
15
 * accessible but can not be marked as const. All functions in the singleton class
16
 * *must* be threadsafe.
17
 *
18
 * Note that there is heavy resistance in Envoy to adding this type of singleton
19
 * if data will persist with state changes across tests, as it becomes difficult
20
 * to write clean unit tests if a state change in one test will persist into
21
 * another test. Be wary of using it. A example of acceptable usage is OsSyscallsImpl,
22
 * where the functions are not strictly speaking const, but affect the OS rather than the
23
 * class itself. An example of unacceptable usage upstream would be for
24
 * globally accessible stat counters, it would have the aforementioned problem
25
 * where state "leaks" across tests.
26
 *
27
 * */
28
template <class T> class TestThreadsafeSingletonInjector;
29
template <class T> class ThreadSafeSingleton {
30
public:
31
559k
  static T& get() {
32
559k
    absl::call_once(ThreadSafeSingleton<T>::create_once_, &ThreadSafeSingleton<T>::Create);
33
559k
    return *ThreadSafeSingleton<T>::instance_;
34
559k
  }
Envoy::ThreadSafeSingleton<Envoy::Http::PrefixValue>::get()
Line
Count
Source
31
43.9k
  static T& get() {
32
43.9k
    absl::call_once(ThreadSafeSingleton<T>::create_once_, &ThreadSafeSingleton<T>::Create);
33
43.9k
    return *ThreadSafeSingleton<T>::instance_;
34
43.9k
  }
Envoy::ThreadSafeSingleton<Envoy::Api::OsSysCallsImpl>::get()
Line
Count
Source
31
492k
  static T& get() {
32
492k
    absl::call_once(ThreadSafeSingleton<T>::create_once_, &ThreadSafeSingleton<T>::Create);
33
492k
    return *ThreadSafeSingleton<T>::instance_;
34
492k
  }
Unexecuted instantiation: Envoy::ThreadSafeSingleton<Envoy::Api::LinuxOsSysCallsImpl>::get()
grpc_mux_impl.cc:Envoy::ThreadSafeSingleton<Envoy::Config::(anonymous namespace)::AllMuxesState>::get()
Line
Count
Source
31
6.85k
  static T& get() {
32
6.85k
    absl::call_once(ThreadSafeSingleton<T>::create_once_, &ThreadSafeSingleton<T>::Create);
33
6.85k
    return *ThreadSafeSingleton<T>::instance_;
34
6.85k
  }
new_grpc_mux_impl.cc:Envoy::ThreadSafeSingleton<Envoy::Config::(anonymous namespace)::AllMuxesState>::get()
Line
Count
Source
31
5.79k
  static T& get() {
32
5.79k
    absl::call_once(ThreadSafeSingleton<T>::create_once_, &ThreadSafeSingleton<T>::Create);
33
5.79k
    return *ThreadSafeSingleton<T>::instance_;
34
5.79k
  }
grpc_mux_impl.cc:Envoy::ThreadSafeSingleton<Envoy::Config::XdsMux::(anonymous namespace)::AllMuxesState>::get()
Line
Count
Source
31
9.99k
  static T& get() {
32
9.99k
    absl::call_once(ThreadSafeSingleton<T>::create_once_, &ThreadSafeSingleton<T>::Create);
33
9.99k
    return *ThreadSafeSingleton<T>::instance_;
34
9.99k
  }
35
36
protected:
37
  template <typename A> friend class TestThreadsafeSingletonInjector;
38
39
120
  static void Create() { instance_ = new T(); }
Envoy::ThreadSafeSingleton<Envoy::Http::PrefixValue>::Create()
Line
Count
Source
39
37
  static void Create() { instance_ = new T(); }
Envoy::ThreadSafeSingleton<Envoy::Api::OsSysCallsImpl>::Create()
Line
Count
Source
39
47
  static void Create() { instance_ = new T(); }
Unexecuted instantiation: Envoy::ThreadSafeSingleton<Envoy::Api::LinuxOsSysCallsImpl>::Create()
grpc_mux_impl.cc:Envoy::ThreadSafeSingleton<Envoy::Config::(anonymous namespace)::AllMuxesState>::Create()
Line
Count
Source
39
12
  static void Create() { instance_ = new T(); }
new_grpc_mux_impl.cc:Envoy::ThreadSafeSingleton<Envoy::Config::(anonymous namespace)::AllMuxesState>::Create()
Line
Count
Source
39
12
  static void Create() { instance_ = new T(); }
grpc_mux_impl.cc:Envoy::ThreadSafeSingleton<Envoy::Config::XdsMux::(anonymous namespace)::AllMuxesState>::Create()
Line
Count
Source
39
12
  static void Create() { instance_ = new T(); }
40
41
  static absl::once_flag create_once_;
42
  static T* instance_;
43
};
44
45
template <class T> absl::once_flag ThreadSafeSingleton<T>::create_once_;
46
47
template <class T> T* ThreadSafeSingleton<T>::instance_ = nullptr;
48
49
// An instance of a singleton class which has the same thread safety properties
50
// as ThreadSafeSingleton, but must be created via initialize prior to access.
51
//
52
// As with ThreadSafeSingleton the use of this class is generally discouraged.
53
template <class T> class InjectableSingleton {
54
public:
55
2.45M
  static T& get() {
56
2.45M
    RELEASE_ASSERT(loader_ != nullptr, "InjectableSingleton used prior to initialization");
57
2.45M
    return *loader_;
58
2.45M
  }
Envoy::InjectableSingleton<Envoy::Network::SocketInterface>::get()
Line
Count
Source
55
2.45M
  static T& get() {
56
2.45M
    RELEASE_ASSERT(loader_ != nullptr, "InjectableSingleton used prior to initialization");
57
2.45M
    return *loader_;
58
2.45M
  }
Envoy::InjectableSingleton<Envoy::Common::Crypto::Utility>::get()
Line
Count
Source
55
5.02k
  static T& get() {
56
5.02k
    RELEASE_ASSERT(loader_ != nullptr, "InjectableSingleton used prior to initialization");
57
5.02k
    return *loader_;
58
5.02k
  }
59
60
  static T* getExisting() { return loader_; }
61
62
254
  static void initialize(T* value) {
63
254
    RELEASE_ASSERT(value != nullptr, "InjectableSingleton initialized with null value.");
64
254
    RELEASE_ASSERT(loader_ == nullptr, "InjectableSingleton initialized multiple times.");
65
254
    loader_ = value;
66
254
  }
Envoy::InjectableSingleton<Envoy::Common::Crypto::Utility>::initialize(Envoy::Common::Crypto::Utility*)
Line
Count
Source
62
122
  static void initialize(T* value) {
63
122
    RELEASE_ASSERT(value != nullptr, "InjectableSingleton initialized with null value.");
64
122
    RELEASE_ASSERT(loader_ == nullptr, "InjectableSingleton initialized multiple times.");
65
122
    loader_ = value;
66
122
  }
Envoy::InjectableSingleton<Envoy::Network::SocketInterface>::initialize(Envoy::Network::SocketInterface*)
Line
Count
Source
62
132
  static void initialize(T* value) {
63
132
    RELEASE_ASSERT(value != nullptr, "InjectableSingleton initialized with null value.");
64
132
    RELEASE_ASSERT(loader_ == nullptr, "InjectableSingleton initialized multiple times.");
65
132
    loader_ = value;
66
132
  }
67
0
  static void clear() { loader_ = nullptr; }
68
69
  // Atomically replace the value, returning the old value.
70
  static T* replaceForTest(T* new_value) { return loader_.exchange(new_value); }
71
72
protected:
73
  static std::atomic<T*> loader_;
74
};
75
76
template <class T> std::atomic<T*> InjectableSingleton<T>::loader_ = nullptr;
77
78
template <class T> class ScopedInjectableLoader {
79
public:
80
254
  explicit ScopedInjectableLoader(std::unique_ptr<T>&& instance) {
81
254
    instance_ = std::move(instance);
82
254
    InjectableSingleton<T>::initialize(instance_.get());
83
254
  }
Envoy::ScopedInjectableLoader<Envoy::Common::Crypto::Utility>::ScopedInjectableLoader(std::__1::unique_ptr<Envoy::Common::Crypto::Utility, std::__1::default_delete<Envoy::Common::Crypto::Utility> >&&)
Line
Count
Source
80
122
  explicit ScopedInjectableLoader(std::unique_ptr<T>&& instance) {
81
122
    instance_ = std::move(instance);
82
122
    InjectableSingleton<T>::initialize(instance_.get());
83
122
  }
Envoy::ScopedInjectableLoader<Envoy::Network::SocketInterface>::ScopedInjectableLoader(std::__1::unique_ptr<Envoy::Network::SocketInterface, std::__1::default_delete<Envoy::Network::SocketInterface> >&&)
Line
Count
Source
80
132
  explicit ScopedInjectableLoader(std::unique_ptr<T>&& instance) {
81
132
    instance_ = std::move(instance);
82
132
    InjectableSingleton<T>::initialize(instance_.get());
83
132
  }
84
  ~ScopedInjectableLoader() { InjectableSingleton<T>::clear(); }
85
86
  T& instance() { return *instance_; }
87
88
private:
89
  std::unique_ptr<T> instance_;
90
};
91
92
// This class saves the singleton object and restore the original singleton at destroy.
93
template <class T> class StackedScopedInjectableLoaderForTest {
94
public:
95
  explicit StackedScopedInjectableLoaderForTest(std::unique_ptr<T>&& instance) {
96
    instance_ = std::move(instance);
97
    original_loader_ = InjectableSingleton<T>::replaceForTest(instance_.get());
98
  }
99
  ~StackedScopedInjectableLoaderForTest() {
100
    InjectableSingleton<T>::replaceForTest(original_loader_);
101
  }
102
103
private:
104
  std::unique_ptr<T> instance_;
105
  T* original_loader_;
106
};
107
108
} // namespace Envoy