Lumiera  0.pre.03
»edit your freedom«
looper.hpp
Go to the documentation of this file.
1 /*
2  LOOPER.hpp - steam dispatcher loop and timing control logic
3 
4  Copyright (C) Lumiera.org
5  2016, Hermann Vosseler <Ichthyostega@web.de>
6 
7  This program is free software; you can redistribute it and/or
8  modify it under the terms of the GNU General Public License as
9  published by the Free Software Foundation; either version 2 of
10  the License, or (at your option) any later version.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 
21 */
22 
23 
49 #ifndef STEAM_CONTROL_LOOPER_H
50 #define STEAM_CONTROL_LOOPER_H
51 
52 #include "lib/time/timevalue.hpp"
53 #include "vault/real-clock.hpp"
54 
55 #include <functional>
56 #include <chrono>
57 
58 
59 
60 namespace steam {
61 namespace control {
62 
63  using lib::time::Time;
64  using lib::time::TimeVar;
65  using lib::time::Offset;
66  using lib::time::Duration;
67  using std::chrono::milliseconds;
68  using vault::RealClock;
69 
70  namespace {
80 
90  }
91 
92 
93 
114  class Looper
115  {
116  using Predicate = std::function<bool(void)>;
117 
118  bool shutdown_ = false;
119  bool disabled_ = false;
120  bool inChange_ = false;
121  bool hasWork_ = false;
122  bool isDirty_ = false;
123 
124  TimeVar gotDirty_ = Time::NEVER;
125 
126  Predicate hasCommandsPending_;
127 
128 
129  public:
130  template<class FUN>
131  Looper(FUN determine_commands_are_waiting)
132  : hasCommandsPending_(determine_commands_are_waiting)
133  { }
134 
135  // standard copy acceptable
136 
137 
138  /* == working state logic == */
139 
140  bool isDying() const { return shutdown_; }
141  bool isDisabled() const { return disabled_ or isDying(); }
142  bool useTimeout() const { return isDirty_ and not isDisabled(); }
143  bool isWorking() const { return hasWork_ and not isDisabled(); }
144  bool idleBuild() const { return isDirty_ and not hasWork_; }
145  bool runBuild() const { return (idleBuild() or forceBuild()) and not isDisabled(); }
146  bool isIdle() const { return not (isWorking() or runBuild() or isDisabled()); }
147 
148 
149  /* == operation control == */
150 
151  void
152  triggerShutdown()
153  {
154  shutdown_ = true;
155  }
156 
157  void
158  enableProcessing(bool yes =true)
159  {
160  disabled_ = not yes;
161  }
162 
173  void
175  {
176  inChange_ = false;
177  if (runBuild())
178  isDirty_ = false; // assume the builder has been triggered in the loop body
179  }
180 
181  bool
183  {
184  return inChange_;
185  }
186 
188  bool
190  {
191  hasWork_ = hasCommandsPending_();
192  bool proceedImmediately = isWorking() or forceBuild() or isDying();
193  inChange_ = proceedImmediately or useTimeout();
194 
195  if (isWorking() and not isDirty_)
196  { // schedule Builder run after timeout
197  startBuilderTimeout();
198  isDirty_ = true;
199  }
200 
201  return proceedImmediately;
202  }
203 
205  bool
206  shallLoop() const
207  {
208  return not isDying();
209  }
210 
211  milliseconds
212  getTimeout() const
213  {
214  if (not useTimeout())
215  return milliseconds::zero();
216  else
217  return milliseconds{
219  * (isDirty_ and not isWorking()? 1 : slowdownFactor())};
220  }
221 
222 
223  private:
224  static uint wakeTimeout_ms();
225  static uint slowdownFactor();
226 
227  void startBuilderTimeout();
228  bool forceBuild() const;
229  };
230 
231 
232 
244  inline uint
246  {
248  }
249 
250  inline uint
251  Looper::slowdownFactor()
252  {
254  }
255 
256  inline void
257  Looper::startBuilderTimeout()
258  {
259  gotDirty_ = RealClock::now();
260  }
261 
265  inline bool
267  {
268  static Duration maxBuildTimeout{Time(wakeTimeout_ms() * slowdownFactor(), 0)};
269 
270  return isDirty_
271  and maxBuildTimeout < Offset(gotDirty_, RealClock::now());
272  }
273 
274 
275 
276 }} // namespace steam::control
277 #endif /*STEAM_CONTROL_LOOPER_H*/
a mutable time value, behaving like a plain number, allowing copy and re-accessing ...
Definition: timevalue.hpp:241
const uint STEAM_DISPATCHER_BUSY_SLOWDOWN_FACTOR
Factor to slow down the latency when the command queue is not empty.
Definition: looper.hpp:89
bool hasPendingChanges() const
< "check point"
Definition: looper.hpp:182
const uint STEAM_DISPATCHER_BUILDER_DELAY_ms
Latency to trigger the Builder after processing command(s).
Definition: looper.hpp:79
bool forceBuild() const
Definition: looper.hpp:266
Steam-Layer implementation namespace root.
bool shallLoop() const
state fusion to control looping
Definition: looper.hpp:206
bool requireAction()
state fusion to control (timed) wait
Definition: looper.hpp:189
Lumiera&#39;s internal time value datatype.
Definition: timevalue.hpp:308
void markStateProcessed()
invoking this function signals that all consequences of past state changes have been processed and ar...
Definition: looper.hpp:174
static const Time NEVER
border condition marker value. NEVER >= any time value
Definition: timevalue.hpp:323
Offset measures a distance in time.
Definition: timevalue.hpp:367
Duration is the internal Lumiera time metric.
Definition: timevalue.hpp:477
Encapsulated control logic for the session thread loop.
Definition: looper.hpp:114
Convenience frontend to access the current raw system time.
Definition: real-clock.hpp:54
a family of time value like entities and their relationships.
Front-end for simplified access to the current wall clock time.
static uint wakeTimeout_ms()
Definition: looper.hpp:245