SuperTinyKernel™ RTOS 1.08.x
Lightweight, high-performance, deterministic, bare-metal C++ RTOS for resource-constrained embedded systems. MIT Open Source License.
Loading...
Searching...
No Matches
stk::time::TimerHost Class Reference

Software timer multiplexer that manages multiple Timer instances on top of a small fixed set of kernel tasks. More...

#include <stk_time_timer.h>

Collaboration diagram for stk::time::TimerHost:

Classes

class  Timer
 Abstract base class for a timer managed by TimerHost. More...
class  TimerWorkerTask
 Internal kernel task used by TimerHost for both the tick task and handler tasks. More...
struct  TimerCommand
 POD command record passed from the public API methods to the tick task via the command queue. More...

Public Types

enum  EConsts : size_t {
  TASK_COUNT = (1U + 1U ) ,
  TASK_TICK_MEMORY_SIZE = Max<size_t>(256U, STK_STACK_SIZE_MIN) ,
  TASK_HANDLER_STACK_SIZE = Max<size_t>( 256U , STK_STACK_SIZE_MIN)
}

Public Member Functions

 TimerHost ()
 Default constructor. Zero-initializes all internal state.
 ~TimerHost ()=default
 Destructor.
void Initialize (IKernel *kernel, EAccessMode mode)
 Initialize timer host instance.
bool Start (Timer &tmr, uint32_t delay, uint32_t period=0)
 Start timer.
bool Stop (Timer &tmr)
 Stop running timer.
bool Reset (Timer &tmr)
 Reset periodic timer's deadline.
bool Restart (Timer &tmr, uint32_t delay, uint32_t period=0)
 Atomically stop and re-start timer.
bool StartOrReset (Timer &tmr, uint32_t delay, uint32_t period=0)
 Start timer if inactive, or reset its deadline if already active and periodic.
bool SetPeriod (Timer &tmr, uint32_t period)
 Change the period of a running periodic timer without affecting its current deadline.
bool IsEmpty () const
 Return true if no timers are currently active.
size_t GetSize () const
 Return number of currently active timers.
bool Shutdown ()
 Shutdown host instance. All timers are stopped and removed from the host.
Ticks GetTimeNow () const
 Get current time.

Private Types

typedef void(* TimerFuncType) (TimerHost *host)
 Timer task function prototype.
typedef StackMemoryDef< TASK_TICK_MEMORY_SIZE >::Type TaskTickMemory
 Stack memory type for the single tick task.
typedef StackMemoryDef< TASK_HANDLER_STACK_SIZE >::Type TimerHostMemory
 Stack memory type for each handler task.
typedef sync::PipeT< Timer *, 32U > ReadyQueue
 Lock-free pipe used to transfer expired timer pointers from the tick task to handler tasks.
typedef sync::PipeT< TimerCommand, 32U > CommandQueue
 Lock-free pipe used to send TimerCommand records from API callers to the tick task.

Private Member Functions

 STK_NONCOPYABLE_CLASS (TimerHost)
void UpdateTime ()
 Tick task body: drives the timer list and dispatches expired timers.
void ProcessTimers ()
 Handler task body: dequeues expired timers and invokes their OnExpired() callbacks.
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.

Private Attributes

TaskTickMemory m_task_tick_memory
 tick task memory
TimerHostMemory m_task_handler_memory [1U]
 handler task memory
TimerWorkerTask m_task_tick
 timer task
TimerWorkerTask m_task_process [1U]
 handler tasks
util::DListHead< Timer, false > m_active
 active timers (tick task only)
ReadyQueue m_queue
 queue of timers ready for handling
CommandQueue m_commands
 command queue
Ticks m_now
 last known current time (ticks)

Detailed Description

Software timer multiplexer that manages multiple Timer instances on top of a small fixed set of kernel tasks.

TimerHost internally runs two categories of tasks:

  • One tick task that maintains the active timer list, evaluates deadlines every wake cycle, and queues expired timers for dispatch.
  • One or more handler tasks (see STK_TIMER_THREADS_COUNT) that dequeue expired timers and invoke their OnExpired() callbacks.

