1
#pragma once
2

            
3
#include <functional>
4

            
5
#include "envoy/init/target.h"
6

            
7
#include "source/common/common/logger.h"
8

            
9
namespace Envoy {
10
namespace Init {
11

            
12
/**
13
 * A target is just a glorified callback function, called by the manager it was registered with.
14
 */
15
using InitializeFn = std::function<void()>;
16

            
17
/**
18
 * Internally, the callback is slightly more sophisticated: it actually takes a WatcherHandlePtr
19
 * that it uses to notify the manager when the target is ready. It saves this pointer when invoked
20
 * and resets it later in `ready`. Users needn't care about this implementation detail, they only
21
 * need to provide an `InitializeFn` above when constructing a target.
22
 */
23
using InternalInitializeFn = std::function<void(WatcherHandlePtr)>;
24

            
25
/**
26
 * A TargetHandleImpl functions as a weak reference to a TargetImpl. It is how a ManagerImpl safely
27
 * tells a target to `initialize` with no guarantees about the target's lifetime.
28
 */
29
class TargetHandleImpl : public TargetHandle, Logger::Loggable<Logger::Id::init> {
30
private:
31
  friend class TargetImpl;
32
  friend class SharedTargetImpl;
33

            
34
  TargetHandleImpl(absl::string_view handle_name, absl::string_view name,
35
                   std::weak_ptr<InternalInitializeFn> fn);
36

            
37
public:
38
  // Init::TargetHandle
39
  bool initialize(const Watcher& watcher) const override;
40

            
41
  absl::string_view name() const override;
42

            
43
private:
44
  // Name of the handle (almost always the name of the ManagerImpl calling the target)
45
  const std::string handle_name_;
46

            
47
  // Name of the target
48
  const std::string name_;
49

            
50
  // The target's callback function, only called if the weak pointer can be "locked"
51
  const std::weak_ptr<InternalInitializeFn> fn_;
52
};
53

            
54
/**
55
 * A TargetImpl is an entity that can be registered with a Manager for initialization. It can only
56
 * be invoked through a TargetHandle.
57
 */
58
class TargetImpl : public Target, Logger::Loggable<Logger::Id::init> {
59
public:
60
  /**
61
   * @param name a human-readable target name, for logging / debugging
62
   * @fn a callback function to invoke when `initialize` is called on the handle. Note that this
63
   *     doesn't take a WatcherHandlePtr (like TargetFn does). Managing the watcher handle is done
64
   *     internally to simplify usage.
65
   */
66
  TargetImpl(absl::string_view name, InitializeFn fn);
67
  ~TargetImpl() override;
68

            
69
  // Init::Target
70
  absl::string_view name() const override;
71
  TargetHandlePtr createHandle(absl::string_view handle_name) const override;
72

            
73
  /**
74
   * Signal to the init manager that this target has finished initializing. This is safe to call
75
   * any time. Calling it before initialization begins or after initialization has already ended
76
   * will have no effect.
77
   * @return true if the init manager received this call, false otherwise.
78
   */
79
  bool ready();
80

            
81
private:
82
  // Human-readable name for logging
83
  const std::string name_;
84

            
85
  // Handle to the ManagerImpl's internal watcher, to call when this target is initialized
86
  WatcherHandlePtr watcher_handle_;
87

            
88
  // The callback function, called via TargetHandleImpl by the manager
89
  std::shared_ptr<InternalInitializeFn> fn_;
90
};
91

            
92
/**
93
 * A specialized Target which can be added by multiple Managers.
94
 * The initialization will be triggered only once.
95
 */
96
class SharedTargetImpl : public Target, Logger::Loggable<Logger::Id::init> {
97
public:
98
  /**
99
   * @param name a human-readable target name, for logging / debugging
100
   * @fn a callback function to invoke when `initialize` is called on the handle. Note that this
101
   *     doesn't take a WatcherHandlePtr (like TargetFn does). Managing the watcher handle is done
102
   *     internally to simplify usage.
103
   */
104
  SharedTargetImpl(absl::string_view name, InitializeFn fn);
105
  ~SharedTargetImpl() override;
106

            
107
  // Init::Target
108
  absl::string_view name() const override;
109
  TargetHandlePtr createHandle(absl::string_view handle_name) const override;
110

            
111
  /**
112
   * Signal to the init manager(s) that this target has finished initializing. This is safe to call
113
   * any time. Calling it before initialization begins or after initialization has already ended
114
   * will have no effect.
115
   * @return true if all init managers received this call, false otherwise.
116
   */
117
  bool ready();
118

            
119
private:
120
  // Human-readable name for logging
121
  const std::string name_;
122

            
123
  // Handle to all the ManagerImpl's internal watcher, to call when this target is initialized.
124
  std::vector<WatcherHandlePtr> watcher_handles_;
125

            
126
  // The callback function, called via TargetHandleImpl by the manager
127
  const std::shared_ptr<InternalInitializeFn> fn_;
128

            
129
  // The state so as to signal the manager when a ready target is added.
130
  bool initialized_{false};
131

            
132
  // To guarantee the initialization function is called once.
133
  std::once_flag once_flag_;
134
};
135

            
136
} // namespace Init
137
} // namespace Envoy