]> git.sur5r.net Git - freertos/blob - FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_pthread_mutex.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_mutex.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_mutex.c\r
28  * @brief Implementation of mutex 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 #include "FreeRTOS_POSIX/utils.h"\r
40 \r
41 /**\r
42  * @brief Initialize a PTHREAD_MUTEX_INITIALIZER mutex.\r
43  *\r
44  * PTHREAD_MUTEX_INITIALIZER sets a flag for a mutex to be initialized later.\r
45  * This function performs the initialization.\r
46  * @param[in] pxMutex The mutex to initialize.\r
47  *\r
48  * @return nothing\r
49  */\r
50 static void prvInitializeStaticMutex( pthread_mutex_internal_t * pxMutex );\r
51 \r
52 /**\r
53  * @brief Default pthread_mutexattr_t.\r
54  */\r
55 static const pthread_mutexattr_internal_t xDefaultMutexAttributes =\r
56 {\r
57     .iType = PTHREAD_MUTEX_DEFAULT,\r
58 };\r
59 \r
60 /*-----------------------------------------------------------*/\r
61 \r
62 static void prvInitializeStaticMutex( pthread_mutex_internal_t * pxMutex )\r
63 {\r
64     /* Check if the mutex needs to be initialized. */\r
65     if( pxMutex->xIsInitialized == pdFALSE )\r
66     {\r
67         /* Mutex initialization must be in a critical section to prevent two threads\r
68          * from initializing it at the same time. */\r
69         taskENTER_CRITICAL();\r
70 \r
71         /* Check again that the mutex is still uninitialized, i.e. it wasn't\r
72          * initialized while this function was waiting to enter the critical\r
73          * section. */\r
74         if( pxMutex->xIsInitialized == pdFALSE )\r
75         {\r
76             /* Set the mutex as the default type. */\r
77             pxMutex->xAttr.iType = PTHREAD_MUTEX_DEFAULT;\r
78 \r
79             /* Call the correct FreeRTOS mutex initialization function based on\r
80              * the mutex type. */\r
81             #if PTHREAD_MUTEX_DEFAULT == PTHREAD_MUTEX_RECURSIVE\r
82                 ( void ) xSemaphoreCreateRecursiveMutexStatic( &pxMutex->xMutex );\r
83             #else\r
84                 ( void ) xSemaphoreCreateMutexStatic( &pxMutex->xMutex );\r
85             #endif\r
86 \r
87             pxMutex->xIsInitialized = pdTRUE;\r
88         }\r
89 \r
90         /* Exit the critical section. */\r
91         taskEXIT_CRITICAL();\r
92     }\r
93 }\r
94 \r
95 /*-----------------------------------------------------------*/\r
96 \r
97 int pthread_mutex_destroy( pthread_mutex_t * mutex )\r
98 {\r
99     pthread_mutex_internal_t * pxMutex = ( pthread_mutex_internal_t * ) ( mutex );\r
100 \r
101     /* Free resources in use by the mutex. */\r
102     if( pxMutex->xTaskOwner == NULL )\r
103     {\r
104         vSemaphoreDelete( ( SemaphoreHandle_t ) &pxMutex->xMutex );\r
105     }\r
106 \r
107     return 0;\r
108 }\r
109 \r
110 /*-----------------------------------------------------------*/\r
111 \r
112 int pthread_mutex_init( pthread_mutex_t * mutex,\r
113                         const pthread_mutexattr_t * attr )\r
114 {\r
115     int iStatus = 0;\r
116     pthread_mutex_internal_t * pxMutex = ( pthread_mutex_internal_t * ) mutex;\r
117 \r
118     if( pxMutex == NULL )\r
119     {\r
120         /* No memory. */\r
121         iStatus = ENOMEM;\r
122     }\r
123 \r
124     if( iStatus == 0 )\r
125     {\r
126         *pxMutex = FREERTOS_POSIX_MUTEX_INITIALIZER;\r
127 \r
128         /* No attributes given, use default attributes. */\r
129         if( attr == NULL )\r
130         {\r
131             pxMutex->xAttr = xDefaultMutexAttributes;\r
132         }\r
133         /* Otherwise, use provided attributes. */\r
134         else\r
135         {\r
136             pxMutex->xAttr = *( ( pthread_mutexattr_internal_t * ) ( attr ) );\r
137         }\r
138 \r
139         /* Call the correct FreeRTOS mutex creation function based on mutex type. */\r
140         if( pxMutex->xAttr.iType == PTHREAD_MUTEX_RECURSIVE )\r
141         {\r
142             /* Recursive mutex. */\r
143             ( void ) xSemaphoreCreateRecursiveMutexStatic( &pxMutex->xMutex );\r
144         }\r
145         else\r
146         {\r
147             /* All other mutex types. */\r
148             ( void ) xSemaphoreCreateMutexStatic( &pxMutex->xMutex );\r
149         }\r
150 \r
151         /* Ensure that the FreeRTOS mutex was successfully created. */\r
152         if( ( SemaphoreHandle_t ) &pxMutex->xMutex == NULL )\r
153         {\r
154             /* Failed to create mutex. Set error EAGAIN and free mutex object. */\r
155             iStatus = EAGAIN;\r
156             vPortFree( pxMutex );\r
157         }\r
158         else\r
159         {\r
160             /* Mutex successfully created. */\r
161             pxMutex->xIsInitialized = pdTRUE;\r
162         }\r
163     }\r
164 \r
165     return iStatus;\r
166 }\r
167 \r
168 /*-----------------------------------------------------------*/\r
169 \r
170 int pthread_mutex_lock( pthread_mutex_t * mutex )\r
171 {\r
172     return pthread_mutex_timedlock( mutex, NULL );\r
173 }\r
174 \r
175 /*-----------------------------------------------------------*/\r
176 \r
177 int pthread_mutex_timedlock( pthread_mutex_t * mutex,\r
178                              const struct timespec * abstime )\r
179 {\r
180     int iStatus = 0;\r
181     pthread_mutex_internal_t * pxMutex = ( pthread_mutex_internal_t * ) ( mutex );\r
182     TickType_t xDelay = portMAX_DELAY;\r
183     BaseType_t xFreeRTOSMutexTakeStatus = pdFALSE;\r
184 \r
185     /* If mutex in uninitialized, perform initialization. */\r
186     prvInitializeStaticMutex( pxMutex );\r
187 \r
188     /* At this point, the mutex should be initialized. */\r
189     configASSERT( pxMutex->xIsInitialized == pdTRUE );\r
190 \r
191     /* Convert abstime to a delay in TickType_t if provided. */\r
192     if( abstime != NULL )\r
193     {\r
194         struct timespec xCurrentTime = { 0 };\r
195 \r
196         /* Get current time */\r
197         if( clock_gettime( CLOCK_REALTIME, &xCurrentTime ) != 0 )\r
198         {\r
199             iStatus = EINVAL;\r
200         }\r
201         else\r
202         {\r
203             iStatus = UTILS_AbsoluteTimespecToDeltaTicks( abstime, &xCurrentTime, &xDelay );\r
204         }\r
205 \r
206         /* If abstime was in the past, still attempt to lock the mutex without\r
207          * blocking, per POSIX spec. */\r
208         if( iStatus == ETIMEDOUT )\r
209         {\r
210             xDelay = 0;\r
211             iStatus = 0;\r
212         }\r
213     }\r
214 \r
215     /* Check if trying to lock a currently owned mutex. */\r
216     if( ( iStatus == 0 ) &&\r
217         ( pxMutex->xAttr.iType == PTHREAD_MUTEX_ERRORCHECK ) &&  /* Only PTHREAD_MUTEX_ERRORCHECK type detects deadlock. */\r
218         ( pxMutex->xTaskOwner == xTaskGetCurrentTaskHandle() ) ) /* Check if locking a currently owned mutex. */\r
219     {\r
220         iStatus = EDEADLK;\r
221     }\r
222 \r
223     if( iStatus == 0 )\r
224     {\r
225         /* Call the correct FreeRTOS mutex take function based on mutex type. */\r
226         if( pxMutex->xAttr.iType == PTHREAD_MUTEX_RECURSIVE )\r
227         {\r
228             xFreeRTOSMutexTakeStatus = xSemaphoreTakeRecursive( ( SemaphoreHandle_t ) &pxMutex->xMutex, xDelay );\r
229         }\r
230         else\r
231         {\r
232             xFreeRTOSMutexTakeStatus = xSemaphoreTake( ( SemaphoreHandle_t ) &pxMutex->xMutex, xDelay );\r
233         }\r
234 \r
235         /* If the mutex was successfully taken, set its owner. */\r
236         if( xFreeRTOSMutexTakeStatus == pdPASS )\r
237         {\r
238             pxMutex->xTaskOwner = xTaskGetCurrentTaskHandle();\r
239         }\r
240         /* Otherwise, the mutex take timed out. */\r
241         else\r
242         {\r
243             iStatus = ETIMEDOUT;\r
244         }\r
245     }\r
246 \r
247     return iStatus;\r
248 }\r
249 \r
250 /*-----------------------------------------------------------*/\r
251 \r
252 int pthread_mutex_trylock( pthread_mutex_t * mutex )\r
253 {\r
254     int iStatus = 0;\r
255     struct timespec xTimeout =\r
256     {\r
257         .tv_sec  = 0,\r
258         .tv_nsec = 0\r
259     };\r
260 \r
261     /* Attempt to lock with no timeout. */\r
262     iStatus = pthread_mutex_timedlock( mutex, &xTimeout );\r
263 \r
264     /* POSIX specifies that this function should return EBUSY instead of\r
265      * ETIMEDOUT for attempting to lock a locked mutex. */\r
266     if( iStatus == ETIMEDOUT )\r
267     {\r
268         iStatus = EBUSY;\r
269     }\r
270 \r
271     return iStatus;\r
272 }\r
273 \r
274 /*-----------------------------------------------------------*/\r
275 \r
276 int pthread_mutex_unlock( pthread_mutex_t * mutex )\r
277 {\r
278     int iStatus = 0;\r
279     pthread_mutex_internal_t * pxMutex = ( pthread_mutex_internal_t * ) ( mutex );\r
280 \r
281     /* If mutex in uninitialized, perform initialization. */\r
282     prvInitializeStaticMutex( pxMutex );\r
283 \r
284     /* Check if trying to unlock an unowned mutex. */\r
285     if( ( ( pxMutex->xAttr.iType == PTHREAD_MUTEX_ERRORCHECK ) ||\r
286           ( pxMutex->xAttr.iType == PTHREAD_MUTEX_RECURSIVE ) ) &&\r
287         ( pxMutex->xTaskOwner != xTaskGetCurrentTaskHandle() ) )\r
288     {\r
289         iStatus = EPERM;\r
290     }\r
291 \r
292     if( iStatus == 0 )\r
293     {\r
294         /* Suspend the scheduler so that\r
295          * mutex is unlocked AND owner is updated atomically */\r
296         vTaskSuspendAll();\r
297 \r
298         /* Call the correct FreeRTOS mutex unlock function based on mutex type. */\r
299         if( pxMutex->xAttr.iType == PTHREAD_MUTEX_RECURSIVE )\r
300         {\r
301             ( void ) xSemaphoreGiveRecursive( ( SemaphoreHandle_t ) &pxMutex->xMutex );\r
302         }\r
303         else\r
304         {\r
305             ( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &pxMutex->xMutex );\r
306         }\r
307 \r
308         /* Update the owner of the mutex. A recursive mutex may still have an\r
309          * owner, so it should be updated with xSemaphoreGetMutexHolder. */\r
310         pxMutex->xTaskOwner = xSemaphoreGetMutexHolder( ( SemaphoreHandle_t ) &pxMutex->xMutex );\r
311 \r
312         /* Resume the scheduler */\r
313         ( void ) xTaskResumeAll();\r
314     }\r
315 \r
316     return iStatus;\r
317 }\r
318 \r
319 /*-----------------------------------------------------------*/\r
320 \r
321 int pthread_mutexattr_destroy( pthread_mutexattr_t * attr )\r
322 {\r
323     ( void ) attr;\r
324 \r
325     return 0;\r
326 }\r
327 \r
328 /*-----------------------------------------------------------*/\r
329 \r
330 int pthread_mutexattr_gettype( const pthread_mutexattr_t * attr,\r
331                                int * type )\r
332 {\r
333     pthread_mutexattr_internal_t * pxAttr = ( pthread_mutexattr_internal_t * ) ( attr );\r
334 \r
335     *type = pxAttr->iType;\r
336 \r
337     return 0;\r
338 }\r
339 \r
340 /*-----------------------------------------------------------*/\r
341 \r
342 int pthread_mutexattr_init( pthread_mutexattr_t * attr )\r
343 {\r
344     *( ( pthread_mutexattr_internal_t * ) ( attr ) ) = xDefaultMutexAttributes;\r
345 \r
346     return 0;\r
347 }\r
348 \r
349 /*-----------------------------------------------------------*/\r
350 \r
351 int pthread_mutexattr_settype( pthread_mutexattr_t * attr,\r
352                                int type )\r
353 {\r
354     int iStatus = 0;\r
355     pthread_mutexattr_internal_t * pxAttr = ( pthread_mutexattr_internal_t * ) ( attr );\r
356 \r
357     switch( type )\r
358     {\r
359         case PTHREAD_MUTEX_NORMAL:\r
360         case PTHREAD_MUTEX_RECURSIVE:\r
361         case PTHREAD_MUTEX_ERRORCHECK:\r
362             pxAttr->iType = type;\r
363             break;\r
364 \r
365         default:\r
366             iStatus = EINVAL;\r
367             break;\r
368     }\r
369 \r
370     return iStatus;\r
371 }\r
372 \r
373 /*-----------------------------------------------------------*/\r