LCOV - code coverage report
Current view: top level - source/common/singleton - threadsafe_singleton.h (source / functions) Hit Total Coverage
Test: coverage.dat Lines: 20 20 100.0 %
Date: 2024-01-05 06:35:25 Functions: 21 24 87.5 %

          Line data    Source code
       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       47078 :   static T& get() {
      32       47078 :     absl::call_once(ThreadSafeSingleton<T>::create_once_, &ThreadSafeSingleton<T>::Create);
      33       47078 :     return *ThreadSafeSingleton<T>::instance_;
      34       47078 :   }
      35             : 
      36             : protected:
      37             :   template <typename A> friend class TestThreadsafeSingletonInjector;
      38             : 
      39         117 :   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      203184 :   static T& get() {
      56      203184 :     RELEASE_ASSERT(loader_ != nullptr, "InjectableSingleton used prior to initialization");
      57      203184 :     return *loader_;
      58      203184 :   }
      59             : 
      60             :   static T* getExisting() { return loader_; }
      61             : 
      62         756 :   static void initialize(T* value) {
      63         756 :     RELEASE_ASSERT(value != nullptr, "InjectableSingleton initialized with null value.");
      64         756 :     RELEASE_ASSERT(loader_ == nullptr, "InjectableSingleton initialized multiple times.");
      65         756 :     loader_ = value;
      66         756 :   }
      67         628 :   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         399 :   explicit ScopedInjectableLoader(std::unique_ptr<T>&& instance) {
      78         399 :     instance_ = std::move(instance);
      79         399 :     InjectableSingleton<T>::initialize(instance_.get());
      80         399 :   }
      81         271 :   ~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

Generated by: LCOV version 1.15