All timers share the same tick and handler tasks, so the total kernel task overhead is constant regardless of how many timers are active.

Two timer modes are supported:

  • One-shot: fires once after delay ticks and becomes inactive automatically.
  • Periodic: fires every period ticks until explicitly stopped.
Note
TimerHost must be initialized before use by calling Initialize(). The maximum number of concurrently active timers is STK_TIMER_COUNT_MAX (default: 32). The maximum timer period is bounded by uint32_t (~49 days at 1 ms resolution).
// define a concrete timer by overriding OnExpired
class HeartbeatTimer : public stk::time::TimerHost::Timer
{
public:
{
// called every 500 ms
ToggleLed();
}
};
// declare host and timer instances (static storage, no heap)
HeartbeatTimer g_Heartbeat;
// one-shot example: send a delayed notification
class NotifyTimer : public stk::time::TimerHost::Timer
{
public:
{
g_Event.Signal();
}
};
NotifyTimer g_Notify;
void SetupTimers(stk::IKernel *kernel)
{
// initialize the host, must be called before Start()
// start 500 ms periodic heartbeat
uint32_t period = stk::GetTicksFromMsec(500);
g_TimerHost.Start(g_Heartbeat, period, period);
// start a one-shot notification after 1 second
uint32_t delay = stk::GetTicksFromMsec(1000);
g_TimerHost.Start(g_Notify, delay);
}
static stk::time::TimerHost * g_TimerHost
@ ACCESS_USER
Unprivileged access mode (access to some hardware is restricted, see CPU manual for details)....
Definition stk_common.h:37
Software timer multiplexer that manages multiple Timer instances on top of a small fixed set of kerne...
void Initialize(IKernel *kernel, EAccessMode mode)
Initialize timer host instance.
bool Start(Timer &tmr, uint32_t delay, uint32_t period=0)
Start timer.
Abstract base class for a timer managed by TimerHost.
virtual void OnExpired(TimerHost *host)=0
Callback invoked by the handler task when this timer expires.
See also
TimerHost::Timer, STK_TIMER_THREADS_COUNT, STK_TIMER_HANDLER_STACK_SIZE, STK_TIMER_COUNT_MAX

Definition at line 111 of file stk_time_timer.h.

Member Typedef Documentation

◆ CommandQueue

Lock-free pipe used to send TimerCommand records from API callers to the tick task.

Definition at line 461 of file stk_time_timer.h.

◆ ReadyQueue

Lock-free pipe used to transfer expired timer pointers from the tick task to handler tasks.

Definition at line 456 of file stk_time_timer.h.

◆ TaskTickMemory

Stack memory type for the single tick task.

Definition at line 446 of file stk_time_timer.h.

◆ TimerFuncType

typedef void(* stk::time::TimerHost::TimerFuncType) (TimerHost *host)
private

Timer task function prototype.

Definition at line 318 of file stk_time_timer.h.

◆ TimerHostMemory

Stack memory type for each handler task.

Definition at line 451 of file stk_time_timer.h.

Member Enumeration Documentation

◆ EConsts

Enumerator
TASK_COUNT 

total number of tasks serving this instance

stack memory size of the tick task

TASK_TICK_MEMORY_SIZE 

stack memory size of the timer handler task

TASK_HANDLER_STACK_SIZE 

Definition at line 114 of file stk_time_timer.h.

115 {
118
121
124 };
#define STK_STACK_SIZE_MIN
Minimum stack size in elements of Word, shared by all stack allocation lower-bound checks.
Definition stk_defs.h:640
#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).
static constexpr T Max(T a, T b) noexcept
Compile-time maximum of two values.
Definition stk_defs.h:759
@ TASK_TICK_MEMORY_SIZE
stack memory size of the timer handler task
@ TASK_COUNT
total number of tasks serving this instance

Constructor & Destructor Documentation

◆ TimerHost()

stk::time::TimerHost::TimerHost ( )
inlineexplicit

Default constructor. Zero-initializes all internal state.

Note
Call Initialize() before using any other member function.

Definition at line 215 of file stk_time_timer.h.

