GCC Code Coverage Report


Directory: ./
File: Timers.h
Date: 2026-10-29 08:11:58
Exec Total Coverage
Lines: 8 8 100.0%
Functions: 3 3 100.0%
Branches: 3 4 75.0%

Line Branch Exec Source
1 #pragma once
2 /*
3 * This file is part of the Falcon Player (FPP) and is Copyright (C)
4 * 2013-2022 by the Falcon Player Developers.
5 *
6 * The Falcon Player (FPP) is free software, and is covered under
7 * multiple Open Source licenses. Please see the included 'LICENSES'
8 * file for descriptions of what files are covered by each license.
9 *
10 * This source file is covered under the LGPL v2.1 as described in the
11 * included LICENSE.LGPL file.
12 */
13
14 // PLUGIN API: native plugins compile against this header and are loaded with
15 // dlopen().
16 // - Plugins call Timers::INSTANCE.addPeriodicTimer()/stopPeriodicTimer()
17 // by symbol.
18 // Data layout here is NOT plugin ABI, so members can change freely. Changing
19 // or removing a signature a plugin calls is: keep the old one as an overload
20 // (as Timers::addPeriodicTimer does) or bump FPP_PLUGIN_API_VERSION in
21 // Plugin.h. See .claude/PLUGIN-ABI.md for which plugins use what.
22
23 #include <atomic>
24 #include <mutex>
25 #include <vector>
26 #include <functional>
27
28 extern long long GetTimeMS();
29 extern long long GetMonotonicTimeMS();
30
31 class Timers {
32 public:
33 static Timers INSTANCE;
34
35 Timers();
36 ~Timers();
37
38 484418 void fireTimers() {
39 // Every main-loop pass. Relaxed: a stale value only fires late by a
40 // pass or calls in early, and fireTimersInternal() works from the
41 // list under the lock either way.
42
1/2
✓ Branch 0 taken 484418 times.
✗ Branch 1 not taken.
484418 if (hasTimers.load(std::memory_order_relaxed)) {
43 484418 long long t = GetMonotonicTimeMS();
44
2/2
✓ Branch 0 taken 20229 times.
✓ Branch 1 taken 464189 times.
968836 if (t >= nextTimer.load(std::memory_order_relaxed)) {
45 20229 fireTimersInternal(t);
46 }
47 }
48 484418 }
49
50 // fireTimeMS is a deadline on the GetTimeMS() wall clock, as callers
51 // (plugins included) have always passed: "GetTimeMS() + delay". It is
52 // turned into a delay on arrival, and the timer then runs on the
53 // monotonic clock, so a later clock step (NTP, an RTC that boots in the
54 // past) doesn't hold it back for the size of the step or fire it early.
55 void addTimer(const std::string& name, long long fireTimeMS, std::function<void()>&& callback);
56 void addTimer(const std::string& name, long long fireTimeMS, const std::string& preset);
57
58 // initialDelayMS lets the FIRST fire land somewhere other than exactly
59 // fireTimeMS from now, without changing the recurring rate (periodicRate
60 // stays fireTimeMS regardless) - e.g. RecurringTasks::startTimers() uses
61 // this to stagger tasks that share the same interval so they don't all
62 // fire in lockstep forever. Defaults to fireTimeMS (original behavior)
63 // when omitted.
64 void addPeriodicTimer(const std::string& name, long long fireTimeMS, std::function<void()>&& callback);
65 void addPeriodicTimer(const std::string& name, long long fireTimeMS, std::function<void()>&& callback,
66 long long initialDelayMS);
67 void stopPeriodicTimer(const std::string& name);
68
69 private:
70 // Read by fireTimers() on the main loop without the lock; written under
71 // it by updateTimers() from whichever thread adds or stops a timer.
72 std::atomic<bool> hasTimers{ false };
73 std::atomic<long long> nextTimer{ 0 };
74
75 class TimerInfo {
76 public:
77 5242 TimerInfo() {}
78 88517 ~TimerInfo() {}
79
80 std::string id;
81 long long fireTimeMS; // GetMonotonicTimeMS() deadline
82 long long periodicRate = 0;
83 std::string commandPreset;
84 std::function<void()> callback;
85 };
86 std::vector<TimerInfo*> timers;
87 std::mutex lock;
88
89 void fireTimersInternal(long long t);
90
91 // these methods must be called with the lock held
92 void fireTimer(TimerInfo*);
93 void updateTimers();
94 };
95