1 // Copyright 2016 The Fuchsia Authors
2 // Copyright (c) 2008-2009 Travis Geiselbrecht
3 //
4 // Use of this source code is governed by a MIT-style
5 // license that can be found in the LICENSE file or at
6 // https://opensource.org/licenses/MIT
7
8 #pragma once
9
10 #include <kernel/spinlock.h>
11 #include <kernel/timer_slack.h>
12 #include <list.h>
13 #include <sys/types.h>
14 #include <zircon/compiler.h>
15 #include <zircon/types.h>
16
17 __BEGIN_CDECLS
18
19 void timer_queue_init(void);
20
21 struct timer;
22 typedef void (*timer_callback)(struct timer*, zx_time_t now, void* arg);
23
24 #define TIMER_MAGIC (0x74696D72) //'timr'
25
26 typedef struct timer {
27 int magic;
28 struct list_node node;
29
30 zx_time_t scheduled_time;
31 zx_duration_t slack; // Stores the applied slack adjustment from
32 // the ideal scheduled_time.
33 timer_callback callback;
34 void* arg;
35
36 volatile int active_cpu; // <0 if inactive
37 volatile bool cancel; // true if cancel is pending
38 } timer_t;
39
40 #define TIMER_INITIAL_VALUE(t) \
41 { \
42 .magic = TIMER_MAGIC, \
43 .node = LIST_INITIAL_CLEARED_VALUE, \
44 .scheduled_time = 0, \
45 .slack = 0, \
46 .callback = NULL, \
47 .arg = NULL, \
48 .active_cpu = -1, \
49 .cancel = false, \
50 }
51
52 // Rules for Timers:
53 // - Timer callbacks occur from interrupt context
54 // - Timers may be programmed or canceled from interrupt or thread context
55 // - Timers may be canceled or reprogrammed from within their callback
56 // - Setting and canceling timers is not thread safe and cannot be done concurrently
57 // - timer_cancel() may spin waiting for a pending timer to complete on another cpu
58
59 // Initialize a timer object
60 void timer_init(timer_t*);
61
62 //
63 // Set up a timer that executes once
64 //
65 // This function specifies a callback function to be run after a specified
66 // deadline passes. The function will be called one time.
67 //
68 // timer: the timer to use
69 // deadline: absolute time, in ns, after which the timer is executed
70 // mode: type of slack to apply, either symmetrical or one-sided to early or late
71 // slack: specifies how much the timer may deviate from the deadline
72 // callback: the function to call when the timer expires
73 // arg: the argument to pass to the callback
74 //
75 // The timer function is declared as:
76 // void callback(timer_t *, zx_time_t now, void *arg) { ... }
77 //
78 // The |slack| parameter defines an interval in which is acceptable to fire the timer:
79 //
80 // - slack.mode == TIMER_SLACK_CENTER -> |deadline - slack.amount| to |deadline + slack.amount|
81 // - slack.mode == TIMER_SLACK_LATE -> |deadline| to |deadline + slack.amount|
82 // - slack.mode == TIMER_SLACK_EARLY -> |deadline - slack.amount| to |deadline|
83 void timer_set(timer_t* timer, zx_time_t deadline, TimerSlack slack,
84 timer_callback callback, void* arg);
85
86 //
87 // Cancel a pending timer
88 //
89 // Returns true if the timer was canceled before it was
90 // scheduled in a cpu and false otherwise or if the timer
91 // was not scheduled at all.
92 //
93 bool timer_cancel(timer_t*);
94
95 // Equivalent to timer_set with no slack
timer_set_oneshot(timer_t * timer,zx_time_t deadline,timer_callback callback,void * arg)96 static inline void timer_set_oneshot(
97 timer_t* timer, zx_time_t deadline, timer_callback callback, void* arg) {
98 return timer_set(timer, deadline, kNoSlack, callback, arg);
99 }
100
101 // Preemption Timers
102 //
103 // Each CPU has a dedicated preemption timer that's managed using specialized functions (prefixed
104 // with timer_preempt_).
105 //
106 // Preemption timers are different from general timers. Preemption timers:
107 //
108 // - are reset frequently by the scheduler so performance is important
109 // - should not be migrated off their CPU when the CPU is shutdown
110 //
111 // Note: A preemption timer may fire even after it has been canceled.
112 //
113
114 //
115 // Set/reset the current CPU's preemption timer.
116 //
117 // When the preemption timer fires, sched_preempt_timer_tick is called.
118 void timer_preempt_reset(zx_time_t deadline);
119
120 //
121 // Cancel the current CPU's preemption timer.
122 void timer_preempt_cancel(void);
123
124 // Internal routines used when bringing cpus online/offline
125
126 // Moves |old_cpu|'s timers (except its preemption timer) to the current cpu
127 void timer_transition_off_cpu(uint old_cpu);
128
129 // This function is to be invoked after resume on each CPU that may have
130 // had timers still on it, in order to restart hardware timers.
131 void timer_thaw_percpu(void);
132
133 // Special helper routine to simultaneously try to acquire a spinlock and check for
134 // timer cancel, which is needed in a few special cases.
135 // returns ZX_OK if spinlock was acquired, ZX_ERR_TIMED_OUT if timer was canceled.
136 zx_status_t timer_trylock_or_cancel(timer_t* t, spin_lock_t* lock) TA_TRY_ACQ(false, lock);
137
138 __END_CDECLS
139