2 * Amazon FreeRTOS POSIX V1.1.0
\r
3 * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
\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
12 * The above copyright notice and this permission notice shall be included in all
\r
13 * copies or substantial portions of the Software.
\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
22 * http://aws.amazon.com/freertos
\r
23 * http://www.FreeRTOS.org
\r
27 * @file FreeRTOS_POSIX_timer.c
\r
28 * @brief Implementation of timer functions in time.h
\r
31 /* C standard library includes. */
\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
42 /* FreeRTOS timer include. */
\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
50 * @brief Internal timer structure.
\r
52 typedef struct timer_internal
\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
59 /*-----------------------------------------------------------*/
\r
61 void prvTimerCallback( TimerHandle_t xTimerHandle )
\r
63 timer_internal_t * pxTimer = ( timer_internal_t * ) pvTimerGetTimerID( xTimerHandle );
\r
64 pthread_t xTimerNotificationThread;
\r
66 /* The value of the timer ID, set in timer_create, should not be NULL. */
\r
67 configASSERT( pxTimer != NULL );
\r
69 /* A value of SIGEV_SIGNAL isn't supported and should not have been successfully
\r
71 configASSERT( pxTimer->xTimerEvent.sigev_notify != SIGEV_SIGNAL );
\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
77 xTimerChangePeriod( xTimerHandle, pxTimer->xTimerPeriod, 0 );
\r
80 /* Create the timer notification thread if requested. */
\r
81 if( pxTimer->xTimerEvent.sigev_notify == SIGEV_THREAD )
\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
87 ( *pxTimer->xTimerEvent.sigev_notify_function )( pxTimer->xTimerEvent.sigev_value );
\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
99 /*-----------------------------------------------------------*/
\r
101 int timer_create( clockid_t clockid,
\r
102 struct sigevent * evp,
\r
103 timer_t * timerid )
\r
106 timer_internal_t * pxTimer = NULL;
\r
108 /* Silence warnings about unused parameters. */
\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
119 /* Allocate memory for a new timer object. */
\r
122 pxTimer = pvPortMalloc( sizeof( timer_internal_t ) );
\r
124 if( pxTimer == NULL )
\r
133 /* Copy the event notification structure and set the current timer period. */
\r
134 pxTimer->xTimerEvent = *evp;
\r
135 pxTimer->xTimerPeriod = 0;
\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
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
151 /*-----------------------------------------------------------*/
\r
153 int timer_delete( timer_t timerid )
\r
155 TimerHandle_t xTimerHandle = timerid;
\r
156 timer_internal_t * pxTimer = ( timer_internal_t * ) pvTimerGetTimerID( xTimerHandle );
\r
158 /* The value of the timer ID, set in timer_create, should not be NULL. */
\r
159 configASSERT( pxTimer != NULL );
\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
166 /* Wait until the timer stop command is processed. */
\r
167 while( xTimerIsTimerActive( xTimerHandle ) == pdTRUE )
\r
172 /* Free the memory in use by the timer. */
\r
173 vPortFree( pxTimer );
\r
178 /*-----------------------------------------------------------*/
\r
180 int timer_getoverrun( timer_t timerid )
\r
182 /* Silence warnings about unused parameters. */
\r
188 /*-----------------------------------------------------------*/
\r
190 int timer_settime( timer_t timerid,
\r
192 const struct itimerspec * value,
\r
193 struct itimerspec * ovalue )
\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
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
203 if( ( UTILS_ValidateTimespec( &value->it_interval ) == false ) ||
\r
204 ( UTILS_ValidateTimespec( &value->it_value ) == false ) )
\r
211 /* Set ovalue, if given. */
\r
212 if( ovalue != NULL )
\r
214 ( void ) timer_gettime( timerid, ovalue );
\r
217 /* Stop the timer if it's currently active. */
\r
218 if( ( iStatus == 0 ) && xTimerIsTimerActive( xTimerHandle ) )
\r
220 ( void ) xTimerStop( xTimerHandle, portMAX_DELAY );
\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
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
230 ( void ) UTILS_TimespecToTicks( &value->it_interval, &xTimerExpirationPeriod );
\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
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
241 /* Absolute timeout. */
\r
242 if( ( flags & TIMER_ABSTIME ) == TIMER_ABSTIME )
\r
244 struct timespec xCurrentTime = { 0 };
\r
246 /* Get current time */
\r
247 if( clock_gettime( CLOCK_REALTIME, &xCurrentTime ) != 0 )
\r
253 iStatus = UTILS_AbsoluteTimespecToDeltaTicks( &value->it_value, &xCurrentTime, &xNextTimerExpiration );
\r
256 /* Make sure xNextTimerExpiration is zero in case we got negative time difference */
\r
259 xNextTimerExpiration = 0;
\r
261 if( iStatus == ETIMEDOUT )
\r
263 /* Set Status to 0 as absolute time is past is treated as expiry but not an error */
\r
268 /* Relative timeout. */
\r
271 ( void ) UTILS_TimespecToTicks( &value->it_value, &xNextTimerExpiration );
\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
280 prvTimerCallback( xTimerHandle );
\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
293 /*-----------------------------------------------------------*/
\r
295 int timer_gettime( timer_t timerid,
\r
296 struct itimerspec * value )
\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
303 /* Set it_value only if the timer is armed. Otherwise, set it to 0. */
\r
304 if( xTimerIsTimerActive( xTimerHandle ) != pdFALSE )
\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
311 value->it_value.tv_sec = 0;
\r
312 value->it_value.tv_nsec = 0;
\r
315 /* Set it_interval only if the timer is periodic. Otherwise, set it to 0. */
\r
316 if( xTimerExpirationPeriod != portMAX_DELAY )
\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
323 value->it_interval.tv_sec = 0;
\r
324 value->it_interval.tv_nsec = 0;
\r
330 /*-----------------------------------------------------------*/
\r