]> git.sur5r.net Git - freertos/blob - FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_pthread_cond.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_cond.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_cond.c\r
28  * @brief Implementation of condition variable functions in pthread.h\r
29  */\r
30 \r
31 /* C standard library includes. */\r
32 #include <limits.h>\r
33 \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
39 \r
40 #include "atomic.h"\r
41 \r
42 /**\r
43  * @brief Initialize a PTHREAD_COND_INITIALIZER cond.\r
44  *\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
48  *\r
49  * @return nothing\r
50  */\r
51 static void prvInitializeStaticCond( pthread_cond_internal_t * pxCond );\r
52 \r
53 /*-----------------------------------------------------------*/\r
54 \r
55 static void prvInitializeStaticCond( pthread_cond_internal_t * pxCond )\r
56 {\r
57     /* Check if the condition variable needs to be initialized. */\r
58     if( pxCond->xIsInitialized == pdFALSE )\r
59     {\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
63 \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
66          * section. */\r
67         if( pxCond->xIsInitialized == pdFALSE )\r
68         {\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
74         }\r
75 \r
76         /* Exit the critical section. */\r
77         taskEXIT_CRITICAL();\r
78     }\r
79 }\r
80 \r
81 /**\r
82  * @brief Check "atomically" if iLocalWaitingThreads == pxCond->iWaitingThreads and decrement.\r
83  */\r
84 static void prvTestAndDecrement( pthread_cond_t * pxCond,\r
85                                  unsigned iLocalWaitingThreads )\r
86 {\r
87     /* Test local copy of threads waiting is larger than zero. */\r
88     while( iLocalWaitingThreads > 0 )\r
89     {\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
93         {\r
94             /* Signal one succeeded. Break. */\r
95             break;\r
96         }\r
97 \r
98         /* Local copy may be out dated. Reload, and retry. */\r
99         iLocalWaitingThreads = pxCond->iWaitingThreads;\r
100     }\r
101 }\r
102 \r
103 /*-----------------------------------------------------------*/\r
104 \r
105 int pthread_cond_broadcast( pthread_cond_t * cond )\r
106 {\r
107     unsigned i = 0;\r
108     pthread_cond_internal_t * pxCond = ( pthread_cond_internal_t * ) ( cond );\r
109 \r
110     /* If the cond is uninitialized, perform initialization. */\r
111     prvInitializeStaticCond( pxCond );\r
112 \r
113     /* Local copy of number of threads waiting. */\r
114     unsigned iLocalWaitingThreads = pxCond->iWaitingThreads;\r
115 \r
116     /* Test local copy of threads waiting is larger than zero. */\r
117     while( iLocalWaitingThreads > 0 )\r
118     {\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
122         {\r
123             /* Unblock all. */\r
124             for( i = 0; i < iLocalWaitingThreads; i++ )\r
125             {\r
126                 ( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &pxCond->xCondWaitSemaphore );\r
127             }\r
128 \r
129             break;\r
130         }\r
131 \r
132         /* Local copy is out dated. Reload, and retry. */\r
133         iLocalWaitingThreads = pxCond->iWaitingThreads;\r
134     }\r
135 \r
136     return 0;\r
137 }\r
138 \r
139 /*-----------------------------------------------------------*/\r
140 \r
141 int pthread_cond_destroy( pthread_cond_t * cond )\r
142 {\r
143     pthread_cond_internal_t * pxCond = ( pthread_cond_internal_t * ) ( cond );\r
144 \r
145     /* Free all resources in use by the cond. */\r
146     vSemaphoreDelete( ( SemaphoreHandle_t ) &pxCond->xCondWaitSemaphore );\r
147 \r
148     return 0;\r
149 }\r
150 \r
151 /*-----------------------------------------------------------*/\r
152 \r
153 int pthread_cond_init( pthread_cond_t * cond,\r
154                        const pthread_condattr_t * attr )\r
155 {\r
156     int iStatus = 0;\r
157     pthread_cond_internal_t * pxCond = ( pthread_cond_internal_t * ) cond;\r
158 \r
159     /* Silence warnings about unused parameters. */\r
160     ( void ) attr;\r
161 \r
162     if( pxCond == NULL )\r
163     {\r
164         iStatus = ENOMEM;\r
165     }\r
166 \r
167     if( iStatus == 0 )\r
168     {\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
172 \r
173         ( void ) xSemaphoreCreateCountingStatic( INT_MAX, 0U, &pxCond->xCondWaitSemaphore );\r
174         pxCond->iWaitingThreads = 0;\r
175     }\r
176 \r
177     return iStatus;\r
178 }\r
179 \r
180 /*-----------------------------------------------------------*/\r
181 \r
182 int pthread_cond_signal( pthread_cond_t * cond )\r
183 {\r
184     pthread_cond_internal_t * pxCond = ( pthread_cond_internal_t * ) ( cond );\r
185 \r
186     /* If the cond is uninitialized, perform initialization. */\r
187     prvInitializeStaticCond( pxCond );\r
188 \r
189     /* Local copy of number of threads waiting. */\r
190     unsigned iLocalWaitingThreads = pxCond->iWaitingThreads;\r
191 \r
192     /* Test local copy of threads waiting is larger than zero. */\r
193     while( iLocalWaitingThreads > 0 )\r
194     {\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
198         {\r
199             /* Unblock one. */\r
200             ( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &pxCond->xCondWaitSemaphore );\r
201 \r
202             /* Signal one succeeded. Break. */\r
203             break;\r
204         }\r
205 \r
206         /* Local copy may be out dated. Reload, and retry. */\r
207         iLocalWaitingThreads = pxCond->iWaitingThreads;\r
208     }\r
209 \r
210     return 0;\r
211 }\r
212 \r
213 /*-----------------------------------------------------------*/\r
214 \r
215 int pthread_cond_timedwait( pthread_cond_t * cond,\r
216                             pthread_mutex_t * mutex,\r
217                             const struct timespec * abstime )\r
218 {\r
219     unsigned iLocalWaitingThreads;\r
220     int iStatus = 0;\r
221     pthread_cond_internal_t * pxCond = ( pthread_cond_internal_t * ) ( cond );\r
222     TickType_t xDelay = portMAX_DELAY;\r
223 \r
224     /* If the cond is uninitialized, perform initialization. */\r
225     prvInitializeStaticCond( pxCond );\r
226 \r
227     /* Convert abstime to a delay in TickType_t if provided. */\r
228     if( abstime != NULL )\r
229     {\r
230         struct timespec xCurrentTime = { 0 };\r
231 \r
232         /* Get current time */\r
233         if( clock_gettime( CLOCK_REALTIME, &xCurrentTime ) != 0 )\r
234         {\r
235             iStatus = EINVAL;\r
236         }\r
237         else\r
238         {\r
239             iStatus = UTILS_AbsoluteTimespecToDeltaTicks( abstime, &xCurrentTime, &xDelay );\r
240         }\r
241     }\r
242 \r
243     /* Increase the counter of threads blocking on condition variable, then\r
244      * unlock mutex. */\r
245     if( iStatus == 0 )\r
246     {\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
250 \r
251         iStatus = pthread_mutex_unlock( mutex );\r
252     }\r
253 \r
254     /* Wait on the condition variable. */\r
255     if( iStatus == 0 )\r
256     {\r
257         if( xSemaphoreTake( ( SemaphoreHandle_t ) &pxCond->xCondWaitSemaphore,\r
258                             xDelay ) == pdPASS )\r
259         {\r
260             /* When successful, relock mutex. */\r
261             iStatus = pthread_mutex_lock( mutex );\r
262         }\r
263         else\r
264         {\r
265             /* Timeout. Relock mutex and decrement number of waiting threads. */\r
266             iStatus = ETIMEDOUT;\r
267             ( void ) pthread_mutex_lock( mutex );\r
268 \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
274         }\r
275     }\r
276     else\r
277     {\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
283     }\r
284 \r
285     return iStatus;\r
286 }\r
287 \r
288 /*-----------------------------------------------------------*/\r
289 \r
290 int pthread_cond_wait( pthread_cond_t * cond,\r
291                        pthread_mutex_t * mutex )\r
292 {\r
293     return pthread_cond_timedwait( cond, mutex, NULL );\r
294 }