xref: /aosp_15_r20/external/pigweed/pw_chrono/public/pw_chrono/system_timer.h (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2021 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 #pragma once
15 
16 #include "pw_chrono/system_clock.h"
17 #include "pw_chrono_backend/system_timer_native.h"
18 #include "pw_function/function.h"
19 
20 namespace pw::chrono {
21 
22 /// The `SystemTimer` allows an `ExpiryCallback` be executed at a set time in
23 /// the future.
24 ///
25 /// The base `SystemTimer` only supports a one-shot style timer with a callback.
26 /// A periodic timer can be implemented by rescheduling the timer in the
27 /// callback through `InvokeAt(kDesiredPeriod + expired_deadline)`.
28 ///
29 /// When implementing a periodic layer on top, the user should be mindful of
30 /// handling missed periodic callbacks. They could opt to invoke the callback
31 /// multiple times with the expected expired_deadline values or instead saturate
32 /// and invoke the callback only once with the latest expired_deadline.
33 ///
34 /// The entire API is thread safe, however it is NOT always IRQ safe.
35 class SystemTimer {
36  public:
37   using native_handle_type = backend::NativeSystemTimerHandle;
38 
39   /// The `ExpiryCallback` is either invoked from a high priority thread or an
40   /// interrupt.
41   ///
42   /// For a given timer instance, its `ExpiryCallback` will not preempt itself.
43   /// This makes it appear like there is a single executor of a timer instance's
44   /// `ExpiryCallback`.
45   ///
46   /// Ergo ExpiryCallbacks should be treated as if they are executed by an
47   /// interrupt, meaning:
48   /// - Processing inside of the callback should be kept to a minimum.
49   /// - Callbacks should never attempt to block.
50   /// - APIs which are not interrupt safe such as pw::sync::Mutex should not be
51   ///   used!
52   using ExpiryCallback =
53       Function<void(SystemClock::time_point expired_deadline)>;
54 
55   /// Constructs the SystemTimer based on the user provided
56   /// `pw::Function<void(SystemClock::time_point expired_deadline)>`. Note that
57   /// The `ExpiryCallback` is either invoked from a high priority thread or an
58   /// interrupt.
59   SystemTimer(ExpiryCallback&& callback);
60 
61   /// Cancels the timer and blocks if necssary if the callback is already being
62   /// processed.
63   ///
64   /// @b Postcondition: The expiry callback is not in progress and will not be
65   /// called in the future.
66   ~SystemTimer();
67 
68   SystemTimer(const SystemTimer&) = delete;
69   SystemTimer(SystemTimer&&) = delete;
70   SystemTimer& operator=(const SystemTimer&) = delete;
71   SystemTimer& operator=(SystemTimer&&) = delete;
72 
73   /// Invokes the expiry callback as soon as possible after at least the
74   /// specified duration.
75   ///
76   /// Scheduling a callback cancels the existing callback (if pending).
77   /// If the callback is already being executed while you reschedule it, it will
78   /// finish callback execution to completion. You are responsible for any
79   /// critical section locks which may be needed for timer coordination.
80   ///
81   /// This is thread safe, it may not be IRQ safe.
82   void InvokeAfter(SystemClock::duration delay);
83 
84   /// Invokes the expiry callback as soon as possible starting at the specified
85   /// time_point.
86   ///
87   /// Scheduling a callback cancels the existing callback (if pending).
88   /// If the callback is already being executed while you reschedule it, it will
89   /// finish callback execution to completion. You are responsible for any
90   /// critical section locks which may be needed for timer coordination.
91   ///
92   /// This is thread safe, it may not be IRQ safe.
93   void InvokeAt(SystemClock::time_point timestamp);
94 
95   /// Cancels the software timer expiry callback if pending.
96   ///
97   /// Canceling a timer which isn't scheduled does nothing.
98   ///
99   /// If the callback is already being executed while you cancel it, it will
100   /// finish callback execution to completion. You are responsible for any
101   /// synchronization which is needed for thread safety.
102   ///
103   /// This is thread safe, it may not be IRQ safe.
104   void Cancel();
105 
106   native_handle_type native_handle();
107 
108  private:
109   /// This may be a wrapper around a native type with additional members.
110   backend::NativeSystemTimer native_type_;
111 };
112 
113 }  // namespace pw::chrono
114 
115 #include "pw_chrono_backend/system_timer_inline.h"
116