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
358 void Initialize(TimerHost *host, Word *stack, size_t stack_size, EAccessMode mode,
359 TimerFuncType const func)
360 {
361 m_host = host;
362 m_func = func;
363 m_stack = stack;
364 m_stack_size = stack_size;
365 m_mode = mode;
367 }
368
372 void SetWeight(int32_t weight) { m_weight = weight; }
373
374 private:
376 void Run() override { m_func(m_host); }
377
383 int32_t m_weight;
384 };
385
416
420 void UpdateTime();
421
425 void ProcessTimers();
426
433 bool ProcessCommands(Timeout next_sleep);
434
441 bool PushCommand(TimerCommand cmd);
442
447
452
457
462
471};
472
473// ---------------------------------------------------------------------------
474// Timer::GetRemainingTicks
475// ---------------------------------------------------------------------------
476
478{
479 uint32_t remaining_ticks = 0U;
480
481 if (m_active)
482 {
483 // if deadline has passed but not yet been processed by the tick task,
484 // remaining would be negative, result fits in uint32_t because delay and
485 // period are uint32_t, so remaining time is bounded by uint32_t max
486 const Ticks remaining = m_deadline - GetTicks();
487
488 if (remaining > 0)
489 {
490 remaining_ticks = static_cast<uint32_t>(remaining);
491 }
492 }
493
494 return remaining_ticks;
495}
496
497// ---------------------------------------------------------------------------
498// Initialize
499// ---------------------------------------------------------------------------
500
501inline void TimerHost::Initialize(IKernel *kernel, EAccessMode mode)
502{
503 for (size_t i = 0U; i < STK_TIMER_THREADS_COUNT; ++i)
504 {
505 m_task_process[i].Initialize(this, m_task_handler_memory[i], TASK_HANDLER_STACK_SIZE, mode, [](TimerHost *host)
506 {
507 host->ProcessTimers();
508 });
509 kernel->AddTask(&m_task_process[i]);
510 }
511
513 {
514 host->UpdateTime();
515 });
516 kernel->AddTask(&m_task_tick);
517}
518
519// ---------------------------------------------------------------------------
520// Start
521// ---------------------------------------------------------------------------
522
523inline bool TimerHost::Start(Timer &tmr, uint32_t delay, uint32_t period)
524{
525 STK_ASSERT(delay <= static_cast<uint32_t>(WAIT_INFINITE));
526 STK_ASSERT((period == 0U) || (period <= static_cast<uint32_t>(WAIT_INFINITE)));
527
528 bool success;
529
530 // timer must not already be active
531 if (!tmr.m_active)
532 {
533 success = PushCommand({
535 .timer = &tmr,
536 .timestamp = GetTicks(),
537 .delay = delay,
538 .period = period
539 });
540 }
541 else
542 {
543 // duplicate attempt to start already started timer is not an error (ignore)
544 success = true;
545 }
546
547 return success;
548}
549
550// ---------------------------------------------------------------------------
551// Stop
552// ---------------------------------------------------------------------------
553
554inline bool TimerHost::Stop(Timer &tmr)
555{
556 bool success;
557
558 // timer must be active
559 if (tmr.m_active)
560 {
561 success = PushCommand({
563 .timer = &tmr,
564 .timestamp = 0,
565 .delay = 0U,
566 .period = 0U
567 });
568 }
569 else
570 {
571 // duplicate attempt to stop already stopped timer is not an error (ignore)
572 success = true;
573 }
574
575 return success;
576}
577
578// ---------------------------------------------------------------------------
579// Reset
580// ---------------------------------------------------------------------------
581
582inline bool TimerHost::Reset(Timer &tmr)
583{
584 bool success;
585
586 // timer must be active and periodic
587 if (tmr.m_active && (tmr.m_period != 0U))
588 {
589 success = PushCommand({
591 .timer = &tmr,
592 .timestamp = GetTicks(),
593 .delay = 0U,
594 .period = 0U
595 });
596 }
597 else
598 {
599 success = false;
600 }
601
602 return success;
603}
604
605// ---------------------------------------------------------------------------
606// Restart
607// ---------------------------------------------------------------------------
608
609inline bool TimerHost::Restart(Timer &tmr, uint32_t delay, uint32_t period)
610{
611 STK_ASSERT(delay <= static_cast<uint32_t>(WAIT_INFINITE));
612 STK_ASSERT((period == 0U) || (period <= static_cast<uint32_t>(WAIT_INFINITE)));
613
614 return PushCommand({
616 .timer = &tmr,
617 .timestamp = GetTicks(),
618 .delay = delay,
619 .period = period
620 });
621}
622
623// ---------------------------------------------------------------------------
624// StartOrReset
625// ---------------------------------------------------------------------------
626
627inline bool TimerHost::StartOrReset(Timer &tmr, uint32_t delay, uint32_t period)
628{
629 STK_ASSERT(delay <= static_cast<uint32_t>(WAIT_INFINITE));
630 STK_ASSERT((period == 0U) || (period <= static_cast<uint32_t>(WAIT_INFINITE)));
631
632 return PushCommand({
634 .timer = &tmr,
635 .timestamp = GetTicks(),
636 .delay = delay,
637 .period = period
638 });
639}
640
641// ---------------------------------------------------------------------------
642// SetPeriod
643// ---------------------------------------------------------------------------
644
645inline bool TimerHost::SetPeriod(Timer &tmr, uint32_t period)
646{
647 bool success;
648
649 // period == 0 is rejected: it would silently convert a periodic timer
650 // to one-shot semantics, which is better expressed via Stop() + Start()
651 if (tmr.m_active && (tmr.m_period != 0U) && (period != 0U) &&
652 (period <= static_cast<uint32_t>(WAIT_INFINITE)))
653 {
654 success = PushCommand({
656 .timer = &tmr,
657 .timestamp = 0,
658 .delay = 0U,
659 .period = period
660 });
661 }
662 else
663 {
664 success = false;
665 }
666
667 return success;
668}
669
670// ---------------------------------------------------------------------------
671// Shutdown
672// ---------------------------------------------------------------------------
673
675{
676 return PushCommand({
678 .timer = nullptr,
679 .timestamp = 0,
680 .delay = 0U,
681 .period = 0U
682 });
683}
684
685// ---------------------------------------------------------------------------
686// UpdateTime (tick task body)
687// ---------------------------------------------------------------------------
688
690{
691 Timeout next_sleep = NO_WAIT;
692
693 while (ProcessCommands(next_sleep))
694 {
695 next_sleep = WAIT_INFINITE;
696 const Ticks now = GetTicks();
697
698 // using WriteVolatile64() to guarantee correct lockless reading order by ReadVolatile64
700
702 while (tmr != nullptr)
703 {
705
706 if (tmr->m_active)
707 {
708 // check if still pending to be handled
709 if (!tmr->m_pending)
710 {
711 bool one_shot = false;
712 const Ticks diff = now - tmr->m_deadline;
713
714 if (diff >= 0)
715 {
716 // set timestamp at which timer expired
717 tmr->m_timestamp = now;
718
719 // avoid updating timer again before it was handled
720 tmr->m_pending = true;
721
722 // periodic
723 if (tmr->m_period != 0U)
724 {
725 // reload (use now to avoid drift accumulation)
726 tmr->m_deadline = now + static_cast<Ticks>(tmr->m_period) - diff;
727 }
728 // one-shot
729 else
730 {
731 one_shot = true;
732
733 // remove from active timers
734 m_active.Unlink(tmr);
735
736 // mark as inactive (must follow Unlink)
737 tmr->m_active = false;
738 }
739
740 __stk_full_memfence();
741
742 // push to the handling queue
743 STK_UNUSED(m_queue.Write(tmr));
744 }
745
746 // one-shot timer does not affect next_sleep
747 if (!one_shot)
748 {
749 const Timeout next_deadline = static_cast<Timeout>(tmr->m_deadline - now);
750 STK_ASSERT(next_deadline > 0);
751
752 if ((next_deadline > 0) && (next_deadline < next_sleep))
753 {
754 next_sleep = next_deadline;
755 }
756 }
757 }
758 }
759 else
760 {
761 // could be stopped externally, remove from active timers
762 m_active.Unlink(tmr);
763 }
764
765 tmr = next;
766 }
767 }
768
769 // unlink all timers on shutdown
770 while (Timer::DLEntryType *const tmr = m_active.GetFirst())
771 {
772 m_active.Unlink(tmr);
773 }
774}
775
776// ---------------------------------------------------------------------------
777// ProcessTimers (handler task body)
778// ---------------------------------------------------------------------------
779
781{
782 Timer *tmr = nullptr;
783 bool keep_running = true;
784
785 while (keep_running)
786 {
787 if (!m_queue.Read(tmr))
788 {
789 break; // no pending timers available
790 }
791
792 // nullptr is the shutdown sentinel pushed by CMD_SHUTDOWN
793 if (tmr == nullptr)
794 {
795 keep_running = false;
796 }
797 else if (tmr->m_pending)
798 {
799 tmr->m_pending = false;
800 tmr->OnExpired(this);
801 }
802 else
803 {
804 // noop
805 }
806 }
807}
808
809// ---------------------------------------------------------------------------
810// ProcessCommands (tick task only)
811// ---------------------------------------------------------------------------
812
813inline bool TimerHost::ProcessCommands(Timeout next_sleep)
814{
815 TimerCommand cmd = {};
816 bool working = true;
817
818 // if nothing is active, sleep indefinitely until a command arrives
819 if (m_active.IsEmpty())
820 {
821 next_sleep = WAIT_INFINITE;
822 }
823
824 while (working)
825 {
826 if (!m_commands.Read(cmd, next_sleep))
827 {
828 break;
829 }
830
831 switch (cmd.cmd)
832 {
834 {
835 Timer *const tmr = cmd.timer;
836 STK_ASSERT(tmr != nullptr);
837
838 // reject if already active or linked (double-start)
839 if (!tmr->m_active)
840 {
841 STK_ASSERT(!tmr->IsLinked());
842
843 tmr->m_deadline = cmd.timestamp + static_cast<Ticks>(cmd.delay);
844 tmr->m_period = cmd.period;
845 tmr->m_active = true;
846 tmr->m_pending = false;
847
848 m_active.LinkBack(tmr);
849 next_sleep = NO_WAIT;
850 }
851
852 break; }
853
855 {
856 Timer *const tmr = cmd.timer;
857 STK_ASSERT(tmr != nullptr);
858
859 tmr->m_active = false;
860 tmr->m_pending = false;
861
862 // allow possibly duplicate CMD_STOP as it is harmless for the logic
863 if (tmr->IsLinked())
864 {
865 m_active.Unlink(tmr);
866 }
867
868 break; }
869
871 {
872 Timer *const tmr = cmd.timer;
873 STK_ASSERT(tmr != nullptr);
874
875 // only reset if still active and periodic
876 if (tmr->m_active && (tmr->m_period != 0U))
877 {
878 STK_ASSERT(tmr->GetHead() == &m_active);
879
880 tmr->m_deadline = cmd.timestamp + static_cast<Ticks>(tmr->m_period);
881 tmr->m_pending = false;
882
883 next_sleep = NO_WAIT;
884 }
885
886 break; }
887
889 {
890 // atomic stop + re-start: no precondition on current timer state
891 Timer *const tmr = cmd.timer;
892 STK_ASSERT(tmr != nullptr);
893
894 // unlink if currently in the active list
895 if (tmr->IsLinked())
896 {
897 m_active.Unlink(tmr);
898 }
899
900 // re-arm with fresh parameters
901 tmr->m_deadline = cmd.timestamp + static_cast<Ticks>(cmd.delay);
902 tmr->m_period = cmd.period;
903 tmr->m_active = true;
904 tmr->m_pending = false;
905 tmr->m_rearming = false;
906
907 // re-link to the back of the list
908 m_active.LinkBack(tmr);
909 next_sleep = NO_WAIT;
910
911 break; }
912
914 {
915 Timer *const tmr = cmd.timer;
916 STK_ASSERT(tmr != nullptr);
917
918 // not currently active: start with supplied parameters
919 if (!tmr->m_active)
920 {
921 STK_ASSERT(!tmr->IsLinked());
922
923 tmr->m_deadline = cmd.timestamp + static_cast<Ticks>(cmd.delay);
924 tmr->m_period = cmd.period;
925 tmr->m_active = true;
926 tmr->m_pending = false;
927 tmr->m_rearming = false;
928
929 m_active.LinkBack(tmr);
930 }
931 // active and periodic: reset deadline anchored to call-site timestamp
932 else if (tmr->m_period != 0U)
933 {
934 STK_ASSERT(tmr->GetHead() == &m_active);
935
936 tmr->m_deadline = cmd.timestamp + static_cast<Ticks>(tmr->m_period);
937 tmr->m_pending = false;
938 }
939 else
940 {
941 // noop
942 }
943
944 // active one-shot: no action - cannot reset a one-shot mid-flight,
945 // caller should use Restart() if unconditional re-arm is needed
946
947 next_sleep = NO_WAIT;
948
949 break; }
950
952 {
953 Timer *const tmr = cmd.timer;
954 STK_ASSERT(tmr != nullptr);
955 STK_ASSERT(cmd.period != 0U);
956
957 // guard: only apply if still active and periodic
958 if (tmr->m_active && (tmr->m_period != 0U))
959 {
960 STK_ASSERT(tmr->GetHead() == &m_active);
961
962 // new period takes effect on the next reload, current deadline is
963 // intentionally left unchanged so the in-flight interval is not
964 // truncated or extended, caller can follow up with Reset() if
965 // immediate application is required
966 tmr->m_period = cmd.period;
967 }
968
969 break; }
970
972 {
973 // wake all handler tasks with shutdown sentinels
974 for (size_t i = 0U; i < STK_TIMER_THREADS_COUNT; ++i)
975 {
976 STK_UNUSED(m_queue.Write(nullptr, NO_WAIT));
977 }
978
979 // signal UpdateTime() to exit its loop
980 working = false;
981
982 break; }
983
984 default:
985 {
986 STK_ASSERT(false);
987
988 break; }
989 }
990 }
991
992 return working;
993}
994
995// ---------------------------------------------------------------------------
996// PushCommand
997// ---------------------------------------------------------------------------
998
1000{
1001 bool success = true;
1002 bool proceed_to_write = true;
1003
1004 const bool is_rearm = (cmd.cmd == TimerCommand::CMD_RESTART) ||
1006
1007 // rearm coalescing (CMD_RESTART and CMD_START_OR_RESET only)
1008 if (is_rearm && (cmd.timer != nullptr))
1009 {
1010 if (cmd.timer->m_rearming)
1011 {
1012 // already rearming - successfully coalesced, no need to write to queue
1013 proceed_to_write = false;
1014 }
1015 else
1016 {
1017 cmd.timer->m_rearming = true;
1018
1019 // prevent compiler from sinking the flag write past Write()
1020 __stk_full_memfence();
1021 }
1022 }
1023
1024 // write to command queue
1025 if (proceed_to_write)
1026 {
1027 if (!m_commands.Write(cmd, NO_WAIT))
1028 {
1029 // revert the flag if this was a failed rearm attempt
1030 if (is_rearm && (cmd.timer != nullptr))
1031 {
1032 cmd.timer->m_rearming = false;
1033 }
1034
1035 // queue full: this indicates a usage error - more commands are being
1036 // issued than the tick task can drain (recoverable in
1037 // release, caller receives false and can retry or escalate)
1038 STK_ASSERT(false);
1039 success = false;
1040 }
1041 }
1042
1043 return success;
1044}
1045
1046} // namespace time
1047} // namespace stk
1048
1049#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:136
EAccessMode
Hardware access modes by the task.
Definition stk_common.h:42
@ ACCESS_USER
Unprivileged access mode (access to some hardware is restricted, see CPU manual for details)....
Definition stk_common.h:43
constexpr Timeout NO_WAIT
Timeout value: return immediately if the synchronization object is not yet signaled (non-blocking pol...
Definition stk_common.h:210
int64_t Ticks
Ticks value.
Definition stk_common.h:151
int32_t Timeout
Timeout time (ticks).
Definition stk_common.h:146
static constexpr T Max(T a, T b)
Compile-time maximum of two values.
Definition stk_defs.h:645
constexpr Weight DEFAULT_WEIGHT
Weight value: default weight of value (1) (see SwitchStrategySmoothWeightedRoundRobin).
Definition stk_common.h:220
static Ticks GetTicks()
Get number of ticks elapsed since kernel start.
Definition stk_helper.h:313
constexpr Timeout WAIT_INFINITE
Timeout value: block indefinitely until the synchronization object is signaled.
Definition stk_common.h:204
static __stk_forceinline void WriteVolatile64(volatile T *addr, T value)
Atomically write a 64-bit volatile value.
Definition stk_arch.h:288
static __stk_forceinline T ReadVolatile64(volatile const T *addr)
Atomically read a 64-bit volatile value.
Definition stk_arch.h:223
Time-related primitives.
Word Type[TStackSize]
Stack memory type.
Definition stk_common.h:295
Interface for a user task.
Definition stk_common.h:670
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 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)