SuperTinyKernel™ RTOS 1.06.x
Lightweight, high-performance, deterministic, bare-metal C++ RTOS for resource-constrained embedded systems. MIT Open Source License.
Loading...
Searching...
No Matches
stk_time_timer.h
Go to the documentation of this file.
1/*
2 * SuperTinyKernel(TM) RTOS: Lightweight High-Performance Deterministic C++ RTOS for Embedded Systems.
3 *
4 * Source: https://github.com/SuperTinyKernel-RTOS
5 *
6 * Copyright (c) 2022-2026 Neutron Code Limited <stk@neutroncode.com>. All Rights Reserved.
7 * License: MIT License, see LICENSE for a full text.
8 */
9
10#ifndef STK_TIME_TIMER_H_
11#define STK_TIME_TIMER_H_
12
13#include "sync/stk_sync_event.h"
14#include "sync/stk_sync_pipe.h"
15
20
21namespace stk {
22namespace time {
23
27#ifndef STK_TIMER_THREADS_COUNT
28 #define STK_TIMER_THREADS_COUNT 1U
29#endif
30
34#ifndef STK_TIMER_HANDLER_STACK_SIZE
35 #define STK_TIMER_HANDLER_STACK_SIZE 256U
36#endif
37
41#ifndef STK_TIMER_COUNT_MAX
42 #define STK_TIMER_COUNT_MAX 32U
43#endif
44
112{
113public:
125
137 class Timer : private util::DListEntry<Timer, false>
138 {
139 friend class TimerHost;
140 friend class util::DListCast; // allow casts because DListEntry is private
141
142 public:
145 explicit Timer()
146 : m_deadline(0), m_timestamp(0), m_period(0U), m_active(false),
147 m_pending(false), m_rearming(false)
148 {}
149
154
158 enum { DLEntryTag = 1 };
159
167 virtual void OnExpired(TimerHost *host) = 0;
168
174 bool IsActive() const { return m_active; }
175
180 Ticks GetDeadline() const { return m_deadline; }
181
186 Ticks GetTimestamp() const { return m_timestamp; }
187
191 uint32_t GetPeriod() const { return m_period; }
192
199 uint32_t GetRemainingTicks() const;
200
201 private:
203
206 uint32_t m_period;
207 volatile bool m_active;
208 volatile bool m_pending;
209 volatile bool m_rearming;
210 };
211
219
223 ~TimerHost() = default;
224
229 void Initialize(IKernel *kernel, EAccessMode mode);
230
237 bool Start(Timer &tmr, uint32_t delay, uint32_t period = 0);
238
243 bool Stop(Timer &tmr);
244
249 bool Reset(Timer &tmr);
250
262 bool Restart(Timer &tmr, uint32_t delay, uint32_t period = 0);
263
277 bool StartOrReset(Timer &tmr, uint32_t delay, uint32_t period = 0);
278
288 bool SetPeriod(Timer &tmr, uint32_t period);
289
294 bool IsEmpty() const { return m_active.IsEmpty(); }
295
300 size_t GetSize() const { return m_active.GetSize(); }
301
305 bool Shutdown();
306
311
312private:
314
318 typedef void (*TimerFuncType) (TimerHost *host);
319
330 class TimerWorkerTask : public ITask
331 {
332 public:
335 : m_func(nullptr), m_host(nullptr), m_stack(nullptr), m_stack_size(0U),
337 {}
338
339 // ITask
340 EAccessMode GetAccessMode() const override { return m_mode; }
341 void OnDeadlineMissed(uint32_t) override {}
342 void OnExit() override {}
343 int32_t GetWeight() const override { return m_weight; }
344 const char *GetTraceName() const override { return nullptr; }
345
346 // IStackMemory
347 const Word *GetStack() const override { return m_stack; }
348 size_t GetStackSize() const override { return m_stack_size; }
349 size_t GetStackSizeBytes() const override { return (m_stack_size * sizeof(Word)); }
350
359 void Initialize(TimerHost *host, Word *stack, size_t stack_size, EAccessMode mode,
360 TimerFuncType const func)
361 {
362 m_host = host;
363 m_func = func;
364 m_stack = stack;
365 m_stack_size = stack_size;
366 m_mode = mode;
368 }
369
373 void SetWeight(int32_t weight) { m_weight = weight; }
374
375 private:
377 void Run() override { m_func(m_host); }
378
384 int32_t m_weight;
385 };
386
417
421 void UpdateTime();
422
426 void ProcessTimers();
427
434 bool ProcessCommands(Timeout next_sleep);
435
442 bool PushCommand(TimerCommand cmd);
443
448
453
458
463
472};
473
474// ---------------------------------------------------------------------------
475// Timer::GetRemainingTicks
476// ---------------------------------------------------------------------------
477
479{
480 uint32_t remaining_ticks = 0U;
481
482 if (m_active)
483 {
484 // if deadline has passed but not yet been processed by the tick task,
485 // remaining would be negative, result fits in uint32_t because delay and
486 // period are uint32_t, so remaining time is bounded by uint32_t max
487 const Ticks remaining = m_deadline - GetTicks();
488
489 if (remaining > 0)
490 {
491 remaining_ticks = static_cast<uint32_t>(remaining);
492 }
493 }
494
495 return remaining_ticks;
496}
497
498// ---------------------------------------------------------------------------
499// Initialize
500// ---------------------------------------------------------------------------
501
502inline void TimerHost::Initialize(IKernel *kernel, EAccessMode mode)
503{
504 for (size_t i = 0U; i < STK_TIMER_THREADS_COUNT; ++i)
505 {
506 m_task_process[i].Initialize(this, m_task_handler_memory[i], TASK_HANDLER_STACK_SIZE, mode, [](TimerHost *host)
507 {
508 host->ProcessTimers();
509 });
510 kernel->AddTask(&m_task_process[i]);
511 }
512
514 {
515 host->UpdateTime();
516 });
517 kernel->AddTask(&m_task_tick);
518}
519
520// ---------------------------------------------------------------------------
521// Start
522// ---------------------------------------------------------------------------
523
524inline bool TimerHost::Start(Timer &tmr, uint32_t delay, uint32_t period)
525{
526 STK_ASSERT(delay <= static_cast<uint32_t>(WAIT_INFINITE));
527 STK_ASSERT((period == 0U) || (period <= static_cast<uint32_t>(WAIT_INFINITE)));
528
529 bool success;
530
531 // timer must not already be active
532 if (!tmr.m_active)
533 {
534 success = PushCommand({
536 .timer = &tmr,
537 .timestamp = GetTicks(),
538 .delay = delay,
539 .period = period
540 });
541 }
542 else
543 {
544 // duplicate attempt to start already started timer is not an error (ignore)
545 success = true;
546 }
547
548 return success;
549}
550
551// ---------------------------------------------------------------------------
552// Stop
553// ---------------------------------------------------------------------------
554
555inline bool TimerHost::Stop(Timer &tmr)
556{
557 bool success;
558
559 // timer must be active
560 if (tmr.m_active)
561 {
562 success = PushCommand({
564 .timer = &tmr,
565 .timestamp = 0,
566 .delay = 0U,
567 .period = 0U
568 });
569 }
570 else
571 {
572 // duplicate attempt to stop already stopped timer is not an error (ignore)
573 success = true;
574 }
575
576 return success;
577}
578
579// ---------------------------------------------------------------------------
580// Reset
581// ---------------------------------------------------------------------------
582
583inline bool TimerHost::Reset(Timer &tmr)
584{
585 bool success;
586
587 // timer must be active and periodic
588 if (tmr.m_active && (tmr.m_period != 0U))
589 {
590 success = PushCommand({
592 .timer = &tmr,
593 .timestamp = GetTicks(),
594 .delay = 0U,
595 .period = 0U
596 });
597 }
598 else
599 {
600 success = false;
601 }
602
603 return success;
604}
605
606// ---------------------------------------------------------------------------
607// Restart
608// ---------------------------------------------------------------------------
609
610inline bool TimerHost::Restart(Timer &tmr, uint32_t delay, uint32_t period)
611{
612 STK_ASSERT(delay <= static_cast<uint32_t>(WAIT_INFINITE));
613 STK_ASSERT((period == 0U) || (period <= static_cast<uint32_t>(WAIT_INFINITE)));
614
615 return PushCommand({
617 .timer = &tmr,
618 .timestamp = GetTicks(),
619 .delay = delay,
620 .period = period
621 });
622}
623
624// ---------------------------------------------------------------------------
625// StartOrReset
626// ---------------------------------------------------------------------------
627
628inline bool TimerHost::StartOrReset(Timer &tmr, uint32_t delay, uint32_t period)
629{
630 STK_ASSERT(delay <= static_cast<uint32_t>(WAIT_INFINITE));
631 STK_ASSERT((period == 0U) || (period <= static_cast<uint32_t>(WAIT_INFINITE)));
632
633 return PushCommand({
635 .timer = &tmr,
636 .timestamp = GetTicks(),
637 .delay = delay,
638 .period = period
639 });
640}
641
642// ---------------------------------------------------------------------------
643// SetPeriod
644// ---------------------------------------------------------------------------
645
646inline bool TimerHost::SetPeriod(Timer &tmr, uint32_t period)
647{
648 bool success;
649
650 // period == 0 is rejected: it would silently convert a periodic timer
651 // to one-shot semantics, which is better expressed via Stop() + Start()
652 if (tmr.m_active && (tmr.m_period != 0U) && (period != 0U) &&
653 (period <= static_cast<uint32_t>(WAIT_INFINITE)))
654 {
655 success = PushCommand({
657 .timer = &tmr,
658 .timestamp = 0,
659 .delay = 0U,
660 .period = period
661 });
662 }
663 else
664 {
665 success = false;
666 }
667
668 return success;
669}
670
671// ---------------------------------------------------------------------------
672// Shutdown
673// ---------------------------------------------------------------------------
674
676{
677 return PushCommand({
679 .timer = nullptr,
680 .timestamp = 0,
681 .delay = 0U,
682 .period = 0U
683 });
684}
685
686// ---------------------------------------------------------------------------
687// UpdateTime (tick task body)
688// ---------------------------------------------------------------------------
689
691{
692 Timeout next_sleep = NO_WAIT;
693
694 while (ProcessCommands(next_sleep))
695 {
696 next_sleep = WAIT_INFINITE;
697 const Ticks now = GetTicks();
698
699 // using WriteVolatile64() to guarantee correct lockless reading order by ReadVolatile64
701
703 while (tmr != nullptr)
704 {
706
707 if (tmr->m_active)
708 {
709 // check if still pending to be handled
710 if (!tmr->m_pending)
711 {
712 bool one_shot = false;
713 const Ticks diff = now - tmr->m_deadline;
714
715 if (diff >= 0)
716 {
717 // set timestamp at which timer expired
718 tmr->m_timestamp = now;
719
720 // avoid updating timer again before it was handled
721 tmr->m_pending = true;
722
723 // periodic
724 if (tmr->m_period != 0U)
725 {
726 // reload (use now to avoid drift accumulation)
727 tmr->m_deadline = now + static_cast<Ticks>(tmr->m_period) - diff;
728 }
729 // one-shot
730 else
731 {
732 one_shot = true;
733
734 // remove from active timers
735 m_active.Unlink(tmr);
736
737 // mark as inactive (must follow Unlink)
738 tmr->m_active = false;
739 }
740
741 __stk_full_memfence();
742
743 // push to the handling queue
744 STK_UNUSED(m_queue.Write(tmr));
745 }
746
747 // one-shot timer does not affect next_sleep
748 if (!one_shot)
749 {
750 const Timeout next_deadline = static_cast<Timeout>(tmr->m_deadline - now);
751 STK_ASSERT(next_deadline > 0);
752
753 if ((next_deadline > 0) && (next_deadline < next_sleep))
754 {
755 next_sleep = next_deadline;
756 }
757 }
758 }
759 }
760 else
761 {
762 // could be stopped externally, remove from active timers
763 m_active.Unlink(tmr);
764 }
765
766 tmr = next;
767 }
768 }
769
770 // unlink all timers on shutdown
771 while (Timer::DLEntryType *const tmr = m_active.GetFirst())
772 {
773 m_active.Unlink(tmr);
774 }
775}
776
777// ---------------------------------------------------------------------------
778// ProcessTimers (handler task body)
779// ---------------------------------------------------------------------------
780
782{
783 Timer *tmr = nullptr;
784 bool keep_running = true;
785
786 while (keep_running)
787 {
788 if (!m_queue.Read(tmr))
789 {
790 break; // no pending timers available
791 }
792
793 // nullptr is the shutdown sentinel pushed by CMD_SHUTDOWN
794 if (tmr == nullptr)
795 {
796 keep_running = false;
797 }
798 else if (tmr->m_pending)
799 {
800 tmr->m_pending = false;
801 tmr->OnExpired(this);
802 }
803 else
804 {
805 // noop
806 }
807 }
808}
809
810// ---------------------------------------------------------------------------
811// ProcessCommands (tick task only)
812// ---------------------------------------------------------------------------
813
814inline bool TimerHost::ProcessCommands(Timeout next_sleep)
815{
816 TimerCommand cmd = {};
817 bool working = true;
818
819 // if nothing is active, sleep indefinitely until a command arrives
820 if (m_active.IsEmpty())
821 {
822 next_sleep = WAIT_INFINITE;
823 }
824
825 while (working)
826 {
827 if (!m_commands.Read(cmd, next_sleep))
828 {
829 break;
830 }
831
832 switch (cmd.cmd)
833 {
835 {
836 Timer *const tmr = cmd.timer;
837 STK_ASSERT(tmr != nullptr);
838
839 // reject if already active or linked (double-start)
840 if (!tmr->m_active)
841 {
842 STK_ASSERT(!tmr->IsLinked());
843
844 tmr->m_deadline = cmd.timestamp + static_cast<Ticks>(cmd.delay);
845 tmr->m_period = cmd.period;
846 tmr->m_active = true;
847 tmr->m_pending = false;
848
849 m_active.LinkBack(tmr);
850 next_sleep = NO_WAIT;
851 }
852
853 break; }
854
856 {
857 Timer *const tmr = cmd.timer;
858 STK_ASSERT(tmr != nullptr);
859
860 tmr->m_active = false;
861 tmr->m_pending = false;
862
863 // allow possibly duplicate CMD_STOP as it is harmless for the logic
864 if (tmr->IsLinked())
865 {
866 m_active.Unlink(tmr);
867 }
868
869 break; }
870
872 {
873 Timer *const tmr = cmd.timer;
874 STK_ASSERT(tmr != nullptr);
875
876 // only reset if still active and periodic
877 if (tmr->m_active && (tmr->m_period != 0U))
878 {
879 STK_ASSERT(tmr->GetHead() == &m_active);
880
881 tmr->m_deadline = cmd.timestamp + static_cast<Ticks>(tmr->m_period);
882 tmr->m_pending = false;
883
884 next_sleep = NO_WAIT;
885 }
886
887 break; }
888
890 {
891 // atomic stop + re-start: no precondition on current timer state
892 Timer *const tmr = cmd.timer;
893 STK_ASSERT(tmr != nullptr);
894
895 // unlink if currently in the active list
896 if (tmr->IsLinked())
897 {
898 m_active.Unlink(tmr);
899 }
900
901 // re-arm with fresh parameters
902 tmr->m_deadline = cmd.timestamp + static_cast<Ticks>(cmd.delay);
903 tmr->m_period = cmd.period;
904 tmr->m_active = true;
905 tmr->m_pending = false;
906 tmr->m_rearming = false;
907
908 // re-link to the back of the list
909 m_active.LinkBack(tmr);
910 next_sleep = NO_WAIT;
911
912 break; }
913
915 {
916 Timer *const tmr = cmd.timer;
917 STK_ASSERT(tmr != nullptr);
918
919 // not currently active: start with supplied parameters
920 if (!tmr->m_active)
921 {
922 STK_ASSERT(!tmr->IsLinked());
923
924 tmr->m_deadline = cmd.timestamp + static_cast<Ticks>(cmd.delay);
925 tmr->m_period = cmd.period;
926 tmr->m_active = true;
927 tmr->m_pending = false;
928 tmr->m_rearming = false;
929
930 m_active.LinkBack(tmr);
931 }
932 // active and periodic: reset deadline anchored to call-site timestamp
933 else if (tmr->m_period != 0U)
934 {
935 STK_ASSERT(tmr->GetHead() == &m_active);
936
937 tmr->m_deadline = cmd.timestamp + static_cast<Ticks>(tmr->m_period);
938 tmr->m_pending = false;
939 }
940 else
941 {
942 // noop
943 }
944
945 // active one-shot: no action - cannot reset a one-shot mid-flight,
946 // caller should use Restart() if unconditional re-arm is needed
947
948 next_sleep = NO_WAIT;
949
950 break; }
951
953 {
954 Timer *const tmr = cmd.timer;
955 STK_ASSERT(tmr != nullptr);
956 STK_ASSERT(cmd.period != 0U);
957
958 // guard: only apply if still active and periodic
959 if (tmr->m_active && (tmr->m_period != 0U))
960 {
961 STK_ASSERT(tmr->GetHead() == &m_active);
962
963 // new period takes effect on the next reload, current deadline is
964 // intentionally left unchanged so the in-flight interval is not
965 // truncated or extended, caller can follow up with Reset() if
966 // immediate application is required
967 tmr->m_period = cmd.period;
968 }
969
970 break; }
971
973 {
974 // wake all handler tasks with shutdown sentinels
975 for (size_t i = 0U; i < STK_TIMER_THREADS_COUNT; ++i)
976 {
977 STK_UNUSED(m_queue.Write(nullptr, NO_WAIT));
978 }
979
980 // signal UpdateTime() to exit its loop
981 working = false;
982
983 break; }
984
985 default:
986 {
987 STK_ASSERT(false);
988
989 break; }
990 }
991 }
992
993 return working;
994}
995
996// ---------------------------------------------------------------------------
997// PushCommand
998// ---------------------------------------------------------------------------
999
1001{
1002 bool success = true;
1003 bool proceed_to_write = true;
1004
1005 const bool is_rearm = (cmd.cmd == TimerCommand::CMD_RESTART) ||
1007
1008 // rearm coalescing (CMD_RESTART and CMD_START_OR_RESET only)
1009 if (is_rearm && (cmd.timer != nullptr))
1010 {
1011 if (cmd.timer->m_rearming)
1012 {
1013 // already rearming - successfully coalesced, no need to write to queue
1014 proceed_to_write = false;
1015 }
1016 else
1017 {
1018 cmd.timer->m_rearming = true;
1019
1020 // prevent compiler from sinking the flag write past Write()
1021 __stk_full_memfence();
1022 }
1023 }
1024
1025 // write to command queue
1026 if (proceed_to_write)
1027 {
1028 if (!m_commands.Write(cmd, NO_WAIT))
1029 {
1030 // revert the flag if this was a failed rearm attempt
1031 if (is_rearm && (cmd.timer != nullptr))
1032 {
1033 cmd.timer->m_rearming = false;
1034 }
1035
1036 // queue full: this indicates a usage error - more commands are being
1037 // issued than the tick task can drain (recoverable in
1038 // release, caller receives false and can retry or escalate)
1039 STK_ASSERT(false);
1040 success = false;
1041 }
1042 }
1043
1044 return success;
1045}
1046
1047} // namespace time
1048} // namespace stk
1049
1050#endif /* STK_TIME_TIMER_H_ */
#define STK_UNUSED(X)
Explicitly marks a variable as unused to suppress compiler warnings.
Definition stk_defs.h:608
#define STK_ASSERT(e)
Runtime assertion. Halts execution if the expression e evaluates to false.
Definition stk_defs.h:409
#define STK_STACK_SIZE_MIN
Minimum stack size in elements of Word, shared by all stack allocation lower-bound checks.
Definition stk_defs.h:533
#define STK_VIRT_DTOR
Makes destructors virtual and compliant to strict rules if STK_STRICT_COMPLIANCY=0.
Definition stk_defs.h:159
Implementation of synchronization primitive: stk::sync::Event.
Implementation of synchronization primitives: stk::sync::Pipe - runtime-sized byte-stream pipe over a...
#define STK_TIMER_THREADS_COUNT
Number of threads handling timers in TimerHost (default: 1).
#define STK_TIMER_HANDLER_STACK_SIZE
Stack size of the timer handler, increase if your timers consume more (default: 256).
Namespace of STK package.
uintptr_t Word
Native processor word type.
Definition stk_common.h:115
EAccessMode
Hardware access mode by the user task.
Definition stk_common.h:32
@ ACCESS_USER
Unprivileged access mode (access to some hardware is restricted, see CPU manual for details).
Definition stk_common.h:33
constexpr Timeout NO_WAIT
Timeout value: return immediately if the synchronization object is not yet signaled (non-blocking pol...
Definition stk_common.h:189
int64_t Ticks
Ticks value.
Definition stk_common.h:130
int32_t Timeout
Timeout time (ticks).
Definition stk_common.h:125
static constexpr T Max(T a, T b)
Compile-time maximum of two values.
Definition stk_defs.h:625
constexpr Weight DEFAULT_WEIGHT
Weight value: default weight of value (1) (see SwitchStrategySmoothWeightedRoundRobin).
Definition stk_common.h:199
static Ticks GetTicks()
Get number of ticks elapsed since kernel start.
Definition stk_helper.h:319
constexpr Timeout WAIT_INFINITE
Timeout value: block indefinitely until the synchronization object is signaled.
Definition stk_common.h:183
static __stk_forceinline void WriteVolatile64(volatile T *addr, T value)
Atomically write a 64-bit volatile value.
Definition stk_arch.h:444
static __stk_forceinline T ReadVolatile64(volatile const T *addr)
Atomically read a 64-bit volatile value.
Definition stk_arch.h:379
Time-related primitives.
Word Type[TStackSize]
Stack memory type.
Definition stk_common.h:274
Interface for a user task.
Definition stk_common.h:599
Interface for the implementation of the kernel of the scheduler. It supports Soft and Hard Real-Time ...
virtual void AddTask(ITask *user_task)=0
Add user task.
Intrusive doubly-linked list container. Manages a collection of DListEntry nodes embedded in host obj...
Intrusive doubly-linked list node. Embed this as a base class in any object (T) that needs to partici...
DListEntry< Timer, TClosedLoop > DLEntryType
DLEntryType * GetNext()
Get the next entry in the list.
DLHeadType * GetHead()
Get the list head this entry currently belongs to.
bool IsLinked() const
Check whether this entry is currently a member of any list.
Helper for casting list entries to concrete (parent) types.
static __stk_forceinline TTargetType * ListEntryToParent(TSourceType *const lentry)
Safely casts an intrusive list entry to its concrete parent container object type.
Thread-safe, type-safe FIFO communication pipe with internal storage.
TimerWorkerTask m_task_process[1U]
handler tasks
TimerHostMemory m_task_handler_memory[1U]
handler task memory
bool SetPeriod(Timer &tmr, uint32_t period)
Change the period of a running periodic timer without affecting its current deadline.
Ticks m_now
last known current time (ticks)
util::DListHead< Timer, false > m_active
active timers (tick task only)
sync::PipeT< TimerCommand, 32U > CommandQueue
Lock-free pipe used to send TimerCommand records from API callers to the tick task.
void Initialize(IKernel *kernel, EAccessMode mode)
Initialize timer host instance.
bool IsEmpty() const
Return true if no timers are currently active.
sync::PipeT< Timer *, 32U > ReadyQueue
Lock-free pipe used to transfer expired timer pointers from the tick task to handler tasks.
bool Stop(Timer &tmr)
Stop running timer.
Ticks GetTimeNow() const
Get current time.
TimerWorkerTask m_task_tick
timer task
size_t GetSize() const
Return number of currently active timers.
STK_NONCOPYABLE_CLASS(TimerHost)
TaskTickMemory m_task_tick_memory
tick task memory
@ TASK_TICK_MEMORY_SIZE
stack memory size of the timer handler task
@ TASK_COUNT
total number of tasks serving this instance
void(* TimerFuncType)(TimerHost *host)
Timer task function prototype.
ReadyQueue m_queue
queue of timers ready for handling
bool Shutdown()
Shutdown host instance. All timers are stopped and removed from the host.
bool Restart(Timer &tmr, uint32_t delay, uint32_t period=0)
Atomically stop and re-start timer.
void UpdateTime()
Tick task body: drives the timer list and dispatches expired timers.
StackMemoryDef< TASK_TICK_MEMORY_SIZE >::Type TaskTickMemory
Stack memory type for the single tick task.
bool StartOrReset(Timer &tmr, uint32_t delay, uint32_t period=0)
Start timer if inactive, or reset its deadline if already active and periodic.
TimerHost()
Default constructor. Zero-initializes all internal state.
bool ProcessCommands(Timeout next_sleep)
Drain the command queue and execute each pending command.
bool PushCommand(TimerCommand cmd)
Enqueue a command for the tick task.
bool Reset(Timer &tmr)
Reset periodic timer's deadline.
void ProcessTimers()
Handler task body: dequeues expired timers and invokes their OnExpired() callbacks.
~TimerHost()=default
Destructor.
CommandQueue m_commands
command queue
StackMemoryDef< TASK_HANDLER_STACK_SIZE >::Type TimerHostMemory
Stack memory type for each handler task.
bool Start(Timer &tmr, uint32_t delay, uint32_t period=0)
Start timer.
Abstract base class for a timer managed by TimerHost.
volatile bool m_active
true if active
Ticks m_deadline
absolute expiration time (ticks)
Ticks GetDeadline() const
Get the absolute time in ticks at which the timer will expire.
volatile bool m_rearming
true while a CMD_RESTART / CMD_START_OR_RESET is already in the command queue
uint32_t GetRemainingTicks() const
Get remaining ticks until the timer next expires.
Ticks m_timestamp
absolute time at which timer expired (ticks), updated by TimerHost
uint32_t m_period
reload period in ticks (0 = one-shot)
STK_VIRT_DTOR ~Timer()=default
Destructor.
bool IsActive() const
Check whether the timer is currently active.
Timer()
Default constructor.
uint32_t GetPeriod() const
Get the reload period of the timer.
volatile bool m_pending
true if pending to be handled
Ticks GetTimestamp() const
Get the tick count at which the timer last expired.
virtual void OnExpired(TimerHost *host)=0
Callback invoked by the handler task when this timer expires.
Internal kernel task used by TimerHost for both the tick task and handler tasks.
EAccessMode GetAccessMode() const override
Get hardware access mode of the user task.
int32_t GetWeight() const override
Get static base weight of the task.
size_t GetStackSizeBytes() const override
Get size of the memory in bytes.
size_t GetStackSize() const override
Get number of elements of the stack memory array.
const char * GetTraceName() const override
Get task trace name set by application.
TimerFuncType m_func
entry function (tick loop or handler loop)
const Word * GetStack() const override
Get pointer to the stack memory.
void SetWeight(int32_t weight)
Override the scheduling weight assigned by Initialize().
TimerWorkerTask()
Default constructor. All members are zero/null-initialized.
size_t m_stack_size
stack size in words
void Initialize(TimerHost *host, Word *stack, size_t stack_size, EAccessMode mode, TimerFuncType const func)
Bind this task to a host, stack buffer, access mode, and entry function.
void Run() override
Timer task entry point.
TimerHost * m_host
owning TimerHost instance
void OnExit() override
Called by the kernel before removal from the scheduling (see stk::KERNEL_DYNAMIC).
Word * m_stack
pointer to stack buffer
void OnDeadlineMissed(uint32_t) override
Called by the scheduler if deadline of the task is missed when Kernel is operating in Hard Real-Time ...
EAccessMode m_mode
kernel access mode
POD command record passed from the public API methods to the tick task via the command queue.
EId
Identifies the operation to perform on the target timer.
@ CMD_SET_PERIOD
change period of a running periodic timer
@ CMD_START_OR_RESET
start if inactive, reset deadline if active and periodic
@ CMD_RESTART
atomic stop + re-start
uint32_t period
reload period ticks (CMD_START / CMD_RESTART / CMD_START_OR_RESET / CMD_SET_PERIOD)
Ticks timestamp
hw tick count captured at call site
uint32_t delay
initial delay ticks (CMD_START / CMD_RESTART / CMD_START_OR_RESET)