217 m_active(), m_now(0)
218 {}
TimerWorkerTask m_task_process[1U]
handler tasks
TimerHostMemory m_task_handler_memory[1U]
handler task memory
Ticks m_now
last known current time (ticks)
util::DListHead< Timer, false > m_active
active timers (tick task only)
TimerWorkerTask m_task_tick
timer task
TaskTickMemory m_task_tick_memory
tick task memory

References m_active, m_now, m_task_handler_memory, m_task_process, m_task_tick, and m_task_tick_memory.

Referenced by Initialize(), stk::time::TimerHost::TimerWorkerTask::Initialize(), and STK_NONCOPYABLE_CLASS().

Here is the caller graph for this function:

◆ ~TimerHost()

stk::time::TimerHost::~TimerHost ( )
default

Destructor.

Note
MISRA deviation: [STK-DEV-005] Rule 10-3-2.

Member Function Documentation

◆ GetSize()

size_t stk::time::TimerHost::GetSize ( ) const
inline

Return number of currently active timers.

Returns
Active timer count.
Note
The value is advisory and may change immediately after the call.

Definition at line 300 of file stk_time_timer.h.

300{ return m_active.GetSize(); }

References m_active.

Referenced by stk_timerhost_get_size().

Here is the caller graph for this function:

◆ GetTimeNow()

Ticks stk::time::TimerHost::GetTimeNow ( ) const
inline

Get current time.

Returns
Current time (ticks).

Definition at line 310 of file stk_time_timer.h.

310{ return hw::ReadVolatile64(&m_now); }
static T ReadVolatile64(volatile const T *addr)
Atomically read a 64-bit volatile value.
Definition stk_arch.h:331

References m_now, and stk::hw::ReadVolatile64().

Referenced by stk_timerhost_get_time_now().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ Initialize()

void stk::time::TimerHost::Initialize ( IKernel * kernel,
EAccessMode mode )
inline

Initialize timer host instance.

Parameters
[in]kernelKernel to which instance will be bound.
[in]modeAccess mode for the timer handling tasks which call expired timers.

Definition at line 501 of file stk_time_timer.h.

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}
TimerHost()
Default constructor. Zero-initializes all internal state.

References stk::ACCESS_USER, stk::IKernel::AddTask(), m_task_handler_memory, m_task_process, m_task_tick, m_task_tick_memory, ProcessTimers(), STK_TIMER_THREADS_COUNT, TASK_HANDLER_STACK_SIZE, TASK_TICK_MEMORY_SIZE, TimerHost(), and UpdateTime().

Referenced by stk::interop_c_helper::InitializeTimerHost().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ IsEmpty()

bool stk::time::TimerHost::IsEmpty ( ) const
inline

Return true if no timers are currently active.

Returns
True if active timer count is zero.
Note
The value is advisory and may change immediately after the call.

Definition at line 294 of file stk_time_timer.h.

294{ return m_active.IsEmpty(); }

References m_active.

Referenced by stk_timerhost_is_empty().

Here is the caller graph for this function:

◆ ProcessCommands()

bool stk::time::TimerHost::ProcessCommands ( Timeout next_sleep)
inlineprivate

Drain the command queue and execute each pending command.

Parameters
[in]next_sleepMaximum ticks to block waiting for the first command when the active list is non-empty. Overridden to WAIT_INFINITE when empty.
Returns
True to continue the tick loop; false when CMD_SHUTDOWN is processed.
Note
Called exclusively from the tick task (UpdateTime()).

