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_pthread.c
\r
28 * @brief Implementation of thread functions in pthread.h
\r
31 /* C standard library includes. */
\r
35 /* FreeRTOS+POSIX includes. */
\r
36 #include "FreeRTOS_POSIX.h"
\r
37 #include "FreeRTOS_POSIX/errno.h"
\r
38 #include "FreeRTOS_POSIX/pthread.h"
\r
41 * @brief Thread attribute object.
\r
43 typedef struct pthread_attr_internal
\r
45 uint16_t usStackSize; /**< Stack size. */
\r
46 uint16_t usSchedPriorityDetachState; /**< Schedule priority 15 bits (LSB) Detach state: 1 bits (MSB) */
\r
47 } pthread_attr_internal_t;
\r
49 #define pthreadDETACH_STATE_MASK 0x8000
\r
50 #define pthreadSCHED_PRIORITY_MASK 0x7FFF
\r
51 #define pthreadDETACH_STATE_SHIFT 15
\r
52 #define pthreadGET_SCHED_PRIORITY( var ) ( ( var ) & ( pthreadSCHED_PRIORITY_MASK ) )
\r
53 #define pthreadIS_JOINABLE( var ) ( ( ( var ) & ( pthreadDETACH_STATE_MASK ) ) == pthreadDETACH_STATE_MASK )
\r
56 * @brief Thread object.
\r
58 typedef struct pthread_internal
\r
60 pthread_attr_internal_t xAttr; /**< Thread attributes. */
\r
61 void * ( *pvStartRoutine )( void * ); /**< Application thread function. */
\r
62 void * xTaskArg; /**< Arguments for application thread function. */
\r
63 TaskHandle_t xTaskHandle; /**< FreeRTOS task handle. */
\r
64 StaticSemaphore_t xJoinBarrier; /**< Synchronizes the two callers of pthread_join. */
\r
65 StaticSemaphore_t xJoinMutex; /**< Ensures that only one other thread may join this thread. */
\r
66 void * xReturn; /**< Return value of pvStartRoutine. */
\r
67 } pthread_internal_t;
\r
70 * @brief Terminates the calling thread.
\r
72 * For joinable threads, this function waits for pthread_join. Otherwise,
\r
73 * it deletes the thread and frees up resources used by the thread.
\r
75 * @return This function does not return.
\r
77 static void prvExitThread( void );
\r
80 * @brief Wrapper function for the user's thread routine.
\r
82 * This function is executed as a FreeRTOS task function.
\r
83 * @param[in] pxArg A pointer to a pthread_internal_t.
\r
87 static void prvRunThread( void * pxArg );
\r
90 * @brief Default pthread_attr_t.
\r
92 static const pthread_attr_internal_t xDefaultThreadAttributes =
\r
94 .usStackSize = PTHREAD_STACK_MIN,
\r
95 .usSchedPriorityDetachState = ( ( uint16_t ) tskIDLE_PRIORITY & pthreadSCHED_PRIORITY_MASK ) | ( PTHREAD_CREATE_JOINABLE << pthreadDETACH_STATE_SHIFT ),
\r
98 /*-----------------------------------------------------------*/
\r
100 static void prvExitThread( void )
\r
102 pthread_internal_t * pxThread = ( pthread_internal_t * ) pthread_self();
\r
104 /* If this thread is joinable, wait for a call to pthread_join. */
\r
105 if( pthreadIS_JOINABLE( pxThread->xAttr.usSchedPriorityDetachState ) )
\r
107 ( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &pxThread->xJoinBarrier );
\r
109 /* Suspend until the call to pthread_join. The caller of pthread_join
\r
110 * will perform cleanup. */
\r
111 vTaskSuspend( NULL );
\r
115 /* For a detached thread, perform cleanup of thread object. */
\r
116 vPortFree( pxThread );
\r
117 vTaskDelete( NULL );
\r
121 /*-----------------------------------------------------------*/
\r
123 static void prvRunThread( void * pxArg )
\r
125 pthread_internal_t * pxThread = ( pthread_internal_t * ) pxArg;
\r
127 /* Run the thread routine. */
\r
128 pxThread->xReturn = pxThread->pvStartRoutine( ( void * ) pxThread->xTaskArg );
\r
130 /* Exit once finished. This function does not return. */
\r
134 /*-----------------------------------------------------------*/
\r
136 int pthread_attr_destroy( pthread_attr_t * attr )
\r
143 /*-----------------------------------------------------------*/
\r
145 int pthread_attr_getdetachstate( const pthread_attr_t * attr,
\r
146 int * detachstate )
\r
148 pthread_attr_internal_t * pxAttr = ( pthread_attr_internal_t * ) ( attr );
\r
150 if( pthreadIS_JOINABLE( pxAttr->usSchedPriorityDetachState ) )
\r
152 *detachstate = PTHREAD_CREATE_JOINABLE;
\r
156 *detachstate = PTHREAD_CREATE_DETACHED;
\r
162 /*-----------------------------------------------------------*/
\r
164 int pthread_attr_getschedparam( const pthread_attr_t * attr,
\r
165 struct sched_param * param )
\r
167 pthread_attr_internal_t * pxAttr = ( pthread_attr_internal_t * ) ( attr );
\r
169 param->sched_priority = ( int ) ( pthreadGET_SCHED_PRIORITY( pxAttr->usSchedPriorityDetachState ) );
\r
174 /*-----------------------------------------------------------*/
\r
176 int pthread_attr_getstacksize( const pthread_attr_t * attr,
\r
177 size_t * stacksize )
\r
179 pthread_attr_internal_t * pxAttr = ( pthread_attr_internal_t * ) ( attr );
\r
181 *stacksize = ( size_t ) pxAttr->usStackSize;
\r
186 /*-----------------------------------------------------------*/
\r
188 int pthread_attr_init( pthread_attr_t * attr )
\r
190 /* Copy the default values into the new thread attributes object. */
\r
191 *( ( pthread_attr_internal_t * ) ( attr ) ) = xDefaultThreadAttributes;
\r
196 /*-----------------------------------------------------------*/
\r
198 int pthread_attr_setdetachstate( pthread_attr_t * attr,
\r
202 pthread_attr_internal_t * pxAttr = ( pthread_attr_internal_t * ) ( attr );
\r
204 if( ( detachstate != PTHREAD_CREATE_DETACHED ) && ( detachstate != PTHREAD_CREATE_JOINABLE ) )
\r
210 /* clear and then set msb bit to detachstate) */
\r
211 pxAttr->usSchedPriorityDetachState &= ~pthreadDETACH_STATE_MASK;
\r
212 pxAttr->usSchedPriorityDetachState |= ( ( uint16_t ) detachstate << pthreadDETACH_STATE_SHIFT );
\r
218 /*-----------------------------------------------------------*/
\r
220 int pthread_attr_setschedparam( pthread_attr_t * attr,
\r
221 const struct sched_param * param )
\r
224 pthread_attr_internal_t * pxAttr = ( pthread_attr_internal_t * ) ( attr );
\r
226 /* Check for NULL param. */
\r
227 if( param == NULL )
\r
232 /* Ensure that param.sched_priority is valid. */
\r
233 if( ( iStatus == 0 ) &&
\r
234 ( ( param->sched_priority > sched_get_priority_max( SCHED_OTHER ) ) ||
\r
235 ( param->sched_priority < 0 ) ) )
\r
240 /* Set the sched_param. */
\r
243 /* clear and then set 15 LSB to schedule priority) */
\r
244 pxAttr->usSchedPriorityDetachState &= ~pthreadSCHED_PRIORITY_MASK;
\r
245 pxAttr->usSchedPriorityDetachState |= ( ( uint16_t ) param->sched_priority );
\r
251 /*-----------------------------------------------------------*/
\r
253 int pthread_attr_setschedpolicy( pthread_attr_t * attr,
\r
256 /* Silence warnings about unused parameters. */
\r
263 /*-----------------------------------------------------------*/
\r
265 int pthread_attr_setstacksize( pthread_attr_t * attr,
\r
269 pthread_attr_internal_t * pxAttr = ( pthread_attr_internal_t * ) ( attr );
\r
271 if( stacksize < PTHREAD_STACK_MIN )
\r
277 pxAttr->usStackSize = ( uint16_t ) stacksize;
\r
283 /*-----------------------------------------------------------*/
\r
285 int pthread_create( pthread_t * thread,
\r
286 const pthread_attr_t * attr,
\r
287 void *( *startroutine )( void * ),
\r
291 pthread_internal_t * pxThread = NULL;
\r
292 struct sched_param xSchedParam = { .sched_priority = tskIDLE_PRIORITY };
\r
294 /* Allocate memory for new thread object. */
\r
295 pxThread = ( pthread_internal_t * ) pvPortMalloc( sizeof( pthread_internal_t ) );
\r
297 if( pxThread == NULL )
\r
305 /* No attributes given, use default attributes. */
\r
308 pxThread->xAttr = xDefaultThreadAttributes;
\r
310 /* Otherwise, use provided attributes. */
\r
313 pxThread->xAttr = *( ( pthread_attr_internal_t * ) ( attr ) );
\r
316 /* Get priority from attributes */
\r
317 xSchedParam.sched_priority = ( int ) pthreadGET_SCHED_PRIORITY( pxThread->xAttr.usSchedPriorityDetachState );
\r
319 /* Set argument and start routine. */
\r
320 pxThread->xTaskArg = arg;
\r
321 pxThread->pvStartRoutine = startroutine;
\r
323 /* If this thread is joinable, create the synchronization mechanisms for
\r
326 if( pthreadIS_JOINABLE( pxThread->xAttr.usSchedPriorityDetachState ) )
\r
328 /* These calls will not fail when their arguments aren't NULL. */
\r
329 ( void ) xSemaphoreCreateMutexStatic( &pxThread->xJoinMutex );
\r
330 ( void ) xSemaphoreCreateBinaryStatic( &pxThread->xJoinBarrier );
\r
336 /* Suspend all tasks to create a critical section. This ensures that
\r
337 * the new thread doesn't exit before a tag is assigned. */
\r
340 /* Create the FreeRTOS task that will run the pthread. */
\r
341 if( xTaskCreate( prvRunThread,
\r
342 posixconfigPTHREAD_TASK_NAME,
\r
343 ( uint16_t ) ( pxThread->xAttr.usStackSize / sizeof( StackType_t ) ),
\r
344 ( void * ) pxThread,
\r
345 xSchedParam.sched_priority,
\r
346 &pxThread->xTaskHandle ) != pdPASS )
\r
348 /* Task creation failed, no memory. */
\r
349 vPortFree( pxThread );
\r
354 /* Store the pointer to the thread object in the task tag. */
\r
355 vTaskSetApplicationTaskTag( pxThread->xTaskHandle, ( TaskHookFunction_t ) pxThread );
\r
357 /* Set the thread object for the user. */
\r
358 *thread = ( pthread_t ) pxThread;
\r
361 /* End the critical section. */
\r
368 /*-----------------------------------------------------------*/
\r
370 int pthread_getschedparam( pthread_t thread,
\r
372 struct sched_param * param )
\r
375 pthread_internal_t * pxThread = ( pthread_internal_t * ) thread;
\r
377 *policy = SCHED_OTHER;
\r
378 param->sched_priority = ( int ) pthreadGET_SCHED_PRIORITY( pxThread->xAttr.usSchedPriorityDetachState );
\r
383 /*-----------------------------------------------------------*/
\r
385 int pthread_equal( pthread_t t1,
\r
391 /*-----------------------------------------------------------*/
\r
393 void pthread_exit( void * value_ptr )
\r
395 pthread_internal_t * pxThread = ( pthread_internal_t * ) pthread_self();
\r
397 /* Set the return value. */
\r
398 pxThread->xReturn = value_ptr;
\r
400 /* Exit this thread. */
\r
404 /*-----------------------------------------------------------*/
\r
406 int pthread_join( pthread_t pthread,
\r
410 pthread_internal_t * pxThread = ( pthread_internal_t * ) pthread;
\r
412 /* Make sure pthread is joinable. Otherwise, this function would block
\r
413 * forever waiting for an unjoinable thread. */
\r
414 if( !pthreadIS_JOINABLE( pxThread->xAttr.usSchedPriorityDetachState ) )
\r
419 /* Only one thread may attempt to join another. Lock the join mutex
\r
420 * to prevent other threads from calling pthread_join on the same thread. */
\r
423 if( xSemaphoreTake( ( SemaphoreHandle_t ) &pxThread->xJoinMutex, 0 ) != pdPASS )
\r
425 /* Another thread has already joined the requested thread, which would
\r
426 * cause this thread to wait forever. */
\r
431 /* Attempting to join the calling thread would cause a deadlock. */
\r
434 if( pthread_equal( pthread_self(), pthread ) != 0 )
\r
442 /* Wait for the joining thread to finish. Because this call waits forever,
\r
443 * it should never fail. */
\r
444 ( void ) xSemaphoreTake( ( SemaphoreHandle_t ) &pxThread->xJoinBarrier, portMAX_DELAY );
\r
446 /* Create a critical section to clean up the joined thread. */
\r
449 /* Release xJoinBarrier and delete it. */
\r
450 ( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &pxThread->xJoinBarrier );
\r
451 vSemaphoreDelete( ( SemaphoreHandle_t ) &pxThread->xJoinBarrier );
\r
453 /* Release xJoinMutex and delete it. */
\r
454 ( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &pxThread->xJoinMutex );
\r
455 vSemaphoreDelete( ( SemaphoreHandle_t ) &pxThread->xJoinMutex );
\r
457 /* Delete the FreeRTOS task that ran the thread. */
\r
458 vTaskDelete( pxThread->xTaskHandle );
\r
460 /* Set the return value. */
\r
461 if( retval != NULL )
\r
463 *retval = pxThread->xReturn;
\r
466 /* Free the thread object. */
\r
467 vPortFree( pxThread );
\r
469 /* End the critical section. */
\r
476 /*-----------------------------------------------------------*/
\r
478 pthread_t pthread_self( void )
\r
480 /* Return a reference to this pthread object, which is stored in the
\r
481 * FreeRTOS task tag. */
\r
482 return ( pthread_t ) xTaskGetApplicationTaskTag( NULL );
\r
485 /*-----------------------------------------------------------*/
\r
487 int pthread_setschedparam( pthread_t thread,
\r
489 const struct sched_param * param )
\r
493 pthread_internal_t * pxThread = ( pthread_internal_t * ) thread;
\r
495 /* Silence compiler warnings about unused parameters. */
\r
498 /* Copy the given sched_param. */
\r
499 iStatus = pthread_attr_setschedparam( ( pthread_attr_t * ) &pxThread->xAttr, param );
\r
503 /* Change the priority of the FreeRTOS task. */
\r
504 vTaskPrioritySet( pxThread->xTaskHandle, param->sched_priority );
\r
510 /*-----------------------------------------------------------*/
\r