diff options
| author | Aditya Naik | 2020-08-03 14:42:06 -0400 |
|---|---|---|
| committer | Aditya Naik | 2020-08-03 14:42:06 -0400 |
| commit | 11a52e4e88bcad1e6bddcf02f78e1cc5eaaec508 (patch) | |
| tree | d7f725c30e618994a0650607ede73ab3efc72c67 /lib/freertos-posix/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_pthread.c | |
| parent | 81b3f3d5336eab67e8eb21bb4011e552f3895a4e (diff) | |
RTOS skeleton with (UNIX) POSIX calls. Reorg of stream files
Diffstat (limited to 'lib/freertos-posix/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_pthread.c')
| -rwxr-xr-x | lib/freertos-posix/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_pthread.c | 510 |
1 files changed, 510 insertions, 0 deletions
diff --git a/lib/freertos-posix/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_pthread.c b/lib/freertos-posix/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_pthread.c new file mode 100755 index 0000000..f34e9ec --- /dev/null +++ b/lib/freertos-posix/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_pthread.c @@ -0,0 +1,510 @@ +/* + * 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_pthread.c + * @brief Implementation of thread functions in pthread.h + */ + +/* C standard library includes. */ +#include <stddef.h> +#include <string.h> + +/* FreeRTOS+POSIX includes. */ +#include "FreeRTOS_POSIX.h" +#include "FreeRTOS_POSIX/errno.h" +#include "FreeRTOS_POSIX/pthread.h" + +/** + * @brief Thread attribute object. + */ +typedef struct pthread_attr_internal +{ + uint16_t usStackSize; /**< Stack size. */ + uint16_t usSchedPriorityDetachState; /**< Schedule priority 15 bits (LSB) Detach state: 1 bits (MSB) */ +} pthread_attr_internal_t; + +#define pthreadDETACH_STATE_MASK 0x8000 +#define pthreadSCHED_PRIORITY_MASK 0x7FFF +#define pthreadDETACH_STATE_SHIFT 15 +#define pthreadGET_SCHED_PRIORITY( var ) ( ( var ) & ( pthreadSCHED_PRIORITY_MASK ) ) +#define pthreadIS_JOINABLE( var ) ( ( ( var ) & ( pthreadDETACH_STATE_MASK ) ) == pthreadDETACH_STATE_MASK ) + +/** + * @brief Thread object. + */ +typedef struct pthread_internal +{ + pthread_attr_internal_t xAttr; /**< Thread attributes. */ + void * ( *pvStartRoutine )( void * ); /**< Application thread function. */ + void * xTaskArg; /**< Arguments for application thread function. */ + TaskHandle_t xTaskHandle; /**< FreeRTOS task handle. */ + StaticSemaphore_t xJoinBarrier; /**< Synchronizes the two callers of pthread_join. */ + StaticSemaphore_t xJoinMutex; /**< Ensures that only one other thread may join this thread. */ + void * xReturn; /**< Return value of pvStartRoutine. */ +} pthread_internal_t; + +/** + * @brief Terminates the calling thread. + * + * For joinable threads, this function waits for pthread_join. Otherwise, + * it deletes the thread and frees up resources used by the thread. + * + * @return This function does not return. + */ +static void prvExitThread( void ); + +/** + * @brief Wrapper function for the user's thread routine. + * + * This function is executed as a FreeRTOS task function. + * @param[in] pxArg A pointer to a pthread_internal_t. + * + * @return nothing + */ +static void prvRunThread( void * pxArg ); + +/** + * @brief Default pthread_attr_t. + */ +static const pthread_attr_internal_t xDefaultThreadAttributes = +{ + .usStackSize = PTHREAD_STACK_MIN, + .usSchedPriorityDetachState = ( ( uint16_t ) tskIDLE_PRIORITY & pthreadSCHED_PRIORITY_MASK ) | ( PTHREAD_CREATE_JOINABLE << pthreadDETACH_STATE_SHIFT ), +}; + +/*-----------------------------------------------------------*/ + +static void prvExitThread( void ) +{ + pthread_internal_t * pxThread = ( pthread_internal_t * ) pthread_self(); + + /* If this thread is joinable, wait for a call to pthread_join. */ + if( pthreadIS_JOINABLE( pxThread->xAttr.usSchedPriorityDetachState ) ) + { + ( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &pxThread->xJoinBarrier ); + + /* Suspend until the call to pthread_join. The caller of pthread_join + * will perform cleanup. */ + vTaskSuspend( NULL ); + } + else + { + /* For a detached thread, perform cleanup of thread object. */ + vPortFree( pxThread ); + vTaskDelete( NULL ); + } +} + +/*-----------------------------------------------------------*/ + +static void prvRunThread( void * pxArg ) +{ + pthread_internal_t * pxThread = ( pthread_internal_t * ) pxArg; + + /* Run the thread routine. */ + pxThread->xReturn = pxThread->pvStartRoutine( ( void * ) pxThread->xTaskArg ); + + /* Exit once finished. This function does not return. */ + prvExitThread(); +} + +/*-----------------------------------------------------------*/ + +int pthread_attr_destroy( pthread_attr_t * attr ) +{ + ( void ) attr; + + return 0; +} + +/*-----------------------------------------------------------*/ + +int pthread_attr_getdetachstate( const pthread_attr_t * attr, + int * detachstate ) +{ + pthread_attr_internal_t * pxAttr = ( pthread_attr_internal_t * ) ( attr ); + + if( pthreadIS_JOINABLE( pxAttr->usSchedPriorityDetachState ) ) + { + *detachstate = PTHREAD_CREATE_JOINABLE; + } + else + { + *detachstate = PTHREAD_CREATE_DETACHED; + } + + return 0; +} + +/*-----------------------------------------------------------*/ + +int pthread_attr_getschedparam( const pthread_attr_t * attr, + struct sched_param * param ) +{ + pthread_attr_internal_t * pxAttr = ( pthread_attr_internal_t * ) ( attr ); + + param->sched_priority = ( int ) ( pthreadGET_SCHED_PRIORITY( pxAttr->usSchedPriorityDetachState ) ); + + return 0; +} + +/*-----------------------------------------------------------*/ + +int pthread_attr_getstacksize( const pthread_attr_t * attr, + size_t * stacksize ) +{ + pthread_attr_internal_t * pxAttr = ( pthread_attr_internal_t * ) ( attr ); + + *stacksize = ( size_t ) pxAttr->usStackSize; + + return 0; +} + +/*-----------------------------------------------------------*/ + +int pthread_attr_init( pthread_attr_t * attr ) +{ + /* Copy the default values into the new thread attributes object. */ + *( ( pthread_attr_internal_t * ) ( attr ) ) = xDefaultThreadAttributes; + + return 0; +} + +/*-----------------------------------------------------------*/ + +int pthread_attr_setdetachstate( pthread_attr_t * attr, + int detachstate ) +{ + int iStatus = 0; + pthread_attr_internal_t * pxAttr = ( pthread_attr_internal_t * ) ( attr ); + + if( ( detachstate != PTHREAD_CREATE_DETACHED ) && ( detachstate != PTHREAD_CREATE_JOINABLE ) ) + { + iStatus = EINVAL; + } + else + { + /* clear and then set msb bit to detachstate) */ + pxAttr->usSchedPriorityDetachState &= ~pthreadDETACH_STATE_MASK; + pxAttr->usSchedPriorityDetachState |= ( ( uint16_t ) detachstate << pthreadDETACH_STATE_SHIFT ); + } + + return iStatus; +} + +/*-----------------------------------------------------------*/ + +int pthread_attr_setschedparam( pthread_attr_t * attr, + const struct sched_param * param ) +{ + int iStatus = 0; + pthread_attr_internal_t * pxAttr = ( pthread_attr_internal_t * ) ( attr ); + + /* Check for NULL param. */ + if( param == NULL ) + { + iStatus = EINVAL; + } + + /* Ensure that param.sched_priority is valid. */ + if( ( iStatus == 0 ) && + ( ( param->sched_priority > sched_get_priority_max( SCHED_OTHER ) ) || + ( param->sched_priority < 0 ) ) ) + { + iStatus = ENOTSUP; + } + + /* Set the sched_param. */ + if( iStatus == 0 ) + { + /* clear and then set 15 LSB to schedule priority) */ + pxAttr->usSchedPriorityDetachState &= ~pthreadSCHED_PRIORITY_MASK; + pxAttr->usSchedPriorityDetachState |= ( ( uint16_t ) param->sched_priority ); + } + + return iStatus; +} + +/*-----------------------------------------------------------*/ + +int pthread_attr_setschedpolicy( pthread_attr_t * attr, + int policy ) +{ + /* Silence warnings about unused parameters. */ + ( void ) attr; + ( void ) policy; + + return 0; +} + +/*-----------------------------------------------------------*/ + +int pthread_attr_setstacksize( pthread_attr_t * attr, + size_t stacksize ) +{ + int iStatus = 0; + pthread_attr_internal_t * pxAttr = ( pthread_attr_internal_t * ) ( attr ); + + if( stacksize < PTHREAD_STACK_MIN ) + { + iStatus = EINVAL; + } + else + { + pxAttr->usStackSize = ( uint16_t ) stacksize; + } + + return iStatus; +} + +/*-----------------------------------------------------------*/ + +int pthread_create( pthread_t * thread, + const pthread_attr_t * attr, + void *( *startroutine )( void * ), + void * arg ) +{ + int iStatus = 0; + pthread_internal_t * pxThread = NULL; + struct sched_param xSchedParam = { .sched_priority = tskIDLE_PRIORITY }; + + /* Allocate memory for new thread object. */ + pxThread = ( pthread_internal_t * ) pvPortMalloc( sizeof( pthread_internal_t ) ); + + if( pxThread == NULL ) + { + /* No memory. */ + iStatus = EAGAIN; + } + + if( iStatus == 0 ) + { + /* No attributes given, use default attributes. */ + if( attr == NULL ) + { + pxThread->xAttr = xDefaultThreadAttributes; + } + /* Otherwise, use provided attributes. */ + else + { + pxThread->xAttr = *( ( pthread_attr_internal_t * ) ( attr ) ); + } + + /* Get priority from attributes */ + xSchedParam.sched_priority = ( int ) pthreadGET_SCHED_PRIORITY( pxThread->xAttr.usSchedPriorityDetachState ); + + /* Set argument and start routine. */ + pxThread->xTaskArg = arg; + pxThread->pvStartRoutine = startroutine; + + /* If this thread is joinable, create the synchronization mechanisms for + * pthread_join. */ + + if( pthreadIS_JOINABLE( pxThread->xAttr.usSchedPriorityDetachState ) ) + { + /* These calls will not fail when their arguments aren't NULL. */ + ( void ) xSemaphoreCreateMutexStatic( &pxThread->xJoinMutex ); + ( void ) xSemaphoreCreateBinaryStatic( &pxThread->xJoinBarrier ); + } + } + + if( iStatus == 0 ) + { + /* Suspend all tasks to create a critical section. This ensures that + * the new thread doesn't exit before a tag is assigned. */ + vTaskSuspendAll(); + + /* Create the FreeRTOS task that will run the pthread. */ + if( xTaskCreate( prvRunThread, + posixconfigPTHREAD_TASK_NAME, + ( uint16_t ) ( pxThread->xAttr.usStackSize / sizeof( StackType_t ) ), + ( void * ) pxThread, + xSchedParam.sched_priority, + &pxThread->xTaskHandle ) != pdPASS ) + { + /* Task creation failed, no memory. */ + vPortFree( pxThread ); + iStatus = EAGAIN; + } + else + { + /* Store the pointer to the thread object in the task tag. */ + vTaskSetApplicationTaskTag( pxThread->xTaskHandle, ( TaskHookFunction_t ) pxThread ); + + /* Set the thread object for the user. */ + *thread = ( pthread_t ) pxThread; + } + + /* End the critical section. */ + xTaskResumeAll(); + } + + return iStatus; +} + +/*-----------------------------------------------------------*/ + +int pthread_getschedparam( pthread_t thread, + int * policy, + struct sched_param * param ) +{ + int iStatus = 0; + pthread_internal_t * pxThread = ( pthread_internal_t * ) thread; + + *policy = SCHED_OTHER; + param->sched_priority = ( int ) pthreadGET_SCHED_PRIORITY( pxThread->xAttr.usSchedPriorityDetachState ); + + return iStatus; +} + +/*-----------------------------------------------------------*/ + +int pthread_equal( pthread_t t1, + pthread_t t2 ) +{ + return t1 == t2; +} + +/*-----------------------------------------------------------*/ + +void pthread_exit( void * value_ptr ) +{ + pthread_internal_t * pxThread = ( pthread_internal_t * ) pthread_self(); + + /* Set the return value. */ + pxThread->xReturn = value_ptr; + + /* Exit this thread. */ + prvExitThread(); +} + +/*-----------------------------------------------------------*/ + +int pthread_join( pthread_t pthread, + void ** retval ) +{ + int iStatus = 0; + pthread_internal_t * pxThread = ( pthread_internal_t * ) pthread; + + /* Make sure pthread is joinable. Otherwise, this function would block + * forever waiting for an unjoinable thread. */ + if( !pthreadIS_JOINABLE( pxThread->xAttr.usSchedPriorityDetachState ) ) + { + iStatus = EDEADLK; + } + + /* Only one thread may attempt to join another. Lock the join mutex + * to prevent other threads from calling pthread_join on the same thread. */ + if( iStatus == 0 ) + { + if( xSemaphoreTake( ( SemaphoreHandle_t ) &pxThread->xJoinMutex, 0 ) != pdPASS ) + { + /* Another thread has already joined the requested thread, which would + * cause this thread to wait forever. */ + iStatus = EDEADLK; + } + } + + /* Attempting to join the calling thread would cause a deadlock. */ + if( iStatus == 0 ) + { + if( pthread_equal( pthread_self(), pthread ) != 0 ) + { + iStatus = EDEADLK; + } + } + + if( iStatus == 0 ) + { + /* Wait for the joining thread to finish. Because this call waits forever, + * it should never fail. */ + ( void ) xSemaphoreTake( ( SemaphoreHandle_t ) &pxThread->xJoinBarrier, portMAX_DELAY ); + + /* Create a critical section to clean up the joined thread. */ + vTaskSuspendAll(); + + /* Release xJoinBarrier and delete it. */ + ( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &pxThread->xJoinBarrier ); + vSemaphoreDelete( ( SemaphoreHandle_t ) &pxThread->xJoinBarrier ); + + /* Release xJoinMutex and delete it. */ + ( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &pxThread->xJoinMutex ); + vSemaphoreDelete( ( SemaphoreHandle_t ) &pxThread->xJoinMutex ); + + /* Delete the FreeRTOS task that ran the thread. */ + vTaskDelete( pxThread->xTaskHandle ); + + /* Set the return value. */ + if( retval != NULL ) + { + *retval = pxThread->xReturn; + } + + /* Free the thread object. */ + vPortFree( pxThread ); + + /* End the critical section. */ + xTaskResumeAll(); + } + + return iStatus; +} + +/*-----------------------------------------------------------*/ + +pthread_t pthread_self( void ) +{ + /* Return a reference to this pthread object, which is stored in the + * FreeRTOS task tag. */ + return ( pthread_t ) xTaskGetApplicationTaskTag( NULL ); +} + +/*-----------------------------------------------------------*/ + +int pthread_setschedparam( pthread_t thread, + int policy, + const struct sched_param * param ) +{ + int iStatus = 0; + + pthread_internal_t * pxThread = ( pthread_internal_t * ) thread; + + /* Silence compiler warnings about unused parameters. */ + ( void ) policy; + + /* Copy the given sched_param. */ + iStatus = pthread_attr_setschedparam( ( pthread_attr_t * ) &pxThread->xAttr, param ); + + if( iStatus == 0 ) + { + /* Change the priority of the FreeRTOS task. */ + vTaskPrioritySet( pxThread->xTaskHandle, param->sched_priority ); + } + + return iStatus; +} + +/*-----------------------------------------------------------*/ |
