Coverage Report

Created: 2023-11-12 09:30

/proc/self/cwd/source/common/singleton/threadsafe_singleton.h
Line
Count
Source
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
796k
  static T& get() {
32
796k
    absl::call_once(ThreadSafeSingleton<T>::create_once_, &ThreadSafeSingleton<T>::Create);
33
796k
    return *ThreadSafeSingleton<T>::instance_;
34
796k
  }
Envoy::ThreadSafeSingleton<Envoy::Http::PrefixValue>::get()
Line
Count
Source
31
37.1k
  static T& get() {
32
37.1k
    absl::call_once(ThreadSafeSingleton<T>::create_once_, &ThreadSafeSingleton<T>::Create);
33
37.1k
    return *ThreadSafeSingleton<T>::instance_;
34
37.1k
  }
Envoy::ThreadSafeSingleton<Envoy::Api::OsSysCallsImpl>::get()
Line
Count
Source
31
734k
  static T& get() {
32
734k
    absl::call_once(ThreadSafeSingleton<T>::create_once_, &ThreadSafeSingleton<T>::Create);
33
734k
    return *ThreadSafeSingleton<T>::instance_;
34
734k
  }
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.89k
  static T& get() {
32
6.89k
    absl::call_once(ThreadSafeSingleton<T>::create_once_, &ThreadSafeSingleton<T>::Create);
33
6.89k
    return *ThreadSafeSingleton<T>::instance_;
34
6.89k
  }
new_grpc_mux_impl.cc:Envoy::ThreadSafeSingleton<Envoy::Config::(anonymous namespace)::AllMuxesState>::get()
Line
Count
Source
31
6.38k
  static T& get() {
32
6.38k
    absl::call_once(ThreadSafeSingleton<T>::create_once_, &ThreadSafeSingleton<T>::Create);
33
6.38k
    return *ThreadSafeSingleton<T>::instance_;
34
6.38k
  }
grpc_mux_impl.cc:Envoy::ThreadSafeSingleton<Envoy::Config::XdsMux::(anonymous namespace)::AllMuxesState>::get()
Line
Count
Source
31
10.9k
  static T& get() {
32
10.9k
    absl::call_once(ThreadSafeSingleton<T>::create_once_, &ThreadSafeSingleton<T>::Create);
33
10.9k
    return *ThreadSafeSingleton<T>::instance_;
34
10.9k
  }
35
36
protected:
37
  template <typename A> friend class TestThreadsafeSingletonInjector;
38
39
112
  static void Create() { instance_ = new T(); }
Envoy::ThreadSafeSingleton<Envoy::Http::PrefixValue>::Create()
Line
Count
Source
39
33
  static void Create() { instance_ = new T(); }
Envoy::ThreadSafeSingleton<Envoy::Api::OsSysCallsImpl>::Create()
Line
Count
Source
39
43
  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.59M
  static T& get() {
56
2.59M
    RELEASE_ASSERT(loader_ != nullptr, "InjectableSingleton used prior to initialization");
57
2.59M
    return *loader_;
58
2.59M
  }
Envoy::InjectableSingleton<Envoy::Network::SocketInterface>::get()
Line
Count
Source
55
2.58M
  static T& get() {
56
2.58M
    RELEASE_ASSERT(loader_ != nullptr, "InjectableSingleton used prior to initialization");
57
2.58M
    return *loader_;
58
2.58M
  }
Envoy::InjectableSingleton<Envoy::Regex::Engine>::get()
Line
Count
Source
55
11.2k
  static T& get() {
56
11.2k
    RELEASE_ASSERT(loader_ != nullptr, "InjectableSingleton used prior to initialization");
57
11.2k
    return *loader_;
58
11.2k
  }
Envoy::InjectableSingleton<Envoy::Common::Crypto::Utility>::get()
Line
Count
Source
55
4.96k
  static T& get() {
56
4.96k
    RELEASE_ASSERT(loader_ != nullptr, "InjectableSingleton used prior to initialization");
57
4.96k
    return *loader_;
58
4.96k
  }
59
60
  static T* getExisting() { return loader_; }
61
62
23.7k
  static void initialize(T* value) {
63
23.7k
    RELEASE_ASSERT(value != nullptr, "InjectableSingleton initialized with null value.");
64
23.7k
    RELEASE_ASSERT(loader_ == nullptr, "InjectableSingleton initialized multiple times.");
65
23.7k
    loader_ = value;
66
23.7k
  }
