Lumiera  0.pre.03
»edit your freedom«
scheduler-commutator-test.cpp
Go to the documentation of this file.
1 /*
2  SchedulerCommutator(Test) - verify dependent activity processing in 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 
28 #include "lib/test/run.hpp"
29 #include "activity-detector.hpp"
32 #include "lib/time/timevalue.hpp"
33 #include "lib/format-cout.hpp"
34 #include "lib/thread.hpp"
35 #include "lib/util.hpp"
36 
37 #include <chrono>
38 
39 using test::Test;
41 
42 
43 namespace vault{
44 namespace gear {
45 namespace test {
46 
47  using lib::time::Time;
48  using lib::time::FSecs;
49  using std::atomic_bool;
50  using lib::ThreadHookable;
52  using util::isSameObject;
53 
54  using std::unique_ptr;
55  using std::make_unique;
56  using std::this_thread::yield;
57  using std::this_thread::sleep_for;
58  using std::chrono_literals::operator ""us;
59 
60 
61  namespace { // Load test parameters
62  const size_t NUM_THREADS = 20;
63  const size_t REPETITIONS = 100;
64  }
65 
66 
67 
68 
69 
70  /******************************************************************/
91  {
92 
93  virtual void
94  run (Arg)
95  {
100  verify_findWork();
103  verify_dispatch();
105  }
106 
107 
110  void
112  {
113  SchedulerInvocation queue;
114  SchedulerCommutator sched;
115  Activity activity;
116  Time when{3,4};
117  Time dead{5,6};
118 
119  // use the ActivityDetector for test instrumentation...
120  ActivityDetector detector;
121  Time now = detector.executionCtx.getSchedTime();
122  CHECK (now < dead);
123 
124  // prepare scenario: some activity is enqueued
125  queue.instruct ({activity, when, dead});
126 
127  // retrieve one event from queue and dispatch it
128  ActivationEvent act = sched.findWork(queue,now);
129  ActivityLang::dispatchChain (act, detector.executionCtx);
130 
131  CHECK (detector.verifyInvocation("CTX-tick").arg(now));
132  CHECK (queue.empty());
133 
134 // cout << detector.showLog()<<endl; // HINT: use this for investigation...
135  }
136 
137 
138 
141  void
143  {
144  SchedulerCommutator sched;
145 
146  auto myself = std::this_thread::get_id();
147  CHECK (not sched.holdsGroomingToken (myself));
148 
149  CHECK (sched.acquireGoomingToken());
150  CHECK ( sched.holdsGroomingToken (myself));
151 
152  sched.dropGroomingToken();
153  CHECK (not sched.holdsGroomingToken (myself));
155  }
156 
158  static void
160  {
161  auto myself = std::this_thread::get_id();
162  CHECK (not sched.holdsGroomingToken(myself));
163  CHECK (sched.acquireGoomingToken());
164  sched.dropGroomingToken();
165  }
166 
167 
168 
173  void
175  {
176  SchedulerCommutator sched;
177 
178  // Case-1: if a thread already holds the token....
179  CHECK (sched.acquireGoomingToken());
180  CHECK (sched.holdsGroomingToken (thisThread()));
181  {
182  auto guard = sched.requireGroomingTokenHere();
183  CHECK (sched.holdsGroomingToken (thisThread()));
184  }// leave scope -> nothing happens in this case
185  CHECK (sched.holdsGroomingToken (thisThread()));
186 
187  // Case-2: when not holding the token...
188  sched.dropGroomingToken();
189  {
190  // acquire automatically (this may block)
191  auto guard = sched.requireGroomingTokenHere();
192  CHECK (sched.holdsGroomingToken (thisThread()));
193  }// leave scope -> dropped automatically
194  CHECK (not sched.holdsGroomingToken (thisThread()));
195 
197  }
198 
199 
200 
206  void
208  {
209  SchedulerCommutator sched;
210 
211  size_t checkSum{0};
212  auto pause_and_sum = [&](size_t i) -> size_t
213  {
214  auto oldSum = checkSum;
215  sleep_for (500us);
216  checkSum = oldSum + i;
217  return 1;
218  };
219  auto protected_sum = [&](size_t i) -> size_t
220  {
221  while (not sched.acquireGoomingToken())
222  yield(); // contend until getting exclusive access
223  pause_and_sum(i);
224  sched.dropGroomingToken();
225  return 1;
226  };
227 
228  threadBenchmark<NUM_THREADS> (pause_and_sum, REPETITIONS);
229 
230  size_t brokenSum = checkSum;
231  checkSum = 0;
232 
233  threadBenchmark<NUM_THREADS> (protected_sum, REPETITIONS);
234 
235  CHECK (brokenSum < checkSum);
236  CHECK (checkSum = NUM_THREADS * REPETITIONS*(REPETITIONS-1)/2);
238  }
239 
240 
241 
242  atomic_bool stopTheHog_{false};
243  unique_ptr<ThreadHookable> groomingHog_;
244  using Launch = ThreadHookable::Launch;
245 
247  void
249  {
250  REQUIRE (not groomingHog_);
251  if (sched.holdsGroomingToken(std::this_thread::get_id()))
252  sched.dropGroomingToken();
253 
254  stopTheHog_ = false;
255  groomingHog_ = make_unique<ThreadHookable>(
256  Launch{[&]{
257  CHECK (sched.acquireGoomingToken());
258  do sleep_for (100us);
259  while (not stopTheHog_);
260  sched.dropGroomingToken();
261  }}
262  .atExit([&](ThreadWrapper& handle)
263  {
265  groomingHog_.reset();
266  })
267  .threadID("grooming-hog"));
268  sleep_for (500us);
269  ENSURE (groomingHog_);
270  }
271 
273  void
275  {
276  stopTheHog_ = true;
277  while (groomingHog_)
278  yield();
279  }
280 
281 
282 
283 
284 
285 // /** @test verify the logic to decide where and when to perform
286 // * the dispatch of a Scheduler Activity chain.
287 // */
288 // void
289 // verify_DispatchDecision()
290 // {
291 // SchedulerCommutator sched;
292 // ___ensureGroomingTokenReleased(sched);
293 //
294 // Time t1{10,0};
295 // Time t2{20,0};
296 // Time t3{30,0};
297 // Time now{t2};
298 //
299 // auto myself = std::this_thread::get_id();
300 // CHECK (sched.decideDispatchNow (t1, now)); // time is before now => good to execute
301 // CHECK (sched.holdsGroomingToken (myself)); // Side-Effect: acquired the Grooming-Token
302 //
303 // CHECK (sched.decideDispatchNow (t1, now)); // also works if Grooming-Token is already acquired
304 // CHECK (sched.holdsGroomingToken (myself));
305 //
306 // CHECK (sched.decideDispatchNow (t2, now)); // Boundary case time == now => good to execute
307 // CHECK (sched.holdsGroomingToken (myself));
308 //
309 // CHECK (not sched.decideDispatchNow (t3, now)); // Task in the future shall not be dispatched now
310 // CHECK (sched.holdsGroomingToken (myself)); // ...and this case has no impact on the Grooming-Token
311 // sched.dropGroomingToken();
312 //
313 // CHECK (not sched.decideDispatchNow (t3, now));
314 // CHECK (not sched.holdsGroomingToken (myself));
315 //
316 // blockGroomingToken(sched);
317 // CHECK (not sched.acquireGoomingToken());
318 //
319 // CHECK (not sched.decideDispatchNow (t1, now)); // unable to acquire => can not decide positively
320 // CHECK (not sched.holdsGroomingToken (myself));
321 //
322 // CHECK (not sched.decideDispatchNow (t2, now));
323 // CHECK (not sched.holdsGroomingToken (myself));
324 //
325 // unblockGroomingToken();
326 //
327 // CHECK (sched.decideDispatchNow (t2, now));
328 // CHECK (sched.holdsGroomingToken (myself));
329 // }
330 
331 
332 
335  void
337  {
338  SchedulerInvocation queue;
339  SchedulerCommutator sched;
340 
341  Time t1{10,0};
342  Time t2{20,0};
343  Time t3{30,0};
344  Time now{t2};
345 
346  CHECK (not sched.findWork (queue, now)); // empty queue, no work found
347 
348  Activity a1{1u,1u};
349  Activity a2{2u,2u};
350  Activity a3{3u,3u};
351 
352  queue.instruct ({a3, t3}); // activity scheduled into the future
353  CHECK (not sched.findWork (queue, now)); // ... not found with time `now`
354  CHECK (t3 == queue.headTime());
355 
356  queue.instruct ({a1, t1});
357  CHECK (isSameObject (a1, *sched.findWork(queue, now))); // but past activity is found
358  CHECK (not sched.findWork (queue, now)); // activity was retrieved
359 
360  queue.instruct ({a2, t2});
361  CHECK (isSameObject (a2, *sched.findWork(queue, now))); // activity scheduled for `now` is found
362  CHECK (not sched.findWork (queue, now)); // nothing more found for `now`
363  CHECK (t3 == queue.headTime());
364  CHECK (not queue.empty()); // yet the future activity a3 is still queued...
365 
366  CHECK (isSameObject (a3, *sched.findWork(queue, t3))); // ...and will be found when querying "later"
367  CHECK (not sched.findWork (queue, t3));
368  CHECK ( queue.empty()); // Everything retrieved and queue really empty
369 
370  queue.instruct ({a2, t2});
371  queue.instruct ({a1, t1});
372  CHECK (isSameObject (a1, *sched.findWork(queue, now))); // the earlier activity is found first
373  CHECK (t2 == queue.headTime());
374  CHECK (isSameObject (a2, *sched.findWork(queue, now)));
375  CHECK (not sched.findWork (queue, now));
376  CHECK ( queue.empty());
377 
378  queue.instruct ({a2, t2}); // prepare activity which /would/ be found...
379  blockGroomingToken(sched); // but prevent this thread from acquiring the GroomingToken
380  CHECK (not sched.findWork (queue, now)); // thus search aborts immediately
381  CHECK (not queue.empty());
382 
383  unblockGroomingToken(); // yet when we're able to get the GroomingToken
384  CHECK (isSameObject (a2, *sched.findWork(queue, now))); // the task can be retrieved
385  CHECK (queue.empty());
386  }
387 
388 
389 
399  void
401  {
402  SchedulerInvocation queue;
403  SchedulerCommutator sched;
404 
405  Time t1{10,0}; Activity a1{1u,1u};
406  Time t2{20,0}; Activity a2{2u,2u};
407  Time t3{30,0}; Activity a3{3u,3u};
408  Time t4{40,0}; Activity a4{4u,4u};
409  // start,deadline, manif.ID, isCompulsory
410  queue.instruct ({a1, t1, t4, ManifestationID{5}});
411  queue.instruct ({a2, t2, t2});
412  queue.instruct ({a3, t3, t3, ManifestationID{23}, true});
413  queue.instruct ({a4, t4, t4});
414  queue.activate(ManifestationID{5});
415  queue.activate(ManifestationID{23});
416 
417  queue.feedPrioritisation();
418  CHECK (t1 == queue.headTime());
419  CHECK (isSameObject (a1, *queue.peekHead()));
420  CHECK (not queue.isMissed(t1));
421  CHECK (not queue.isOutdated(t1));
422 
423  queue.drop(ManifestationID{5});
424  CHECK (t1 == queue.headTime());
425  CHECK (not queue.isMissed(t1));
426  CHECK ( queue.isOutdated(t1));
427 
428  CHECK (not sched.findWork(queue, t1));
429  CHECK (t2 == queue.headTime());
430  CHECK (isSameObject (a2, *queue.peekHead()));
431  CHECK (not queue.isMissed (t2));
432  CHECK (not queue.isOutdated(t2));
433  CHECK ( queue.isMissed (t3));
434  CHECK ( queue.isOutdated(t3));
435 
436  CHECK (not sched.findWork(queue, t2+Time{5,0}));
437  CHECK (t3 == queue.headTime());
438  CHECK (isSameObject (a3, *queue.peekHead()));
439  CHECK (not queue.isMissed (t3));
440  CHECK (not queue.isOutdated (t3));
441  CHECK (not queue.isOutOfTime(t3));
442  CHECK ( queue.isMissed (t4));
443  CHECK ( queue.isOutdated (t4));
444  CHECK ( queue.isOutOfTime(t4));
445 
446  CHECK (not sched.findWork(queue, t4));
447  CHECK (t3 == queue.headTime());
448  CHECK (not queue.isMissed (t3));
449  CHECK (not queue.isOutdated (t3));
450  CHECK (not queue.isOutOfTime(t3));
451  CHECK ( queue.isMissed (t4));
452  CHECK ( queue.isOutdated (t4));
453  CHECK ( queue.isOutOfTime(t4));
454 
455  queue.drop(ManifestationID{23});
456  CHECK (t3 == queue.headTime());
457  CHECK (not queue.isMissed (t3));
458  CHECK ( queue.isOutdated (t3));
459  CHECK (not queue.isOutOfTime(t3));
460  CHECK ( queue.isMissed (t4));
461  CHECK ( queue.isOutdated (t4));
462  CHECK (not queue.isOutOfTime(t4));
463 
464  CHECK (isSameObject (a3, *queue.peekHead()));
465  CHECK (isSameObject (a4, *sched.findWork(queue, t4)));
466  CHECK (queue.empty());
467  }
468 
469 
470 
473  void
475  {
476  // rigged execution environment to detect activations--------------
477  ActivityDetector detector;
478  Activity& activity = detector.buildActivationProbe ("testActivity");
479  auto makeEvent = [&](Time start) { return ActivationEvent{activity, start, start+Time{0,1}}; };
480  // set a dummy deadline to pass the sanity check
481  SchedulerInvocation queue;
482  SchedulerCommutator sched;
483 
484  Time now = detector.executionCtx.getSchedTime();
485  Time past {Time::ZERO};
486  Time future{now+now};
487 
488  // no one holds the GroomingToken
490  auto myself = std::this_thread::get_id();
491  CHECK (sched.acquireGoomingToken());
492 
493  // Activity with start time way into the past is enqueued, but then discarded
494  CHECK (activity::PASS == sched.postChain (makeEvent(past), queue));
495  CHECK (detector.ensureNoInvocation("testActivity")); // not invoked
496  CHECK (queue.peekHead()); // still in the queue...
497  CHECK (not sched.findWork (queue,now)); // but it is not retrieved due to deadline
498  CHECK (not queue.peekHead()); // and thus was dropped
499  CHECK (queue.empty());
500 
501  // future Activity is enqueued by short-circuit directly into the PriorityQueue if possible
502  CHECK (activity::PASS == sched.postChain (makeEvent(future), queue));
503  CHECK ( sched.holdsGroomingToken (myself));
504  CHECK (not queue.empty());
505  CHECK (isSameObject (activity, *queue.peekHead())); // appears at Head, implying it's in Priority-Queue
506 
507  queue.pullHead();
508  sched.dropGroomingToken();
509  CHECK (not sched.holdsGroomingToken (myself));
510  CHECK (queue.empty());
511 
512  // ...but GroomingToken is not acquired explicitly; Activity is just placed into the Instruct-Queue
513  CHECK (activity::PASS == sched.postChain (makeEvent(future), queue));
514  CHECK (not sched.holdsGroomingToken (myself));
515  CHECK (not queue.peekHead()); // not appearing at Head this time,
516  CHECK (not queue.empty()); // rather waiting in the Instruct-Queue
517 
518 
519  blockGroomingToken(sched);
520  CHECK (activity::PASS == sched.postChain (makeEvent(now), queue));
521  CHECK (not sched.holdsGroomingToken (myself));
522  CHECK (not queue.peekHead()); // was enqueued, not executed
523 
524  // Note: this test did not cause any direct invocation;
525  // all provided events were queued only
526  CHECK (detector.ensureNoInvocation("testActivity"));
527 
528  // As sanity-check: the first event was enqueued and the picked up;
529  // two further cases where enqueued; we could retrieve them if
530  // re-acquiring the GroomingToken and using suitable query-time
532  queue.feedPrioritisation();
533  CHECK (now == queue.headTime());
534  CHECK (isSameObject (activity, *sched.findWork(queue, now)));
535  CHECK (sched.holdsGroomingToken (myself)); // findWork() acquired the token
536  CHECK (future == queue.headTime());
537  CHECK (not queue.isDue(now));
538  CHECK ( queue.isDue(future));
539  CHECK (sched.findWork(queue, future));
540  CHECK ( queue.empty());
541  }
542 
543 
544 
552  void
554  {
555  // rigged execution environment to detect activations--------------
556  ActivityDetector detector;
557  Activity& activity = detector.buildActivationProbe ("testActivity");
558  // set a dummy deadline to pass the sanity check
559  SchedulerInvocation queue;
560  SchedulerCommutator sched;
561  LoadController lCtrl;
562 
563  Time start{0,1};
564  Time dead{0,10};
565  // prepare the queue with one activity
566  CHECK (Time::NEVER == queue.headTime());
567  queue.instruct ({activity, start, dead});
568  queue.feedPrioritisation();
569  CHECK (start == queue.headTime());
570 
571  // for the first testcase,
572  // set Grooming-Token to be blocked
573  blockGroomingToken(sched);
574  auto myself = std::this_thread::get_id();
575  CHECK (not sched.holdsGroomingToken (myself));
576 
577  // invoking the dequeue and dispatch requires some wiring
578  // with functionality provided by other parts of the scheduler
579  auto getSchedTime = detector.executionCtx.getSchedTime;
580  auto executeActivity = [&](ActivationEvent event)
581  {
582  return ActivityLang::dispatchChain (event, detector.executionCtx);
583  };
584 
585  // Invoke the pull-work functionality directly from this thread
586  // (in real usage, this function is invoked from a worker)
587  CHECK (activity::KICK == sched.dispatchCapacity (queue
588  ,lCtrl
589  ,executeActivity
590  ,getSchedTime));
591  CHECK (not queue.empty());
592  // the first invocation was kicked back,
593  // since the Grooming-token could not be acquired.
595 
596  // ...now this thread can acquire, fetch from queue and dispatch....
597  CHECK (activity::PASS == sched.dispatchCapacity (queue
598  ,lCtrl
599  ,executeActivity
600  ,getSchedTime));
601 
602  CHECK (queue.empty());
603  CHECK (not sched.holdsGroomingToken (myself));
604  CHECK (detector.verifyInvocation("testActivity"));
605  }
606 
607 
608 
609 
620  void
622  { // ·==================================================================== setup a rigged Job
623  Time nominal{7,7};
624  Time start{0,1};
625  Time dead{0,10};
626 
627  ActivityDetector detector;
628  Job testJob{detector.buildMockJob("testJob", nominal, 12345)};
629 
630  BlockFlowAlloc bFlow;
631  ActivityLang activityLang{bFlow};
632 
633  // Build the Activity-Term for a simple calculation job...
634  Activity& anchor = activityLang.buildCalculationJob (testJob, start,dead)
635  .post(); // retrieve the entrance point to the chain
636 
637  // insert instrumentation to trace activation
638  detector.watchGate (anchor.next, "theGate");
639 
640 
641  // ·=================================================================== setup test subject
642  SchedulerInvocation queue;
643  SchedulerCommutator sched;
644 
645  // no one holds the GroomingToken
647  auto myself = std::this_thread::get_id();
648  CHECK (not sched.holdsGroomingToken (myself));
649 
650  TimeVar now{Time::ZERO};
651 
652  // rig the ExecutionCtx to allow manipulating "current scheduler time"
653  detector.executionCtx.getSchedTime = [&]{ return Time{now}; };
654  // rig the λ-work to verify GroomingToken and to drop it then
655  detector.executionCtx.work.implementedAs(
656  [&](Time, size_t)
657  {
658  CHECK (sched.holdsGroomingToken (myself));
659  sched.dropGroomingToken();
660  });
661 
662 
663  // ·=================================================================== actual test sequence
664  // Add the Activity-Term to be scheduled for planned start-Time
665  sched.postChain (ActivationEvent{anchor, start}, queue);
666  CHECK (detector.ensureNoInvocation("testJob"));
667  CHECK (not sched.holdsGroomingToken (myself));
668  CHECK (not queue.empty());
669 
670  // later->"now"
671  now = Time{555,5};
672  detector.incrementSeq();
673 
674  // Assuming a worker runs "later" and retrieves work...
675  ActivationEvent act = sched.findWork(queue,now);
676  CHECK (sched.holdsGroomingToken (myself)); // acquired the GroomingToken
677  CHECK (isSameObject(*act, anchor)); // "found" the rigged Activity as next piece of work
678 
679  // dispatch the Activity-chain just retrieved from the queue
680  ActivityLang::dispatchChain (act, detector.executionCtx);
681 
682  CHECK (queue.empty());
683  CHECK (not sched.holdsGroomingToken (myself)); // the λ-work was invoked and dropped the GroomingToken
684 
685  CHECK (detector.verifySeqIncrement(1)
686  .beforeInvocation("theGate").arg("5.555 ⧐ Act(GATE")
687  .beforeInvocation("after-theGate").arg("⧐ Act(WORKSTART")
688  .beforeInvocation("CTX-work").arg("5.555","")
689  .beforeInvocation("testJob") .arg("7.007",12345)
690  .beforeInvocation("CTX-done").arg("5.555",""));
691 
692 // cout << detector.showLog()<<endl; // HINT: use this for investigation...
693  }
694  };
695 
696 
698  LAUNCHER (SchedulerCommutator_test, "unit engine");
699 
700 
701 
702 }}} // namespace vault::gear::test
a mutable time value, behaving like a plain number, allowing copy and re-accessing ...
Definition: timevalue.hpp:241
activity::Proc postChain(ActivationEvent event, SchedulerInvocation &layer1)
This is the primary entrance point to the Scheduler.
Record to describe an Activity, to happen within the Scheduler&#39;s control flow.
Definition: activity.hpp:235
auto threadBenchmark(FUN const &subject, const size_t repeatCnt=DEFAULT_RUNS)
perform a multithreaded microbenchmark.
Automatically use custom string conversion in C++ stream output.
bool holdsGroomingToken(ThreadID id) noexcept
check if the indicated thread currently holds the right to conduct internal state transitions...
void dropGroomingToken() noexcept
relinquish the right for internal state transitions.
Definition: run.hpp:49
Scheduler Layer-2 : execution of Scheduler Activities.
auto thisThread()
convenient short-notation, also used by SchedulerService
ActivationEvent findWork(SchedulerInvocation &layer1, Time now)
Look into the queues and possibly retrieve work due by now.
Functions to perform (multithreaded) timing measurement on a given functor.
Lumiera&#39;s internal time value datatype.
Definition: timevalue.hpp:308
static void ___ensureGroomingTokenReleased(SchedulerCommutator &sched)
Controller to coordinate resource usage related to the Scheduler.
void instruct(ActivationEvent actEvent)
Accept an ActivationEvent with an Activity for time-bound execution.
void activate(ManifestationID manID)
Enable entries marked with a specific ManifestationID to be processed.
Abstract Base Class for all testcases.
Definition: run.hpp:62
Term builder and execution framework to perform chains of scheduler Activities.
bool isOutdated(Time now) const
determine if Activity at scheduler is outdated and should be discarded
Marker for current (and obsolete) manifestations of a CalcStream processed by the Render-Engine...
Definition: activity.hpp:93
Diagnostic context to record and evaluate activations within the Scheduler.
Simple test class runner.
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...
Convenience front-end to simplify and codify basic thread handling.
boost::rational< int64_t > FSecs
rational representation of fractional seconds
Definition: timevalue.hpp:229
Activity & buildActivationProbe(string id)
build a rigged HOOK-Activity to record each invocation
bool isMissed(Time now) const
determine if Activity at scheduler head missed it&#39;s deadline
uint incrementSeq()
increment the internal invocation sequence number
Activity * next
Activities are organised into chains to represent relations based on verbs.
Definition: activity.hpp:258
Diagnostic setup to instrument and observe Activity activations.
Layer-2 of the Scheduler: coordination and interaction of activities.
static const Time NEVER
border condition marker value. NEVER >= any time value
Definition: timevalue.hpp:323
bool isOutOfTime(Time now) const
detect a compulsory Activity at scheduler head with missed deadline
Extended variant of the standard case, allowing to install callbacks (hook functions) to be invoked d...
Definition: thread.hpp:724
ScopedGroomingGuard requireGroomingTokenHere()
a scope guard to force acquisition of the GroomingToken
static activity::Proc dispatchChain(Activity *chain, EXE &executionCtx)
Execution Framework: dispatch performance of a chain of Activities.
ActivationEvent pullHead()
Retrieve from the scheduling queue the entry with earliest start time.
Individual frame rendering task, forwarding to a closure.
Definition: job.h:277
a family of time value like entities and their relationships.
void feedPrioritisation()
Pick up all new events from the entrance queue and enqueue them to be retrieved ordered by start time...
ActivityMatch & arg(ARGS const &...args)
qualifier: additionally match the function arguments
Vault-Layer implementation namespace root.
bool isDue(Time now) const
Determine if there is work to do right now.
bool acquireGoomingToken() noexcept
acquire the right to perform internal state transitions.
Scheduler Layer-1 : time based dispatch.
activity::Proc dispatchCapacity(SchedulerInvocation &, LoadController &, DISPATCH, CLOCK)
Implementation of the worker-Functor:
void detach_thread_from_wrapper()
allow to detach explicitly — independent from thread-function&#39;s state.
Definition: thread.hpp:239
bool isSameObject(A const &a, B const &b)
compare plain object identity, bypassing any custom comparison operators.
Definition: util.hpp:372