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