]> git.sur5r.net Git - freertos/blob - FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_timer.c
Add the Labs projects provided in the V10.2.1_191129 zip file.
[freertos] / FreeRTOS-Labs / Demo / FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator / lib / FreeRTOS-Plus-POSIX / source / FreeRTOS_POSIX_timer.c
1 /*\r
2  * Amazon FreeRTOS POSIX V1.1.0\r
3  * Copyright (C) 2018 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
4  *\r
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
6  * this software and associated documentation files (the "Software"), to deal in\r
7  * the Software without restriction, including without limitation the rights to\r
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
9  * the Software, and to permit persons to whom the Software is furnished to do so,\r
10  * subject to the following conditions:\r
11  *\r
12  * The above copyright notice and this permission notice shall be included in all\r
13  * copies or substantial portions of the Software.\r
14  *\r
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
17  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
18  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
19  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
20  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
21  *\r
22  * http://aws.amazon.com/freertos\r
23  * http://www.FreeRTOS.org\r
24  */\r
25 \r
26 /**\r
27  * @file FreeRTOS_POSIX_timer.c\r
28  * @brief Implementation of timer functions in time.h\r
29  */\r
30 \r
31 /* C standard library includes. */\r
32 #include <stddef.h>\r
33 \r
34 /* FreeRTOS+POSIX includes. */\r
35 #include "FreeRTOS_POSIX.h"\r
36 #include "FreeRTOS_POSIX/errno.h"\r
37 #include "FreeRTOS_POSIX/pthread.h"\r
38 #include "FreeRTOS_POSIX/signal.h"\r
39 #include "FreeRTOS_POSIX/time.h"\r
40 #include "FreeRTOS_POSIX/utils.h"\r
41 \r
42 /* FreeRTOS timer include. */\r
43 #include "timers.h"\r
44 \r
45 /* Timespec zero check macros. */\r
46 #define TIMESPEC_IS_ZERO( xTimespec )        ( xTimespec.tv_sec == 0 && xTimespec.tv_nsec == 0 ) /**< Check for 0. */\r
47 #define TIMESPEC_IS_NOT_ZERO( xTimespec )    ( !( TIMESPEC_IS_ZERO( xTimespec ) ) )              /**< Check for not 0. */\r
48 \r
49 /**\r
50  * @brief Internal timer structure.\r
51  */\r
52 typedef struct timer_internal\r
53 {\r
54     StaticTimer_t xTimerBuffer;  /**< Memory that holds the FreeRTOS timer. */\r
55     struct sigevent xTimerEvent; /**< What to do when this timer expires. */\r
56     TickType_t xTimerPeriod;     /**< Period of this timer. */\r
57 } timer_internal_t;\r
58 \r
59 /*-----------------------------------------------------------*/\r
60 \r
61 void prvTimerCallback( TimerHandle_t xTimerHandle )\r
62 {\r
63     timer_internal_t * pxTimer = ( timer_internal_t * ) pvTimerGetTimerID( xTimerHandle );\r
64     pthread_t xTimerNotificationThread;\r
65 \r
66     /* The value of the timer ID, set in timer_create, should not be NULL. */\r
67     configASSERT( pxTimer != NULL );\r
68 \r
69     /* A value of SIGEV_SIGNAL isn't supported and should not have been successfully\r
70      * set. */\r
71     configASSERT( pxTimer->xTimerEvent.sigev_notify != SIGEV_SIGNAL );\r
72 \r
73     /* Update the timer period, which may need to be set to an it_interval\r
74      * argument. This call should not block. */\r
75     if( pxTimer->xTimerPeriod > 0 )\r
76     {\r
77         xTimerChangePeriod( xTimerHandle, pxTimer->xTimerPeriod, 0 );\r
78     }\r
79 \r
80     /* Create the timer notification thread if requested. */\r
81     if( pxTimer->xTimerEvent.sigev_notify == SIGEV_THREAD )\r
82     {\r
83         /* if the user has provided thread attributes, create a thread\r
84          * with the provided attributes. Otherwise dispatch callback directly */\r
85         if( pxTimer->xTimerEvent.sigev_notify_attributes == NULL )\r
86         {\r
87             ( *pxTimer->xTimerEvent.sigev_notify_function )( pxTimer->xTimerEvent.sigev_value );\r
88         }\r
89         else\r
90         {\r
91             ( void ) pthread_create( &xTimerNotificationThread,\r
92                                      pxTimer->xTimerEvent.sigev_notify_attributes,\r
93                                      ( void * ( * )( void * ) )pxTimer->xTimerEvent.sigev_notify_function,\r
94                                      pxTimer->xTimerEvent.sigev_value.sival_ptr );\r
95         }\r
96     }\r
97 }\r
98 \r
99 /*-----------------------------------------------------------*/\r
100 \r
101 int timer_create( clockid_t clockid,\r
102                   struct sigevent * evp,\r
103                   timer_t * timerid )\r
104 {\r
105     int iStatus = 0;\r
106     timer_internal_t * pxTimer = NULL;\r
107 \r
108     /* Silence warnings about unused parameters. */\r
109     ( void ) clockid;\r
110 \r
111     /* POSIX specifies that when evp is NULL, the behavior shall be as is\r
112      * sigev_notify is SIGEV_SIGNAL. SIGEV_SIGNAL is currently not supported. */\r
113     if( ( evp == NULL ) || ( evp->sigev_notify == SIGEV_SIGNAL ) )\r
114     {\r
115         errno = ENOTSUP;\r
116         iStatus = -1;\r
117     }\r
118 \r
119     /* Allocate memory for a new timer object. */\r
120     if( iStatus == 0 )\r
121     {\r
122         pxTimer = pvPortMalloc( sizeof( timer_internal_t ) );\r
123 \r
124         if( pxTimer == NULL )\r
125         {\r
126             errno = EAGAIN;\r
127             iStatus = -1;\r
128         }\r
129     }\r
130 \r
131     if( iStatus == 0 )\r
132     {\r
133         /* Copy the event notification structure and set the current timer period. */\r
134         pxTimer->xTimerEvent = *evp;\r
135         pxTimer->xTimerPeriod = 0;\r
136 \r
137         /* Create a new FreeRTOS timer. This call will not fail because the\r
138          * memory for it has already been allocated, so the output parameter is\r
139          * also set. */\r
140         *timerid = ( timer_t ) xTimerCreateStatic( posixconfigTIMER_NAME,    /* Timer name. */\r
141                                                    portMAX_DELAY,            /* Initial timer period. Timers are created disarmed. */\r
142                                                    pdFALSE,                  /* Don't auto-reload timer. */\r
143                                                    ( void * ) pxTimer,       /* Timer id. */\r
144                                                    prvTimerCallback,         /* Timer expiration callback. */\r
145                                                    &pxTimer->xTimerBuffer ); /* Pre-allocated memory for timer. */\r
146     }\r
147 \r
148     return iStatus;\r
149 }\r
150 \r
151 /*-----------------------------------------------------------*/\r
152 \r
153 int timer_delete( timer_t timerid )\r
154 {\r
155     TimerHandle_t xTimerHandle = timerid;\r
156     timer_internal_t * pxTimer = ( timer_internal_t * ) pvTimerGetTimerID( xTimerHandle );\r
157 \r
158     /* The value of the timer ID, set in timer_create, should not be NULL. */\r
159     configASSERT( pxTimer != NULL );\r
160 \r
161     /* Stop the FreeRTOS timer. Because the timer is statically allocated, no call\r
162      * to xTimerDelete is necessary. The timer is stopped so that it's not referenced\r
163      * anywhere. xTimerStop will not fail when it has unlimited block time. */\r
164     ( void ) xTimerStop( xTimerHandle, portMAX_DELAY );\r
165 \r
166     /* Wait until the timer stop command is processed. */\r
167     while( xTimerIsTimerActive( xTimerHandle ) == pdTRUE )\r
168     {\r
169         vTaskDelay( 1 );\r
170     }\r
171 \r
172     /* Free the memory in use by the timer. */\r
173     vPortFree( pxTimer );\r
174 \r
175     return 0;\r
176 }\r
177 \r
178 /*-----------------------------------------------------------*/\r
179 \r
180 int timer_getoverrun( timer_t timerid )\r
181 {\r
182     /* Silence warnings about unused parameters. */\r
183     ( void ) timerid;\r
184 \r
185     return 0;\r
186 }\r
187 \r
188 /*-----------------------------------------------------------*/\r
189 \r
190 int timer_settime( timer_t timerid,\r
191                    int flags,\r
192                    const struct itimerspec * value,\r
193                    struct itimerspec * ovalue )\r
194 {\r
195     int iStatus = 0;\r
196     TimerHandle_t xTimerHandle = timerid;\r
197     timer_internal_t * pxTimer = ( timer_internal_t * ) pvTimerGetTimerID( xTimerHandle );\r
198     TickType_t xNextTimerExpiration = 0, xTimerExpirationPeriod = 0;\r
199 \r
200     /* Validate the value argument, but only if the timer isn't being disarmed. */\r
201     if( TIMESPEC_IS_NOT_ZERO( value->it_value ) )\r
202     {\r
203         if( ( UTILS_ValidateTimespec( &value->it_interval ) == false ) ||\r
204             ( UTILS_ValidateTimespec( &value->it_value ) == false ) )\r
205         {\r
206             errno = EINVAL;\r
207             iStatus = -1;\r
208         }\r
209     }\r
210 \r
211     /* Set ovalue, if given. */\r
212     if( ovalue != NULL )\r
213     {\r
214         ( void ) timer_gettime( timerid, ovalue );\r
215     }\r
216 \r
217     /* Stop the timer if it's currently active. */\r
218     if( ( iStatus == 0 ) && xTimerIsTimerActive( xTimerHandle ) )\r
219     {\r
220         ( void ) xTimerStop( xTimerHandle, portMAX_DELAY );\r
221     }\r
222 \r
223     /* Only restart the timer if it_value is not zero. */\r
224     if( ( iStatus == 0 ) && TIMESPEC_IS_NOT_ZERO( value->it_value ) )\r
225     {\r
226         /* Convert it_interval to ticks, but only if it_interval is not 0. If\r
227          * it_interval is 0, then the timer is not periodic. */\r
228         if( TIMESPEC_IS_NOT_ZERO( value->it_interval ) )\r
229         {\r
230             ( void ) UTILS_TimespecToTicks( &value->it_interval, &xTimerExpirationPeriod );\r
231         }\r
232 \r
233         /* Set the new timer period. A non-periodic timer will have its period set\r
234          * to portMAX_DELAY. */\r
235         pxTimer->xTimerPeriod = xTimerExpirationPeriod;\r
236 \r
237         /* Convert it_value to ticks, but only if it_value is not 0. If it_value\r
238          * is 0, then the timer will remain disarmed. */\r
239         if( TIMESPEC_IS_NOT_ZERO( value->it_value ) )\r
240         {\r
241             /* Absolute timeout. */\r
242             if( ( flags & TIMER_ABSTIME ) == TIMER_ABSTIME )\r
243             {\r
244                 struct timespec xCurrentTime = { 0 };\r
245 \r
246                 /* Get current time */\r
247                 if( clock_gettime( CLOCK_REALTIME, &xCurrentTime ) != 0 )\r
248                 {\r
249                     iStatus = EINVAL;\r
250                 }\r
251                 else\r
252                 {\r
253                     iStatus = UTILS_AbsoluteTimespecToDeltaTicks( &value->it_value, &xCurrentTime, &xNextTimerExpiration );\r
254                 }\r
255 \r
256                 /* Make sure xNextTimerExpiration is zero in case we got negative time difference */\r
257                 if( iStatus != 0 )\r
258                 {\r
259                     xNextTimerExpiration = 0;\r
260 \r
261                     if( iStatus == ETIMEDOUT )\r
262                     {\r
263                         /* Set Status to 0 as absolute time is past is treated as expiry but not an error */\r
264                         iStatus = 0;\r
265                     }\r
266                 }\r
267             }\r
268             /* Relative timeout. */\r
269             else\r
270             {\r
271                 ( void ) UTILS_TimespecToTicks( &value->it_value, &xNextTimerExpiration );\r
272             }\r
273         }\r
274 \r
275         /* If xNextTimerExpiration is still 0, that means that it_value specified\r
276          * an absolute timeout in the past. Per POSIX spec, a notification should be\r
277          * triggered immediately. */\r
278         if( xNextTimerExpiration == 0 )\r
279         {\r
280             prvTimerCallback( xTimerHandle );\r
281         }\r
282         else\r
283         {\r
284             /* Set the timer to expire at the it_value, then start it. */\r
285             ( void ) xTimerChangePeriod( xTimerHandle, xNextTimerExpiration, portMAX_DELAY );\r
286             ( void ) xTimerStart( xTimerHandle, xNextTimerExpiration );\r
287         }\r
288     }\r
289 \r
290     return iStatus;\r
291 }\r
292 \r
293 /*-----------------------------------------------------------*/\r
294 \r
295 int timer_gettime( timer_t timerid,\r
296                    struct itimerspec * value )\r
297 {\r
298     TimerHandle_t xTimerHandle = timerid;\r
299     timer_internal_t * pxTimer = ( timer_internal_t * ) pvTimerGetTimerID( xTimerHandle );\r
300     TickType_t xNextExpirationTime = xTimerGetExpiryTime( xTimerHandle ) - xTaskGetTickCount(),\r
301                xTimerExpirationPeriod = pxTimer->xTimerPeriod;\r
302 \r
303     /* Set it_value only if the timer is armed. Otherwise, set it to 0. */\r
304     if( xTimerIsTimerActive( xTimerHandle ) != pdFALSE )\r
305     {\r
306         value->it_value.tv_sec = ( time_t ) ( xNextExpirationTime / configTICK_RATE_HZ );\r
307         value->it_value.tv_nsec = ( long ) ( ( xNextExpirationTime % configTICK_RATE_HZ ) * NANOSECONDS_PER_TICK );\r
308     }\r
309     else\r
310     {\r
311         value->it_value.tv_sec = 0;\r
312         value->it_value.tv_nsec = 0;\r
313     }\r
314 \r
315     /* Set it_interval only if the timer is periodic. Otherwise, set it to 0. */\r
316     if( xTimerExpirationPeriod != portMAX_DELAY )\r
317     {\r
318         value->it_interval.tv_sec = ( time_t ) ( xTimerExpirationPeriod / configTICK_RATE_HZ );\r
319         value->it_interval.tv_nsec = ( long ) ( ( xTimerExpirationPeriod % configTICK_RATE_HZ ) * NANOSECONDS_PER_TICK );\r
320     }\r
321     else\r
322     {\r
323         value->it_interval.tv_sec = 0;\r
324         value->it_interval.tv_nsec = 0;\r
325     }\r
326 \r
327     return 0;\r
328 }\r
329 \r
330 /*-----------------------------------------------------------*/\r