/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 |