DetectorGraph  2.0
timeoutpublisherservice.hpp
Go to the documentation of this file.
1 // Copyright 2017 Nest Labs, Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef DETECTORGRAPH_INCLUDE_TIMEOUTPUBLISHERSERVICE_HPP_
16 #define DETECTORGRAPH_INCLUDE_TIMEOUTPUBLISHERSERVICE_HPP_
17 
18 #include "graph.hpp"
19 #include "topicstate.hpp"
20 
21 #if defined(BUILD_FEATURE_DETECTORGRAPH_CONFIG_LITE)
22 // LITE_BEGIN
23 #include "detectorgraphliteconfig.hpp"
25 // LITE_END
26 #else
27 // FULL_BEGIN
28 #include "dglogging.hpp"
29 #include <vector>
30 // FULL_END
31 #endif
32 
33 
34 namespace DetectorGraph
35 {
36 
39 
40 typedef uint64_t TimeOffset;
41 
42 /**
43  * @brief A service that provides Timer function to DetectorGraph Detectors
44  *
45  * TimeoutPublisherService is used/shared among many TimeoutPublishers
46  * (Detectors) to add the notion of timed publications to DetectorGraph.
47  */
49 {
50  // Types and classes used internally
51  /**
52  * @brief Internal DispatcherInterface for dispatching any scheduled
53  TopicState to Graph::PushData<T>
54  */
55  struct DispatcherInterface
56  {
57  virtual void Dispatch(Graph& aGraph) = 0;
58  virtual ~DispatcherInterface() {}
59  };
60 
61  /**
62  * @brief Internal Dispatcher for dispatching a particular scheduled
63  TopicState to Graph::PushData<T>
64  */
65  template<class T>
66  struct Dispatcher : public DispatcherInterface
67  {
68  Dispatcher() : mData() {}
69  Dispatcher(const T& aData) : mData(aData) {}
70  virtual void Dispatch(Graph& aGraph)
71  {
72  aGraph.PushData<T>(mData);
73  }
74  const T mData;
75  };
76 
77  /**
78  * @brief Internal Dispatcher for periodically dispatching TopicState to Graph::PushData<T>
79  *
80  * This internal data structure holds a periodically-triggered dispatcher. It is also used to track
81  * the time between triggers, so that different dispatchers can use the same synchronized metronome timer.
82  */
83  struct PeriodicPublishingSeries
84  {
85  TimeOffset mPublishingPeriodMsec;
86  TimeOffset mMetronomeAccumulator;
87  DispatcherInterface* mpDispatcher;
88 
89  PeriodicPublishingSeries(TimeOffset aPublishingPeriodMsec,
90  DispatcherInterface* aDispatcher)
91  : mPublishingPeriodMsec(aPublishingPeriodMsec)
92  , mMetronomeAccumulator(0)
93  , mpDispatcher(aDispatcher) {}
94  };
95 
96 
97 #if defined(BUILD_FEATURE_DETECTORGRAPH_CONFIG_LITE)
98  typedef SequenceContainer<DispatcherInterface*,
99  DetectorGraphConfig::kMaxNumberOfTimeouts> TimeoutDispatchersContainer;
100  typedef SequenceContainer<PeriodicPublishingSeries,
101  DetectorGraphConfig::kMaxNumberOfPeriodicTimers> PeriodicPublishingSeriesContainer;
102  struct TimeoutCtxt {};
103  typedef StaticTypedAllocator<DispatcherInterface, TimeoutCtxt> TimeoutDispatchersAllocator;
104  struct PeriodicCtxt {};
105  typedef StaticTypedAllocator<DispatcherInterface, PeriodicCtxt> PeriodicDispatchersAllocator;
106 #else
107  typedef std::vector<DispatcherInterface*> TimeoutDispatchersContainer;
108  typedef std::vector<PeriodicPublishingSeries> PeriodicPublishingSeriesContainer;
109 #endif
110 
111 public:
112  /**
113  * @brief Constructor that initializes the service connected to a graph
114  *
115  * @param[in] graph The graph to which timed out TopicStates will be posted
116  */
118 
119  /**
120  * @brief Destructor
121  *
122  * Deletes all dynamically allocated pending TopicStates
123  */
124  virtual ~TimeoutPublisherService();
125 
126  /**
127  * @brief Starts a Metronome to publish scheduled TopicStates
128  *
129  * Calling this method starts a metronome(periodic timer).
130  * TimeoutPublisherService will start publishing scheduled TopicStates periodically to graph.
131  */
133 
134  /**
135  * @brief Returns a unique id/handle for a new timer
136  *
137  * Different TimeoutPublishers will call this to 'acquire' a timer. The
138  * handle is then used throughout the API to refer to any individual timer.
139  * Note that this will never return kInvalidTimeoutPublisherHandle.
140  */
141  TimeoutPublisherHandle GetUniqueTimerHandle();
142 
143  /**
144  * @brief Schedules a TopicState for publishing periodically
145  *
146  * This is called by different Detectors with a TopicState and a publishing period.
147  * This method updates the metronome period based on the GCD of the requested publishing period.
148  * Calling 'StartPeriodicPublishing' will start publishing `T` to the graph periodically
149  * with interval @param aPeriodInMilliseconds .
150  *
151  * @param aPeriodInMilliseconds The regular period at which T should be published.
152  */
153  template<class T>
154  void SchedulePeriodicPublishing(const TimeOffset aPeriodInMilliseconds)
155  {
156 #if defined(BUILD_FEATURE_DETECTORGRAPH_CONFIG_LITE)
157  SchedulePeriodicPublishingDispatcher(mPeriodicDispatchersAllocator.New<Dispatcher<T>>(), aPeriodInMilliseconds);
158 #else
159  SchedulePeriodicPublishingDispatcher(new Dispatcher<T>(), aPeriodInMilliseconds);
160 #endif
161 #if defined(BUILD_FEATURE_DETECTORGRAPH_CONFIG_INSTRUMENT_RESOURCE_USAGE)
162 #if defined(BUILD_FEATURE_DETECTORGRAPH_CONFIG_LITE)
163  DG_LOG("Scheduling PeriodicPublishing every %d milliseconds\n", aPeriodInMilliseconds);
164 #else
165  DG_LOG("Scheduling PeriodicPublishing of %s every %d milliseconds\n", T().GetName(), aPeriodInMilliseconds);
166 #endif
167 #endif
168  }
169 
170  /**
171  * @brief Schedules a TopicState for Publishing after a timeout
172  *
173  * This is called internally by TimeoutPublishers. It starts a timer set to
174  * expire at a given deadline. When the deadline is reached @param aData is
175  * Published to the graph.
176  * Calling this method on an pending @param aTimerHandle resets it
177  * (canceling any previous timeouts)
178  *
179  * @param aData The TopicState to be published when the deadline expires.
180  * @param aMillisecondsFromNow The deadline relative to now.
181  * @param aTimerHandle A unique handle for this timer.
182  */
183  template<class T>
184  void ScheduleTimeout(const T& aData, const TimeOffset aMillisecondsFromNow, const TimeoutPublisherHandle aTimerHandle)
185  {
186  // Due to Lite limitations we need to cancel/free the old Dispatcher for the same handle before we schedule the new one.
187  CancelPublishOnTimeout(aTimerHandle);
188 #if defined(BUILD_FEATURE_DETECTORGRAPH_CONFIG_LITE)
189  ScheduleTimeoutDispatcher(mTimeoutDispatchersAllocator.New<Dispatcher<T>>(aData), aMillisecondsFromNow, aTimerHandle);
190 #else
191  ScheduleTimeoutDispatcher(new Dispatcher<T>(aData), aMillisecondsFromNow, aTimerHandle);
192 #endif
193 #if defined(BUILD_FEATURE_DETECTORGRAPH_CONFIG_INSTRUMENT_RESOURCE_USAGE)
194 #if defined(BUILD_FEATURE_DETECTORGRAPH_CONFIG_LITE)
195  DG_LOG("Scheduling Timeout in %d milliseconds\n", aMillisecondsFromNow);
196 #else
197  DG_LOG("Scheduling Timeout for %s in %d milliseconds\n", aData.GetName(), aMillisecondsFromNow);
198 #endif
199 #endif
200  }
201 
202  /**
203  * @brief Cancels a timeout and deletes the stored TopicState
204  *
205  * This is called by different TimeoutPublishers when a timeout must be
206  * canceled.
207  */
208  void CancelPublishOnTimeout(const TimeoutPublisherHandle aTimerHandle);
209 
210  /**
211  * @brief Returns weather the timeout for a given handle has expired/fired
212  already.
213  *
214  * This will also return true if the referred timer never existed.
215  */
216  bool HasTimeoutExpired(const TimeoutPublisherHandle aTimerHandle) const;
217 
218  /**
219  * @brief Should return the time offset to Epoch
220  *
221  * This must be implemented by subclasses. Different detectors may call
222  * this to acquire a timestamp - usually used to "stamp" a TopicState.
223  * This clock may jump back & forth due to time sync.
224  */
225  virtual TimeOffset GetTime() const = 0;
226 
227  /**
228  * @brief Should return monotonic time since some unspecified starting point.
229  *
230  * This must be implemented by subclasses.
231  * Returns the time offset to an unspecified point back in time that should
232  * not change for the duration of this instance.
233  * Different detectors may call this to acquire a consistent, strictly
234  * increasing, time offset valid for the duration of this object's instance.
235  */
236  virtual TimeOffset GetMonotonicTime() const = 0;
237 
238 protected:
239  /**
240  * @brief Fires/Dispatches a TopicState that was pending on a timeout
241  *
242  * This method should be called by a particular subclasses of
243  * TimeoutPublisherService to notify the service that the actual
244  * internal timers have expired/fired.
245  */
246  void TimeoutExpired(const TimeoutPublisherHandle aTimerHandle);
247 
248  /**
249  * @brief Should setup a timeout for the given handle.
250  *
251  * This must be implemented by subclasses. This should initialize a unique
252  * timer for that handle (if it doesn't already exist) and set it's timeout
253  * accordingly.
254  */
255  virtual void SetTimeout(const TimeOffset aMillisecondsFromNow, const TimeoutPublisherHandle) = 0;
256 
257  /**
258  * @brief Should start a timer for the given handle.
259  *
260  * This must be implemented by subclasses. This should start the timer.
261  */
262  virtual void Start(const TimeoutPublisherHandle) = 0;
263 
264  /**
265  * @brief Should cancel the timer the given handle.
266  *
267  * This must be implemented by subclasses. This should cancel the timer.
268  */
269  virtual void Cancel(const TimeoutPublisherHandle) = 0;
270 
271  /**
272  * @brief Update metronome counters and Fires/Dispatches TopicStates that was pending on scheduled period.
273  *
274  * This method should be called by a particular subclasses of
275  * TimeoutPublisherService to notify the service that the actual
276  * internal period timer has fired.
277  */
278  void MetronomeFired();
279 
280  /**
281  * @brief Should start the metronome (periodic timer) for the given period.
282  *
283  * This must be implemented by subclasses. This should start the periodic timer.
284  */
285  virtual void StartMetronome(const TimeOffset aPeriodInMilliseconds) = 0;
286 
287  /**
288  * @brief Should stop the metronome.
289  *
290  * This must be implemented by subclasses. This should stop the periodic timer.
291  */
292  virtual void CancelMetronome() = 0;
293 
294 private:
295  /**
296  * @brief Internal type-agnostic method to schedule timeouts
297  */
298  void ScheduleTimeoutDispatcher(DispatcherInterface* aDispatcher, const TimeOffset aMillisecondsFromNow, const TimeoutPublisherHandle aTimerHandle);
299 
300  /**
301  * @brief Internal type-agnostic method to schedule periodic timers
302  */
303  void SchedulePeriodicPublishingDispatcher(DispatcherInterface* aDispatcher, const TimeOffset aPeriodInMilliseconds);
304 
305  /**
306  * @brief Euclidean algorithm to compute great common divisor(GCD)
307  */
308  TimeOffset gcd(TimeOffset lhs, TimeOffset rhs);
309 
310  /**
311  * @brief Reference to the graph to which timed out TopicStates will be
312  pushed/posted.
313  */
314  Graph& mrGraph;
315 
316  /**
317  * @brief Metronome period which used for periodic Topicstates publishing
318  */
319  TimeOffset mMetronomePeriodMsec;
320 
321  /**
322  * @brief Map of pending TopicStates per Handle
323  */
324  TimeoutDispatchersContainer mTimeoutDispatchers;
325 
326  /**
327  * @brief List of scheduled periodic TopicStates dispatcher
328  */
329  PeriodicPublishingSeriesContainer mPeriodicSeries;
330 
331 #if defined(BUILD_FEATURE_DETECTORGRAPH_CONFIG_LITE)
332  TimeoutDispatchersAllocator mTimeoutDispatchersAllocator;
333  PeriodicDispatchersAllocator mPeriodicDispatchersAllocator;
334 #endif
335 };
336 
337 } // namespace DetectorGraph
338 
339 #endif // DETECTORGRAPH_INCLUDE_TIMEOUTPUBLISHERSERVICE_HPP_
bool HasTimeoutExpired(const TimeoutPublisherHandle aTimerHandle) const
Returns weather the timeout for a given handle has expired/fired already.
void CancelPublishOnTimeout(const TimeoutPublisherHandle aTimerHandle)
Cancels a timeout and deletes the stored TopicState.
virtual void Start(const TimeoutPublisherHandle)=0
Should start a timer for the given handle.
void SchedulePeriodicPublishing(const TimeOffset aPeriodInMilliseconds)
Schedules a TopicState for publishing periodically.
virtual TimeOffset GetMonotonicTime() const =0
Should return monotonic time since some unspecified starting point.
Implements a graph of Topics & Detectors with Input/Output APIs.
Definition: graph.hpp:127
TimeoutPublisherHandle GetUniqueTimerHandle()
Returns a unique id/handle for a new timer.
void PushData(const TTopicState &aTopicState)
Push data to a specific topic in the graph.
Definition: graph.hpp:187
TimeoutPublisherService(Graph &graph)
Constructor that initializes the service connected to a graph.
virtual void SetTimeout(const TimeOffset aMillisecondsFromNow, const TimeoutPublisherHandle)=0
Should setup a timeout for the given handle.
A service that provides Timer function to DetectorGraph Detectors.
void DG_LOG(const char *aLogString,...)
Definition: dglogging.cpp:22
virtual void StartMetronome(const TimeOffset aPeriodInMilliseconds)=0
Should start the metronome (periodic timer) for the given period.
void ScheduleTimeout(const T &aData, const TimeOffset aMillisecondsFromNow, const TimeoutPublisherHandle aTimerHandle)
Schedules a TopicState for Publishing after a timeout.
void StartPeriodicPublishing()
Starts a Metronome to publish scheduled TopicStates.
virtual void CancelMetronome()=0
Should stop the metronome.
void TimeoutExpired(const TimeoutPublisherHandle aTimerHandle)
Fires/Dispatches a TopicState that was pending on a timeout.
void MetronomeFired()
Update metronome counters and Fires/Dispatches TopicStates that was pending on scheduled period...
virtual TimeOffset GetTime() const =0
Should return the time offset to Epoch.
virtual void Cancel(const TimeoutPublisherHandle)=0
Should cancel the timer the given handle.