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_mutex.c
\r
28 * @brief Implementation of mutex 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
39 #include "FreeRTOS_POSIX/utils.h"
\r
42 * @brief Initialize a PTHREAD_MUTEX_INITIALIZER mutex.
\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
50 static void prvInitializeStaticMutex( pthread_mutex_internal_t * pxMutex );
\r
53 * @brief Default pthread_mutexattr_t.
\r
55 static const pthread_mutexattr_internal_t xDefaultMutexAttributes =
\r
57 .iType = PTHREAD_MUTEX_DEFAULT,
\r
60 /*-----------------------------------------------------------*/
\r
62 static void prvInitializeStaticMutex( pthread_mutex_internal_t * pxMutex )
\r
64 /* Check if the mutex needs to be initialized. */
\r
65 if( pxMutex->xIsInitialized == pdFALSE )
\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
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
74 if( pxMutex->xIsInitialized == pdFALSE )
\r
76 /* Set the mutex as the default type. */
\r
77 pxMutex->xAttr.iType = PTHREAD_MUTEX_DEFAULT;
\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
84 ( void ) xSemaphoreCreateMutexStatic( &pxMutex->xMutex );
\r
87 pxMutex->xIsInitialized = pdTRUE;
\r
90 /* Exit the critical section. */
\r
91 taskEXIT_CRITICAL();
\r
95 /*-----------------------------------------------------------*/
\r
97 int pthread_mutex_destroy( pthread_mutex_t * mutex )
\r
99 pthread_mutex_internal_t * pxMutex = ( pthread_mutex_internal_t * ) ( mutex );
\r
101 /* Free resources in use by the mutex. */
\r
102 if( pxMutex->xTaskOwner == NULL )
\r
104 vSemaphoreDelete( ( SemaphoreHandle_t ) &pxMutex->xMutex );
\r
110 /*-----------------------------------------------------------*/
\r
112 int pthread_mutex_init( pthread_mutex_t * mutex,
\r
113 const pthread_mutexattr_t * attr )
\r
116 pthread_mutex_internal_t * pxMutex = ( pthread_mutex_internal_t * ) mutex;
\r
118 if( pxMutex == NULL )
\r
126 *pxMutex = FREERTOS_POSIX_MUTEX_INITIALIZER;
\r
128 /* No attributes given, use default attributes. */
\r
131 pxMutex->xAttr = xDefaultMutexAttributes;
\r
133 /* Otherwise, use provided attributes. */
\r
136 pxMutex->xAttr = *( ( pthread_mutexattr_internal_t * ) ( attr ) );
\r
139 /* Call the correct FreeRTOS mutex creation function based on mutex type. */
\r
140 if( pxMutex->xAttr.iType == PTHREAD_MUTEX_RECURSIVE )
\r
142 /* Recursive mutex. */
\r
143 ( void ) xSemaphoreCreateRecursiveMutexStatic( &pxMutex->xMutex );
\r
147 /* All other mutex types. */
\r
148 ( void ) xSemaphoreCreateMutexStatic( &pxMutex->xMutex );
\r
151 /* Ensure that the FreeRTOS mutex was successfully created. */
\r
152 if( ( SemaphoreHandle_t ) &pxMutex->xMutex == NULL )
\r
154 /* Failed to create mutex. Set error EAGAIN and free mutex object. */
\r
156 vPortFree( pxMutex );
\r
160 /* Mutex successfully created. */
\r
161 pxMutex->xIsInitialized = pdTRUE;
\r
168 /*-----------------------------------------------------------*/
\r
170 int pthread_mutex_lock( pthread_mutex_t * mutex )
\r
172 return pthread_mutex_timedlock( mutex, NULL );
\r
175 /*-----------------------------------------------------------*/
\r
177 int pthread_mutex_timedlock( pthread_mutex_t * mutex,
\r
178 const struct timespec * abstime )
\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
185 /* If mutex in uninitialized, perform initialization. */
\r
186 prvInitializeStaticMutex( pxMutex );
\r
188 /* At this point, the mutex should be initialized. */
\r
189 configASSERT( pxMutex->xIsInitialized == pdTRUE );
\r
191 /* Convert abstime to a delay in TickType_t if provided. */
\r
192 if( abstime != NULL )
\r
194 struct timespec xCurrentTime = { 0 };
\r
196 /* Get current time */
\r
197 if( clock_gettime( CLOCK_REALTIME, &xCurrentTime ) != 0 )
\r
203 iStatus = UTILS_AbsoluteTimespecToDeltaTicks( abstime, &xCurrentTime, &xDelay );
\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
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
225 /* Call the correct FreeRTOS mutex take function based on mutex type. */
\r
226 if( pxMutex->xAttr.iType == PTHREAD_MUTEX_RECURSIVE )
\r
228 xFreeRTOSMutexTakeStatus = xSemaphoreTakeRecursive( ( SemaphoreHandle_t ) &pxMutex->xMutex, xDelay );
\r
232 xFreeRTOSMutexTakeStatus = xSemaphoreTake( ( SemaphoreHandle_t ) &pxMutex->xMutex, xDelay );
\r
235 /* If the mutex was successfully taken, set its owner. */
\r
236 if( xFreeRTOSMutexTakeStatus == pdPASS )
\r
238 pxMutex->xTaskOwner = xTaskGetCurrentTaskHandle();
\r
240 /* Otherwise, the mutex take timed out. */
\r
243 iStatus = ETIMEDOUT;
\r
250 /*-----------------------------------------------------------*/
\r
252 int pthread_mutex_trylock( pthread_mutex_t * mutex )
\r
255 struct timespec xTimeout =
\r
261 /* Attempt to lock with no timeout. */
\r
262 iStatus = pthread_mutex_timedlock( mutex, &xTimeout );
\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
274 /*-----------------------------------------------------------*/
\r
276 int pthread_mutex_unlock( pthread_mutex_t * mutex )
\r
279 pthread_mutex_internal_t * pxMutex = ( pthread_mutex_internal_t * ) ( mutex );
\r
281 /* If mutex in uninitialized, perform initialization. */
\r
282 prvInitializeStaticMutex( pxMutex );
\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
294 /* Suspend the scheduler so that
\r
295 * mutex is unlocked AND owner is updated atomically */
\r
298 /* Call the correct FreeRTOS mutex unlock function based on mutex type. */
\r
299 if( pxMutex->xAttr.iType == PTHREAD_MUTEX_RECURSIVE )
\r
301 ( void ) xSemaphoreGiveRecursive( ( SemaphoreHandle_t ) &pxMutex->xMutex );
\r
305 ( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &pxMutex->xMutex );
\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
312 /* Resume the scheduler */
\r
313 ( void ) xTaskResumeAll();
\r
319 /*-----------------------------------------------------------*/
\r
321 int pthread_mutexattr_destroy( pthread_mutexattr_t * attr )
\r
328 /*-----------------------------------------------------------*/
\r
330 int pthread_mutexattr_gettype( const pthread_mutexattr_t * attr,
\r
333 pthread_mutexattr_internal_t * pxAttr = ( pthread_mutexattr_internal_t * ) ( attr );
\r
335 *type = pxAttr->iType;
\r
340 /*-----------------------------------------------------------*/
\r
342 int pthread_mutexattr_init( pthread_mutexattr_t * attr )
\r
344 *( ( pthread_mutexattr_internal_t * ) ( attr ) ) = xDefaultMutexAttributes;
\r
349 /*-----------------------------------------------------------*/
\r
351 int pthread_mutexattr_settype( pthread_mutexattr_t * attr,
\r
355 pthread_mutexattr_internal_t * pxAttr = ( pthread_mutexattr_internal_t * ) ( attr );
\r
359 case PTHREAD_MUTEX_NORMAL:
\r
360 case PTHREAD_MUTEX_RECURSIVE:
\r
361 case PTHREAD_MUTEX_ERRORCHECK:
\r
362 pxAttr->iType = type;
\r
373 /*-----------------------------------------------------------*/
\r