Envoy::InjectableSingleton<Envoy::Common::Crypto::Utility>::initialize(Envoy::Common::Crypto::Utility*)
Line
Count
Source
62
116
  static void initialize(T* value) {
63
116
    RELEASE_ASSERT(value != nullptr, "InjectableSingleton initialized with null value.");
64
116
    RELEASE_ASSERT(loader_ == nullptr, "InjectableSingleton initialized multiple times.");
65
116
    loader_ = value;
66
116
  }
Envoy::InjectableSingleton<Envoy::Network::SocketInterface>::initialize(Envoy::Network::SocketInterface*)
Line
Count
Source
62
126
  static void initialize(T* value) {
63
126
    RELEASE_ASSERT(value != nullptr, "InjectableSingleton initialized with null value.");
64
126
    RELEASE_ASSERT(loader_ == nullptr, "InjectableSingleton initialized multiple times.");
65
126
    loader_ = value;
66
126
  }
Envoy::InjectableSingleton<Envoy::Regex::Engine>::initialize(Envoy::Regex::Engine*)
Line
Count
Source
62
23.5k
  static void initialize(T* value) {
63
23.5k
    RELEASE_ASSERT(value != nullptr, "InjectableSingleton initialized with null value.");
64
23.5k
    RELEASE_ASSERT(loader_ == nullptr, "InjectableSingleton initialized multiple times.");
65
23.5k
    loader_ = value;
66
23.5k
  }
67
23.5k
  static void clear() { loader_ = nullptr; }
Unexecuted instantiation: Envoy::InjectableSingleton<Envoy::Network::SocketInterface>::clear()
Envoy::InjectableSingleton<Envoy::Regex::Engine>::clear()
Line
Count
Source
67
23.5k
  static void clear() { loader_ = nullptr; }
68
69
protected:
70
  static std::atomic<T*> loader_;
71
};
72
73
template <class T> std::atomic<T*> InjectableSingleton<T>::loader_ = nullptr;
74
75
template <class T> class ScopedInjectableLoader {
76
public:
77
8.75k
  explicit ScopedInjectableLoader(std::unique_ptr<T>&& instance) {
78
8.75k
    instance_ = std::move(instance);
79
8.75k
    InjectableSingleton<T>::initialize(instance_.get());
80
8.75k
  }
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
77
116
  explicit ScopedInjectableLoader(std::unique_ptr<T>&& instance) {
78
116
    instance_ = std::move(instance);
79
116
    InjectableSingleton<T>::initialize(instance_.get());
80
116
  }
Envoy::ScopedInjectableLoader<Envoy::Network::SocketInterface>::ScopedInjectableLoader(std::__1::unique_ptr<Envoy::Network::SocketInterface, std::__1::default_delete<Envoy::Network::SocketInterface> >&&)
Line
Count
Source
77
126
  explicit ScopedInjectableLoader(std::unique_ptr<T>&& instance) {
78
126
    instance_ = std::move(instance);
79
126
    InjectableSingleton<T>::initialize(instance_.get());
80
126
  }
Envoy::ScopedInjectableLoader<Envoy::Regex::Engine>::ScopedInjectableLoader(std::__1::unique_ptr<Envoy::Regex::Engine, std::__1::default_delete<Envoy::Regex::Engine> >&&)
Line
Count
Source
77
8.51k
  explicit ScopedInjectableLoader(std::unique_ptr<T>&& instance) {
78
8.51k
    instance_ = std::move(instance);
79
8.51k
    InjectableSingleton<T>::initialize(instance_.get());
80
8.51k
  }
81
8.51k
  ~ScopedInjectableLoader() { InjectableSingleton<T>::clear(); }
82
83
  T& instance() { return *instance_; }
84
85
private:
86
  std::unique_ptr<T> instance_;
87
};
88
89
// This class saves the singleton object and restore the original singleton at destroy. This class
90
// is not thread safe. It can be used in single thread test.
91
template <class T>
92
class StackedScopedInjectableLoader :
93
    // To access the protected loader_.
94
    protected InjectableSingleton<T> {
95
public:
96
  explicit StackedScopedInjectableLoader(std::unique_ptr<T>&& instance) {
97
    original_loader_ = InjectableSingleton<T>::getExisting();
98
    InjectableSingleton<T>::clear();
99
    instance_ = std::move(instance);
100
    InjectableSingleton<T>::initialize(instance_.get());
101
  }
102
  ~StackedScopedInjectableLoader() { InjectableSingleton<T>::loader_ = original_loader_; }
103
104
private:
105
  std::unique_ptr<T> instance_;
106
  T* original_loader_;
107
};
108
109
} // namespace Envoy