]> begriffs open source - freertos/blob - timers.c
Do not call exit() on MSVC Port when calling vPortEndScheduler (#624)
[freertos] / timers.c
1 /*
2  * FreeRTOS Kernel <DEVELOPMENT BRANCH>
3  * Copyright (C) 2021 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
4  *
5  * SPDX-License-Identifier: MIT
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy of
8  * this software and associated documentation files (the "Software"), to deal in
9  * the Software without restriction, including without limitation the rights to
10  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11  * the Software, and to permit persons to whom the Software is furnished to do so,
12  * subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in all
15  * copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  *
24  * https://www.FreeRTOS.org
25  * https://github.com/FreeRTOS
26  *
27  */
28
29 /* Standard includes. */
30 #include <stdlib.h>
31
32 /* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
33  * all the API functions to use the MPU wrappers.  That should only be done when
34  * task.h is included from an application file. */
35 #define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
36
37 #include "FreeRTOS.h"
38 #include "task.h"
39 #include "queue.h"
40 #include "timers.h"
41
42 #if ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 0 )
43     #error configUSE_TIMERS must be set to 1 to make the xTimerPendFunctionCall() function available.
44 #endif
45
46 /* Lint e9021, e961 and e750 are suppressed as a MISRA exception justified
47  * because the MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined
48  * for the header files above, but not in this file, in order to generate the
49  * correct privileged Vs unprivileged linkage and placement. */
50 #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e9021 !e961 !e750. */
51
52
53 /* This entire source file will be skipped if the application is not configured
54  * to include software timer functionality.  This #if is closed at the very bottom
55  * of this file.  If you want to include software timer functionality then ensure
56  * configUSE_TIMERS is set to 1 in FreeRTOSConfig.h. */
57 #if ( configUSE_TIMERS == 1 )
58
59 /* Misc definitions. */
60     #define tmrNO_DELAY                    ( ( TickType_t ) 0U )
61     #define tmrMAX_TIME_BEFORE_OVERFLOW    ( ( TickType_t ) -1 )
62
63 /* The name assigned to the timer service task.  This can be overridden by
64  * defining trmTIMER_SERVICE_TASK_NAME in FreeRTOSConfig.h. */
65     #ifndef configTIMER_SERVICE_TASK_NAME
66         #define configTIMER_SERVICE_TASK_NAME    "Tmr Svc"
67     #endif
68
69 /* Bit definitions used in the ucStatus member of a timer structure. */
70     #define tmrSTATUS_IS_ACTIVE                  ( ( uint8_t ) 0x01 )
71     #define tmrSTATUS_IS_STATICALLY_ALLOCATED    ( ( uint8_t ) 0x02 )
72     #define tmrSTATUS_IS_AUTORELOAD              ( ( uint8_t ) 0x04 )
73
74 /* The definition of the timers themselves. */
75     typedef struct tmrTimerControl                  /* The old naming convention is used to prevent breaking kernel aware debuggers. */
76     {
77         const char * pcTimerName;                   /*<< Text name.  This is not used by the kernel, it is included simply to make debugging easier. */ /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
78         ListItem_t xTimerListItem;                  /*<< Standard linked list item as used by all kernel features for event management. */
79         TickType_t xTimerPeriodInTicks;             /*<< How quickly and often the timer expires. */
80         void * pvTimerID;                           /*<< An ID to identify the timer.  This allows the timer to be identified when the same callback is used for multiple timers. */
81         TimerCallbackFunction_t pxCallbackFunction; /*<< The function that will be called when the timer expires. */
82         #if ( configUSE_TRACE_FACILITY == 1 )
83             UBaseType_t uxTimerNumber;              /*<< An ID assigned by trace tools such as FreeRTOS+Trace */
84         #endif
85         uint8_t ucStatus;                           /*<< Holds bits to say if the timer was statically allocated or not, and if it is active or not. */
86     } xTIMER;
87
88 /* The old xTIMER name is maintained above then typedefed to the new Timer_t
89  * name below to enable the use of older kernel aware debuggers. */
90     typedef xTIMER Timer_t;
91
92 /* The definition of messages that can be sent and received on the timer queue.
93  * Two types of message can be queued - messages that manipulate a software timer,
94  * and messages that request the execution of a non-timer related callback.  The
95  * two message types are defined in two separate structures, xTimerParametersType
96  * and xCallbackParametersType respectively. */
97     typedef struct tmrTimerParameters
98     {
99         TickType_t xMessageValue; /*<< An optional value used by a subset of commands, for example, when changing the period of a timer. */
100         Timer_t * pxTimer;        /*<< The timer to which the command will be applied. */
101     } TimerParameter_t;
102
103
104     typedef struct tmrCallbackParameters
105     {
106         PendedFunction_t pxCallbackFunction; /* << The callback function to execute. */
107         void * pvParameter1;                 /* << The value that will be used as the callback functions first parameter. */
108         uint32_t ulParameter2;               /* << The value that will be used as the callback functions second parameter. */
109     } CallbackParameters_t;
110
111 /* The structure that contains the two message types, along with an identifier
112  * that is used to determine which message type is valid. */
113     typedef struct tmrTimerQueueMessage
114     {
115         BaseType_t xMessageID; /*<< The command being sent to the timer service task. */
116         union
117         {
118             TimerParameter_t xTimerParameters;
119
120             /* Don't include xCallbackParameters if it is not going to be used as
121              * it makes the structure (and therefore the timer queue) larger. */
122             #if ( INCLUDE_xTimerPendFunctionCall == 1 )
123                 CallbackParameters_t xCallbackParameters;
124             #endif /* INCLUDE_xTimerPendFunctionCall */
125         } u;
126     } DaemonTaskMessage_t;
127
128 /*lint -save -e956 A manual analysis and inspection has been used to determine
129  * which static variables must be declared volatile. */
130
131 /* The list in which active timers are stored.  Timers are referenced in expire
132  * time order, with the nearest expiry time at the front of the list.  Only the
133  * timer service task is allowed to access these lists.
134  * xActiveTimerList1 and xActiveTimerList2 could be at function scope but that
135  * breaks some kernel aware debuggers, and debuggers that reply on removing the
136  * static qualifier. */
137     PRIVILEGED_DATA static List_t xActiveTimerList1;
138     PRIVILEGED_DATA static List_t xActiveTimerList2;
139     PRIVILEGED_DATA static List_t * pxCurrentTimerList;
140     PRIVILEGED_DATA static List_t * pxOverflowTimerList;
141
142 /* A queue that is used to send commands to the timer service task. */
143     PRIVILEGED_DATA static QueueHandle_t xTimerQueue = NULL;
144     PRIVILEGED_DATA static TaskHandle_t xTimerTaskHandle = NULL;
145
146 /*lint -restore */
147
148 /*-----------------------------------------------------------*/
149
150 /*
151  * Initialise the infrastructure used by the timer service task if it has not
152  * been initialised already.
153  */
154     static void prvCheckForValidListAndQueue( void ) PRIVILEGED_FUNCTION;
155
156 /*
157  * The timer service task (daemon).  Timer functionality is controlled by this
158  * task.  Other tasks communicate with the timer service task using the
159  * xTimerQueue queue.
160  */
161     static portTASK_FUNCTION_PROTO( prvTimerTask, pvParameters ) PRIVILEGED_FUNCTION;
162
163 /*
164  * Called by the timer service task to interpret and process a command it
165  * received on the timer queue.
166  */
167     static void prvProcessReceivedCommands( void ) PRIVILEGED_FUNCTION;
168
169 /*
170  * Insert the timer into either xActiveTimerList1, or xActiveTimerList2,
171  * depending on if the expire time causes a timer counter overflow.
172  */
173     static BaseType_t prvInsertTimerInActiveList( Timer_t * const pxTimer,
174                                                   const TickType_t xNextExpiryTime,
175                                                   const TickType_t xTimeNow,
176                                                   const TickType_t xCommandTime ) PRIVILEGED_FUNCTION;
177
178 /*
179  * Reload the specified auto-reload timer.  If the reloading is backlogged,
180  * clear the backlog, calling the callback for each additional reload.  When
181  * this function returns, the next expiry time is after xTimeNow.
182  */
183     static void prvReloadTimer( Timer_t * const pxTimer,
184                                 TickType_t xExpiredTime,
185                                 const TickType_t xTimeNow ) PRIVILEGED_FUNCTION;
186
187 /*
188  * An active timer has reached its expire time.  Reload the timer if it is an
189  * auto-reload timer, then call its callback.
190  */
191     static void prvProcessExpiredTimer( const TickType_t xNextExpireTime,
192                                         const TickType_t xTimeNow ) PRIVILEGED_FUNCTION;
193
194 /*
195  * The tick count has overflowed.  Switch the timer lists after ensuring the
196  * current timer list does not still reference some timers.
197  */
198     static void prvSwitchTimerLists( void ) PRIVILEGED_FUNCTION;
199
200 /*
201  * Obtain the current tick count, setting *pxTimerListsWereSwitched to pdTRUE
202  * if a tick count overflow occurred since prvSampleTimeNow() was last called.
203  */
204     static TickType_t prvSampleTimeNow( BaseType_t * const pxTimerListsWereSwitched ) PRIVILEGED_FUNCTION;
205
206 /*
207  * If the timer list contains any active timers then return the expire time of
208  * the timer that will expire first and set *pxListWasEmpty to false.  If the
209  * timer list does not contain any timers then return 0 and set *pxListWasEmpty
210  * to pdTRUE.
211  */
212     static TickType_t prvGetNextExpireTime( BaseType_t * const pxListWasEmpty ) PRIVILEGED_FUNCTION;
213
214 /*
215  * If a timer has expired, process it.  Otherwise, block the timer service task
216  * until either a timer does expire or a command is received.
217  */
218     static void prvProcessTimerOrBlockTask( const TickType_t xNextExpireTime,
219                                             BaseType_t xListWasEmpty ) PRIVILEGED_FUNCTION;
220
221 /*
222  * Called after a Timer_t structure has been allocated either statically or
223  * dynamically to fill in the structure's members.
224  */
225     static void prvInitialiseNewTimer( const char * const pcTimerName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
226                                        const TickType_t xTimerPeriodInTicks,
227                                        const BaseType_t xAutoReload,
228                                        void * const pvTimerID,
229                                        TimerCallbackFunction_t pxCallbackFunction,
230                                        Timer_t * pxNewTimer ) PRIVILEGED_FUNCTION;
231 /*-----------------------------------------------------------*/
232
233     BaseType_t xTimerCreateTimerTask( void )
234     {
235         BaseType_t xReturn = pdFAIL;
236
237         /* This function is called when the scheduler is started if
238          * configUSE_TIMERS is set to 1.  Check that the infrastructure used by the
239          * timer service task has been created/initialised.  If timers have already
240          * been created then the initialisation will already have been performed. */
241         prvCheckForValidListAndQueue();
242
243         if( xTimerQueue != NULL )
244         {
245             #if ( configSUPPORT_STATIC_ALLOCATION == 1 )
246             {
247                 StaticTask_t * pxTimerTaskTCBBuffer = NULL;
248                 StackType_t * pxTimerTaskStackBuffer = NULL;
249                 uint32_t ulTimerTaskStackSize;
250
251                 vApplicationGetTimerTaskMemory( &pxTimerTaskTCBBuffer, &pxTimerTaskStackBuffer, &ulTimerTaskStackSize );
252                 xTimerTaskHandle = xTaskCreateStatic( prvTimerTask,
253                                                       configTIMER_SERVICE_TASK_NAME,
254                                                       ulTimerTaskStackSize,
255                                                       NULL,
256                                                       ( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT,
257                                                       pxTimerTaskStackBuffer,
258                                                       pxTimerTaskTCBBuffer );
259
260                 if( xTimerTaskHandle != NULL )
261                 {
262                     xReturn = pdPASS;
263                 }
264             }
265             #else /* if ( configSUPPORT_STATIC_ALLOCATION == 1 ) */
266             {
267                 xReturn = xTaskCreate( prvTimerTask,
268                                        configTIMER_SERVICE_TASK_NAME,
269                                        configTIMER_TASK_STACK_DEPTH,
270                                        NULL,
271                                        ( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT,
272                                        &xTimerTaskHandle );
273             }
274             #endif /* configSUPPORT_STATIC_ALLOCATION */
275         }
276         else
277         {
278             mtCOVERAGE_TEST_MARKER();
279         }
280
281         configASSERT( xReturn );
282         return xReturn;
283     }
284 /*-----------------------------------------------------------*/
285
286     #if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
287
288         TimerHandle_t xTimerCreate( const char * const pcTimerName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
289                                     const TickType_t xTimerPeriodInTicks,
290                                     const BaseType_t xAutoReload,
291                                     void * const pvTimerID,
292                                     TimerCallbackFunction_t pxCallbackFunction )
293         {
294             Timer_t * pxNewTimer;
295
296             pxNewTimer = ( Timer_t * ) pvPortMalloc( sizeof( Timer_t ) ); /*lint !e9087 !e9079 All values returned by pvPortMalloc() have at least the alignment required by the MCU's stack, and the first member of Timer_t is always a pointer to the timer's mame. */
297
298             if( pxNewTimer != NULL )
299             {
300                 /* Status is thus far zero as the timer is not created statically
301                  * and has not been started.  The auto-reload bit may get set in
302                  * prvInitialiseNewTimer. */
303                 pxNewTimer->ucStatus = 0x00;
304                 prvInitialiseNewTimer( pcTimerName, xTimerPeriodInTicks, xAutoReload, pvTimerID, pxCallbackFunction, pxNewTimer );
305             }
306
307             return pxNewTimer;
308         }
309
310     #endif /* configSUPPORT_DYNAMIC_ALLOCATION */
311 /*-----------------------------------------------------------*/
312
313     #if ( configSUPPORT_STATIC_ALLOCATION == 1 )
314
315         TimerHandle_t xTimerCreateStatic( const char * const pcTimerName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
316                                           const TickType_t xTimerPeriodInTicks,
317                                           const BaseType_t xAutoReload,
318                                           void * const pvTimerID,
319                                           TimerCallbackFunction_t pxCallbackFunction,
320                                           StaticTimer_t * pxTimerBuffer )
321         {
322             Timer_t * pxNewTimer;
323
324             #if ( configASSERT_DEFINED == 1 )
325             {
326                 /* Sanity check that the size of the structure used to declare a
327                  * variable of type StaticTimer_t equals the size of the real timer
328                  * structure. */
329                 volatile size_t xSize = sizeof( StaticTimer_t );
330                 configASSERT( xSize == sizeof( Timer_t ) );
331                 ( void ) xSize; /* Keeps lint quiet when configASSERT() is not defined. */
332             }
333             #endif /* configASSERT_DEFINED */
334
335             /* A pointer to a StaticTimer_t structure MUST be provided, use it. */
336             configASSERT( pxTimerBuffer );
337             pxNewTimer = ( Timer_t * ) pxTimerBuffer; /*lint !e740 !e9087 StaticTimer_t is a pointer to a Timer_t, so guaranteed to be aligned and sized correctly (checked by an assert()), so this is safe. */
338
339             if( pxNewTimer != NULL )
340             {
341                 /* Timers can be created statically or dynamically so note this
342                  * timer was created statically in case it is later deleted.  The
343                  * auto-reload bit may get set in prvInitialiseNewTimer(). */
344                 pxNewTimer->ucStatus = tmrSTATUS_IS_STATICALLY_ALLOCATED;
345
346                 prvInitialiseNewTimer( pcTimerName, xTimerPeriodInTicks, xAutoReload, pvTimerID, pxCallbackFunction, pxNewTimer );
347             }
348
349             return pxNewTimer;
350         }
351
352     #endif /* configSUPPORT_STATIC_ALLOCATION */
353 /*-----------------------------------------------------------*/
354
355     static void prvInitialiseNewTimer( const char * const pcTimerName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
356                                        const TickType_t xTimerPeriodInTicks,
357                                        const BaseType_t xAutoReload,
358                                        void * const pvTimerID,
359                                        TimerCallbackFunction_t pxCallbackFunction,
360                                        Timer_t * pxNewTimer )
361     {
362         /* 0 is not a valid value for xTimerPeriodInTicks. */
363         configASSERT( ( xTimerPeriodInTicks > 0 ) );
364
365         /* Ensure the infrastructure used by the timer service task has been
366          * created/initialised. */
367         prvCheckForValidListAndQueue();
368
369         /* Initialise the timer structure members using the function
370          * parameters. */
371         pxNewTimer->pcTimerName = pcTimerName;
372         pxNewTimer->xTimerPeriodInTicks = xTimerPeriodInTicks;
373         pxNewTimer->pvTimerID = pvTimerID;
374         pxNewTimer->pxCallbackFunction = pxCallbackFunction;
375         vListInitialiseItem( &( pxNewTimer->xTimerListItem ) );
376
377         if( xAutoReload != pdFALSE )
378         {
379             pxNewTimer->ucStatus |= tmrSTATUS_IS_AUTORELOAD;
380         }
381
382         traceTIMER_CREATE( pxNewTimer );
383     }
384 /*-----------------------------------------------------------*/
385
386     BaseType_t xTimerGenericCommand( TimerHandle_t xTimer,
387                                      const BaseType_t xCommandID,
388                                      const TickType_t xOptionalValue,
389                                      BaseType_t * const pxHigherPriorityTaskWoken,
390                                      const TickType_t xTicksToWait )
391     {
392         BaseType_t xReturn = pdFAIL;
393         DaemonTaskMessage_t xMessage;
394
395         configASSERT( xTimer );
396
397         /* Send a message to the timer service task to perform a particular action
398          * on a particular timer definition. */
399         if( xTimerQueue != NULL )
400         {
401             /* Send a command to the timer service task to start the xTimer timer. */
402             xMessage.xMessageID = xCommandID;
403             xMessage.u.xTimerParameters.xMessageValue = xOptionalValue;
404             xMessage.u.xTimerParameters.pxTimer = xTimer;
405
406             if( xCommandID < tmrFIRST_FROM_ISR_COMMAND )
407             {
408                 if( xTaskGetSchedulerState() == taskSCHEDULER_RUNNING )
409                 {
410                     xReturn = xQueueSendToBack( xTimerQueue, &xMessage, xTicksToWait );
411                 }
412                 else
413                 {
414                     xReturn = xQueueSendToBack( xTimerQueue, &xMessage, tmrNO_DELAY );
415                 }
416             }
417             else
418             {
419                 xReturn = xQueueSendToBackFromISR( xTimerQueue, &xMessage, pxHigherPriorityTaskWoken );
420             }
421
422             traceTIMER_COMMAND_SEND( xTimer, xCommandID, xOptionalValue, xReturn );
423         }
424         else
425         {
426             mtCOVERAGE_TEST_MARKER();
427         }
428
429         return xReturn;
430     }
431 /*-----------------------------------------------------------*/
432
433     TaskHandle_t xTimerGetTimerDaemonTaskHandle( void )
434     {
435         /* If xTimerGetTimerDaemonTaskHandle() is called before the scheduler has been
436          * started, then xTimerTaskHandle will be NULL. */
437         configASSERT( ( xTimerTaskHandle != NULL ) );
438         return xTimerTaskHandle;
439     }
440 /*-----------------------------------------------------------*/
441
442     TickType_t xTimerGetPeriod( TimerHandle_t xTimer )
443     {
444         Timer_t * pxTimer = xTimer;
445
446         configASSERT( xTimer );
447         return pxTimer->xTimerPeriodInTicks;
448     }
449 /*-----------------------------------------------------------*/
450
451     void vTimerSetReloadMode( TimerHandle_t xTimer,
452                               const BaseType_t xAutoReload )
453     {
454         Timer_t * pxTimer = xTimer;
455
456         configASSERT( xTimer );
457         taskENTER_CRITICAL();
458         {
459             if( xAutoReload != pdFALSE )
460             {
461                 pxTimer->ucStatus |= tmrSTATUS_IS_AUTORELOAD;
462             }
463             else
464             {
465                 pxTimer->ucStatus &= ( ( uint8_t ) ~tmrSTATUS_IS_AUTORELOAD );
466             }
467         }
468         taskEXIT_CRITICAL();
469     }
470 /*-----------------------------------------------------------*/
471
472     BaseType_t xTimerGetReloadMode( TimerHandle_t xTimer )
473     {
474         Timer_t * pxTimer = xTimer;
475         BaseType_t xReturn;
476
477         configASSERT( xTimer );
478         taskENTER_CRITICAL();
479         {
480             if( ( pxTimer->ucStatus & tmrSTATUS_IS_AUTORELOAD ) == 0 )
481             {
482                 /* Not an auto-reload timer. */
483                 xReturn = pdFALSE;
484             }
485             else
486             {
487                 /* Is an auto-reload timer. */
488                 xReturn = pdTRUE;
489             }
490         }
491         taskEXIT_CRITICAL();
492
493         return xReturn;
494     }
495
496     UBaseType_t uxTimerGetReloadMode( TimerHandle_t xTimer )
497     {
498         return ( UBaseType_t ) xTimerGetReloadMode( xTimer );
499     }
500 /*-----------------------------------------------------------*/
501
502     TickType_t xTimerGetExpiryTime( TimerHandle_t xTimer )
503     {
504         Timer_t * pxTimer = xTimer;
505         TickType_t xReturn;
506
507         configASSERT( xTimer );
508         xReturn = listGET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ) );
509         return xReturn;
510     }
511 /*-----------------------------------------------------------*/
512
513     const char * pcTimerGetName( TimerHandle_t xTimer ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
514     {
515         Timer_t * pxTimer = xTimer;
516
517         configASSERT( xTimer );
518         return pxTimer->pcTimerName;
519     }
520 /*-----------------------------------------------------------*/
521
522     static void prvReloadTimer( Timer_t * const pxTimer,
523                                 TickType_t xExpiredTime,
524                                 const TickType_t xTimeNow )
525     {
526         /* Insert the timer into the appropriate list for the next expiry time.
527          * If the next expiry time has already passed, advance the expiry time,
528          * call the callback function, and try again. */
529         while( prvInsertTimerInActiveList( pxTimer, ( xExpiredTime + pxTimer->xTimerPeriodInTicks ), xTimeNow, xExpiredTime ) != pdFALSE )
530         {
531             /* Advance the expiry time. */
532             xExpiredTime += pxTimer->xTimerPeriodInTicks;
533
534             /* Call the timer callback. */
535             traceTIMER_EXPIRED( pxTimer );
536             pxTimer->pxCallbackFunction( ( TimerHandle_t ) pxTimer );
537         }
538     }
539 /*-----------------------------------------------------------*/
540
541     static void prvProcessExpiredTimer( const TickType_t xNextExpireTime,
542                                         const TickType_t xTimeNow )
543     {
544         Timer_t * const pxTimer = ( Timer_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxCurrentTimerList ); /*lint !e9087 !e9079 void * is used as this macro is used with tasks too.  Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */
545
546         /* Remove the timer from the list of active timers.  A check has already
547          * been performed to ensure the list is not empty. */
548
549         ( void ) uxListRemove( &( pxTimer->xTimerListItem ) );
550
551         /* If the timer is an auto-reload timer then calculate the next
552          * expiry time and re-insert the timer in the list of active timers. */
553         if( ( pxTimer->ucStatus & tmrSTATUS_IS_AUTORELOAD ) != 0 )
554         {
555             prvReloadTimer( pxTimer, xNextExpireTime, xTimeNow );
556         }
557         else
558         {
559             pxTimer->ucStatus &= ( ( uint8_t ) ~tmrSTATUS_IS_ACTIVE );
560         }
561
562         /* Call the timer callback. */
563         traceTIMER_EXPIRED( pxTimer );
564         pxTimer->pxCallbackFunction( ( TimerHandle_t ) pxTimer );
565     }
566 /*-----------------------------------------------------------*/
567
568     static portTASK_FUNCTION( prvTimerTask, pvParameters )
569     {
570         TickType_t xNextExpireTime;
571         BaseType_t xListWasEmpty;
572
573         /* Just to avoid compiler warnings. */
574         ( void ) pvParameters;
575
576         #if ( configUSE_DAEMON_TASK_STARTUP_HOOK == 1 )
577         {
578             extern void vApplicationDaemonTaskStartupHook( void );
579
580             /* Allow the application writer to execute some code in the context of
581              * this task at the point the task starts executing.  This is useful if the
582              * application includes initialisation code that would benefit from
583              * executing after the scheduler has been started. */
584             vApplicationDaemonTaskStartupHook();
585         }
586         #endif /* configUSE_DAEMON_TASK_STARTUP_HOOK */
587
588         for( ; ; )
589         {
590             /* Query the timers list to see if it contains any timers, and if so,
591              * obtain the time at which the next timer will expire. */
592             xNextExpireTime = prvGetNextExpireTime( &xListWasEmpty );
593
594             /* If a timer has expired, process it.  Otherwise, block this task
595              * until either a timer does expire, or a command is received. */
596             prvProcessTimerOrBlockTask( xNextExpireTime, xListWasEmpty );
597
598             /* Empty the command queue. */
599             prvProcessReceivedCommands();
600         }
601     }
602 /*-----------------------------------------------------------*/
603
604     static void prvProcessTimerOrBlockTask( const TickType_t xNextExpireTime,
605                                             BaseType_t xListWasEmpty )
606     {
607         TickType_t xTimeNow;
608         BaseType_t xTimerListsWereSwitched;
609
610         vTaskSuspendAll();
611         {
612             /* Obtain the time now to make an assessment as to whether the timer
613              * has expired or not.  If obtaining the time causes the lists to switch
614              * then don't process this timer as any timers that remained in the list
615              * when the lists were switched will have been processed within the
616              * prvSampleTimeNow() function. */
617             xTimeNow = prvSampleTimeNow( &xTimerListsWereSwitched );
618
619             if( xTimerListsWereSwitched == pdFALSE )
620             {
621                 /* The tick count has not overflowed, has the timer expired? */
622                 if( ( xListWasEmpty == pdFALSE ) && ( xNextExpireTime <= xTimeNow ) )
623                 {
624                     ( void ) xTaskResumeAll();
625                     prvProcessExpiredTimer( xNextExpireTime, xTimeNow );
626                 }
627                 else
628                 {
629                     /* The tick count has not overflowed, and the next expire
630                      * time has not been reached yet.  This task should therefore
631                      * block to wait for the next expire time or a command to be
632                      * received - whichever comes first.  The following line cannot
633                      * be reached unless xNextExpireTime > xTimeNow, except in the
634                      * case when the current timer list is empty. */
635                     if( xListWasEmpty != pdFALSE )
636                     {
637                         /* The current timer list is empty - is the overflow list
638                          * also empty? */
639                         xListWasEmpty = listLIST_IS_EMPTY( pxOverflowTimerList );
640                     }
641
642                     vQueueWaitForMessageRestricted( xTimerQueue, ( xNextExpireTime - xTimeNow ), xListWasEmpty );
643
644                     if( xTaskResumeAll() == pdFALSE )
645                     {
646                         /* Yield to wait for either a command to arrive, or the
647                          * block time to expire.  If a command arrived between the
648                          * critical section being exited and this yield then the yield
649                          * will not cause the task to block. */
650                         portYIELD_WITHIN_API();
651                     }
652                     else
653                     {
654                         mtCOVERAGE_TEST_MARKER();
655                     }
656                 }
657             }
658             else
659             {
660                 ( void ) xTaskResumeAll();
661             }
662         }
663     }
664 /*-----------------------------------------------------------*/
665
666     static TickType_t prvGetNextExpireTime( BaseType_t * const pxListWasEmpty )
667     {
668         TickType_t xNextExpireTime;
669
670         /* Timers are listed in expiry time order, with the head of the list
671          * referencing the task that will expire first.  Obtain the time at which
672          * the timer with the nearest expiry time will expire.  If there are no
673          * active timers then just set the next expire time to 0.  That will cause
674          * this task to unblock when the tick count overflows, at which point the
675          * timer lists will be switched and the next expiry time can be
676          * re-assessed.  */
677         *pxListWasEmpty = listLIST_IS_EMPTY( pxCurrentTimerList );
678
679         if( *pxListWasEmpty == pdFALSE )
680         {
681             xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList );
682         }
683         else
684         {
685             /* Ensure the task unblocks when the tick count rolls over. */
686             xNextExpireTime = ( TickType_t ) 0U;
687         }
688
689         return xNextExpireTime;
690     }
691 /*-----------------------------------------------------------*/
692
693     static TickType_t prvSampleTimeNow( BaseType_t * const pxTimerListsWereSwitched )
694     {
695         TickType_t xTimeNow;
696         PRIVILEGED_DATA static TickType_t xLastTime = ( TickType_t ) 0U; /*lint !e956 Variable is only accessible to one task. */
697
698         xTimeNow = xTaskGetTickCount();
699
700         if( xTimeNow < xLastTime )
701         {
702             prvSwitchTimerLists();
703             *pxTimerListsWereSwitched = pdTRUE;
704         }
705         else
706         {
707             *pxTimerListsWereSwitched = pdFALSE;
708         }
709
710         xLastTime = xTimeNow;
711
712         return xTimeNow;
713     }
714 /*-----------------------------------------------------------*/
715
716     static BaseType_t prvInsertTimerInActiveList( Timer_t * const pxTimer,
717                                                   const TickType_t xNextExpiryTime,
718                                                   const TickType_t xTimeNow,
719                                                   const TickType_t xCommandTime )
720     {
721         BaseType_t xProcessTimerNow = pdFALSE;
722
723         listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xNextExpiryTime );
724         listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer );
725
726         if( xNextExpiryTime <= xTimeNow )
727         {
728             /* Has the expiry time elapsed between the command to start/reset a
729              * timer was issued, and the time the command was processed? */
730             if( ( ( TickType_t ) ( xTimeNow - xCommandTime ) ) >= pxTimer->xTimerPeriodInTicks ) /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
731             {
732                 /* The time between a command being issued and the command being
733                  * processed actually exceeds the timers period.  */
734                 xProcessTimerNow = pdTRUE;
735             }
736             else
737             {
738                 vListInsert( pxOverflowTimerList, &( pxTimer->xTimerListItem ) );
739             }
740         }
741         else
742         {
743             if( ( xTimeNow < xCommandTime ) && ( xNextExpiryTime >= xCommandTime ) )
744             {
745                 /* If, since the command was issued, the tick count has overflowed
746                  * but the expiry time has not, then the timer must have already passed
747                  * its expiry time and should be processed immediately. */
748                 xProcessTimerNow = pdTRUE;
749             }
750             else
751             {
752                 vListInsert( pxCurrentTimerList, &( pxTimer->xTimerListItem ) );
753             }
754         }
755
756         return xProcessTimerNow;
757     }
758 /*-----------------------------------------------------------*/
759
760     static void prvProcessReceivedCommands( void )
761     {
762         DaemonTaskMessage_t xMessage;
763         Timer_t * pxTimer;
764         BaseType_t xTimerListsWereSwitched;
765         TickType_t xTimeNow;
766
767         while( xQueueReceive( xTimerQueue, &xMessage, tmrNO_DELAY ) != pdFAIL ) /*lint !e603 xMessage does not have to be initialised as it is passed out, not in, and it is not used unless xQueueReceive() returns pdTRUE. */
768         {
769             #if ( INCLUDE_xTimerPendFunctionCall == 1 )
770             {
771                 /* Negative commands are pended function calls rather than timer
772                  * commands. */
773                 if( xMessage.xMessageID < ( BaseType_t ) 0 )
774                 {
775                     const CallbackParameters_t * const pxCallback = &( xMessage.u.xCallbackParameters );
776
777                     /* The timer uses the xCallbackParameters member to request a
778                      * callback be executed.  Check the callback is not NULL. */
779                     configASSERT( pxCallback );
780
781                     /* Call the function. */
782                     pxCallback->pxCallbackFunction( pxCallback->pvParameter1, pxCallback->ulParameter2 );
783                 }
784                 else
785                 {
786                     mtCOVERAGE_TEST_MARKER();
787                 }
788             }
789             #endif /* INCLUDE_xTimerPendFunctionCall */
790
791             /* Commands that are positive are timer commands rather than pended
792              * function calls. */
793             if( xMessage.xMessageID >= ( BaseType_t ) 0 )
794             {
795                 /* The messages uses the xTimerParameters member to work on a
796                  * software timer. */
797                 pxTimer = xMessage.u.xTimerParameters.pxTimer;
798
799                 if( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) == pdFALSE ) /*lint !e961. The cast is only redundant when NULL is passed into the macro. */
800                 {
801                     /* The timer is in a list, remove it. */
802                     ( void ) uxListRemove( &( pxTimer->xTimerListItem ) );
803                 }
804                 else
805                 {
806                     mtCOVERAGE_TEST_MARKER();
807                 }
808
809                 traceTIMER_COMMAND_RECEIVED( pxTimer, xMessage.xMessageID, xMessage.u.xTimerParameters.xMessageValue );
810
811                 /* In this case the xTimerListsWereSwitched parameter is not used, but
812                  *  it must be present in the function call.  prvSampleTimeNow() must be
813                  *  called after the message is received from xTimerQueue so there is no
814                  *  possibility of a higher priority task adding a message to the message
815                  *  queue with a time that is ahead of the timer daemon task (because it
816                  *  pre-empted the timer daemon task after the xTimeNow value was set). */
817                 xTimeNow = prvSampleTimeNow( &xTimerListsWereSwitched );
818
819                 switch( xMessage.xMessageID )
820                 {
821                     case tmrCOMMAND_START:
822                     case tmrCOMMAND_START_FROM_ISR:
823                     case tmrCOMMAND_RESET:
824                     case tmrCOMMAND_RESET_FROM_ISR:
825                         /* Start or restart a timer. */
826                         pxTimer->ucStatus |= tmrSTATUS_IS_ACTIVE;
827
828                         if( prvInsertTimerInActiveList( pxTimer, xMessage.u.xTimerParameters.xMessageValue + pxTimer->xTimerPeriodInTicks, xTimeNow, xMessage.u.xTimerParameters.xMessageValue ) != pdFALSE )
829                         {
830                             /* The timer expired before it was added to the active
831                              * timer list.  Process it now. */
832                             if( ( pxTimer->ucStatus & tmrSTATUS_IS_AUTORELOAD ) != 0 )
833                             {
834                                 prvReloadTimer( pxTimer, xMessage.u.xTimerParameters.xMessageValue + pxTimer->xTimerPeriodInTicks, xTimeNow );
835                             }
836                             else
837                             {
838                                 pxTimer->ucStatus &= ( ( uint8_t ) ~tmrSTATUS_IS_ACTIVE );
839                             }
840
841                             /* Call the timer callback. */
842                             traceTIMER_EXPIRED( pxTimer );
843                             pxTimer->pxCallbackFunction( ( TimerHandle_t ) pxTimer );
844                         }
845                         else
846                         {
847                             mtCOVERAGE_TEST_MARKER();
848                         }
849
850                         break;
851
852                     case tmrCOMMAND_STOP:
853                     case tmrCOMMAND_STOP_FROM_ISR:
854                         /* The timer has already been removed from the active list. */
855                         pxTimer->ucStatus &= ( ( uint8_t ) ~tmrSTATUS_IS_ACTIVE );
856                         break;
857
858                     case tmrCOMMAND_CHANGE_PERIOD:
859                     case tmrCOMMAND_CHANGE_PERIOD_FROM_ISR:
860                         pxTimer->ucStatus |= tmrSTATUS_IS_ACTIVE;
861                         pxTimer->xTimerPeriodInTicks = xMessage.u.xTimerParameters.xMessageValue;
862                         configASSERT( ( pxTimer->xTimerPeriodInTicks > 0 ) );
863
864                         /* The new period does not really have a reference, and can
865                          * be longer or shorter than the old one.  The command time is
866                          * therefore set to the current time, and as the period cannot
867                          * be zero the next expiry time can only be in the future,
868                          * meaning (unlike for the xTimerStart() case above) there is
869                          * no fail case that needs to be handled here. */
870                         ( void ) prvInsertTimerInActiveList( pxTimer, ( xTimeNow + pxTimer->xTimerPeriodInTicks ), xTimeNow, xTimeNow );
871                         break;
872
873                     case tmrCOMMAND_DELETE:
874                         #if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
875                         {
876                             /* The timer has already been removed from the active list,
877                              * just free up the memory if the memory was dynamically
878                              * allocated. */
879                             if( ( pxTimer->ucStatus & tmrSTATUS_IS_STATICALLY_ALLOCATED ) == ( uint8_t ) 0 )
880                             {
881                                 vPortFree( pxTimer );
882                             }
883                             else
884                             {
885                                 pxTimer->ucStatus &= ( ( uint8_t ) ~tmrSTATUS_IS_ACTIVE );
886                             }
887                         }
888                         #else /* if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) */
889                         {
890                             /* If dynamic allocation is not enabled, the memory
891                              * could not have been dynamically allocated. So there is
892                              * no need to free the memory - just mark the timer as
893                              * "not active". */
894                             pxTimer->ucStatus &= ( ( uint8_t ) ~tmrSTATUS_IS_ACTIVE );
895                         }
896                         #endif /* configSUPPORT_DYNAMIC_ALLOCATION */
897                         break;
898
899                     default:
900                         /* Don't expect to get here. */
901                         break;
902                 }
903             }
904         }
905     }
906 /*-----------------------------------------------------------*/
907
908     static void prvSwitchTimerLists( void )
909     {
910         TickType_t xNextExpireTime;
911         List_t * pxTemp;
912
913         /* The tick count has overflowed.  The timer lists must be switched.
914          * If there are any timers still referenced from the current timer list
915          * then they must have expired and should be processed before the lists
916          * are switched. */
917         while( listLIST_IS_EMPTY( pxCurrentTimerList ) == pdFALSE )
918         {
919             xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList );
920
921             /* Process the expired timer.  For auto-reload timers, be careful to
922              * process only expirations that occur on the current list.  Further
923              * expirations must wait until after the lists are switched. */
924             prvProcessExpiredTimer( xNextExpireTime, tmrMAX_TIME_BEFORE_OVERFLOW );
925         }
926
927         pxTemp = pxCurrentTimerList;
928         pxCurrentTimerList = pxOverflowTimerList;
929         pxOverflowTimerList = pxTemp;
930     }
931 /*-----------------------------------------------------------*/
932
933     static void prvCheckForValidListAndQueue( void )
934     {
935         /* Check that the list from which active timers are referenced, and the
936          * queue used to communicate with the timer service, have been
937          * initialised. */
938         taskENTER_CRITICAL();
939         {
940             if( xTimerQueue == NULL )
941             {
942                 vListInitialise( &xActiveTimerList1 );
943                 vListInitialise( &xActiveTimerList2 );
944                 pxCurrentTimerList = &xActiveTimerList1;
945                 pxOverflowTimerList = &xActiveTimerList2;
946
947                 #if ( configSUPPORT_STATIC_ALLOCATION == 1 )
948                 {
949                     /* The timer queue is allocated statically in case
950                      * configSUPPORT_DYNAMIC_ALLOCATION is 0. */
951                     PRIVILEGED_DATA static StaticQueue_t xStaticTimerQueue;                                                                          /*lint !e956 Ok to declare in this manner to prevent additional conditional compilation guards in other locations. */
952                     PRIVILEGED_DATA static uint8_t ucStaticTimerQueueStorage[ ( size_t ) configTIMER_QUEUE_LENGTH * sizeof( DaemonTaskMessage_t ) ]; /*lint !e956 Ok to declare in this manner to prevent additional conditional compilation guards in other locations. */
953
954                     xTimerQueue = xQueueCreateStatic( ( UBaseType_t ) configTIMER_QUEUE_LENGTH, ( UBaseType_t ) sizeof( DaemonTaskMessage_t ), &( ucStaticTimerQueueStorage[ 0 ] ), &xStaticTimerQueue );
955                 }
956                 #else
957                 {
958                     xTimerQueue = xQueueCreate( ( UBaseType_t ) configTIMER_QUEUE_LENGTH, sizeof( DaemonTaskMessage_t ) );
959                 }
960                 #endif /* if ( configSUPPORT_STATIC_ALLOCATION == 1 ) */
961
962                 #if ( configQUEUE_REGISTRY_SIZE > 0 )
963                 {
964                     if( xTimerQueue != NULL )
965                     {
966                         vQueueAddToRegistry( xTimerQueue, "TmrQ" );
967                     }
968                     else
969                     {
970                         mtCOVERAGE_TEST_MARKER();
971                     }
972                 }
973                 #endif /* configQUEUE_REGISTRY_SIZE */
974             }
975             else
976             {
977                 mtCOVERAGE_TEST_MARKER();
978             }
979         }
980         taskEXIT_CRITICAL();
981     }
982 /*-----------------------------------------------------------*/
983
984     BaseType_t xTimerIsTimerActive( TimerHandle_t xTimer )
985     {
986         BaseType_t xReturn;
987         Timer_t * pxTimer = xTimer;
988
989         configASSERT( xTimer );
990
991         /* Is the timer in the list of active timers? */
992         taskENTER_CRITICAL();
993         {
994             if( ( pxTimer->ucStatus & tmrSTATUS_IS_ACTIVE ) == 0 )
995             {
996                 xReturn = pdFALSE;
997             }
998             else
999             {
1000                 xReturn = pdTRUE;
1001             }
1002         }
1003         taskEXIT_CRITICAL();
1004
1005         return xReturn;
1006     } /*lint !e818 Can't be pointer to const due to the typedef. */
1007 /*-----------------------------------------------------------*/
1008
1009     void * pvTimerGetTimerID( const TimerHandle_t xTimer )
1010     {
1011         Timer_t * const pxTimer = xTimer;
1012         void * pvReturn;
1013
1014         configASSERT( xTimer );
1015
1016         taskENTER_CRITICAL();
1017         {
1018             pvReturn = pxTimer->pvTimerID;
1019         }
1020         taskEXIT_CRITICAL();
1021
1022         return pvReturn;
1023     }
1024 /*-----------------------------------------------------------*/
1025
1026     void vTimerSetTimerID( TimerHandle_t xTimer,
1027                            void * pvNewID )
1028     {
1029         Timer_t * const pxTimer = xTimer;
1030
1031         configASSERT( xTimer );
1032
1033         taskENTER_CRITICAL();
1034         {
1035             pxTimer->pvTimerID = pvNewID;
1036         }
1037         taskEXIT_CRITICAL();
1038     }
1039 /*-----------------------------------------------------------*/
1040
1041     #if ( INCLUDE_xTimerPendFunctionCall == 1 )
1042
1043         BaseType_t xTimerPendFunctionCallFromISR( PendedFunction_t xFunctionToPend,
1044                                                   void * pvParameter1,
1045                                                   uint32_t ulParameter2,
1046                                                   BaseType_t * pxHigherPriorityTaskWoken )
1047         {
1048             DaemonTaskMessage_t xMessage;
1049             BaseType_t xReturn;
1050
1051             /* Complete the message with the function parameters and post it to the
1052              * daemon task. */
1053             xMessage.xMessageID = tmrCOMMAND_EXECUTE_CALLBACK_FROM_ISR;
1054             xMessage.u.xCallbackParameters.pxCallbackFunction = xFunctionToPend;
1055             xMessage.u.xCallbackParameters.pvParameter1 = pvParameter1;
1056             xMessage.u.xCallbackParameters.ulParameter2 = ulParameter2;
1057
1058             xReturn = xQueueSendFromISR( xTimerQueue, &xMessage, pxHigherPriorityTaskWoken );
1059
1060             tracePEND_FUNC_CALL_FROM_ISR( xFunctionToPend, pvParameter1, ulParameter2, xReturn );
1061
1062             return xReturn;
1063         }
1064
1065     #endif /* INCLUDE_xTimerPendFunctionCall */
1066 /*-----------------------------------------------------------*/
1067
1068     #if ( INCLUDE_xTimerPendFunctionCall == 1 )
1069
1070         BaseType_t xTimerPendFunctionCall( PendedFunction_t xFunctionToPend,
1071                                            void * pvParameter1,
1072                                            uint32_t ulParameter2,
1073                                            TickType_t xTicksToWait )
1074         {
1075             DaemonTaskMessage_t xMessage;
1076             BaseType_t xReturn;
1077
1078             /* This function can only be called after a timer has been created or
1079              * after the scheduler has been started because, until then, the timer
1080              * queue does not exist. */
1081             configASSERT( xTimerQueue );
1082
1083             /* Complete the message with the function parameters and post it to the
1084              * daemon task. */
1085             xMessage.xMessageID = tmrCOMMAND_EXECUTE_CALLBACK;
1086             xMessage.u.xCallbackParameters.pxCallbackFunction = xFunctionToPend;
1087             xMessage.u.xCallbackParameters.pvParameter1 = pvParameter1;
1088             xMessage.u.xCallbackParameters.ulParameter2 = ulParameter2;
1089
1090             xReturn = xQueueSendToBack( xTimerQueue, &xMessage, xTicksToWait );
1091
1092             tracePEND_FUNC_CALL( xFunctionToPend, pvParameter1, ulParameter2, xReturn );
1093
1094             return xReturn;
1095         }
1096
1097     #endif /* INCLUDE_xTimerPendFunctionCall */
1098 /*-----------------------------------------------------------*/
1099
1100     #if ( configUSE_TRACE_FACILITY == 1 )
1101
1102         UBaseType_t uxTimerGetTimerNumber( TimerHandle_t xTimer )
1103         {
1104             return ( ( Timer_t * ) xTimer )->uxTimerNumber;
1105         }
1106
1107     #endif /* configUSE_TRACE_FACILITY */
1108 /*-----------------------------------------------------------*/
1109
1110     #if ( configUSE_TRACE_FACILITY == 1 )
1111
1112         void vTimerSetTimerNumber( TimerHandle_t xTimer,
1113                                    UBaseType_t uxTimerNumber )
1114         {
1115             ( ( Timer_t * ) xTimer )->uxTimerNumber = uxTimerNumber;
1116         }
1117
1118     #endif /* configUSE_TRACE_FACILITY */
1119 /*-----------------------------------------------------------*/
1120
1121 /* This entire source file will be skipped if the application is not configured
1122  * to include software timer functionality.  If you want to include software timer
1123  * functionality then ensure configUSE_TIMERS is set to 1 in FreeRTOSConfig.h. */
1124 #endif /* configUSE_TIMERS == 1 */