Definition at line 813 of file stk_time_timer.h.

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}
#define STK_UNUSED(X)
Explicitly marks a variable as unused to suppress compiler warnings.
Definition stk_defs.h:715
#define STK_ASSERT(e)
Runtime assertion. Halts execution if the expression e evaluates to false.
Definition stk_defs.h:516
static constexpr Timeout NO_WAIT
Timeout value: return immediately if the synchronization object is not yet signaled (non-blocking pol...
Definition stk_common.h:217
int64_t Ticks
Ticks value.
Definition stk_common.h:158
static constexpr Timeout WAIT_INFINITE
Timeout value: block indefinitely until the synchronization object is signaled.
Definition stk_common.h:211
ReadyQueue m_queue
queue of timers ready for handling
CommandQueue m_commands
command queue
POD command record passed from the public API methods to the tick task via the command queue.
@ 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

References stk::time::TimerHost::TimerCommand::cmd, stk::time::TimerHost::TimerCommand::CMD_RESET, stk::time::TimerHost::TimerCommand::CMD_RESTART, stk::time::TimerHost::TimerCommand::CMD_SET_PERIOD, stk::time::TimerHost::TimerCommand::CMD_SHUTDOWN, stk::time::TimerHost::TimerCommand::CMD_START, stk::time::TimerHost::TimerCommand::CMD_START_OR_RESET, stk::time::TimerHost::TimerCommand::CMD_STOP, stk::time::TimerHost::TimerCommand::delay, stk::util::DListEntry< T, TClosedLoop >::GetHead(), stk::util::DListEntry< T, TClosedLoop >::IsLinked(), m_active, stk::time::TimerHost::Timer::m_active, m_commands, stk::time::TimerHost::Timer::m_deadline, stk::time::TimerHost::Timer::m_pending, stk::time::TimerHost::Timer::m_period, m_queue, stk::time::TimerHost::Timer::m_rearming, stk::NO_WAIT, stk::time::TimerHost::TimerCommand::period, STK_ASSERT, STK_TIMER_THREADS_COUNT, STK_UNUSED, stk::time::TimerHost::TimerCommand::timer, stk::time::TimerHost::TimerCommand::timestamp, and stk::WAIT_INFINITE.

Referenced by UpdateTime().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ ProcessTimers()

void stk::time::TimerHost::ProcessTimers ( )
inlineprivate

Handler task body: dequeues expired timers and invokes their OnExpired() callbacks.

Note
Runs in each handler task context. Loops until a nullptr sentinel is dequeued.

Definition at line 780 of file stk_time_timer.h.

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}

References stk::time::TimerHost::Timer::m_pending, m_queue, and stk::time::TimerHost::Timer::OnExpired().

Referenced by Initialize().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ PushCommand()

bool stk::time::TimerHost::PushCommand ( TimerCommand cmd)
inlineprivate

Enqueue a command for the tick task.

Parameters
[in]cmdFully initialized TimerCommand to push.
Returns
True on success, false if the command queue is full.
Note
May be called from any task context. On queue-full the assertion fires in debug builds; in release the caller receives false and may retry or escalate.

Definition at line 999 of file stk_time_timer.h.

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}

References stk::time::TimerHost::TimerCommand::cmd, stk::time::TimerHost::TimerCommand::CMD_RESTART, stk::time::TimerHost::TimerCommand::CMD_START_OR_RESET, m_commands, stk::time::TimerHost::Timer::m_rearming, stk::NO_WAIT, STK_ASSERT, and stk::time::TimerHost::TimerCommand::timer.

Referenced by Reset(), Restart(), SetPeriod(), Shutdown(), Start(), StartOrReset(), and Stop().

Here is the caller graph for this function:

◆ Reset()

bool stk::time::TimerHost::Reset ( Timer & tmr)
inline

Reset periodic timer's deadline.

Parameters
[in]tmrTimer instance. Must be active and periodic.
Returns
True on success, false if timer is not active, not periodic, or command queue is full.

Definition at line 582 of file stk_time_timer.h.

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}
static Ticks GetTicks()
Get number of ticks elapsed since kernel start.
Definition stk_helper.h:434
bool PushCommand(TimerCommand cmd)
Enqueue a command for the tick task.

References stk::time::TimerHost::TimerCommand::CMD_RESET, stk::GetTicks(), stk::time::TimerHost::Timer::m_active, stk::time::TimerHost::Timer::m_period, and PushCommand().

Referenced by stk_timer_reset().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ Restart()

bool stk::time::TimerHost::Restart ( Timer & tmr,
uint32_t delay,
uint32_t period = 0 )
inline

Atomically stop and re-start timer.

