summaryrefslogtreecommitdiff
path: root/lib/freertos-posix/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_pthread.c
diff options
context:
space:
mode:
authorAditya Naik2020-08-03 14:42:06 -0400
committerAditya Naik2020-08-03 14:42:06 -0400
commit11a52e4e88bcad1e6bddcf02f78e1cc5eaaec508 (patch)
treed7f725c30e618994a0650607ede73ab3efc72c67 /lib/freertos-posix/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_pthread.c
parent81b3f3d5336eab67e8eb21bb4011e552f3895a4e (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-xlib/freertos-posix/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_pthread.c510
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;
+}
+
+/*-----------------------------------------------------------*/