2 * Copyright (c) <2014>, Olivier Matz <zer0@droids-corp.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
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.
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.
29 /* Inspired from Intel DPDK rte_timer library */
31 * Copyright (c) <2010>, Intel Corporation
32 * All rights reserved.
34 * Redistribution and use in source and binary forms, with or without
35 * modification, are permitted provided that the following conditions
38 * - Redistributions of source code must retain the above copyright
39 * notice, this list of conditions and the following disclaimer.
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
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.
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.
67 #include <aversive/queue.h>
70 /* #define CALLOUT_DEBUG */
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
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.
83 * The module locks interrupts when doing critical operations, ensuring that
84 * critical data are accessed atomically.
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".
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).
100 #define CALLOUT_MAX_RECURSION 5
104 * The structure that stores the timer statistics, mostly useful for debug
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 */
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 */
125 * The tyoe of a callout callback function.
127 typedef void (callout_cb_t)(struct callout_mgr *cm, struct callout *tim,
131 * A callout structure, storing all data associated to a timer.
134 LIST_ENTRY(callout) next; /**< next/prev in list */
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 */
144 callout_cb_t *f; /**< callback function pointer */
145 void *arg; /**< argument given to the cb function. */
148 /* define the callout list */
149 LIST_HEAD(callout_list, callout);
151 /* static initializer for a timer structure */
152 #define CALLOUT_INITIALIZER { }
155 * Type of the function used by a callout manager to get a time reference
157 typedef uint16_t (get_time_t)(void);
160 * An instance of callout manager. It is possible to have several managers. A
161 * callout is attached to one manager at a time.
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 */
171 struct callout_debug_stats stats; /**< stats */
176 * Initialize a callout manager
178 * The callout manager must be initialized before callout_add() or
179 * callout_manage() can be called.
182 * Pointer to the uninitialized callout manager structure.
184 * Pointer to a function that returns a time reference (unsigned 16 bits).
186 void callout_mgr_init(struct callout_mgr *cm, get_time_t *get_time);
189 * Initialize a callout structure and set callback function
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.
196 * The timer to initialize.
198 * The priority of the callout (high value means higher priority)
200 * The callback function of the timer.
202 * The user argument of the callback function.
204 void callout_init(struct callout *tim, callout_cb_t f, void *arg,
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.
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
219 * The callout manager where the timer should be scheduled
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).
226 * 0 on success, negative on error
228 int callout_schedule(struct callout_mgr *cm, struct callout *tim,
232 * Reschedule a callout
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.
238 * Using this function is advised to avoid drift if you want to have periodic
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
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.
250 * The callout manager where the timer should be scheduled
254 * The number of ticks before the callback function is called, relative to
255 * the "expire" value of the timer
257 * 0 on success, negative on error
259 int callout_reschedule(struct callout_mgr *cm, struct callout *tim,
266 * The callout_stop() function stops a timer associated with the
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.
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
280 * The callout manager where the timer is or was scheduled
284 * 0 on success, negative on error
286 void callout_stop(struct callout_mgr *cm, struct callout *tim);
290 * Return the state of a timer
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
300 static inline uint8_t callout_state(struct callout *tim)
306 * Manage the timer list and execute callback functions.
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
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
316 * The function must be called with IRQ allowed.
318 void callout_manage(struct callout_mgr *cm);
321 * Dump statistics about timers.
323 void callout_dump_stats(struct callout_mgr *cm);
326 * Set the current priority level
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.
332 * The returned value should be stored by the caller and restored with
333 * callout_mgr_restore_prio(), preferably in the same function.
336 * The callout manager
338 * The new running priority
341 * The value of the running priority before the call og this function
343 uint8_t callout_mgr_set_prio(struct callout_mgr *cm, uint8_t new_prio);
346 * Restore the current priority level
348 * Used after a call to callout_mgr_set_prio().
351 * The callout manager
353 * The old running priority
355 void callout_mgr_restore_prio(struct callout_mgr *cm, uint8_t old_prio);
357 #endif /* _CALLOUT_H_ */