Lumiera  0.pre.03
»edit your freedom«
activity.hpp
Go to the documentation of this file.
1 /*
2  ACTIVITY.hpp - elementary operation to be handled by the scheduler
3 
4  Copyright (C) Lumiera.org
5  2023, 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 
64 #ifndef SRC_VAULT_GEAR_ACTIVITY_H_
65 #define SRC_VAULT_GEAR_ACTIVITY_H_
66 
67 
68 #include "vault/common.hpp"
69 #include "vault/gear/job.h"
70 #include "lib/time/timevalue.hpp"
71 #include "lib/meta/function.hpp"
72 #include "lib/util.hpp"
73 
74 
75 namespace vault{
76 namespace gear {
77 
79  using lib::time::TimeVar;
80  using lib::time::Offset;
81 
82  namespace error = lumiera::error;
83 
86 
94  {
95  uint32_t id_;
96 
97  public:
98  ManifestationID (uint32_t rawID =0)
99  : id_{rawID}
100  { }
101  // standard copy operations acceptable
102 
103  explicit operator uint32_t() const { return id_;}
104  explicit operator bool() const { return id_ != 0; }
105 
106  friend bool operator== (ManifestationID const& a, ManifestationID const& b) { return a.id_ == b.id_; }
107  friend bool operator!= (ManifestationID const& a, ManifestationID const& b) { return not (a == b); }
108  };
109  HashVal hash_value (ManifestationID const& id);
111 
112  class Activity;
113 
114 
115  namespace activity {
116 
124  class Instant
125  {
126  int64_t microTick_;
127 
128  public:
129  Instant() =default; // @suppress("Class members should be properly initialized")
130 
132  : microTick_{_raw(time)}
133  { }
134 
135  operator TimeVar() const
136  {
137  return TimeValue{microTick_};
138  }
139 
140  // default copy acceptable
141  };
142 
143 
149  enum Proc {PASS
154  };
155 
156 
162  class Hook
163  {
164  public:
165  virtual ~Hook();
166 
180  virtual Proc activation ( Activity& thisHook
181  , Time now
182  , void* executionCtx) =0;
183 
185  virtual Proc notify ( Activity& thisHook
186  , Time now
187  , void* executionCtx) =0;
188 
189  virtual Time getDeadline() const =0;
190 
191  virtual std::string
192  diagnostic() const
193  {
194  return "Activity::Hook";
195  }
196 
197  operator std::string() const
198  {
199  return diagnostic();
200  }
201  };
202 
203 
210  template<class EXE>
211  constexpr void
213  {
214  ASSERT_MEMBER_FUNCTOR (&EXE::post, Proc(Time, Time, Activity*, EXE&));
215  ASSERT_MEMBER_FUNCTOR (&EXE::work, void(Time, size_t));
216  ASSERT_MEMBER_FUNCTOR (&EXE::done, void(Time, size_t));
217  ASSERT_MEMBER_FUNCTOR (&EXE::tick, Proc(Time));
218 
219  ASSERT_MEMBER_FUNCTOR (&EXE::getSchedTime, Time());
220  }
221 
222  }//(End)namespace activity
223 
224 
225 
226 
227  /*********************************************/
235  class Activity
236  {
237  using Instant = activity::Instant;
238 
239  public:
241  enum Verb {INVOKE
242  ,WORKSTART
243  ,WORKSTOP
244  ,NOTIFY
245  ,GATE
246  ,POST
247  ,FEED
248  ,HOOK
249  ,TICK
250  };
251 
252  const Verb verb_;
253 
259 
260 
261  /* === Activity Data Arguments === */
262 
264  struct Feed
265  {
266  uint64_t one;
267  uint64_t two;
268  };
269 
271  struct Timing
272  {
273  Instant instant;
274  size_t quality;
275  };
276 
278  struct Callback
279  {
280  activity::Hook* hook;
281  size_t arg;
282  };
283 
285  struct Condition
286  {
287  int rest;
289 
290  bool isDead (Time now) const { return dead <= now;}
291  bool isHold () const { return rest > 0; }
292  bool isFree (Time now) const { return not (isHold() or isDead(now)); }
293  Time getDeadline() const { return Time{dead}; }
294  void incDependencies() { ++rest; }
295 
296  Time
297  lockPermanently()
298  {
299  auto oldDeadline{dead};
300  dead = Time::MIN;
301  return Time{oldDeadline};
302  }
303  };
304 
306  struct TimeWindow
307  {
308  Instant life;
309  Instant dead;
310  };
311 
313  struct Invocation
314  {
315  JobFunctor* task;
316  Instant time;
317  };
318 
321  {
322  Activity* target;
323  Instant timing;
324  };
325 
326 
329  {
330  Feed feed;
331  Timing timing;
332  Callback callback;
333  Condition condition;
334  TimeWindow timeWindow;
335  Invocation invocation;
336  Notification notification;
337  };
338  ArgumentData data_;
339 
340 
341  explicit
342  Activity (Verb verb) noexcept
343  : verb_{verb}
344  , next{nullptr}
345  {
346  setDefaultArg (verb);
347  }
348 
349  // using default copy/assignment
350 
351 
352  /* ==== special case initialisation ==== */
353 
354  Activity (uint64_t o1, uint64_t o2) noexcept
355  : Activity{FEED}
356  {
357  data_.feed.one = o1;
358  data_.feed.two = o2;
359  }
360 
361  Activity (JobFunctor& job, Time nominalTime, Activity& feed) noexcept
362  : Activity{INVOKE}
363  {
364  data_.invocation.task = &job;
365  data_.invocation.time = nominalTime;
366  next = &feed;
367  }
368 
369  explicit
370  Activity (Activity* target, Time limitWhen =Time::ANYTIME) noexcept
371  : Activity{NOTIFY}
372  {
373  data_.notification.target = target;
374  data_.notification.timing = limitWhen;
375  }
376 
377  explicit
378  Activity (int expectNotifications, Time deadline = Time::NEVER) noexcept
379  : Activity{GATE}
380  {
381  data_.condition.rest = expectNotifications;
382  data_.condition.dead = deadline;
383  }
384 
385  Activity (Time when, Activity* followUp) noexcept
386  : verb_{POST}
387  , next{followUp}
388  {
389  data_.timeWindow = {when,when};
390  }
391 
392  Activity (Time start, Time after, Activity* followUp) noexcept
393  : verb_{POST}
394  , next{followUp}
395  {
396  data_.timeWindow = {start,after};
397  }
398 
399  Activity (activity::Hook& callback, size_t arg) noexcept
400  : Activity{HOOK}
401  {
402  data_.callback.hook = &callback;
403  data_.callback.arg = arg;
404  }
405 
406  Activity() noexcept
407  : Activity{TICK}
408  { }
409 
411  operator std::string() const;
412 
413  std::string showVerb() const;
414  std::string showData() const;
415 
416 
417  /********************************************************/
422  template<class EXE>
423  activity::Proc activate (Time now, EXE& executionCtx);
424 
425  template<class EXE>
426  activity::Proc dispatch (Time now, EXE& executionCtx);
427 
428 
429  /* === special case access and manipulation === */
430  bool
431  is (Activity::Verb expectedVerb) const
432  {
433  return expectedVerb == this->verb_;
434  }
435 
436  void
437  incDependencies()
438  {
439  REQUIRE (is (GATE));
440  data_.condition.incDependencies();
441  }
442 
443  void
444  setNotificationTarget (Activity* target, Time limitStart =Time::ANYTIME)
445  {
446  REQUIRE (is (NOTIFY));
447  data_.notification.target = target;
448  data_.notification.timing = limitStart;
449  }
450 
451  Time
453  {
454  return is(POST)? util::max (start, Time{data_.timeWindow.life})
455  : start;
456  }
457 
458  Time
460  {
461  return is(POST)? util::min (death, Time{data_.timeWindow.dead})
462  : death;
463  }
464 
465 
466  private:
467  void
468  setDefaultArg (Verb verb) noexcept
469  {
470  data_ = {0,0};
471  switch (verb) {
472  case INVOKE:
473  data_.invocation.time = Time::ANYTIME;
474  break;
475  case WORKSTART:
476  case WORKSTOP:
477  data_.timing.instant = Time::NEVER;
478  break;
479  case GATE:
480  data_.condition.rest = 1;
481  data_.condition.dead = Time::NEVER;
482  break;
483  case POST:
484  data_.timeWindow.life = Time::ANYTIME;
485  data_.timeWindow.dead = Time::NEVER;
486  break;
487  default:
488  break;
489  }
490  }
491 
492 
494  invokeFunktor (Time) noexcept
495  {
496  REQUIRE (verb_ == INVOKE);
497  REQUIRE (next);
498  REQUIRE (next->verb_ == FEED);
499  REQUIRE (next->next);
500  REQUIRE (next->next->verb_ == FEED);
501  REQUIRE (data_.invocation.task);
502 
503  JobClosure& functor = static_cast<JobClosure&> (*data_.invocation.task);
504  lumiera_jobParameter param;
505  param.nominalTime = _raw(Time{data_.invocation.time});
506  param.invoKey.code.w1 = next->data_.feed.one;
507  param.invoKey.code.w2 = next->data_.feed.two;
509  try {
510  functor.invokeJobOperation (param);
511  }
512  ON_EXCEPTION_RETURN (activity::HALT, "Render Job invocation");
513  //
514  return activity::PASS;
515  }
516 
517 
518  template<class EXE>
520  signalStart (Time now, EXE& executionCtx)
521  {
522  executionCtx.work (now, data_.timing.quality);
523  return activity::PASS;
524  }
525 
526  template<class EXE>
528  signalStop (Time now, EXE& executionCtx)
529  {
530  executionCtx.done (now, data_.timing.quality);
531  return activity::PASS;
532  }
533 
534  template<class EXE>
536  checkGate (Time now, EXE&)
537  {
538  REQUIRE (GATE == verb_);
539  if (data_.condition.isDead(now)) // beyond deadline
540  return activity::SKIP;
541  if (data_.condition.isHold()) // prerequisite count not(yet) fulfilled -> block further activation
542  return activity::SKIP;
543  else
544  return activity::PASS;
545  }
546 
548  receiveGateNotification (Time now)
549  {
550  REQUIRE (GATE == verb_);
551  if (data_.condition.rest > 0)
552  {
553  --data_.condition.rest;
554  // maybe the Gate has been opened by this notification?
555  if (data_.condition.isFree(now))
556  {//yes => activate gated chain but lock redundant invocations
557  data_.condition.lockPermanently();
558  return activity::PASS;
559  } }
560  return activity::SKIP;
561  }
562 
563  template<class EXE>
565  postSelf (Time now, EXE& executionCtx)
566  {
567  REQUIRE (next);
568  if (is(POST))
569  return executionCtx.post (Time{data_.timeWindow.life},Time{data_.timeWindow.dead}, this, executionCtx);
570  else
571  return executionCtx.post (now,Time::NEVER, this, executionCtx);
572  }
573 
574  template<class EXE>
576  postNotify (Time now, EXE& executionCtx)
577  {
578  REQUIRE (is(NOTIFY));
579  Activity* target = data_.notification.target;
580  REQUIRE (target);
581  REQUIRE (not target->is(HOOK) or target->data_.callback.hook);
582  Time startHint = target->is(GATE) or
583  target->is(HOOK)? Time{data_.notification.timing}
584  : now;
585  Time deadline = target->is(GATE)? target->data_.condition.getDeadline()
586  : target->is(HOOK)? target->data_.callback.hook->getDeadline()
587  : Time::NEVER;
588  // indirectly forward to Activity::dispatch()
589  return executionCtx.post (startHint,deadline, target, executionCtx);
590  }
591 
592  template<class EXE>
594  callHook (Time now, EXE& executionCtx)
595  {
596  return data_.callback.hook? data_.callback.hook->activation(*this, now, &executionCtx)
597  : activity::PASS;
598  }
599 
600  template<class EXE>
602  notifyHook (Time now, EXE& executionCtx)
603  {
604  return data_.callback.hook? data_.callback.hook->notify (*this, now, &executionCtx)
605  : activity::PASS;
606  }
607 
608  template<class EXE>
610  doTick (Time now, EXE& executionCtx)
611  {
612  return executionCtx.tick (now);
613  }
614  };
615 
616 
617 
618 
633  template<class EXE>
635  Activity::activate (Time now, EXE& executionCtx)
636  {
637  activity::_verify_usable_as_ExecutionContext<EXE>();
638 
639  switch (verb_) {
640  case INVOKE:
641  return invokeFunktor (now);
642  case WORKSTART:
643  return signalStart (now, executionCtx);
644  case WORKSTOP:
645  return signalStop (now, executionCtx);
646  case NOTIFY:
647  return postNotify (now, executionCtx);
648  case POST:
649  return postSelf (now, executionCtx);
650  case GATE:
651  return checkGate (now, executionCtx);
652  case FEED:
653  return activity::PASS;
654  case HOOK:
655  return callHook (now, executionCtx);
656  case TICK:
657  return doTick (now, executionCtx);
658  default:
659  NOTREACHED ("uncovered Activity verb in activation function.");
660  }
661  }
662 
663 
683  template<class EXE>
685  Activity::dispatch (Time now, EXE& executionCtx)
686  {
687  activity::_verify_usable_as_ExecutionContext<EXE>();
688 
689  switch (verb_) {
690  case POST:
691  case FEED: // signal just to proceed with next...
692  return activity::PASS;
693  case GATE:
694  return receiveGateNotification (now);
695  case HOOK:
696  return notifyHook (now, executionCtx);
697  default:
698  return activate (now, executionCtx);
699  }
700  }
701 
702 
703 }} // namespace vault::gear
704 #endif /*SRC_VAULT_GEAR_ACTIVITY_H_*/
static const Time ANYTIME
border condition marker value. ANYTIME <= any time value
Definition: timevalue.hpp:322
a mutable time value, behaving like a plain number, allowing copy and re-accessing ...
Definition: timevalue.hpp:241
Time window to define for activation.
Definition: activity.hpp:306
Record to describe an Activity, to happen within the Scheduler&#39;s control flow.
Definition: activity.hpp:235
< special definitions for the Scheduler activity language
Definition: activity.hpp:124
#define ON_EXCEPTION_RETURN(_VAL_, _OP_DESCR_)
convenience shortcut to catch and absorb any exception, then returning a default value instead...
Definition: error.hpp:313
Extension point to invoke.
Definition: activity.hpp:278
Access gate condition to evaluate.
Definition: activity.hpp:285
abandon this play / render process
Definition: activity.hpp:153
#define ASSERT_MEMBER_FUNCTOR(_EXPR_, _SIG_)
Macro for a compile-time check to verify some member is present and comprises something invokable wit...
Definition: function.hpp:282
int rest
alive while rest > 0
Definition: activity.hpp:287
constexpr void _verify_usable_as_ExecutionContext()
Definition to emulate a Concept for the Execution Context.
Definition: activity.hpp:212
Time constrainedDeath(Time death)
Definition: activity.hpp:459
activity::Proc activate(Time now, EXE &executionCtx)
Core Operation: Activate and perform this Activity.
Definition: activity.hpp:635
Lumiera&#39;s internal time value datatype.
Definition: timevalue.hpp:308
virtual Proc notify(Activity &thisHook, Time now, void *executionCtx)=0
Callback when dispatching a NOTIFY-Activity to thisHook.
Marker for current (and obsolete) manifestations of a CalcStream processed by the Render-Engine...
Definition: activity.hpp:93
Metaprogramming tools for transforming functor types.
External work functor to activate.
Definition: activity.hpp:313
Verb
All possible kinds of activities.
Definition: activity.hpp:241
nothing to do; wait and re-check for work later
Definition: activity.hpp:151
Extension point to invoke a callback from Activity activation.
Definition: activity.hpp:162
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...
Payload data to provide.
Definition: activity.hpp:264
pass on the activation down the chain
Definition: activity.hpp:149
back pressure; get out of the way but be back soon
Definition: activity.hpp:152
activity::Proc dispatch(Time now, EXE &executionCtx)
Entrance point for an activation, which has been dispatched indirectly through the dispatch and/or pr...
Definition: activity.hpp:685
Activity * next
Activities are organised into chains to represent relations based on verbs.
Definition: activity.hpp:258
Definition of a render job.
ExampleStrategy::Qualifier two(string additionalArg)
definition of another qualifier two(arg), accepting an additional argument
skip rest of the Activity chain for good
Definition: activity.hpp:150
Basic set of definitions and includes commonly used together (Vault).
size_t HashVal
a STL compatible hash value
Definition: hash-value.h:56
static const Time NEVER
border condition marker value. NEVER >= any time value
Definition: timevalue.hpp:323
Interface of the closure for frame rendering jobs.
Definition: job.h:244
Offset measures a distance in time.
Definition: timevalue.hpp:367
virtual Proc activation(Activity &thisHook, Time now, void *executionCtx)=0
Callback on activation of the corresponding HOOK-Activity.
Instant dead
alive while time < dead
Definition: activity.hpp:288
Timing observation to propagate.
Definition: activity.hpp:271
Proc
Result instruction from Activity activation.
Definition: activity.hpp:149
ExampleStrategy::Qualifier one()
definition of a qualifier one()
a family of time value like entities and their relationships.
basic constant internal time value.
Definition: timevalue.hpp:142
Storage of Argument data dependent on Activity::verb_.
Definition: activity.hpp:328
Time constrainedStart(Time start)
Definition: activity.hpp:452
Vault-Layer implementation namespace root.
Notification towards another Activity.
Definition: activity.hpp:320