summaryrefslogtreecommitdiff
path: root/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_timer.c
diff options
context:
space:
mode:
Diffstat (limited to 'FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_timer.c')
-rw-r--r--FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_timer.c330
1 files changed, 330 insertions, 0 deletions
diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_timer.c b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_timer.c
new file mode 100644
index 000000000..05fbca873
--- /dev/null
+++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_timer.c
@@ -0,0 +1,330 @@
+/*
+ * Amazon FreeRTOS POSIX V1.1.0
+ * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * http://aws.amazon.com/freertos
+ * http://www.FreeRTOS.org
+ */
+
+/**
+ * @file FreeRTOS_POSIX_timer.c
+ * @brief Implementation of timer functions in time.h
+ */
+
+/* C standard library includes. */
+#include <stddef.h>
+
+/* FreeRTOS+POSIX includes. */
+#include "FreeRTOS_POSIX.h"
+#include "FreeRTOS_POSIX/errno.h"
+#include "FreeRTOS_POSIX/pthread.h"
+#include "FreeRTOS_POSIX/signal.h"
+#include "FreeRTOS_POSIX/time.h"
+#include "FreeRTOS_POSIX/utils.h"
+
+/* FreeRTOS timer include. */
+#include "timers.h"
+
+/* Timespec zero check macros. */
+#define TIMESPEC_IS_ZERO( xTimespec ) ( xTimespec.tv_sec == 0 && xTimespec.tv_nsec == 0 ) /**< Check for 0. */
+#define TIMESPEC_IS_NOT_ZERO( xTimespec ) ( !( TIMESPEC_IS_ZERO( xTimespec ) ) ) /**< Check for not 0. */
+
+/**
+ * @brief Internal timer structure.
+ */
+typedef struct timer_internal
+{
+ StaticTimer_t xTimerBuffer; /**< Memory that holds the FreeRTOS timer. */
+ struct sigevent xTimerEvent; /**< What to do when this timer expires. */
+ TickType_t xTimerPeriod; /**< Period of this timer. */
+} timer_internal_t;
+
+/*-----------------------------------------------------------*/
+
+void prvTimerCallback( TimerHandle_t xTimerHandle )
+{
+ timer_internal_t * pxTimer = ( timer_internal_t * ) pvTimerGetTimerID( xTimerHandle );
+ pthread_t xTimerNotificationThread;
+
+ /* The value of the timer ID, set in timer_create, should not be NULL. */
+ configASSERT( pxTimer != NULL );
+
+ /* A value of SIGEV_SIGNAL isn't supported and should not have been successfully
+ * set. */
+ configASSERT( pxTimer->xTimerEvent.sigev_notify != SIGEV_SIGNAL );
+
+ /* Update the timer period, which may need to be set to an it_interval
+ * argument. This call should not block. */
+ if( pxTimer->xTimerPeriod > 0 )
+ {
+ xTimerChangePeriod( xTimerHandle, pxTimer->xTimerPeriod, 0 );
+ }
+
+ /* Create the timer notification thread if requested. */
+ if( pxTimer->xTimerEvent.sigev_notify == SIGEV_THREAD )
+ {
+ /* if the user has provided thread attributes, create a thread
+ * with the provided attributes. Otherwise dispatch callback directly */
+ if( pxTimer->xTimerEvent.sigev_notify_attributes == NULL )
+ {
+ ( *pxTimer->xTimerEvent.sigev_notify_function )( pxTimer->xTimerEvent.sigev_value );
+ }
+ else
+ {
+ ( void ) pthread_create( &xTimerNotificationThread,
+ pxTimer->xTimerEvent.sigev_notify_attributes,
+ ( void * ( * )( void * ) )pxTimer->xTimerEvent.sigev_notify_function,
+ pxTimer->xTimerEvent.sigev_value.sival_ptr );
+ }
+ }
+}
+
+/*-----------------------------------------------------------*/
+
+int timer_create( clockid_t clockid,
+ struct sigevent * evp,
+ timer_t * timerid )
+{
+ int iStatus = 0;
+ timer_internal_t * pxTimer = NULL;
+
+ /* Silence warnings about unused parameters. */
+ ( void ) clockid;
+
+ /* POSIX specifies that when evp is NULL, the behavior shall be as is
+ * sigev_notify is SIGEV_SIGNAL. SIGEV_SIGNAL is currently not supported. */
+ if( ( evp == NULL ) || ( evp->sigev_notify == SIGEV_SIGNAL ) )
+ {
+ errno = ENOTSUP;
+ iStatus = -1;
+ }
+
+ /* Allocate memory for a new timer object. */
+ if( iStatus == 0 )
+ {
+ pxTimer = pvPortMalloc( sizeof( timer_internal_t ) );
+
+ if( pxTimer == NULL )
+ {
+ errno = EAGAIN;
+ iStatus = -1;
+ }
+ }
+
+ if( iStatus == 0 )
+ {
+ /* Copy the event notification structure and set the current timer period. */
+ pxTimer->xTimerEvent = *evp;
+ pxTimer->xTimerPeriod = 0;
+
+ /* Create a new FreeRTOS timer. This call will not fail because the
+ * memory for it has already been allocated, so the output parameter is
+ * also set. */
+ *timerid = ( timer_t ) xTimerCreateStatic( posixconfigTIMER_NAME, /* Timer name. */
+ portMAX_DELAY, /* Initial timer period. Timers are created disarmed. */
+ pdFALSE, /* Don't auto-reload timer. */
+ ( void * ) pxTimer, /* Timer id. */
+ prvTimerCallback, /* Timer expiration callback. */
+ &pxTimer->xTimerBuffer ); /* Pre-allocated memory for timer. */
+ }
+
+ return iStatus;
+}
+
+/*-----------------------------------------------------------*/
+
+int timer_delete( timer_t timerid )
+{
+ TimerHandle_t xTimerHandle = timerid;
+ timer_internal_t * pxTimer = ( timer_internal_t * ) pvTimerGetTimerID( xTimerHandle );
+
+ /* The value of the timer ID, set in timer_create, should not be NULL. */
+ configASSERT( pxTimer != NULL );
+
+ /* Stop the FreeRTOS timer. Because the timer is statically allocated, no call
+ * to xTimerDelete is necessary. The timer is stopped so that it's not referenced
+ * anywhere. xTimerStop will not fail when it has unlimited block time. */
+ ( void ) xTimerStop( xTimerHandle, portMAX_DELAY );
+
+ /* Wait until the timer stop command is processed. */
+ while( xTimerIsTimerActive( xTimerHandle ) == pdTRUE )
+ {
+ vTaskDelay( 1 );
+ }
+
+ /* Free the memory in use by the timer. */
+ vPortFree( pxTimer );
+
+ return 0;
+}
+
+/*-----------------------------------------------------------*/
+
+int timer_getoverrun( timer_t timerid )
+{
+ /* Silence warnings about unused parameters. */
+ ( void ) timerid;
+
+ return 0;
+}
+
+/*-----------------------------------------------------------*/
+
+int timer_settime( timer_t timerid,
+ int flags,
+ const struct itimerspec * value,
+ struct itimerspec * ovalue )
+{
+ int iStatus = 0;
+ TimerHandle_t xTimerHandle = timerid;
+ timer_internal_t * pxTimer = ( timer_internal_t * ) pvTimerGetTimerID( xTimerHandle );
+ TickType_t xNextTimerExpiration = 0, xTimerExpirationPeriod = 0;
+
+ /* Validate the value argument, but only if the timer isn't being disarmed. */
+ if( TIMESPEC_IS_NOT_ZERO( value->it_value ) )
+ {
+ if( ( UTILS_ValidateTimespec( &value->it_interval ) == false ) ||
+ ( UTILS_ValidateTimespec( &value->it_value ) == false ) )
+ {
+ errno = EINVAL;
+ iStatus = -1;
+ }
+ }
+
+ /* Set ovalue, if given. */
+ if( ovalue != NULL )
+ {
+ ( void ) timer_gettime( timerid, ovalue );
+ }
+
+ /* Stop the timer if it's currently active. */
+ if( ( iStatus == 0 ) && xTimerIsTimerActive( xTimerHandle ) )
+ {
+ ( void ) xTimerStop( xTimerHandle, portMAX_DELAY );
+ }
+
+ /* Only restart the timer if it_value is not zero. */
+ if( ( iStatus == 0 ) && TIMESPEC_IS_NOT_ZERO( value->it_value ) )
+ {
+ /* Convert it_interval to ticks, but only if it_interval is not 0. If
+ * it_interval is 0, then the timer is not periodic. */
+ if( TIMESPEC_IS_NOT_ZERO( value->it_interval ) )
+ {
+ ( void ) UTILS_TimespecToTicks( &value->it_interval, &xTimerExpirationPeriod );
+ }
+
+ /* Set the new timer period. A non-periodic timer will have its period set
+ * to portMAX_DELAY. */
+ pxTimer->xTimerPeriod = xTimerExpirationPeriod;
+
+ /* Convert it_value to ticks, but only if it_value is not 0. If it_value
+ * is 0, then the timer will remain disarmed. */
+ if( TIMESPEC_IS_NOT_ZERO( value->it_value ) )
+ {
+ /* Absolute timeout. */
+ if( ( flags & TIMER_ABSTIME ) == TIMER_ABSTIME )
+ {
+ struct timespec xCurrentTime = { 0 };
+
+ /* Get current time */
+ if( clock_gettime( CLOCK_REALTIME, &xCurrentTime ) != 0 )
+ {
+ iStatus = EINVAL;
+ }
+ else
+ {
+ iStatus = UTILS_AbsoluteTimespecToDeltaTicks( &value->it_value, &xCurrentTime, &xNextTimerExpiration );
+ }
+
+ /* Make sure xNextTimerExpiration is zero in case we got negative time difference */
+ if( iStatus != 0 )
+ {
+ xNextTimerExpiration = 0;
+
+ if( iStatus == ETIMEDOUT )
+ {
+ /* Set Status to 0 as absolute time is past is treated as expiry but not an error */
+ iStatus = 0;
+ }
+ }
+ }
+ /* Relative timeout. */
+ else
+ {
+ ( void ) UTILS_TimespecToTicks( &value->it_value, &xNextTimerExpiration );
+ }
+ }
+
+ /* If xNextTimerExpiration is still 0, that means that it_value specified
+ * an absolute timeout in the past. Per POSIX spec, a notification should be
+ * triggered immediately. */
+ if( xNextTimerExpiration == 0 )
+ {
+ prvTimerCallback( xTimerHandle );
+ }
+ else
+ {
+ /* Set the timer to expire at the it_value, then start it. */
+ ( void ) xTimerChangePeriod( xTimerHandle, xNextTimerExpiration, portMAX_DELAY );
+ ( void ) xTimerStart( xTimerHandle, xNextTimerExpiration );
+ }
+ }
+
+ return iStatus;
+}
+
+/*-----------------------------------------------------------*/
+
+int timer_gettime( timer_t timerid,
+ struct itimerspec * value )
+{
+ TimerHandle_t xTimerHandle = timerid;
+ timer_internal_t * pxTimer = ( timer_internal_t * ) pvTimerGetTimerID( xTimerHandle );
+ TickType_t xNextExpirationTime = xTimerGetExpiryTime( xTimerHandle ) - xTaskGetTickCount(),
+ xTimerExpirationPeriod = pxTimer->xTimerPeriod;
+
+ /* Set it_value only if the timer is armed. Otherwise, set it to 0. */
+ if( xTimerIsTimerActive( xTimerHandle ) != pdFALSE )
+ {
+ value->it_value.tv_sec = ( time_t ) ( xNextExpirationTime / configTICK_RATE_HZ );
+ value->it_value.tv_nsec = ( long ) ( ( xNextExpirationTime % configTICK_RATE_HZ ) * NANOSECONDS_PER_TICK );
+ }
+ else
+ {
+ value->it_value.tv_sec = 0;
+ value->it_value.tv_nsec = 0;
+ }
+
+ /* Set it_interval only if the timer is periodic. Otherwise, set it to 0. */
+ if( xTimerExpirationPeriod != portMAX_DELAY )
+ {
+ value->it_interval.tv_sec = ( time_t ) ( xTimerExpirationPeriod / configTICK_RATE_HZ );
+ value->it_interval.tv_nsec = ( long ) ( ( xTimerExpirationPeriod % configTICK_RATE_HZ ) * NANOSECONDS_PER_TICK );
+ }
+ else
+ {
+ value->it_interval.tv_sec = 0;
+ value->it_interval.tv_nsec = 0;
+ }
+
+ return 0;
+}
+
+/*-----------------------------------------------------------*/