Parameters
[in]tmrTimer instance (active or inactive).
[in]delayInitial delay in ticks before first expiration.
[in]periodReload period in ticks (0 is one-shot timer).
Returns
True on success, false if command queue is full.
Note
Unlike calling Stop() followed by Start(), this operation is atomic with respect to the tick task: the timer cannot fire between the implicit stop and re-start, and only one command queue slot is consumed. Useful for watchdog refresh and debounce reset patterns. Safe to call regardless of whether the timer is currently active.

Definition at line 609 of file stk_time_timer.h.

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}

References stk::time::TimerHost::TimerCommand::CMD_RESTART, stk::GetTicks(), PushCommand(), STK_ASSERT, and stk::WAIT_INFINITE.

Referenced by stk_timer_restart().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ SetPeriod()

bool stk::time::TimerHost::SetPeriod ( Timer & tmr,
uint32_t period )
inline

Change the period of a running periodic timer without affecting its current deadline.

Parameters
[in]tmrTimer instance. Must be active and periodic.
[in]periodNew reload period in ticks. Must be non-zero.
Returns
True on success, false if timer is not active, not periodic, period is zero, or command queue is full.
Note
The new period takes effect on the next reload after the current deadline fires. To apply the new period immediately (restart from now), call Reset() after SetPeriod().

Definition at line 645 of file stk_time_timer.h.

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}

References stk::time::TimerHost::TimerCommand::CMD_SET_PERIOD, stk::time::TimerHost::Timer::m_active, stk::time::TimerHost::Timer::m_period, PushCommand(), and stk::WAIT_INFINITE.

Referenced by stk_timer_set_period().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ Shutdown()

bool stk::time::TimerHost::Shutdown ( )
inline

Shutdown host instance. All timers are stopped and removed from the host.

Returns
True on success, false if command queue is full.

Definition at line 674 of file stk_time_timer.h.

675{
676 return PushCommand({
678 .timer = nullptr,
679 .timestamp = 0,
680 .delay = 0U,
681 .period = 0U
682 });
683}

References stk::time::TimerHost::TimerCommand::CMD_SHUTDOWN, and PushCommand().

Referenced by stk_timerhost_shutdown().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ Start()

bool stk::time::TimerHost::Start ( Timer & tmr,
uint32_t delay,
uint32_t period = 0 )
inline

Start timer.

Parameters
[in]tmrTimer instance. Must not already be active.
[in]delayInitial delay in ticks before first expiration.
[in]periodReload period in ticks (0 is one-shot timer).
Returns
True on success, false if timer is already active or command queue is full.

Definition at line 523 of file stk_time_timer.h.

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}

References stk::time::TimerHost::TimerCommand::CMD_START, stk::GetTicks(), stk::time::TimerHost::Timer::m_active, PushCommand(), STK_ASSERT, and stk::WAIT_INFINITE.

Referenced by stk_timer_start().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ StartOrReset()

bool stk::time::TimerHost::StartOrReset ( Timer & tmr,
uint32_t delay,
uint32_t period = 0 )
inline

Start timer if inactive, or reset its deadline if already active and periodic.

Parameters
[in]tmrTimer instance (active or inactive).
[in]delayInitial delay in ticks (used only when starting).
[in]periodReload period in ticks (used only when starting, 0 is one-shot).
Returns
True on success, false if command queue is full.
Note
Collapses the common pattern: if (timer.IsActive()) host.Reset(timer); else host.Start(timer, delay, period); into a single atomic operation, eliminating the TOCTOU race between the IsActive() check and the subsequent call. If the timer is active but one-shot, no action is taken (a one-shot timer mid-flight cannot be reset; use Restart() instead).

Definition at line 627 of file stk_time_timer.h.

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}

References stk::time::TimerHost::TimerCommand::CMD_START_OR_RESET, stk::GetTicks(), PushCommand(), STK_ASSERT, and stk::WAIT_INFINITE.

Referenced by stk_timer_start_or_reset().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ STK_NONCOPYABLE_CLASS()

stk::time::TimerHost::STK_NONCOPYABLE_CLASS ( TimerHost )
private

References TimerHost().

