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)
5  2023, Hermann Vosseler <Ichthyostega@web.de>
6 
7   **Lumiera** is free software; you can redistribute it and/or modify it
8   under the terms of the GNU General Public License as published by the
9   Free Software Foundation; either version 2 of the License, or (at your
10   option) any later version. See the file COPYING for further details.
11 
12 */
13 
14 
55 #ifndef SRC_VAULT_GEAR_ACTIVITY_H_
56 #define SRC_VAULT_GEAR_ACTIVITY_H_
57 
58 
59 #include "vault/common.hpp"
60 #include "vault/gear/job.h"
61 #include "lib/time/timevalue.hpp"
62 #include "lib/meta/function.hpp"
63 #include "lib/util.hpp"
64 
65 
66 namespace vault{
67 namespace gear {
68 
70  using lib::time::TimeVar;
71  using lib::time::Offset;
72 
73  namespace error = lumiera::error;
74 
77 
85  {
86  uint32_t id_;
87 
88  public:
89  ManifestationID (uint32_t rawID =0)
90  : id_{rawID}
91  { }
92  // standard copy operations acceptable
93 
94  explicit operator uint32_t() const { return id_;}
95  explicit operator bool() const { return id_ != 0; }
96 
97  friend bool operator== (ManifestationID const& a, ManifestationID const& b) { return a.id_ == b.id_; }
98  friend bool operator!= (ManifestationID const& a, ManifestationID const& b) { return not (a == b); }
99  };
100  HashVal hash_value (ManifestationID const& id);
102 
103  class Activity;
104 
105 
106  namespace activity {
107 
115  class Instant
116  {
117  int64_t microTick_;
118 
119  public:
120  Instant() =default; // @suppress("Class members should be properly initialized")
121 
123  : microTick_{_raw(time)}
124  { }
125 
126  operator TimeVar() const
127  {
128  return TimeValue{microTick_};
129  }
130 
131  // default copy acceptable
132  };
133 
134 
140  enum Proc {PASS
145  };
146 
147 
153  class Hook
154  {
155  public:
156  virtual ~Hook();
157 
171  virtual Proc activation ( Activity& thisHook
172  , Time now
173  , void* executionCtx) =0;
174 
176  virtual Proc notify ( Activity& thisHook
177  , Time now
178  , void* executionCtx) =0;
179 
180  virtual Time getDeadline() const =0;
181 
182  virtual std::string
183  diagnostic() const
184  {
185  return "Activity::Hook";
186  }
187 
188  operator std::string() const
189  {
190  return diagnostic();
191  }
192  };
193 
194 
201  template<class EXE>
202  constexpr void
204  {
205  ASSERT_MEMBER_FUNCTOR (&EXE::post, Proc(Time, Time, Activity*, EXE&));
206  ASSERT_MEMBER_FUNCTOR (&EXE::work, void(Time, size_t));
207  ASSERT_MEMBER_FUNCTOR (&EXE::done, void(Time, size_t));
208  ASSERT_MEMBER_FUNCTOR (&EXE::tick, Proc(Time));
209 
210  ASSERT_MEMBER_FUNCTOR (&EXE::getSchedTime, Time());
211  }
212 
213  }//(End)namespace activity
214 
215 
216 
217 
218  /*********************************************/
226  class Activity
227  {
228  using Instant = activity::Instant;
229 
230  public:
232  enum Verb {INVOKE
233  ,WORKSTART
234  ,WORKSTOP
235  ,NOTIFY
236  ,GATE
237  ,POST
238  ,FEED
239  ,HOOK
240  ,TICK
241  };
242 
243  const Verb verb_;
244 
250 
251 
252  /* === Activity Data Arguments === */
253 
255  struct Feed
256  {
257  uint64_t one;
258  uint64_t two;
259  };
260 
262  struct Timing
263  {
264  Instant instant;
265  size_t quality;
266  };
267 
269  struct Callback
270  {
271  activity::Hook* hook;
272  size_t arg;
273  };
274 
276  struct Condition
277  {
278  int rest;
280 
281  bool isDead (Time now) const { return dead <= now;}
282  bool isHold () const { return rest > 0; }
283  bool isFree (Time now) const { return not (isHold() or isDead(now)); }
284  Time getDeadline() const { return Time{dead}; }
285  void incDependencies() { ++rest; }
286 
287  Time
288  lockPermanently()
289  {
290  auto oldDeadline{dead};
291  dead = Time::MIN;
292  return Time{oldDeadline};
293  }
294  };
295 
297  struct TimeWindow
298  {
299  Instant life;
300  Instant dead;
301  };
302 
304  struct Invocation
305  {
306  JobFunctor* task;
307  Instant time;
308  };
309 
312  {
313  Activity* target;
314  Instant timing;
315  };
316 
317 
320  {
321  Feed feed;
322  Timing timing;
323  Callback callback;
324  Condition condition;
325  TimeWindow timeWindow;
326  Invocation invocation;
327  Notification notification;
328  };
329  ArgumentData data_;
330 
331 
332  explicit
333  Activity (Verb verb) noexcept
334  : verb_{verb}
335  , next{nullptr}
336  {
337  setDefaultArg (verb);
338  }
339 
340  // using default copy/assignment
341 
342 
343  /* ==== special case initialisation ==== */
344 
345  Activity (uint64_t o1, uint64_t o2) noexcept
346  : Activity{FEED}
347  {
348  data_.feed.one = o1;
349  data_.feed.two = o2;
350  }
351 
352  Activity (JobFunctor& job, Time nominalTime, Activity& feed) noexcept
353  : Activity{INVOKE}
354  {
355  data_.invocation.task = &job;
356  data_.invocation.time = nominalTime;
357  next = &feed;
358  }
359 
360  explicit
361  Activity (Activity* target, Time limitWhen =Time::ANYTIME) noexcept
362  : Activity{NOTIFY}
363  {
364  data_.notification.target = target;
365  data_.notification.timing = limitWhen;
366  }
367 
368  explicit
369  Activity (int expectNotifications, Time deadline = Time::NEVER) noexcept
370  : Activity{GATE}
371  {
372  data_.condition.rest = expectNotifications;
373  data_.condition.dead = deadline;
374  }
375 
376  Activity (Time when, Activity* followUp) noexcept
377  : verb_{POST}
378  , next{followUp}
379  {
380  data_.timeWindow = {when,when};
381  }
382 
383  Activity (Time start, Time after, Activity* followUp) noexcept
384  : verb_{POST}
385  , next{followUp}
386  {
387  data_.timeWindow = {start,after};
388  }
389 
390  Activity (activity::Hook& callback, size_t arg) noexcept
391  : Activity{HOOK}
392  {
393  data_.callback.hook = &callback;
394  data_.callback.arg = arg;
395  }
396 
397  Activity() noexcept
398  : Activity{TICK}
399  { }
400 
402  operator std::string() const;
403 
404  std::string showVerb() const;
405  std::string showData() const;
406 
407 
408  /********************************************************/
413  template<class EXE>
414  activity::Proc activate (Time now, EXE& executionCtx);
415 
416  template<class EXE>
417  activity::Proc dispatch (Time now, EXE& executionCtx);
418 
419 
420  /* === special case access and manipulation === */
421  bool
422  is (Activity::Verb expectedVerb) const
423  {
424  return expectedVerb == this->verb_;
425  }
426 
427  void
428  incDependencies()
429  {
430  REQUIRE (is (GATE));
431  data_.condition.incDependencies();
432  }
433 
434  void
435  setNotificationTarget (Activity* target, Time limitStart =Time::ANYTIME)
436  {
437  REQUIRE (is (NOTIFY));
438  data_.notification.target = target;
439  data_.notification.timing = limitStart;
440  }
441 
442  Time
444  {
445  return is(POST)? util::max (start, Time{data_.timeWindow.life})
446  : start;
447  }
448 
449  Time
451  {
452  return is(POST)? util::min (death, Time{data_.timeWindow.dead})
453  : death;
454  }
455 
456 
457  private:
458  void
459  setDefaultArg (Verb verb) noexcept
460  {
461  data_ = {0,0};
462  switch (verb) {
463  case INVOKE:
464  data_.invocation.time = Time::ANYTIME;
465  break;
466  case WORKSTART:
467  case WORKSTOP:
468  data_.timing.instant = Time::NEVER;
469  break;
470  case GATE:
471  data_.condition.rest = 1;
472  data_.condition.dead = Time::NEVER;
473  break;
474  case POST:
475  data_.timeWindow.life = Time::ANYTIME;
476  data_.timeWindow.dead = Time::NEVER;
477  break;
478  default:
479  break;
480  }
481  }
482 
483 
485  invokeFunktor (Time) noexcept
486  {
487  REQUIRE (verb_ == INVOKE);
488  REQUIRE (next);
489  REQUIRE (next->verb_ == FEED);
490  REQUIRE (next->next);
491  REQUIRE (next->next->verb_ == FEED);
492  REQUIRE (data_.invocation.task);
493 
494  JobClosure& functor = static_cast<JobClosure&> (*data_.invocation.task);
495  lumiera_jobParameter param;
496  param.nominalTime = _raw(Time{data_.invocation.time});
497  param.invoKey.code.w1 = next->data_.feed.one;
498  param.invoKey.code.w2 = next->data_.feed.two;
500  try {
501  functor.invokeJobOperation (param);
502  }
503  ON_EXCEPTION_RETURN (activity::HALT, "Render Job invocation");
504  //
505  return activity::PASS;
506  }
507 
508 
509  template<class EXE>
511  signalStart (Time now, EXE& executionCtx)
512  {
513  executionCtx.work (now, data_.timing.quality);
514  return activity::PASS;
515  }
516 
517  template<class EXE>
519  signalStop (Time now, EXE& executionCtx)
520  {
521  executionCtx.done (now, data_.timing.quality);
522  return activity::PASS;
523  }
524 
525  template<class EXE>
527  checkGate (Time now, EXE&)
528  {
529  REQUIRE (GATE == verb_);
530  if (data_.condition.isDead(now)) // beyond deadline
531  return activity::SKIP;
532  if (data_.condition.isHold()) // prerequisite count not(yet) fulfilled -> block further activation
533  return activity::SKIP;
534  else
535  return activity::PASS;
536  }
537 
539  receiveGateNotification (Time now)
540  {
541  REQUIRE (GATE == verb_);
542  if (data_.condition.rest > 0)
543  {
544  --data_.condition.rest;
545  // maybe the Gate has been opened by this notification?
546  if (data_.condition.isFree(now))
547  {//yes => activate gated chain but lock redundant invocations
548  data_.condition.lockPermanently();
549  return activity::PASS;
550  } }
551  return activity::SKIP;
552  }
553 
554  template<class EXE>
556  postSelf (Time now, EXE& executionCtx)
557  {
558  REQUIRE (next);
559  if (is(POST))
560  return executionCtx.post (Time{data_.timeWindow.life},Time{data_.timeWindow.dead}, this, executionCtx);
561  else
562  return executionCtx.post (now,Time::NEVER, this, executionCtx);
563  }
564 
565  template<class EXE>
567  postNotify (Time now, EXE& executionCtx)
568  {
569  REQUIRE (is(NOTIFY));
570  Activity* target = data_.notification.target;
571  REQUIRE (target);
572  REQUIRE (not target->is(HOOK) or target->data_.callback.hook);
573  Time startHint = target->is(GATE) or
574  target->is(HOOK)? Time{data_.notification.timing}
575  : now;
576  Time deadline = target->is(GATE)? target->data_.condition.getDeadline()
577  : target->is(HOOK)? target->data_.callback.hook->getDeadline()
578  : Time::NEVER;
579  // indirectly forward to Activity::dispatch()
580  return executionCtx.post (startHint,deadline, target, executionCtx);
581  }
582 
583  template<class EXE>
585  callHook (Time now, EXE& executionCtx)
586  {
587  return data_.callback.hook? data_.callback.hook->activation(*this, now, &executionCtx)
588  : activity::PASS;
589  }
590 
591  template<class EXE>
593  notifyHook (Time now, EXE& executionCtx)
594  {
595  return data_.callback.hook? data_.callback.hook->notify (*this, now, &executionCtx)
596  : activity::PASS;
597  }
598 
599  template<class EXE>
601  doTick (Time now, EXE& executionCtx)
602  {
603  return executionCtx.tick (now);
604  }
605  };
606 
607 
608 
609 
624  template<class EXE>
626  Activity::activate (Time now, EXE& executionCtx)
627  {
628  activity::_verify_usable_as_ExecutionContext<EXE>();
629 
630  switch (verb_) {
631  case INVOKE:
632  return invokeFunktor (now);
633  case WORKSTART:
634  return signalStart (now, executionCtx);
635  case WORKSTOP:
636  return signalStop (now, executionCtx);
637  case NOTIFY:
638  return postNotify (now, executionCtx);
639  case POST:
640  return postSelf (now, executionCtx);
641  case GATE:
642  return checkGate (now, executionCtx);
643  case FEED:
644  return activity::PASS;
645  case HOOK:
646  return callHook (now, executionCtx);
647  case TICK:
648  return doTick (now, executionCtx);
649  default:
650  NOTREACHED ("uncovered Activity verb in activation function.");
651  }
652  }
653 
654 
674  template<class EXE>
676  Activity::dispatch (Time now, EXE& executionCtx)
677  {
678  activity::_verify_usable_as_ExecutionContext<EXE>();
679 
680  switch (verb_) {
681  case POST:
682  case FEED: // signal just to proceed with next...
683  return activity::PASS;
684  case GATE:
685  return receiveGateNotification (now);
686  case HOOK:
687  return notifyHook (now, executionCtx);
688  default:
689  return activate (now, executionCtx);
690  }
691  }
692 
693 
694 }} // namespace vault::gear
695 #endif /*SRC_VAULT_GEAR_ACTIVITY_H_*/
static const Time ANYTIME
border condition marker value. ANYTIME <= any time value
Definition: timevalue.hpp:313
a mutable time value, behaving like a plain number, allowing copy and re-accessing ...
Definition: timevalue.hpp:232
Time window to define for activation.
Definition: activity.hpp:297
Record to describe an Activity, to happen within the Scheduler&#39;s control flow.
Definition: activity.hpp:226
< special definitions for the Scheduler activity language
Definition: activity.hpp:115
#define ON_EXCEPTION_RETURN(_VAL_, _OP_DESCR_)
convenience shortcut to catch and absorb any exception, then returning a default value instead...
Definition: error.hpp:304
Extension point to invoke.
Definition: activity.hpp:269
Access gate condition to evaluate.
Definition: activity.hpp:276
abandon this play / render process
Definition: activity.hpp:144
#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:273
int rest
alive while rest > 0
Definition: activity.hpp:278
constexpr void _verify_usable_as_ExecutionContext()
Definition to emulate a Concept for the Execution Context.
Definition: activity.hpp:203
Time constrainedDeath(Time death)
Definition: activity.hpp:450
activity::Proc activate(Time now, EXE &executionCtx)
Core Operation: Activate and perform this Activity.
Definition: activity.hpp:626
Lumiera&#39;s internal time value datatype.
Definition: timevalue.hpp:299
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:84
Metaprogramming tools for transforming functor types.
External work functor to activate.
Definition: activity.hpp:304
Verb
All possible kinds of activities.
Definition: activity.hpp:232
nothing to do; wait and re-check for work later
Definition: activity.hpp:142
Extension point to invoke a callback from Activity activation.
Definition: activity.hpp:153
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...
Payload data to provide.
Definition: activity.hpp:255
pass on the activation down the chain
Definition: activity.hpp:140
back pressure; get out of the way but be back soon
Definition: activity.hpp:143
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:676
Activity * next
Activities are organised into chains to represent relations based on verbs.
Definition: activity.hpp:249
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:141
Basic set of definitions and includes commonly used together (Vault).
size_t HashVal
a STL compatible hash value
Definition: hash-value.h:52
static const Time NEVER
border condition marker value. NEVER >= any time value
Definition: timevalue.hpp:314
Interface of the closure for frame rendering jobs.
Definition: job.h:235
Offset measures a distance in time.
Definition: timevalue.hpp:358
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:279
Timing observation to propagate.
Definition: activity.hpp:262
Proc
Result instruction from Activity activation.
Definition: activity.hpp:140
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:133
Storage of Argument data dependent on Activity::verb_.
Definition: activity.hpp:319
Time constrainedStart(Time start)
Definition: activity.hpp:443
Vault-Layer implementation namespace root.
Notification towards another Activity.
Definition: activity.hpp:311