TNeoKernel  v1.02
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
tn_timer.h
Go to the documentation of this file.
1 /*******************************************************************************
2  *
3  * TNeoKernel: real-time kernel initially based on TNKernel
4  *
5  * TNKernel: copyright © 2004, 2013 Yuri Tiomkin.
6  * PIC32-specific routines: copyright © 2013, 2014 Anders Montonen.
7  * TNeoKernel: copyright © 2014 Dmitry Frank.
8  *
9  * TNeoKernel was born as a thorough review and re-implementation of
10  * TNKernel. The new kernel has well-formed code, inherited bugs are fixed
11  * as well as new features being added, and it is tested carefully with
12  * unit-tests.
13  *
14  * API is changed somewhat, so it's not 100% compatible with TNKernel,
15  * hence the new name: TNeoKernel.
16  *
17  * Permission to use, copy, modify, and distribute this software in source
18  * and binary forms and its documentation for any purpose and without fee
19  * is hereby granted, provided that the above copyright notice appear
20  * in all copies and that both that copyright notice and this permission
21  * notice appear in supporting documentation.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE DMITRY FRANK AND CONTRIBUTORS "AS IS"
24  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DMITRY FRANK OR CONTRIBUTORS BE
27  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
33  * THE POSSIBILITY OF SUCH DAMAGE.
34  *
35  ******************************************************************************/
36 
37 /**
38  * \file
39  *
40  * Timer is a kernel object that is used to ask the kernel to call some
41  * user-provided function at a particular time in the future, based on the
42  * $(TN_SYS_TIMER_LINK) tick.
43  *
44  * If you need to repeatedly wake up particular task, you can create semaphore
45  * which you should \ref tn_sem_wait() "wait for" in the task, and \ref
46  * tn_sem_isignal() "signal" in the timer callback (remember that you should
47  * use `tn_sem_isignal()` in this callback, since it is called from an ISR).
48  *
49  * If you need to perform rather fast action (such as toggle some pin, or the
50  * like), consider doing that right in the timer callback, in order to avoid
51  * context switch overhead.
52  *
53  * The timer callback approach provides ultimate flexibility.
54  *
55  * In the spirit of TNeoKernel, timers are as lightweight as possible. That's
56  * why there is only one type of timer: the single-shot timer. If you need your
57  * timer to fire repeatedly, you can easily restart it from the timer function
58  * by the `tn_timer_start()`, so it's not a problem.
59  *
60  * When timer fires, the user-provided function is called. Be aware of the
61  * following:
62  *
63  * - Function is called from an ISR context (namely, from $(TN_SYS_TIMER_LINK)
64  * ISR, by the `tn_tick_int_processing()`);
65  * - Function is called with global interrupts disabled.
66  *
67  * Consequently:
68  *
69  * - It's legal to call interrupt services from this function;
70  * - You should make sure that your interrupt stack is enough for this
71  * function;
72  * - The function should be as fast as possible;
73  * - The function should not enable interrupts unconditionally. Consider using
74  * `tn_arch_sr_save_int_dis()` and `tn_arch_sr_restore()` if you need.
75  *
76  * See `#TN_TimerFunc` for the prototype of the function that could be
77  * scheduled.
78  *
79  * \section timers_implementation Implementation of timers
80  *
81  * Although you don't have to understand the implementation of timers to use
82  * them, it is probably worth knowing, particularly because the kernel have an
83  * option `#TN_TICK_LISTS_CNT` to customize the balance between performance of
84  * `tn_tick_int_processing()` and memory occupied by timers.
85  *
86  * The easiest implementation of timers could be something like this: we
87  * have just a single list with all active timers, and at every system tick
88  * we should walk through all the timers in this list, and do the following
89  * with each timer:
90  *
91  * - Decrement timeout by 1
92  * - If new timeout is 0, then remove that timer from the list (i.e. make timer
93  * inactive), and fire the appropriate timer function.
94  *
95  * This approach has drawbacks:
96  *
97  * - We can't manage timers from the function called by timer. If we do so
98  * (say, if we start new timer), then the timer list gets modified. But we
99  * are currently iterating through this list, so, it's quite easy to mix
100  * things up.
101  * - It is inefficient on rather large amount of timers and/or with large
102  * timeouts: we should iterate through all of them each system tick.
103  *
104  * The latter is probably not so critical in the embedded world since large
105  * amount of timers is unlikely there; whereas the former is actually notable.
106  *
107  * So, different approach was applied. The main idea is taken from the mainline
108  * Linux kernel source, but the implementation was simplified much because (1)
109  * embedded systems have much less resources, and (2) the kernel doesn't need
110  * to scale as well as Linux does. You can read about Linux timers
111  * implementation in the book "Linux Device Drivers", 3rd edition:
112  *
113  * - Time, Delays, and Deferred Work
114  * - Kernel Timers
115  * - The Implementation of Kernel Timers
116  *
117  * This book is freely available at http://lwn.net/Kernel/LDD3/ .
118  *
119  * So, TNeoKernel's implementation:
120  *
121  * We have configurable value `N` that is a power of two, typical values are
122  * `4`, `8` or `16`.
123  *
124  * If the timer expires in the next `1` to `(N - 1)` system ticks, it is added
125  * to one of the `N` lists (the so-called "tick" lists) devoted to short-range
126  * timers using the least significant bits of the `timeout` value. If it
127  * expires farther in the future, it is added to the "generic" list.
128  *
129  * Each `N`-th system tick, all the timers from "generic" list are walked
130  * through, and the following is performed with each timer:
131  *
132  * - `timeout` value decremented by `N`
133  * - if resulting `timeout` is less than `N`, timer is moved to the appropriate
134  * "tick" list.
135  *
136  * At *every* system tick, all the timers from current "tick" list are fired
137  * unconditionally. This is an efficient and nice solution.
138  *
139  * The attentive reader may want to ask why do we use `(N - 1)` "tick" lists if
140  * we actually have `N` lists. That's because, again, we want to be able to
141  * modify timers from the timer function. If we use `N` lists, and user wants
142  * to add new timer with `timeout` equal to `N`, then new timer will be added
143  * to the same list which is iterated through at the moment, and things will be
144  * mixed up.
145  *
146  * If we use `(N - 1)` lists, we are guaranteed that new timers can't be added
147  * to the current "tick" list while we are iterating through it.
148  * (although timer can be deleted from that list, but it's ok)
149  *
150  * The `N` in the TNeoKernel is configured by the compile-time option
151  * `#TN_TICK_LISTS_CNT`.
152  */
153 
154 
155 #ifndef _TN_TIMER_H
156 #define _TN_TIMER_H
157 
158 /*******************************************************************************
159  * INCLUDED FILES
160  ******************************************************************************/
161 
162 #include "tn_list.h"
163 #include "tn_common.h"
164 
165 
166 
167 #ifdef __cplusplus
168 extern "C" { /*}*/
169 #endif
170 
171 /*******************************************************************************
172  * PUBLIC TYPES
173  ******************************************************************************/
174 
175 struct TN_Timer;
176 
177 
178 /**
179  * Prototype of the function that should be called by timer.
180  *
181  * When timer fires, the user-provided function is called. Be aware of the
182  * following:
183  * - Function is called from ISR context (namely, from $(TN_SYS_TIMER_LINK)
184  * ISR, by the `tn_tick_int_processing()`);
185  * - Function is called with global interrupts disabled.
186  *
187  * Consequently:
188  *
189  * - It's legal to call interrupt services from this function;
190  * - The function should be as fast as possible.
191  *
192  * @param timer
193  * Timer that caused function to be called
194  * @param p_user_data
195  * The user-provided pointer given to `tn_timer_create()`.
196  */
197 typedef void (TN_TimerFunc)(struct TN_Timer *timer, void *p_user_data);
198 
199 /**
200  * Timer
201  */
202 struct TN_Timer {
203  ///
204  /// A list item to be included in the $(TN_SYS_TIMER_LINK) queue
205  struct TN_ListItem timer_queue;
206  ///
207  /// Function to be called by timer
209  ///
210  /// User data pointer that is given to user-provided `func`.
211  void *p_user_data;
212  ///
213  /// Current (left) timeout value
215  ///
216  /// id for object validity verification
218 };
219 
220 
221 /*******************************************************************************
222  * GLOBAL VARIABLES
223  ******************************************************************************/
224 
225 /*******************************************************************************
226  * DEFINITIONS
227  ******************************************************************************/
228 
229 /*******************************************************************************
230  * PUBLIC FUNCTION PROTOTYPES
231  ******************************************************************************/
232 
233 /**
234  * Construct the timer. `id_timer` field should not contain
235  * `#TN_ID_TIMER`, otherwise, `#TN_RC_WPARAM` is returned.
236  *
237  * $(TN_CALL_FROM_TASK)
238  * $(TN_CALL_FROM_ISR)
239  * $(TN_LEGEND_LINK)
240  *
241  * @param timer
242  * Pointer to already allocated `struct TN_Timer`
243  * @param func
244  * Function to be called by timer, can't be `NULL`. See `TN_TimerFunc()`
245  * @param p_user_data
246  * User data pointer that is given to user-provided `func`.
247  *
248  * @return
249  * * `#TN_RC_OK` if timer was successfully created;
250  * * `#TN_RC_WPARAM` if wrong params were given.
251  */
253  struct TN_Timer *timer,
254  TN_TimerFunc *func,
255  void *p_user_data
256  );
257 
258 /**
259  * Destruct the timer. If the timer is active, it is cancelled first.
260  *
261  * $(TN_CALL_FROM_TASK)
262  * $(TN_CALL_FROM_ISR)
263  * $(TN_LEGEND_LINK)
264  *
265  * @param timer timer to destruct
266  *
267  * @return
268  * * `#TN_RC_OK` if timer was successfully deleted;
269  * * `#TN_RC_WCONTEXT` if called from wrong context;
270  * * If `#TN_CHECK_PARAM` is non-zero, additional return codes
271  * are available: `#TN_RC_WPARAM` and `#TN_RC_INVALID_OBJ`.
272  */
273 enum TN_RCode tn_timer_delete(struct TN_Timer *timer);
274 
275 /**
276  * Start or restart the timer: that is, schedule the timer's function (given to
277  * `tn_timer_create()`) to be called later by the kernel. See `TN_TimerFunc()`.
278  *
279  * It is legal to restart already active timer. In this case, the timer will be
280  * cancelled first.
281  *
282  * $(TN_CALL_FROM_TASK)
283  * $(TN_CALL_FROM_ISR)
284  * $(TN_LEGEND_LINK)
285  *
286  * @param timer
287  * Timer to start
288  * @param timeout
289  * Number of system ticks after which timer should fire (i.e. function
290  * should be called). **Note** that `timeout` can't be `#TN_WAIT_INFINITE` or
291  * `0`.
292  *
293  * @return
294  * * `#TN_RC_OK` if timer was successfully started;
295  * * `#TN_RC_WCONTEXT` if called from wrong context;
296  * * `#TN_RC_WPARAM` if wrong params were given: say, `timeout` is either
297  * `#TN_WAIT_INFINITE` or `0`.
298  * * If `#TN_CHECK_PARAM` is non-zero, additional return code
299  * is available: `#TN_RC_INVALID_OBJ`.
300  */
301 enum TN_RCode tn_timer_start(struct TN_Timer *timer, TN_Timeout timeout);
302 
303 /**
304  * If timer is active, cancel it. If timer is already inactive, nothing is
305  * changed.
306  *
307  * $(TN_CALL_FROM_TASK)
308  * $(TN_CALL_FROM_ISR)
309  * $(TN_LEGEND_LINK)
310  *
311  * @param timer
312  * Timer to cancel
313  *
314  * @return
315  * * `#TN_RC_OK` if timer was successfully cancelled;
316  * * `#TN_RC_WCONTEXT` if called from wrong context;
317  * * If `#TN_CHECK_PARAM` is non-zero, additional return codes
318  * are available: `#TN_RC_WPARAM` and `#TN_RC_INVALID_OBJ`.
319  */
320 enum TN_RCode tn_timer_cancel(struct TN_Timer *timer);
321 
322 /**
323  * Set user-provided function and pointer to user data for the timer.
324  * Can be called if timer is either active or inactive.
325  *
326  * $(TN_CALL_FROM_TASK)
327  * $(TN_CALL_FROM_ISR)
328  * $(TN_LEGEND_LINK)
329  *
330  * @param timer
331  * Pointer to timer
332  * @param func
333  * Function to be called by timer, can't be `NULL`. See `TN_TimerFunc()`
334  * @param p_user_data
335  * User data pointer that is given to user-provided `func`.
336  *
337  * @return
338  * * `#TN_RC_OK` if operation was successfull;
339  * * `#TN_RC_WPARAM` if wrong params were given.
340  */
342  struct TN_Timer *timer,
343  TN_TimerFunc *func,
344  void *p_user_data
345  );
346 
347 /**
348  * Returns whether given timer is active or inactive.
349  *
350  * $(TN_CALL_FROM_TASK)
351  * $(TN_CALL_FROM_ISR)
352  * $(TN_LEGEND_LINK)
353  *
354  * @param timer
355  * Pointer to timer
356  * @param p_is_active
357  * Pointer to `#BOOL` variable in which resulting value should be stored
358  *
359  * @return
360  * * `#TN_RC_OK` if operation was successfull;
361  * * `#TN_RC_WPARAM` if wrong params were given.
362  */
363 enum TN_RCode tn_timer_is_active(struct TN_Timer *timer, BOOL *p_is_active);
364 
365 /**
366  * Returns how many $(TN_SYS_TIMER_LINK) ticks (at most) is left for the timer
367  * to expire. If timer is inactive, 0 is returned.
368  *
369  * $(TN_CALL_FROM_TASK)
370  * $(TN_CALL_FROM_ISR)
371  * $(TN_LEGEND_LINK)
372  *
373  * @param timer
374  * Pointer to timer
375  * @param p_time_left
376  * Pointer to `#TN_Timeout` variable in which resulting value should be
377  * stored
378  *
379  * @return
380  * * `#TN_RC_OK` if operation was successfull;
381  * * `#TN_RC_WPARAM` if wrong params were given.
382  */
384  struct TN_Timer *timer,
385  TN_Timeout *p_time_left
386  );
387 
388 #ifdef __cplusplus
389 } /* extern "C" */
390 #endif
391 
392 #endif // _TN_TIMER_H
393 
394 /*******************************************************************************
395  * end of file
396  ******************************************************************************/
397 
398 
enum TN_RCode tn_timer_cancel(struct TN_Timer *timer)
If timer is active, cancel it.
enum TN_RCode tn_timer_create(struct TN_Timer *timer, TN_TimerFunc *func, void *p_user_data)
Construct the timer.
struct TN_ListItem timer_queue
A list item to be included in the system timer queue.
Definition: tn_timer.h:205
enum TN_RCode tn_timer_is_active(struct TN_Timer *timer, BOOL *p_is_active)
Returns whether given timer is active or inactive.
enum TN_RCode tn_timer_delete(struct TN_Timer *timer)
Destruct the timer.
enum TN_RCode tn_timer_time_left(struct TN_Timer *timer, TN_Timeout *p_time_left)
Returns how many system timer ticks (at most) is left for the timer to expire.
#define BOOL
boolean type definition
Definition: tn_common.h:222
TN_RCode
Result code returned by kernel services.
Definition: tn_common.h:100
TN_ObjId
Magic number for object validity verification.
Definition: tn_common.h:87
unsigned long TN_Timeout
The value representing maximum number of system ticks to wait.
Definition: tn_common.h:203
enum TN_RCode tn_timer_set_func(struct TN_Timer *timer, TN_TimerFunc *func, void *p_user_data)
Set user-provided function and pointer to user data for the timer.
Definitions used through the whole kernel.
enum TN_ObjId id_timer
id for object validity verification
Definition: tn_timer.h:217
Timer.
Definition: tn_timer.h:202
TN_Timeout timeout_cur
Current (left) timeout value.
Definition: tn_timer.h:214
TN_TimerFunc * func
Function to be called by timer.
Definition: tn_timer.h:208
void * p_user_data
User data pointer that is given to user-provided func.
Definition: tn_timer.h:211
void( TN_TimerFunc)(struct TN_Timer *timer, void *p_user_data)
Prototype of the function that should be called by timer.
Definition: tn_timer.h:197
enum TN_RCode tn_timer_start(struct TN_Timer *timer, TN_Timeout timeout)
Start or restart the timer: that is, schedule the timer's function (given to tn_timer_create()) to be...