]> git.sur5r.net Git - freertos/blob - FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_pthread.c
Add the Labs projects provided in the V10.2.1_191129 zip file.
[freertos] / FreeRTOS-Labs / Demo / FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator / lib / FreeRTOS-Plus-POSIX / source / FreeRTOS_POSIX_pthread.c
1 /*\r
2  * Amazon FreeRTOS POSIX V1.1.0\r
3  * Copyright (C) 2018 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
4  *\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
11  *\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
14  *\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
21  *\r
22  * http://aws.amazon.com/freertos\r
23  * http://www.FreeRTOS.org\r
24  */\r
25 \r
26 /**\r
27  * @file FreeRTOS_POSIX_pthread.c\r
28  * @brief Implementation of thread functions in pthread.h\r
29  */\r
30 \r
31 /* C standard library includes. */\r
32 #include <stddef.h>\r
33 #include <string.h>\r
34 \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
39 \r
40 /**\r
41  * @brief Thread attribute object.\r
42  */\r
43 typedef struct pthread_attr_internal\r
44 {\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
48 \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
54 \r
55 /**\r
56  * @brief Thread object.\r
57  */\r
58 typedef struct pthread_internal\r
59 {\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
68 \r
69 /**\r
70  * @brief Terminates the calling thread.\r
71  *\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
74  *\r
75  * @return This function does not return.\r
76  */\r
77 static void prvExitThread( void );\r
78 \r
79 /**\r
80  * @brief Wrapper function for the user's thread routine.\r
81  *\r
82  * This function is executed as a FreeRTOS task function.\r
83  * @param[in] pxArg A pointer to a pthread_internal_t.\r
84  *\r
85  * @return nothing\r
86  */\r
87 static void prvRunThread( void * pxArg );\r
88 \r
89 /**\r
90  * @brief Default pthread_attr_t.\r
91  */\r
92 static const pthread_attr_internal_t xDefaultThreadAttributes =\r
93 {\r
94     .usStackSize                = PTHREAD_STACK_MIN,\r
95     .usSchedPriorityDetachState = ( ( uint16_t ) tskIDLE_PRIORITY & pthreadSCHED_PRIORITY_MASK ) | ( PTHREAD_CREATE_JOINABLE << pthreadDETACH_STATE_SHIFT ),\r
96 };\r
97 \r
98 /*-----------------------------------------------------------*/\r
99 \r
100 static void prvExitThread( void )\r
101 {\r
102     pthread_internal_t * pxThread = ( pthread_internal_t * ) pthread_self();\r
103 \r
104     /* If this thread is joinable, wait for a call to pthread_join. */\r
105     if( pthreadIS_JOINABLE( pxThread->xAttr.usSchedPriorityDetachState ) )\r
106     {\r
107         ( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &pxThread->xJoinBarrier );\r
108 \r
109         /* Suspend until the call to pthread_join. The caller of pthread_join\r
110          * will perform cleanup. */\r
111         vTaskSuspend( NULL );\r
112     }\r
113     else\r
114     {\r
115         /* For a detached thread, perform cleanup of thread object. */\r
116         vPortFree( pxThread );\r
117         vTaskDelete( NULL );\r
118     }\r
119 }\r
120 \r
121 /*-----------------------------------------------------------*/\r
122 \r
123 static void prvRunThread( void * pxArg )\r
124 {\r
125     pthread_internal_t * pxThread = ( pthread_internal_t * ) pxArg;\r
126 \r
127     /* Run the thread routine. */\r
128     pxThread->xReturn = pxThread->pvStartRoutine( ( void * ) pxThread->xTaskArg );\r
129 \r
130     /* Exit once finished. This function does not return. */\r
131     prvExitThread();\r
132 }\r
133 \r
134 /*-----------------------------------------------------------*/\r
135 \r
136 int pthread_attr_destroy( pthread_attr_t * attr )\r
137 {\r
138     ( void ) attr;\r
139 \r
140     return 0;\r
141 }\r
142 \r
143 /*-----------------------------------------------------------*/\r
144 \r
145 int pthread_attr_getdetachstate( const pthread_attr_t * attr,\r
146                                  int * detachstate )\r
147 {\r
148     pthread_attr_internal_t * pxAttr = ( pthread_attr_internal_t * ) ( attr );\r
149 \r
150     if( pthreadIS_JOINABLE( pxAttr->usSchedPriorityDetachState ) )\r
151     {\r
152         *detachstate = PTHREAD_CREATE_JOINABLE;\r
153     }\r
154     else\r
155     {\r
156         *detachstate = PTHREAD_CREATE_DETACHED;\r
157     }\r
158 \r
159     return 0;\r
160 }\r
161 \r
162 /*-----------------------------------------------------------*/\r
163 \r
164 int pthread_attr_getschedparam( const pthread_attr_t * attr,\r
165                                 struct sched_param * param )\r
166 {\r
167     pthread_attr_internal_t * pxAttr = ( pthread_attr_internal_t * ) ( attr );\r
168 \r
169     param->sched_priority = ( int ) ( pthreadGET_SCHED_PRIORITY( pxAttr->usSchedPriorityDetachState ) );\r
170 \r
171     return 0;\r
172 }\r
173 \r
174 /*-----------------------------------------------------------*/\r
175 \r
176 int pthread_attr_getstacksize( const pthread_attr_t * attr,\r
177                                size_t * stacksize )\r
178 {\r
179     pthread_attr_internal_t * pxAttr = ( pthread_attr_internal_t * ) ( attr );\r
180 \r
181     *stacksize = ( size_t ) pxAttr->usStackSize;\r
182 \r
183     return 0;\r
184 }\r
185 \r
186 /*-----------------------------------------------------------*/\r
187 \r
188 int pthread_attr_init( pthread_attr_t * attr )\r
189 {\r
190     /* Copy the default values into the new thread attributes object. */\r
191     *( ( pthread_attr_internal_t * ) ( attr ) ) = xDefaultThreadAttributes;\r
192 \r
193     return 0;\r
194 }\r
195 \r
196 /*-----------------------------------------------------------*/\r
197 \r
198 int pthread_attr_setdetachstate( pthread_attr_t * attr,\r
199                                  int detachstate )\r
200 {\r
201     int iStatus = 0;\r
202     pthread_attr_internal_t * pxAttr = ( pthread_attr_internal_t * ) ( attr );\r
203 \r
204     if( ( detachstate != PTHREAD_CREATE_DETACHED ) && ( detachstate != PTHREAD_CREATE_JOINABLE ) )\r
205     {\r
206         iStatus = EINVAL;\r
207     }\r
208     else\r
209     {\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
213     }\r
214 \r
215     return iStatus;\r
216 }\r
217 \r
218 /*-----------------------------------------------------------*/\r
219 \r
220 int pthread_attr_setschedparam( pthread_attr_t * attr,\r
221                                 const struct sched_param * param )\r
222 {\r
223     int iStatus = 0;\r
224     pthread_attr_internal_t * pxAttr = ( pthread_attr_internal_t * ) ( attr );\r
225 \r
226     /* Check for NULL param. */\r
227     if( param == NULL )\r
228     {\r
229         iStatus = EINVAL;\r
230     }\r
231 \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
236     {\r
237         iStatus = ENOTSUP;\r
238     }\r
239 \r
240     /* Set the sched_param. */\r
241     if( iStatus == 0 )\r
242     {\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
246     }\r
247 \r
248     return iStatus;\r
249 }\r
250 \r
251 /*-----------------------------------------------------------*/\r
252 \r
253 int pthread_attr_setschedpolicy( pthread_attr_t * attr,\r
254                                  int policy )\r
255 {\r
256     /* Silence warnings about unused parameters. */\r
257     ( void ) attr;\r
258     ( void ) policy;\r
259 \r
260     return 0;\r
261 }\r
262 \r
263 /*-----------------------------------------------------------*/\r
264 \r
265 int pthread_attr_setstacksize( pthread_attr_t * attr,\r
266                                size_t stacksize )\r
267 {\r
268     int iStatus = 0;\r
269     pthread_attr_internal_t * pxAttr = ( pthread_attr_internal_t * ) ( attr );\r
270 \r
271     if( stacksize < PTHREAD_STACK_MIN )\r
272     {\r
273         iStatus = EINVAL;\r
274     }\r
275     else\r
276     {\r
277         pxAttr->usStackSize = ( uint16_t ) stacksize;\r
278     }\r
279 \r
280     return iStatus;\r
281 }\r
282 \r
283 /*-----------------------------------------------------------*/\r
284 \r
285 int pthread_create( pthread_t * thread,\r
286                     const pthread_attr_t * attr,\r
287                     void *( *startroutine )( void * ),\r
288                     void * arg )\r
289 {\r
290     int iStatus = 0;\r
291     pthread_internal_t * pxThread = NULL;\r
292     struct sched_param xSchedParam = { .sched_priority = tskIDLE_PRIORITY };\r
293 \r
294     /* Allocate memory for new thread object. */\r
295     pxThread = ( pthread_internal_t * ) pvPortMalloc( sizeof( pthread_internal_t ) );\r
296 \r
297     if( pxThread == NULL )\r
298     {\r
299         /* No memory. */\r
300         iStatus = EAGAIN;\r
301     }\r
302 \r
303     if( iStatus == 0 )\r
304     {\r
305         /* No attributes given, use default attributes. */\r
306         if( attr == NULL )\r
307         {\r
308             pxThread->xAttr = xDefaultThreadAttributes;\r
309         }\r
310         /* Otherwise, use provided attributes. */\r
311         else\r
312         {\r
313             pxThread->xAttr = *( ( pthread_attr_internal_t * ) ( attr ) );\r
314         }\r
315 \r
316         /* Get priority from attributes */\r
317         xSchedParam.sched_priority = ( int ) pthreadGET_SCHED_PRIORITY( pxThread->xAttr.usSchedPriorityDetachState );\r
318 \r
319         /* Set argument and start routine. */\r
320         pxThread->xTaskArg = arg;\r
321         pxThread->pvStartRoutine = startroutine;\r
322 \r
323         /* If this thread is joinable, create the synchronization mechanisms for\r
324          * pthread_join. */\r
325 \r
326         if( pthreadIS_JOINABLE( pxThread->xAttr.usSchedPriorityDetachState ) )\r
327         {\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
331         }\r
332     }\r
333 \r
334     if( iStatus == 0 )\r
335     {\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
338         vTaskSuspendAll();\r
339 \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
347         {\r
348             /* Task creation failed, no memory. */\r
349             vPortFree( pxThread );\r
350             iStatus = EAGAIN;\r
351         }\r
352         else\r
353         {\r
354             /* Store the pointer to the thread object in the task tag. */\r
355             vTaskSetApplicationTaskTag( pxThread->xTaskHandle, ( TaskHookFunction_t ) pxThread );\r
356 \r
357             /* Set the thread object for the user. */\r
358             *thread = ( pthread_t ) pxThread;\r
359         }\r
360 \r
361         /* End the critical section. */\r
362         xTaskResumeAll();\r
363     }\r
364 \r
365     return iStatus;\r
366 }\r
367 \r
368 /*-----------------------------------------------------------*/\r
369 \r
370 int pthread_getschedparam( pthread_t thread,\r
371                            int * policy,\r
372                            struct sched_param * param )\r
373 {\r
374     int iStatus = 0;\r
375     pthread_internal_t * pxThread = ( pthread_internal_t * ) thread;\r
376 \r
377     *policy = SCHED_OTHER;\r
378     param->sched_priority = ( int ) pthreadGET_SCHED_PRIORITY( pxThread->xAttr.usSchedPriorityDetachState );\r
379 \r
380     return iStatus;\r
381 }\r
382 \r
383 /*-----------------------------------------------------------*/\r
384 \r
385 int pthread_equal( pthread_t t1,\r
386                    pthread_t t2 )\r
387 {\r
388     return t1 == t2;\r
389 }\r
390 \r
391 /*-----------------------------------------------------------*/\r
392 \r
393 void pthread_exit( void * value_ptr )\r
394 {\r
395     pthread_internal_t * pxThread = ( pthread_internal_t * ) pthread_self();\r
396 \r
397     /* Set the return value. */\r
398     pxThread->xReturn = value_ptr;\r
399 \r
400     /* Exit this thread. */\r
401     prvExitThread();\r
402 }\r
403 \r
404 /*-----------------------------------------------------------*/\r
405 \r
406 int pthread_join( pthread_t pthread,\r
407                   void ** retval )\r
408 {\r
409     int iStatus = 0;\r
410     pthread_internal_t * pxThread = ( pthread_internal_t * ) pthread;\r
411 \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
415     {\r
416         iStatus = EDEADLK;\r
417     }\r
418 \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
421     if( iStatus == 0 )\r
422     {\r
423         if( xSemaphoreTake( ( SemaphoreHandle_t ) &pxThread->xJoinMutex, 0 ) != pdPASS )\r
424         {\r
425             /* Another thread has already joined the requested thread, which would\r
426              * cause this thread to wait forever. */\r
427             iStatus = EDEADLK;\r
428         }\r
429     }\r
430 \r
431     /* Attempting to join the calling thread would cause a deadlock. */\r
432     if( iStatus == 0 )\r
433     {\r
434         if( pthread_equal( pthread_self(), pthread ) != 0 )\r
435         {\r
436             iStatus = EDEADLK;\r
437         }\r
438     }\r
439 \r
440     if( iStatus == 0 )\r
441     {\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
445 \r
446         /* Create a critical section to clean up the joined thread. */\r
447         vTaskSuspendAll();\r
448 \r
449         /* Release xJoinBarrier and delete it. */\r
450         ( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &pxThread->xJoinBarrier );\r
451         vSemaphoreDelete( ( SemaphoreHandle_t ) &pxThread->xJoinBarrier );\r
452 \r
453         /* Release xJoinMutex and delete it. */\r
454         ( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &pxThread->xJoinMutex );\r
455         vSemaphoreDelete( ( SemaphoreHandle_t ) &pxThread->xJoinMutex );\r
456 \r
457         /* Delete the FreeRTOS task that ran the thread. */\r
458         vTaskDelete( pxThread->xTaskHandle );\r
459 \r
460         /* Set the return value. */\r
461         if( retval != NULL )\r
462         {\r
463             *retval = pxThread->xReturn;\r
464         }\r
465 \r
466         /* Free the thread object. */\r
467         vPortFree( pxThread );\r
468 \r
469         /* End the critical section. */\r
470         xTaskResumeAll();\r
471     }\r
472 \r
473     return iStatus;\r
474 }\r
475 \r
476 /*-----------------------------------------------------------*/\r
477 \r
478 pthread_t pthread_self( void )\r
479 {\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
483 }\r
484 \r
485 /*-----------------------------------------------------------*/\r
486 \r
487 int pthread_setschedparam( pthread_t thread,\r
488                            int policy,\r
489                            const struct sched_param * param )\r
490 {\r
491     int iStatus = 0;\r
492 \r
493     pthread_internal_t * pxThread = ( pthread_internal_t * ) thread;\r
494 \r
495     /* Silence compiler warnings about unused parameters. */\r
496     ( void ) policy;\r
497 \r
498     /* Copy the given sched_param. */\r
499     iStatus = pthread_attr_setschedparam( ( pthread_attr_t * ) &pxThread->xAttr, param );\r
500 \r
501     if( iStatus == 0 )\r
502     {\r
503         /* Change the priority of the FreeRTOS task. */\r
504         vTaskPrioritySet( pxThread->xTaskHandle, param->sched_priority );\r
505     }\r
506 \r
507     return iStatus;\r
508 }\r
509 \r
510 /*-----------------------------------------------------------*/\r