callout: add a new module which is an alternative to the scheduler
[aversive.git] / modules / base / callout / callout.h
1 /*
2  * Copyright (c) <2014>, Olivier Matz <zer0@droids-corp.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  *       notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above copyright
11  *       notice, this list of conditions and the following disclaimer in the
12  *       documentation and/or other materials provided with the distribution.
13  *     * Neither the name of the University of California, Berkeley nor the
14  *       names of its contributors may be used to endorse or promote products
15  *       derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 /* Inspired from Intel DPDK rte_timer library */
30 /*-
31  * Copyright (c) <2010>, Intel Corporation
32  * All rights reserved.
33  *
34  * Redistribution and use in source and binary forms, with or without
35  * modification, are permitted provided that the following conditions
36  * are met:
37  *
38  * - Redistributions of source code must retain the above copyright
39  *   notice, this list of conditions and the following disclaimer.
40  *
41  * - Redistributions in binary form must reproduce the above copyright
42  *   notice, this list of conditions and the following disclaimer in
43  *   the documentation and/or other materials provided with the
44  *   distribution.
45  *
46  * - Neither the name of Intel Corporation nor the names of its
47  *   contributors may be used to endorse or promote products derived
48  *   from this software without specific prior written permission.
49  *
50  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
51  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
52  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
53  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
54  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
55  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
56  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
57  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
59  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
60  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
61  * OF THE POSSIBILITY OF SUCH DAMAGE.
62  */
63
64 #ifndef _CALLOUT_H_
65 #define _CALLOUT_H_
66
67 #include <aversive/queue.h>
68
69 #define CALLOUT_STATS
70 /* #define CALLOUT_DEBUG */
71
72 /**
73  * This module provides a timer service to Aversive similar to the old
74  * "scheduler" module. The manager function callout_manage() can be called from
75  * an interrupt (like the scheduler does) or from a standard function (usually a
76  * main-loop).
77  *
78  * Each timer has a priority: the timers with higher priorities are scheduled
79  * before the others. This feature is mostly useful when the manager is called
80  * from an interrupt. Indeed, the callback function of a timer with a high
81  * priority cannot be preempted by a timer with a lower priority.
82  *
83  * The module locks interrupts when doing critical operations, ensuring that
84  * critical data are accessed atomically.
85  *
86  * State of timers:
87  * - stopped: initial state after callout_init()
88  * - scheduled: after a call to callout_schedule(), the timer is in the
89  *   scheduled list of the callout manager
90  * - expired: after a call to callout_manage(), if the expire time of a
91  *   timer is reached, it is moved in a local list and its state is
92  *   changed to "expired".
93  * - before starting the callback, the timer goes in state "running".
94  *
95  * Once running, the associated timer is not touched anymore by
96  * callout_manage(). As a result, the timer MUST be either reloaded or stopped
97  * (and potentially freed).
98  */
99
100 #define CALLOUT_MAX_RECURSION 5
101
102 #ifdef CALLOUT_STATS
103 /**
104  * The structure that stores the timer statistics, mostly useful for debug
105  * purposes.
106  */
107 struct callout_debug_stats {
108         uint32_t schedule;      /**< nb of calls to callout_(re)schedule() */
109         uint32_t stop;          /**< nb of calls to callout_stop() */
110         uint32_t manage;        /**< nb of calls to callout_manage() */
111         uint32_t max_recursion; /** manage() skipped due to max recursion */
112         uint32_t delayed;       /** task delayed a bit due to low prio */
113         uint32_t hard_delayed;  /** task recheduled later due to low priority */
114
115         uint8_t cur_scheduled;  /**< current number of scheduled timers */
116         uint8_t cur_expired;    /**< current number of expired timers */
117         uint8_t cur_running;    /**< current number of running timers */
118 };
119 #endif
120
121 struct callout;
122 struct callout_mgr;
123
124 /**
125  * The tyoe of a callout callback function.
126  */
127 typedef void (callout_cb_t)(struct callout_mgr *cm, struct callout *tim,
128         void *arg);
129
130 /**
131  * A callout structure, storing all data associated to a timer.
132  */
133 struct callout {
134         LIST_ENTRY(callout) next; /**< next/prev in list */
135
136 #define CALLOUT_STATE_STOPPED    0 /**< not scheduled */
137 #define CALLOUT_STATE_SCHEDULED  1 /**< pres*/
138 #define CALLOUT_STATE_EXPIRED    2
139 #define CALLOUT_STATE_RUNNING    3
140         uint8_t state;             /**< stopped, scheduled, expired */
141         uint8_t priority;          /**< the priority of the timer */
142         uint16_t expire;           /**< time when timer should expire */
143
144         callout_cb_t *f;           /**< callback function pointer */
145         void *arg;                 /**< argument given to the cb function. */
146 };
147
148 /* define the callout list */
149 LIST_HEAD(callout_list, callout);
150
151 /* static initializer for a timer structure */
152 #define CALLOUT_INITIALIZER { }
153
154 /**
155  * Type of the function used by a callout manager to get a time reference
156  */
157 typedef uint16_t (get_time_t)(void);
158
159 /**
160  * An instance of callout manager. It is possible to have several managers. A
161  * callout is attached to one manager at a time.
162  */
163 struct callout_mgr {
164         get_time_t *get_time; /**< func used to get the time reference */
165         uint16_t prev_time;   /**< time of previous call */
166         uint8_t cur_priority; /** priority of running event */
167         uint8_t nb_recursion; /** number of recursion */
168         struct callout_list sched_list; /**< list of scheduled timers */
169
170 #ifdef CALLOUT_STATS
171         struct callout_debug_stats stats; /**< stats */
172 #endif
173 };
174
175 /**
176  * Initialize a callout manager
177  *
178  * The callout manager must be initialized before callout_add() or
179  * callout_manage() can be called.
180  *
181  * @param cm
182  *   Pointer to the uninitialized callout manager structure.
183  * @param get_time
184  *   Pointer to a function that returns a time reference (unsigned 16 bits).
185  */
186 void callout_mgr_init(struct callout_mgr *cm, get_time_t *get_time);
187
188 /**
189  * Initialize a callout structure and set callback function
190  *
191  * Before doing any operation on the callout structure, it has to be initialized
192  * with this function. It is possible to reinitialize a timer that has been
193  * previously scheduled, but it must be stopped.
194  *
195  * @param tim
196  *   The timer to initialize.
197  * @param priority
198  *   The priority of the callout (high value means higher priority)
199  * @param f
200  *   The callback function of the timer.
201  * @param arg
202  *   The user argument of the callback function.
203  */
204 void callout_init(struct callout *tim, callout_cb_t f, void *arg,
205         uint8_t priority);
206
207 /**
208  * Schedule a callout
209  *
210  * The callout_schedule() function adds the timer in the scheduled list. After
211  * the specified amount of ticks are elapsed, the callback function of the timer
212  * previously given to callout_init() will be invoked with its argument.
213  *
214  * The given "tick" value is relative to the current time, and is 16 bits
215  * wide. As it internally uses signed 16 bits comparison, the max value for
216  * ticks is 32767.
217  *
218  * @param cm
219  *   The callout manager where the timer should be scheduled
220  * @param tim
221  *   The timer handle
222  * @param ticks
223  *   The number of ticks before the callback function is called, relative to now
224  *   (the reference is given by the get_time() function of the callout manager).
225  * @return
226  *   0 on success, negative on error
227  */
228 int callout_schedule(struct callout_mgr *cm, struct callout *tim,
229         uint16_t ticks);
230
231 /**
232  * Reschedule a callout
233  *
234  * This function does exactly the same than callout_schedule() except that
235  * the given time "ticks" is not relative to the current time but to the
236  * "expire" field of the timer.
237  *
238  * Using this function is advised to avoid drift if you want to have periodic
239  * timers.
240  *
241  * This function should preferably be called from the callback function of
242  * the timer. Indeed, if the "expire" field should be a known value or it
243  * can result in an undefined behavior
244  *
245  * The given "tick" value is relative to the "expire" field of the timer, and is
246  * 16 bits wide. As it internally uses signed 16 bits comparison, the max value
247  * for ticks is 32767.
248  *
249  * @param cm
250  *   The callout manager where the timer should be scheduled
251  * @param tim
252  *   The timer handle
253  * @param ticks
254  *   The number of ticks before the callback function is called, relative to
255  *   the "expire" value of the timer
256  * @return
257  *   0 on success, negative on error
258  */
259 int callout_reschedule(struct callout_mgr *cm, struct callout *tim,
260         uint16_t ticks);
261
262
263 /**
264  * Stop a timer.
265  *
266  * The callout_stop() function stops a timer associated with the
267  * timer handle tim.
268  *
269  * If the timer is scheduled or expired, it is removed from the list: the
270  * callback function won't be invoked. If the timer is stopped or running the
271  * function does nothing.
272  *
273  * If a timer structure is dynamically allocated, invoking callout_stop() is
274  * needed before freeing the structure, even if the freeing occurs in a
275  * callback. Indeed, this function can be called safely from a timer
276  * callback. If it succeeds, the timer is not referenced anymore by the callout
277  * manager.
278  *
279  * @param cm
280  *   The callout manager where the timer is or was scheduled
281  * @param tim
282  *   The timer
283  * @return
284  *   0 on success, negative on error
285  */
286 void callout_stop(struct callout_mgr *cm, struct callout *tim);
287
288
289 /**
290  * Return the state of a timer
291  *
292  * @param tim
293  *   The timer
294  * @return
295  *   - CALLOUT_STATE_STOPPED: the timer is stopped
296  *   - CALLOUT_STATE_SCHEDULED: the timer is scheduled
297  *   - CALLOUT_STATE_EXPIRED: the timer was moved in a local list before
298  *     execution
299  */
300 static inline uint8_t callout_state(struct callout *tim)
301 {
302         return tim->state;
303 }
304
305 /**
306  * Manage the timer list and execute callback functions.
307  *
308  * This function must be called periodically, either from a loop of from an
309  * interrupt. It browses the list of scheduled timers and runs all timers that
310  * are expired.
311  *
312  * This function must be called at least every 16384 reference ticks of
313  * cm->get_time(), but calling it more often is recommanded to avoid delaying
314  * task abusively.
315  *
316  * The function must be called with IRQ allowed.
317  */
318 void callout_manage(struct callout_mgr *cm);
319
320 /**
321  * Dump statistics about timers.
322  */
323 void callout_dump_stats(struct callout_mgr *cm);
324
325 /**
326  * Set the current priority level
327  *
328  * Prevent callout with a priority lower than "new_prio" to be executed.
329  * If the current priority of the callout manager is already lower higher
330  * than "new_prio", the function won't change the running priority.
331  *
332  * The returned value should be stored by the caller and restored with
333  * callout_mgr_restore_prio(), preferably in the same function.
334  *
335  * @param cm
336  *   The callout manager
337  * @param new_prio
338  *   The new running priority
339  *
340  * @return
341  *   The value of the running priority before the call og this function
342  */
343 uint8_t callout_mgr_set_prio(struct callout_mgr *cm, uint8_t new_prio);
344
345 /**
346  * Restore the current priority level
347  *
348  * Used after a call to callout_mgr_set_prio().
349  *
350  * @param cm
351  *   The callout manager
352  * @param old_prio
353  *   The old running priority
354  */
355 void callout_mgr_restore_prio(struct callout_mgr *cm, uint8_t old_prio);
356
357 #endif /* _CALLOUT_H_ */