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_cond.c
\r
28 * @brief Implementation of condition variable functions in pthread.h
\r
31 /* C standard library includes. */
\r
34 /* FreeRTOS+POSIX includes. */
\r
35 #include "FreeRTOS_POSIX.h"
\r
36 #include "FreeRTOS_POSIX/errno.h"
\r
37 #include "FreeRTOS_POSIX/pthread.h"
\r
38 #include "FreeRTOS_POSIX/utils.h"
\r
43 * @brief Initialize a PTHREAD_COND_INITIALIZER cond.
\r
45 * PTHREAD_COND_INITIALIZER sets a flag for a cond to be initialized later.
\r
46 * This function performs the initialization.
\r
47 * @param[in] pxCond The cond to initialize.
\r
51 static void prvInitializeStaticCond( pthread_cond_internal_t * pxCond );
\r
53 /*-----------------------------------------------------------*/
\r
55 static void prvInitializeStaticCond( pthread_cond_internal_t * pxCond )
\r
57 /* Check if the condition variable needs to be initialized. */
\r
58 if( pxCond->xIsInitialized == pdFALSE )
\r
60 /* Cond initialization must be in a critical section to prevent two threads
\r
61 * from initializing it at the same time. */
\r
62 taskENTER_CRITICAL();
\r
64 /* Check again that the cond is still uninitialized, i.e. it wasn't
\r
65 * initialized while this function was waiting to enter the critical
\r
67 if( pxCond->xIsInitialized == pdFALSE )
\r
69 /* Set the members of the cond. The semaphore create calls will never fail
\r
70 * when their arguments aren't NULL. */
\r
71 pxCond->xIsInitialized = pdTRUE;
\r
72 ( void ) xSemaphoreCreateCountingStatic( INT_MAX, 0U, &pxCond->xCondWaitSemaphore );
\r
73 pxCond->iWaitingThreads = 0;
\r
76 /* Exit the critical section. */
\r
77 taskEXIT_CRITICAL();
\r
82 * @brief Check "atomically" if iLocalWaitingThreads == pxCond->iWaitingThreads and decrement.
\r
84 static void prvTestAndDecrement( pthread_cond_t * pxCond,
\r
85 unsigned iLocalWaitingThreads )
\r
87 /* Test local copy of threads waiting is larger than zero. */
\r
88 while( iLocalWaitingThreads > 0 )
\r
90 /* Test-and-set. Atomically check whether the copy in memory has changed.
\r
91 * And, if not decrease the copy of threads waiting in memory. */
\r
92 if( ATOMIC_COMPARE_AND_SWAP_SUCCESS == Atomic_CompareAndSwap_u32( ( uint32_t * ) &pxCond->iWaitingThreads, ( uint32_t ) iLocalWaitingThreads - 1, ( uint32_t ) iLocalWaitingThreads ) )
\r
94 /* Signal one succeeded. Break. */
\r
98 /* Local copy may be out dated. Reload, and retry. */
\r
99 iLocalWaitingThreads = pxCond->iWaitingThreads;
\r
103 /*-----------------------------------------------------------*/
\r
105 int pthread_cond_broadcast( pthread_cond_t * cond )
\r
108 pthread_cond_internal_t * pxCond = ( pthread_cond_internal_t * ) ( cond );
\r
110 /* If the cond is uninitialized, perform initialization. */
\r
111 prvInitializeStaticCond( pxCond );
\r
113 /* Local copy of number of threads waiting. */
\r
114 unsigned iLocalWaitingThreads = pxCond->iWaitingThreads;
\r
116 /* Test local copy of threads waiting is larger than zero. */
\r
117 while( iLocalWaitingThreads > 0 )
\r
119 /* Test-and-set. Atomically check whether the copy in memory has changed.
\r
120 * And, if not set the copy of threads waiting in memory to zero. */
\r
121 if( ATOMIC_COMPARE_AND_SWAP_SUCCESS == Atomic_CompareAndSwap_u32( ( uint32_t * ) &pxCond->iWaitingThreads, 0, ( uint32_t ) iLocalWaitingThreads ) )
\r
124 for( i = 0; i < iLocalWaitingThreads; i++ )
\r
126 ( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &pxCond->xCondWaitSemaphore );
\r
132 /* Local copy is out dated. Reload, and retry. */
\r
133 iLocalWaitingThreads = pxCond->iWaitingThreads;
\r
139 /*-----------------------------------------------------------*/
\r
141 int pthread_cond_destroy( pthread_cond_t * cond )
\r
143 pthread_cond_internal_t * pxCond = ( pthread_cond_internal_t * ) ( cond );
\r
145 /* Free all resources in use by the cond. */
\r
146 vSemaphoreDelete( ( SemaphoreHandle_t ) &pxCond->xCondWaitSemaphore );
\r
151 /*-----------------------------------------------------------*/
\r
153 int pthread_cond_init( pthread_cond_t * cond,
\r
154 const pthread_condattr_t * attr )
\r
157 pthread_cond_internal_t * pxCond = ( pthread_cond_internal_t * ) cond;
\r
159 /* Silence warnings about unused parameters. */
\r
162 if( pxCond == NULL )
\r
169 /* Set the members of the cond. The semaphore create calls will never fail
\r
170 * when their arguments aren't NULL. */
\r
171 pxCond->xIsInitialized = pdTRUE;
\r
173 ( void ) xSemaphoreCreateCountingStatic( INT_MAX, 0U, &pxCond->xCondWaitSemaphore );
\r
174 pxCond->iWaitingThreads = 0;
\r
180 /*-----------------------------------------------------------*/
\r
182 int pthread_cond_signal( pthread_cond_t * cond )
\r
184 pthread_cond_internal_t * pxCond = ( pthread_cond_internal_t * ) ( cond );
\r
186 /* If the cond is uninitialized, perform initialization. */
\r
187 prvInitializeStaticCond( pxCond );
\r
189 /* Local copy of number of threads waiting. */
\r
190 unsigned iLocalWaitingThreads = pxCond->iWaitingThreads;
\r
192 /* Test local copy of threads waiting is larger than zero. */
\r
193 while( iLocalWaitingThreads > 0 )
\r
195 /* Test-and-set. Atomically check whether the copy in memory has changed.
\r
196 * And, if not decrease the copy of threads waiting in memory. */
\r
197 if( ATOMIC_COMPARE_AND_SWAP_SUCCESS == Atomic_CompareAndSwap_u32( ( uint32_t * ) &pxCond->iWaitingThreads, ( uint32_t ) iLocalWaitingThreads - 1, ( uint32_t ) iLocalWaitingThreads ) )
\r
200 ( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &pxCond->xCondWaitSemaphore );
\r
202 /* Signal one succeeded. Break. */
\r
206 /* Local copy may be out dated. Reload, and retry. */
\r
207 iLocalWaitingThreads = pxCond->iWaitingThreads;
\r
213 /*-----------------------------------------------------------*/
\r
215 int pthread_cond_timedwait( pthread_cond_t * cond,
\r
216 pthread_mutex_t * mutex,
\r
217 const struct timespec * abstime )
\r
219 unsigned iLocalWaitingThreads;
\r
221 pthread_cond_internal_t * pxCond = ( pthread_cond_internal_t * ) ( cond );
\r
222 TickType_t xDelay = portMAX_DELAY;
\r
224 /* If the cond is uninitialized, perform initialization. */
\r
225 prvInitializeStaticCond( pxCond );
\r
227 /* Convert abstime to a delay in TickType_t if provided. */
\r
228 if( abstime != NULL )
\r
230 struct timespec xCurrentTime = { 0 };
\r
232 /* Get current time */
\r
233 if( clock_gettime( CLOCK_REALTIME, &xCurrentTime ) != 0 )
\r
239 iStatus = UTILS_AbsoluteTimespecToDeltaTicks( abstime, &xCurrentTime, &xDelay );
\r
243 /* Increase the counter of threads blocking on condition variable, then
\r
247 /* Atomically increments thread waiting by 1, and
\r
248 * stores number of threads waiting before increment. */
\r
249 iLocalWaitingThreads = Atomic_Increment_u32( ( uint32_t * ) &pxCond->iWaitingThreads );
\r
251 iStatus = pthread_mutex_unlock( mutex );
\r
254 /* Wait on the condition variable. */
\r
257 if( xSemaphoreTake( ( SemaphoreHandle_t ) &pxCond->xCondWaitSemaphore,
\r
258 xDelay ) == pdPASS )
\r
260 /* When successful, relock mutex. */
\r
261 iStatus = pthread_mutex_lock( mutex );
\r
265 /* Timeout. Relock mutex and decrement number of waiting threads. */
\r
266 iStatus = ETIMEDOUT;
\r
267 ( void ) pthread_mutex_lock( mutex );
\r
269 /* Atomically decrements thread waiting by 1.
\r
270 * If iLocalWaitingThreads is updated by other thread(s) in between,
\r
271 * this implementation guarantees to decrement by 1 based on the
\r
272 * value currently in pxCond->iWaitingThreads. */
\r
273 prvTestAndDecrement( pxCond, iLocalWaitingThreads + 1 );
\r
278 /* Atomically decrements thread waiting by 1.
\r
279 * If iLocalWaitingThreads is updated by other thread(s) in between,
\r
280 * this implementation guarantees to decrement by 1 based on the
\r
281 * value currently in pxCond->iWaitingThreads. */
\r
282 prvTestAndDecrement( pxCond, iLocalWaitingThreads + 1 );
\r
288 /*-----------------------------------------------------------*/
\r
290 int pthread_cond_wait( pthread_cond_t * cond,
\r
291 pthread_mutex_t * mutex )
\r
293 return pthread_cond_timedwait( cond, mutex, NULL );
\r