]> git.sur5r.net Git - freertos/blob - Demo/Common/Minimal/recmutex.c
Remove compiler warnings.
[freertos] / Demo / Common / Minimal / recmutex.c
1 /*
2         FreeRTOS.org V5.0.0 - Copyright (C) 2003-2008 Richard Barry.
3
4         This file is part of the FreeRTOS.org distribution.
5
6         FreeRTOS.org is free software; you can redistribute it and/or modify
7         it under the terms of the GNU General Public License as published by
8         the Free Software Foundation; either version 2 of the License, or
9         (at your option) any later version.
10
11         FreeRTOS.org is distributed in the hope that it will be useful,
12         but WITHOUT ANY WARRANTY; without even the implied warranty of
13         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14         GNU General Public License for more details.
15
16         You should have received a copy of the GNU General Public License
17         along with FreeRTOS.org; if not, write to the Free Software
18         Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
20         A special exception to the GPL can be applied should you wish to distribute
21         a combined work that includes FreeRTOS.org, without being obliged to provide
22         the source code for any proprietary components.  See the licensing section 
23         of http://www.FreeRTOS.org for full details of how and when the exception
24         can be applied.
25
26     ***************************************************************************
27     ***************************************************************************
28     *                                                                         *
29     * SAVE TIME AND MONEY!  We can port FreeRTOS.org to your own hardware,    *
30     * and even write all or part of your application on your behalf.          *
31     * See http://www.OpenRTOS.com for details of the services we provide to   *
32     * expedite your project.                                                  *
33     *                                                                         *
34     ***************************************************************************
35     ***************************************************************************
36
37         Please ensure to read the configuration and relevant port sections of the
38         online documentation.
39
40         http://www.FreeRTOS.org - Documentation, latest information, license and 
41         contact details.
42
43         http://www.SafeRTOS.com - A version that is certified for use in safety 
44         critical systems.
45
46         http://www.OpenRTOS.com - Commercial support, development, porting, 
47         licensing and training services.
48 */
49
50 /*
51         The tasks defined on this page demonstrate the use of recursive mutexes.
52
53         For recursive mutex functionality the created mutex should be created using
54         xSemaphoreCreateRecursiveMutex(), then be manipulated
55         using the xSemaphoreTakeRecursive() and xSemaphoreGiveRecursive() API
56         functions.
57
58         This demo creates three tasks all of which access the same recursive mutex:
59
60         prvRecursiveMutexControllingTask() has the highest priority so executes 
61         first and grabs the mutex.  It then performs some recursive accesses - 
62         between each of which it sleeps for a short period to let the lower 
63         priority tasks execute.  When it has completed its demo functionality
64         it gives the mutex back before suspending itself.
65
66         prvRecursiveMutexBlockingTask() attempts to access the mutex by performing
67         a blocking 'take'.  The blocking task has a lower priority than the 
68         controlling     task so by the time it executes the mutex has already been
69         taken by the controlling task,  causing the blocking task to block.  It 
70         does not unblock until the controlling task has given the mutex back, 
71         and it does not actually run until the controlling task has suspended 
72         itself (due to the relative priorities).  When it eventually does obtain
73         the mutex all it does is give the mutex back prior to also suspending 
74         itself.  At this point both the controlling task and the blocking task are 
75         suspended.
76
77         prvRecursiveMutexPollingTask() runs at the idle priority.  It spins round
78         a tight loop attempting to obtain the mutex with a non-blocking call.  As
79         the lowest priority task it will not successfully obtain the mutex until
80         both the controlling and blocking tasks are suspended.  Once it eventually 
81         does obtain the mutex it first unsuspends both the controlling task and
82         blocking task prior to giving the mutex back - resulting in the polling
83         task temporarily inheriting the controlling tasks priority.
84 */
85
86 /* Scheduler include files. */
87 #include "FreeRTOS.h"
88 #include "task.h"
89 #include "semphr.h"
90
91 /* Demo app include files. */
92 #include "recmutex.h"
93
94 /* Priorities assigned to the three tasks. */
95 #define recmuCONTROLLING_TASK_PRIORITY  ( tskIDLE_PRIORITY + 2 )
96 #define recmuBLOCKING_TASK_PRIORITY             ( tskIDLE_PRIORITY + 1 )
97 #define recmuPOLLING_TASK_PRIORITY              ( tskIDLE_PRIORITY + 0 )
98
99 /* The recursive call depth. */
100 #define recmuMAX_COUNT                                  ( 10 )
101
102 /* Misc. */
103 #define recmuSHORT_DELAY                                ( 20 / portTICK_RATE_MS )
104 #define recmuNO_DELAY                                   ( ( portTickType ) 0 )
105 #define recmuTWO_TICK_DELAY                             ( ( portTickType ) 2 )
106
107 /* The three tasks as described at the top of this file. */
108 static void prvRecursiveMutexControllingTask( void *pvParameters );
109 static void prvRecursiveMutexBlockingTask( void *pvParameters );
110 static void prvRecursiveMutexPollingTask( void *pvParameters );
111
112 /* The mutex used by the demo. */
113 static xSemaphoreHandle xMutex;
114
115 /* Variables used to detect and latch errors. */
116 static volatile portBASE_TYPE xErrorOccurred = pdFALSE, xControllingIsSuspended = pdFALSE, xBlockingIsSuspended = pdFALSE;
117 static volatile unsigned portBASE_TYPE uxControllingCycles = 0, uxBlockingCycles, uxPollingCycles = 0;
118
119 /* Handles of the two higher priority tasks, required so they can be resumed 
120 (unsuspended). */
121 static xTaskHandle xControllingTaskHandle, xBlockingTaskHandle;
122
123 /*-----------------------------------------------------------*/
124
125 void vStartRecursiveMutexTasks( void )
126 {
127         /* Just creates the mutex and the three tasks. */
128
129         xMutex = xSemaphoreCreateRecursiveMutex();
130
131         if( xMutex != NULL )
132         {
133                 xTaskCreate( prvRecursiveMutexControllingTask, ( signed portCHAR * ) "Rec1", configMINIMAL_STACK_SIZE, NULL, recmuCONTROLLING_TASK_PRIORITY, &xControllingTaskHandle );
134         xTaskCreate( prvRecursiveMutexBlockingTask, ( signed portCHAR * ) "Rec2", configMINIMAL_STACK_SIZE, NULL, recmuBLOCKING_TASK_PRIORITY, &xBlockingTaskHandle );
135         xTaskCreate( prvRecursiveMutexPollingTask, ( signed portCHAR * ) "Rec3", configMINIMAL_STACK_SIZE, NULL, recmuPOLLING_TASK_PRIORITY, NULL );
136         }
137 }
138 /*-----------------------------------------------------------*/
139
140 static void prvRecursiveMutexControllingTask( void *pvParameters )
141 {
142 unsigned portBASE_TYPE ux;
143 \r
144         /* Just to remove compiler warning. */\r
145         ( void ) pvParameters;\r
146
147         for( ;; )
148         {
149                 /* Should not be able to 'give' the mutex, as we have not yet 'taken'
150                 it. */
151                 if( xSemaphoreGiveRecursive( xMutex ) == pdPASS )
152                 {
153                         xErrorOccurred = pdTRUE;
154                 }
155
156                 for( ux = 0; ux < recmuMAX_COUNT; ux++ )
157                 {
158                         /* We should now be able to take the mutex as many times as
159                         we like.  A one tick delay is used so the polling task will
160                         inherit our priority on all but the first cycle of this task. 
161                         If we did not block attempting to receive the mutex then no
162                         priority inheritance would occur. */
163                         if( xSemaphoreTakeRecursive( xMutex, recmuTWO_TICK_DELAY ) != pdPASS )
164                         {
165                                 xErrorOccurred = pdTRUE;
166                         }
167
168                         /* Ensure the other task attempting to access the mutex (and the
169                         other demo tasks) are able to execute. */
170                         vTaskDelay( recmuSHORT_DELAY );
171                 }
172
173                 /* For each time we took the mutex, give it back. */
174                 for( ux = 0; ux < recmuMAX_COUNT; ux++ )
175                 {
176                         /* Ensure the other task attempting to access the mutex (and the
177                         other demo tasks) are able to execute. */
178                         vTaskDelay( recmuSHORT_DELAY );
179
180                         /* We should now be able to give the mutex as many times as we
181                         took it. */
182                         if( xSemaphoreGiveRecursive( xMutex ) != pdPASS )
183                         {
184                                 xErrorOccurred = pdTRUE;
185                         }
186                 }
187
188                 /* Having given it back the same number of times as it was taken, we
189                 should no longer be the mutex owner, so the next give sh ould fail. */
190                 if( xSemaphoreGiveRecursive( xMutex ) == pdPASS )
191                 {
192                         xErrorOccurred = pdTRUE;
193                 }
194
195                 /* Keep count of the number of cycles this task has performed so a 
196                 stall can be detected. */
197                 uxControllingCycles++;
198
199                 /* Suspend ourselves to the blocking task can execute. */
200                 xControllingIsSuspended = pdTRUE;
201                 vTaskSuspend( NULL );
202                 xControllingIsSuspended = pdFALSE;
203         }
204 }
205 /*-----------------------------------------------------------*/
206
207 static void prvRecursiveMutexBlockingTask( void *pvParameters )
208 {\r
209         /* Just to remove compiler warning. */\r
210         ( void ) pvParameters;\r
211
212         for( ;; )
213         {
214                 /* Attempt to obtain the mutex.  We should block until the 
215                 controlling task has given up the mutex, and not actually execute
216                 past this call until the controlling task is suspended. */
217                 if( xSemaphoreTakeRecursive( xMutex, portMAX_DELAY ) == pdPASS )
218                 {
219                         if( xControllingIsSuspended != pdTRUE )
220                         {
221                                 /* Did not expect to execute until the controlling task was
222                                 suspended. */
223                                 xErrorOccurred = pdTRUE;
224                         }
225                         else
226                         {
227                                 /* Give the mutex back before suspending ourselves to allow
228                                 the polling task to obtain the mutex. */
229                                 if( xSemaphoreGiveRecursive( xMutex ) != pdPASS )
230                                 {
231                                         xErrorOccurred = pdTRUE;
232                                 }
233
234                                 xBlockingIsSuspended = pdTRUE;
235                                 vTaskSuspend( NULL );
236                                 xBlockingIsSuspended = pdFALSE;
237                         }
238                 }
239                 else
240                 {
241                         /* We should not leave the xSemaphoreTakeRecursive() function
242                         until the mutex was obtained. */
243                         xErrorOccurred = pdTRUE;
244                 }
245
246                 /* The controlling and blocking tasks should be in lock step. */
247                 if( uxControllingCycles != ( uxBlockingCycles + 1 ) )
248                 {
249                         xErrorOccurred = pdTRUE;
250                 }
251
252                 /* Keep count of the number of cycles this task has performed so a 
253                 stall can be detected. */
254                 uxBlockingCycles++;
255         }
256 }
257 /*-----------------------------------------------------------*/
258
259 static void prvRecursiveMutexPollingTask( void *pvParameters )
260 {\r
261         /* Just to remove compiler warning. */
262         ( void ) pvParameters;
263 \r
264         for( ;; )
265         {
266                 /* Keep attempting to obtain the mutex.  We should only obtain it when
267                 the blocking task has suspended itself. */
268                 if( xSemaphoreTakeRecursive( xMutex, recmuNO_DELAY ) == pdPASS )
269                 {
270                         /* Is the blocking task suspended? */
271                         if( xBlockingIsSuspended != pdTRUE )
272                         {
273                                 xErrorOccurred = pdTRUE;
274                         }
275                         else
276                         {
277                                 /* Keep count of the number of cycles this task has performed so 
278                                 a stall can be detected. */
279                                 uxPollingCycles++;
280
281                                 /* We can resume the other tasks here even though they have a
282                                 higher priority than the polling task.  When they execute they
283                                 will attempt to obtain the mutex but fail because the polling
284                                 task is still the mutex holder.  The polling task (this task)
285                                 will then inherit the higher priority. */                               
286                                 vTaskResume( xBlockingTaskHandle );
287                 vTaskResume( xControllingTaskHandle );
288                         
289                                 /* Release the mutex, disinheriting the higher priority again. */
290                                 if( xSemaphoreGiveRecursive( xMutex ) != pdPASS )
291                                 {
292                                         xErrorOccurred = pdTRUE;
293                                 }
294                         }
295                 }
296
297                 #if configUSE_PREEMPTION == 0
298                 {
299                         taskYIELD();
300                 }
301                 #endif
302         }
303 }
304 /*-----------------------------------------------------------*/
305
306 /* This is called to check that all the created tasks are still running. */
307 portBASE_TYPE xAreRecursiveMutexTasksStillRunning( void )
308 {
309 portBASE_TYPE xReturn;
310 static unsigned portBASE_TYPE uxLastControllingCycles = 0, uxLastBlockingCycles = 0, uxLastPollingCycles = 0;
311
312         /* Is the controlling task still cycling? */
313         if( uxLastControllingCycles == uxControllingCycles )
314         {
315                 xErrorOccurred = pdTRUE;
316         }
317         else
318         {
319                 uxLastControllingCycles = uxControllingCycles;
320         }
321
322         /* Is the blocking task still cycling? */
323         if( uxLastBlockingCycles == uxBlockingCycles )
324         {
325                 xErrorOccurred = pdTRUE;
326         }
327         else
328         {
329                 uxLastBlockingCycles = uxBlockingCycles;
330         }
331
332         /* Is the polling task still cycling? */
333         if( uxLastPollingCycles == uxPollingCycles )
334         {
335                 xErrorOccurred = pdTRUE;
336         }
337         else
338         {
339                 uxLastPollingCycles = uxPollingCycles;
340         }
341
342         if( xErrorOccurred == pdTRUE )
343         {
344                 xReturn = pdFAIL;
345         }
346         else
347         {
348                 xReturn = pdTRUE;
349         }
350
351         return xReturn;
352 }
353
354
355
356