initial revision
[ucgine.git] / lib / callout / include / ucg_callout.h
1 /*
2  * Copyright (c) <2014-2015>, 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 UCG_CALLOUT_H_
65 #define UCG_CALLOUT_H_
66
67 #include <sys/queue.h>
68
69 #define UCG_CALLOUT_STATS
70 /* #define UCG_CALLOUT_DEBUG */
71
72 /**
73  * This module provides a timer service. The manager function
74  * ucg_callout_manage() can be called from an interrupt or from a
75  * standard function (usually a main-loop). In the latter case, no
76  * preemption is possible.
77  *
78  * Each timer has a priority: the timers with higher priorities are
79  * scheduled before the others. This feature is mostly useful when the
80  * manager is called from an interrupt. Indeed, the callback function of
81  * a timer with a high priority cannot be preempted by a timer with a
82  * lower priority.
83  *
84  * The module locks interrupts when doing critical operations, ensuring that
85  * critical data are accessed atomically.
86  *
87  * State of timers:
88  * - stopped: initial state after ucg_callout_init()
89  * - scheduled: after a call to ucg_callout_schedule(), the timer is in the
90  *   scheduled list of the callout manager
91  * - expired: after a call to ucg_callout_manage(), if the expire time of a
92  *   timer is reached, it is moved in a local list and its state is
93  *   changed to "expired".
94  * - before starting the callback, the timer goes in state "running".
95  *
96  * Once running, the associated timer is not touched anymore by
97  * ucg_callout_manage(). As a result, the timer MUST be either reloaded
98  * or stopped (and potentially freed).
99  */
100
101 /**
102  * Maximum number of nested preemptions.
103  */
104 #define UCG_CALLOUT_MAX_RECURSION 5
105
106 #ifdef UCG_CALLOUT_STATS
107 /**
108  * The structure that stores the timer statistics, mostly useful for debug
109  * purposes.
110  */
111 struct ucg_callout_debug_stats {
112         uint32_t schedule;      /**< nb of calls to ucg_callout_(re)schedule() */
113         uint32_t stop;          /**< nb of calls to ucg_callout_stop() */
114         uint32_t manage;        /**< nb of calls to ucg_callout_manage() */
115         uint32_t max_recursion; /** manage() skipped due to max recursion */
116         uint32_t delayed;       /** task delayed a bit due to low prio */
117         uint32_t hard_delayed;  /** task recheduled later due to low priority */
118
119         uint8_t cur_scheduled;  /**< current number of scheduled timers */
120         uint8_t cur_expired;    /**< current number of expired timers */
121         uint8_t cur_running;    /**< current number of running timers */
122 };
123 #endif
124
125 struct ucg_callout;
126 struct ucg_callout_mgr;
127
128 /**
129  * The type of a callout callback function.
130  */
131 typedef void (ucg_callout_cb_t)(struct ucg_callout_mgr *cm,
132         struct ucg_callout *tim, void *arg);
133
134 /**
135  * A callout structure, storing all data associated to a timer.
136  */
137 struct ucg_callout {
138         LIST_ENTRY(ucg_callout) next; /**< next/prev in list */
139
140 #define UCG_CALLOUT_STATE_STOPPED    0 /**< not scheduled */
141 #define UCG_CALLOUT_STATE_SCHEDULED  1 /**< in the scheduled list */
142 #define UCG_CALLOUT_STATE_EXPIRED    2 /**< expired, will be executed soon */
143 #define UCG_CALLOUT_STATE_RUNNING    3 /**< being executed */
144         uint8_t state;             /**< stopped, scheduled, expired */
145         uint8_t priority;          /**< the priority of the timer */
146         uint16_t expire;           /**< time when timer should expire */
147
148         ucg_callout_cb_t *f;       /**< callback function pointer */
149         void *arg;                 /**< argument given to the cb function. */
150 };
151
152 /* define the callout list */
153 LIST_HEAD(ucg_callout_list, ucg_callout);
154
155 /* static initializer for a timer structure */
156 #define UCG_CALLOUT_INITIALIZER { }
157
158 /**
159  * Type of the function used by a callout manager to get a time reference
160  */
161 typedef uint16_t (ucg_callout_get_time_t)(void);
162
163 /**
164  * An instance of callout manager. It is possible to have several
165  * managers. A callout is attached to one manager at a time.
166  */
167 struct ucg_callout_mgr {
168         ucg_callout_get_time_t *get_time; /**< func to get the time reference */
169         uint16_t prev_time;   /**< time of previous call */
170         uint8_t cur_priority; /** priority of running event */
171         uint8_t nb_recursion; /** number of recursion */
172         struct ucg_callout_list sched_list; /**< list of scheduled timers */
173
174 #ifdef UCG_CALLOUT_STATS
175         struct ucg_callout_debug_stats stats; /**< stats */
176 #endif
177 };
178
179 /**
180  * Initialize a callout manager
181  *
182  * The callout manager must be initialized before ucg_callout_add() or
183  * ucg_callout_manage() can be called.
184  *
185  * @param cm
186  *   Pointer to the uninitialized callout manager structure.
187  * @param get_time
188  *   Pointer to a function that returns a time reference (unsigned 16 bits).
189  */
190 void ucg_callout_mgr_init(struct ucg_callout_mgr *cm,
191         ucg_callout_get_time_t *get_time);
192
193 /**
194  * Initialize a callout structure and set callback function
195  *
196  * Before doing any operation on the callout structure, it has to be
197  * initialized with this function. It is possible to reinitialize a
198  * timer that has been previously scheduled, but it must be stopped.
199  *
200  * @param tim
201  *   The timer to initialize.
202  * @param priority
203  *   The priority of the callout (high value means higher priority)
204  * @param f
205  *   The callback function of the timer.
206  * @param arg
207  *   The user argument of the callback function.
208  */
209 void ucg_callout_init(struct ucg_callout *tim, ucg_callout_cb_t f, void *arg,
210         uint8_t priority);
211
212 /**
213  * Schedule a callout
214  *
215  * The ucg_callout_schedule() function adds the timer in the scheduled
216  * list. After the specified amount of ticks are elapsed, the callback
217  * function of the timer previously given to ucg_callout_init() will be
218  * invoked with its argument.
219  *
220  * The given "tick" value is relative to the current time, and is 16 bits
221  * wide. As it internally uses signed 16 bits comparison, the max value for
222  * ticks is 32767.
223  *
224  * @param cm
225  *   The callout manager where the timer should be scheduled
226  * @param tim
227  *   The timer handle
228  * @param ticks
229  *   The number of ticks before the callback function is called, relative to now
230  *   (the reference is given by the get_time() function of the callout manager).
231  * @return
232  *   0 on success, negative on error
233  */
234 int ucg_callout_schedule(struct ucg_callout_mgr *cm, struct ucg_callout *tim,
235         uint16_t ticks);
236
237 /**
238  * Reschedule a callout
239  *
240  * This function does exactly the same than ucg_callout_schedule()
241  * except that the given time "ticks" is not relative to the current
242  * time but to the "expire" field of the timer.
243  *
244  * Using this function is advised to avoid drift if you want to have periodic
245  * timers.
246  *
247  * This function should preferably be called from the callback function of
248  * the timer. Indeed, if the "expire" field should be a known value or it
249  * can result in an undefined behavior
250  *
251  * The given "tick" value is relative to the "expire" field of the
252  * timer, and is 16 bits wide. As it internally uses signed 16 bits
253  * comparison, the max value for ticks is 32767.
254  *
255  * @param cm
256  *   The callout manager where the timer should be scheduled
257  * @param tim
258  *   The timer handle
259  * @param ticks
260  *   The number of ticks before the callback function is called, relative to
261  *   the "expire" value of the timer
262  * @return
263  *   0 on success, negative on error
264  */
265 int ucg_callout_reschedule(struct ucg_callout_mgr *cm, struct ucg_callout *tim,
266         uint16_t ticks);
267
268 /**
269  * Stop a timer.
270  *
271  * The ucg_callout_stop() function stops a timer associated with the
272  * timer handle tim.
273  *
274  * If the timer is scheduled or expired, it is removed from the list:
275  * the callback function won't be invoked. If the timer is stopped or
276  * running the function does nothing.
277  *
278  * If a timer structure is dynamically allocated, invoking
279  * ucg_callout_stop() is needed before freeing the structure, even if
280  * the freeing occurs in a callback. Indeed, this function can be called
281  * safely from a timer callback. If it succeeds, the timer is not
282  * referenced anymore by the callout manager.
283  *
284  * @param cm
285  *   The callout manager where the timer is or was scheduled
286  * @param tim
287  *   The timer
288  * @return
289  *   0 on success, negative on error
290  */
291 void ucg_callout_stop(struct ucg_callout_mgr *cm, struct ucg_callout *tim);
292
293 /**
294  * Return the state of a timer
295  *
296  * @param tim
297  *   The timer
298  * @return
299  *   - UCG_CALLOUT_STATE_STOPPED: the timer is stopped
300  *   - UCG_CALLOUT_STATE_SCHEDULED: the timer is scheduled
301  *   - UCG_CALLOUT_STATE_EXPIRED: the timer was moved in a local list before
302  *     execution
303  */
304 static inline uint8_t ucg_callout_state(struct ucg_callout *tim)
305 {
306         return tim->state;
307 }
308
309 /**
310  * Manage the timer list and execute callback functions.
311  *
312  * This function must be called periodically, either from a loop of from
313  * an interrupt. It browses the list of scheduled timers and runs all
314  * timers that are expired.
315  *
316  * This function must be called at least every 16384 reference ticks of
317  * cm->get_time(), but calling it more often is recommanded to avoid
318  * delaying task abusively.
319  *
320  * The function must be called with IRQ allowed.
321  */
322 void ucg_callout_manage(struct ucg_callout_mgr *cm);
323
324 /**
325  * Dump statistics about timers.
326  */
327 void ucg_callout_dump_stats(struct ucg_callout_mgr *cm);
328
329 /**
330  * Set the current priority level
331  *
332  * Prevent callout with a priority lower than "new_prio" to be executed.
333  * If the current priority of the callout manager is already lower higher
334  * than "new_prio", the function won't change the running priority.
335  *
336  * The returned value should be stored by the caller and restored with
337  * ucg_callout_mgr_restore_prio(), preferably in the same function.
338  *
339  * @param cm
340  *   The callout manager
341  * @param new_prio
342  *   The new running priority
343  *
344  * @return
345  *   The value of the running priority before the call og this function
346  */
347 uint8_t ucg_callout_mgr_set_prio(struct ucg_callout_mgr *cm, uint8_t new_prio);
348
349 /**
350  * Restore the current priority level
351  *
352  * Used after a call to ucg_callout_mgr_set_prio().
353  *
354  * @param cm
355  *   The callout manager
356  * @param old_prio
357  *   The old running priority
358  */
359 void ucg_callout_mgr_restore_prio(struct ucg_callout_mgr *cm, uint8_t old_prio);
360
361 #endif /* UCG_CALLOUT_H_ */