summaryrefslogtreecommitdiff
path: root/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_pthread_cond.c
diff options
context:
space:
mode:
Diffstat (limited to 'FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_pthread_cond.c')
-rw-r--r--FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_pthread_cond.c294
1 files changed, 294 insertions, 0 deletions
diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_pthread_cond.c b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_pthread_cond.c
new file mode 100644
index 000000000..9c6a73469
--- /dev/null
+++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_pthread_cond.c
@@ -0,0 +1,294 @@
+/*
+ * Amazon FreeRTOS POSIX V1.1.0
+ * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * http://aws.amazon.com/freertos
+ * http://www.FreeRTOS.org
+ */
+
+/**
+ * @file FreeRTOS_POSIX_pthread_cond.c
+ * @brief Implementation of condition variable functions in pthread.h
+ */
+
+/* C standard library includes. */
+#include <limits.h>
+
+/* FreeRTOS+POSIX includes. */
+#include "FreeRTOS_POSIX.h"
+#include "FreeRTOS_POSIX/errno.h"
+#include "FreeRTOS_POSIX/pthread.h"
+#include "FreeRTOS_POSIX/utils.h"
+
+#include "atomic.h"
+
+/**
+ * @brief Initialize a PTHREAD_COND_INITIALIZER cond.
+ *
+ * PTHREAD_COND_INITIALIZER sets a flag for a cond to be initialized later.
+ * This function performs the initialization.
+ * @param[in] pxCond The cond to initialize.
+ *
+ * @return nothing
+ */
+static void prvInitializeStaticCond( pthread_cond_internal_t * pxCond );
+
+/*-----------------------------------------------------------*/
+
+static void prvInitializeStaticCond( pthread_cond_internal_t * pxCond )
+{
+ /* Check if the condition variable needs to be initialized. */
+ if( pxCond->xIsInitialized == pdFALSE )
+ {
+ /* Cond initialization must be in a critical section to prevent two threads
+ * from initializing it at the same time. */
+ taskENTER_CRITICAL();
+
+ /* Check again that the cond is still uninitialized, i.e. it wasn't
+ * initialized while this function was waiting to enter the critical
+ * section. */
+ if( pxCond->xIsInitialized == pdFALSE )
+ {
+ /* Set the members of the cond. The semaphore create calls will never fail
+ * when their arguments aren't NULL. */
+ pxCond->xIsInitialized = pdTRUE;
+ ( void ) xSemaphoreCreateCountingStatic( INT_MAX, 0U, &pxCond->xCondWaitSemaphore );
+ pxCond->iWaitingThreads = 0;
+ }
+
+ /* Exit the critical section. */
+ taskEXIT_CRITICAL();
+ }
+}
+
+/**
+ * @brief Check "atomically" if iLocalWaitingThreads == pxCond->iWaitingThreads and decrement.
+ */
+static void prvTestAndDecrement( pthread_cond_t * pxCond,
+ unsigned iLocalWaitingThreads )
+{
+ /* Test local copy of threads waiting is larger than zero. */
+ while( iLocalWaitingThreads > 0 )
+ {
+ /* Test-and-set. Atomically check whether the copy in memory has changed.
+ * And, if not decrease the copy of threads waiting in memory. */
+ if( ATOMIC_COMPARE_AND_SWAP_SUCCESS == Atomic_CompareAndSwap_u32( ( uint32_t * ) &pxCond->iWaitingThreads, ( uint32_t ) iLocalWaitingThreads - 1, ( uint32_t ) iLocalWaitingThreads ) )
+ {
+ /* Signal one succeeded. Break. */
+ break;
+ }
+
+ /* Local copy may be out dated. Reload, and retry. */
+ iLocalWaitingThreads = pxCond->iWaitingThreads;
+ }
+}
+
+/*-----------------------------------------------------------*/
+
+int pthread_cond_broadcast( pthread_cond_t * cond )
+{
+ unsigned i = 0;
+ pthread_cond_internal_t * pxCond = ( pthread_cond_internal_t * ) ( cond );
+
+ /* If the cond is uninitialized, perform initialization. */
+ prvInitializeStaticCond( pxCond );
+
+ /* Local copy of number of threads waiting. */
+ unsigned iLocalWaitingThreads = pxCond->iWaitingThreads;
+
+ /* Test local copy of threads waiting is larger than zero. */
+ while( iLocalWaitingThreads > 0 )
+ {
+ /* Test-and-set. Atomically check whether the copy in memory has changed.
+ * And, if not set the copy of threads waiting in memory to zero. */
+ if( ATOMIC_COMPARE_AND_SWAP_SUCCESS == Atomic_CompareAndSwap_u32( ( uint32_t * ) &pxCond->iWaitingThreads, 0, ( uint32_t ) iLocalWaitingThreads ) )
+ {
+ /* Unblock all. */
+ for( i = 0; i < iLocalWaitingThreads; i++ )
+ {
+ ( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &pxCond->xCondWaitSemaphore );
+ }
+
+ break;
+ }
+
+ /* Local copy is out dated. Reload, and retry. */
+ iLocalWaitingThreads = pxCond->iWaitingThreads;
+ }
+
+ return 0;
+}
+
+/*-----------------------------------------------------------*/
+
+int pthread_cond_destroy( pthread_cond_t * cond )
+{
+ pthread_cond_internal_t * pxCond = ( pthread_cond_internal_t * ) ( cond );
+
+ /* Free all resources in use by the cond. */
+ vSemaphoreDelete( ( SemaphoreHandle_t ) &pxCond->xCondWaitSemaphore );
+
+ return 0;
+}
+
+/*-----------------------------------------------------------*/
+
+int pthread_cond_init( pthread_cond_t * cond,
+ const pthread_condattr_t * attr )
+{
+ int iStatus = 0;
+ pthread_cond_internal_t * pxCond = ( pthread_cond_internal_t * ) cond;
+
+ /* Silence warnings about unused parameters. */
+ ( void ) attr;
+
+ if( pxCond == NULL )
+ {
+ iStatus = ENOMEM;
+ }
+
+ if( iStatus == 0 )
+ {
+ /* Set the members of the cond. The semaphore create calls will never fail
+ * when their arguments aren't NULL. */
+ pxCond->xIsInitialized = pdTRUE;
+
+ ( void ) xSemaphoreCreateCountingStatic( INT_MAX, 0U, &pxCond->xCondWaitSemaphore );
+ pxCond->iWaitingThreads = 0;
+ }
+
+ return iStatus;
+}
+
+/*-----------------------------------------------------------*/
+
+int pthread_cond_signal( pthread_cond_t * cond )
+{
+ pthread_cond_internal_t * pxCond = ( pthread_cond_internal_t * ) ( cond );
+
+ /* If the cond is uninitialized, perform initialization. */
+ prvInitializeStaticCond( pxCond );
+
+ /* Local copy of number of threads waiting. */
+ unsigned iLocalWaitingThreads = pxCond->iWaitingThreads;
+
+ /* Test local copy of threads waiting is larger than zero. */
+ while( iLocalWaitingThreads > 0 )
+ {
+ /* Test-and-set. Atomically check whether the copy in memory has changed.
+ * And, if not decrease the copy of threads waiting in memory. */
+ if( ATOMIC_COMPARE_AND_SWAP_SUCCESS == Atomic_CompareAndSwap_u32( ( uint32_t * ) &pxCond->iWaitingThreads, ( uint32_t ) iLocalWaitingThreads - 1, ( uint32_t ) iLocalWaitingThreads ) )
+ {
+ /* Unblock one. */
+ ( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &pxCond->xCondWaitSemaphore );
+
+ /* Signal one succeeded. Break. */
+ break;
+ }
+
+ /* Local copy may be out dated. Reload, and retry. */
+ iLocalWaitingThreads = pxCond->iWaitingThreads;
+ }
+
+ return 0;
+}
+
+/*-----------------------------------------------------------*/
+
+int pthread_cond_timedwait( pthread_cond_t * cond,
+ pthread_mutex_t * mutex,
+ const struct timespec * abstime )
+{
+ unsigned iLocalWaitingThreads;
+ int iStatus = 0;
+ pthread_cond_internal_t * pxCond = ( pthread_cond_internal_t * ) ( cond );
+ TickType_t xDelay = portMAX_DELAY;
+
+ /* If the cond is uninitialized, perform initialization. */
+ prvInitializeStaticCond( pxCond );
+
+ /* Convert abstime to a delay in TickType_t if provided. */
+ if( abstime != NULL )
+ {
+ struct timespec xCurrentTime = { 0 };
+
+ /* Get current time */
+ if( clock_gettime( CLOCK_REALTIME, &xCurrentTime ) != 0 )
+ {
+ iStatus = EINVAL;
+ }
+ else
+ {
+ iStatus = UTILS_AbsoluteTimespecToDeltaTicks( abstime, &xCurrentTime, &xDelay );
+ }
+ }
+
+ /* Increase the counter of threads blocking on condition variable, then
+ * unlock mutex. */
+ if( iStatus == 0 )
+ {
+ /* Atomically increments thread waiting by 1, and
+ * stores number of threads waiting before increment. */
+ iLocalWaitingThreads = Atomic_Increment_u32( ( uint32_t * ) &pxCond->iWaitingThreads );
+
+ iStatus = pthread_mutex_unlock( mutex );
+ }
+
+ /* Wait on the condition variable. */
+ if( iStatus == 0 )
+ {
+ if( xSemaphoreTake( ( SemaphoreHandle_t ) &pxCond->xCondWaitSemaphore,
+ xDelay ) == pdPASS )
+ {
+ /* When successful, relock mutex. */
+ iStatus = pthread_mutex_lock( mutex );
+ }
+ else
+ {
+ /* Timeout. Relock mutex and decrement number of waiting threads. */
+ iStatus = ETIMEDOUT;
+ ( void ) pthread_mutex_lock( mutex );
+
+ /* Atomically decrements thread waiting by 1.
+ * If iLocalWaitingThreads is updated by other thread(s) in between,
+ * this implementation guarantees to decrement by 1 based on the
+ * value currently in pxCond->iWaitingThreads. */
+ prvTestAndDecrement( pxCond, iLocalWaitingThreads + 1 );
+ }
+ }
+ else
+ {
+ /* Atomically decrements thread waiting by 1.
+ * If iLocalWaitingThreads is updated by other thread(s) in between,
+ * this implementation guarantees to decrement by 1 based on the
+ * value currently in pxCond->iWaitingThreads. */
+ prvTestAndDecrement( pxCond, iLocalWaitingThreads + 1 );
+ }
+
+ return iStatus;
+}
+
+/*-----------------------------------------------------------*/
+
+int pthread_cond_wait( pthread_cond_t * cond,
+ pthread_mutex_t * mutex )
+{
+ return pthread_cond_timedwait( cond, mutex, NULL );
+} \ No newline at end of file