summaryrefslogtreecommitdiff
path: root/src/timer.h
diff options
context:
space:
mode:
authorRichard Braun <rbraun@sceen.net>2017-10-14 23:45:04 +0200
committerRichard Braun <rbraun@sceen.net>2018-01-04 01:57:38 +0100
commit9437f135da9fab16180fc64cdd64e2a3bb3d5b7a (patch)
tree8cd3d9e769c2af24463d58e8ba416aae9de9ce7b /src/timer.h
Initial commit
Diffstat (limited to 'src/timer.h')
-rw-r--r--src/timer.h136
1 files changed, 136 insertions, 0 deletions
diff --git a/src/timer.h b/src/timer.h
new file mode 100644
index 0000000..e4a531e
--- /dev/null
+++ b/src/timer.h
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2017 Richard Braun.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ *
+ * Software timer module.
+ */
+
+#ifndef _TIMER_H
+#define _TIMER_H
+
+#include <stdbool.h>
+
+#include <lib/list.h>
+
+/*
+ * Type for timer callback functions.
+ *
+ * These functions run in the context of the timer thread.
+ */
+typedef void (*timer_fn_t)(void *arg);
+
+struct timer {
+ struct list node;
+ unsigned long ticks;
+ timer_fn_t fn;
+ void *arg;
+};
+
+/*
+ * Check if a time, in ticks, is considered to have expired/occurred
+ * compared to a given reference time, also in ticks.
+ *
+ * A time is considered expired when it's strictly in the past compared
+ * to the given reference time, and occurred when it's expired or equal
+ * to the reference time.
+ */
+bool timer_ticks_expired(unsigned long ticks, unsigned long ref);
+bool timer_ticks_occurred(unsigned long ticks, unsigned long ref);
+
+/*
+ * Initialize the timer module.
+ */
+void timer_setup(void);
+
+/*
+ * Return the current time, in ticks.
+ */
+unsigned long timer_now(void);
+
+/*
+ * Initialize a timer.
+ *
+ * A timer may only be safely initialized when not scheduled.
+ */
+void timer_init(struct timer *timer, timer_fn_t fn, void *arg);
+
+/*
+ * Schedule a timer.
+ *
+ * The timer callback function is called at or after the given scheduled
+ * (absolute) time, in ticks. If the scheduled time denotes the past, the
+ * timer function is called immediately.
+ *
+ * A timer may only be safely scheduled when not already scheduled. When
+ * a timer expires and its callback function runs, it is not considered
+ * scheduled any more, and may be safely rescheduled from within the
+ * callback function. This is how periodic timers are implemented.
+ *
+ * Note that a timer callback function never runs immediately at its
+ * scheduled time. The duration between the actual scheduled time and the
+ * time at which the timer callback function runs is called the latency.
+ * Ideally, this latency should be as short as possible and never exceed
+ * a maximum limit, i.e. be time-bounded. That's what real-time systems
+ * are about. Unfortunately, it's quite difficult to achieve most of the
+ * time. There are many sources of unexpected latency such as thread
+ * scheduling (if not using a real-time scheduling algorithm), priority
+ * inversions, other interrupts, cache/TLB misses, contention on the system
+ * bus (e.g. when the CPU and a DMA controller compete to become the bus
+ * master for a transfer), and memory (DDR SDRAM) access requests being
+ * reordered by the controller, to name the most common.
+ *
+ * Also note that, in addition to latency, another parameter that affects
+ * the processing of a timer is resolution. In this implementation, the
+ * timer is configured to raise interrupts at the thread scheduler
+ * frequency, normally 100 Hz, making the resolution 10ms, which is
+ * considered a low resolution. This means that a timer cannot be
+ * scheduled to trigger at times that aren't multiples of 10ms on the
+ * clock used by the timer system. Finally, note that when scheduling
+ * relative timers, unless stated otherwise, the time for the timer to
+ * trigger is less than the time requested. This is because the "current
+ * time" always marks the past. For example, with the 10ms resolution
+ * timer system used here, timer_now() could return 1000 when the "real"
+ * current time is actually 1000.9. Assuming the timer is scheduled to
+ * trigger at 1001, this means that, instead of waiting a complete tick,
+ * the timer would trigger only a tenth of the requested time after being
+ * scheduled.
+ *
+ * What this interface guarantees is that the function never runs before
+ * its scheduled time.
+ *
+ * Finally, for the sake of simplicity, this function doesn't provide a
+ * way to cancel a timer.
+ */
+void timer_schedule(struct timer *timer, unsigned long ticks);
+
+/*
+ * Return the scheduled time of a timer, in ticks.
+ */
+unsigned long timer_get_time(const struct timer *timer);
+
+/*
+ * Report a periodic tick to the timer module.
+ *
+ * This function is called by the hardware timer driver interrupt handler.
+ */
+void timer_report_tick(void);
+
+#endif /* _TIMER_H */