Here is the call graph for this function:

◆ Stop()

bool stk::time::TimerHost::Stop ( Timer & tmr)
inline

Stop running timer.

Parameters
[in]tmrTimer instance. Must be active.
Returns
True on success, false if timer is not active or command queue is full.

Definition at line 554 of file stk_time_timer.h.

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}

References stk::time::TimerHost::TimerCommand::CMD_STOP, stk::time::TimerHost::Timer::m_active, and PushCommand().

Referenced by FrtosPendDrainer::OnExpired(), and stk_timer_stop().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ UpdateTime()

void stk::time::TimerHost::UpdateTime ( )
inlineprivate

Tick task body: drives the timer list and dispatches expired timers.

Note
Runs exclusively in the tick task context. Loops until CMD_SHUTDOWN is received.

Definition at line 689 of file stk_time_timer.h.

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 {
704 Timer *const next = util::DListCast::ListEntryToParent<Timer>(tmr->GetNext());
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}
int32_t Timeout
Timeout time (ticks).
Definition stk_common.h:153
static void WriteVolatile64(volatile T *addr, T value)
Atomically write a 64-bit volatile value.
Definition stk_arch.h:396
DListEntry< Timer, TClosedLoop > DLEntryType
static __stk_forceinline TTargetType * ListEntryToParent(TSourceType *const lentry)
Safely casts an intrusive list entry to its concrete parent container object type.
bool ProcessCommands(Timeout next_sleep)
Drain the command queue and execute each pending command.

References stk::util::DListEntry< T, TClosedLoop >::GetNext(), stk::GetTicks(), stk::util::DListCast::ListEntryToParent(), m_active, stk::time::TimerHost::Timer::m_active, stk::time::TimerHost::Timer::m_deadline, m_now, stk::time::TimerHost::Timer::m_pending, stk::time::TimerHost::Timer::m_period, m_queue, stk::time::TimerHost::Timer::m_timestamp, stk::NO_WAIT, ProcessCommands(), STK_ASSERT, STK_UNUSED, stk::WAIT_INFINITE, and stk::hw::WriteVolatile64().

Referenced by Initialize().

Here is the call graph for this function:
Here is the caller graph for this function:

Member Data Documentation

◆ m_active

util::DListHead<Timer, false> stk::time::TimerHost::m_active
private

active timers (tick task only)

Definition at line 467 of file stk_time_timer.h.

Referenced by GetSize(), IsEmpty(), ProcessCommands(), TimerHost(), and UpdateTime().

◆ m_commands

CommandQueue stk::time::TimerHost::m_commands
private

command queue

Definition at line 469 of file stk_time_timer.h.

Referenced by ProcessCommands(), and PushCommand().

◆ m_now

Ticks stk::time::TimerHost::m_now
private

last known current time (ticks)

Definition at line 470 of file stk_time_timer.h.

Referenced by GetTimeNow(), TimerHost(), and UpdateTime().

◆ m_queue

ReadyQueue stk::time::TimerHost::m_queue
private

queue of timers ready for handling

Definition at line 468 of file stk_time_timer.h.

Referenced by ProcessCommands(), ProcessTimers(), and UpdateTime().

◆ m_task_handler_memory

TimerHostMemory stk::time::TimerHost::m_task_handler_memory[1U]
private

handler task memory

Definition at line 464 of file stk_time_timer.h.

Referenced by Initialize(), and TimerHost().

◆ m_task_process

TimerWorkerTask stk::time::TimerHost::m_task_process[1U]
private

handler tasks

Definition at line 466 of file stk_time_timer.h.

Referenced by Initialize(), and TimerHost().

◆ m_task_tick

TimerWorkerTask stk::time::TimerHost::m_task_tick
private

timer task

Definition at line 465 of file stk_time_timer.h.

Referenced by Initialize(), and TimerHost().

◆ m_task_tick_memory

TaskTickMemory stk::time::TimerHost::m_task_tick_memory
private

tick task memory

Definition at line 463 of file stk_time_timer.h.

Referenced by Initialize(), and TimerHost().


The documentation for this class was generated from the following file: