]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/Common/Full/semtest.c
Update version numbers to V7.4.1.
[freertos] / FreeRTOS / Demo / Common / Full / semtest.c
1 /*\r
2     FreeRTOS V7.4.1 - Copyright (C) 2013 Real Time Engineers Ltd.\r
3 \r
4     FEATURES AND PORTS ARE ADDED TO FREERTOS ALL THE TIME.  PLEASE VISIT\r
5     http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.\r
6 \r
7     ***************************************************************************\r
8      *                                                                       *\r
9      *    FreeRTOS tutorial books are available in pdf and paperback.        *\r
10      *    Complete, revised, and edited pdf reference manuals are also       *\r
11      *    available.                                                         *\r
12      *                                                                       *\r
13      *    Purchasing FreeRTOS documentation will not only help you, by       *\r
14      *    ensuring you get running as quickly as possible and with an        *\r
15      *    in-depth knowledge of how to use FreeRTOS, it will also help       *\r
16      *    the FreeRTOS project to continue with its mission of providing     *\r
17      *    professional grade, cross platform, de facto standard solutions    *\r
18      *    for microcontrollers - completely free of charge!                  *\r
19      *                                                                       *\r
20      *    >>> See http://www.FreeRTOS.org/Documentation for details. <<<     *\r
21      *                                                                       *\r
22      *    Thank you for using FreeRTOS, and thank you for your support!      *\r
23      *                                                                       *\r
24     ***************************************************************************\r
25 \r
26 \r
27     This file is part of the FreeRTOS distribution.\r
28 \r
29     FreeRTOS is free software; you can redistribute it and/or modify it under\r
30     the terms of the GNU General Public License (version 2) as published by the\r
31     Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
32 \r
33     >>>>>>NOTE<<<<<< The modification to the GPL is included to allow you to\r
34     distribute a combined work that includes FreeRTOS without being obliged to\r
35     provide the source code for proprietary components outside of the FreeRTOS\r
36     kernel.\r
37 \r
38     FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY\r
39     WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS\r
40     FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more\r
41     details. You should have received a copy of the GNU General Public License\r
42     and the FreeRTOS license exception along with FreeRTOS; if not it can be\r
43     viewed here: http://www.freertos.org/a00114.html and also obtained by\r
44     writing to Real Time Engineers Ltd., contact details for whom are available\r
45     on the FreeRTOS WEB site.\r
46 \r
47     1 tab == 4 spaces!\r
48 \r
49     ***************************************************************************\r
50      *                                                                       *\r
51      *    Having a problem?  Start by reading the FAQ "My application does   *\r
52      *    not run, what could be wrong?"                                     *\r
53      *                                                                       *\r
54      *    http://www.FreeRTOS.org/FAQHelp.html                               *\r
55      *                                                                       *\r
56     ***************************************************************************\r
57 \r
58 \r
59     http://www.FreeRTOS.org - Documentation, books, training, latest versions, \r
60     license and Real Time Engineers Ltd. contact details.\r
61 \r
62     http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,\r
63     including FreeRTOS+Trace - an indispensable productivity tool, and our new\r
64     fully thread aware and reentrant UDP/IP stack.\r
65 \r
66     http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High \r
67     Integrity Systems, who sell the code with commercial support, \r
68     indemnification and middleware, under the OpenRTOS brand.\r
69     \r
70     http://www.SafeRTOS.com - High Integrity Systems also provide a safety \r
71     engineered and independently SIL3 certified version for use in safety and \r
72     mission critical applications that require provable dependability.\r
73 */\r
74 \r
75 /**\r
76  * Creates two sets of two tasks.  The tasks within a set share a variable, access \r
77  * to which is guarded by a semaphore.\r
78  * \r
79  * Each task starts by attempting to obtain the semaphore.  On obtaining a \r
80  * semaphore a task checks to ensure that the guarded variable has an expected \r
81  * value.  It then clears the variable to zero before counting it back up to the \r
82  * expected value in increments of 1.  After each increment the variable is checked \r
83  * to ensure it contains the value to which it was just set. When the starting \r
84  * value is again reached the task releases the semaphore giving the other task in \r
85  * the set a chance to do exactly the same thing.  The starting value is high \r
86  * enough to ensure that a tick is likely to occur during the incrementing loop.\r
87  *\r
88  * An error is flagged if at any time during the process a shared variable is \r
89  * found to have a value other than that expected.  Such an occurrence would \r
90  * suggest an error in the mutual exclusion mechanism by which access to the \r
91  * variable is restricted.\r
92  *\r
93  * The first set of two tasks poll their semaphore.  The second set use blocking \r
94  * calls.\r
95  *\r
96  * \page SemTestC semtest.c\r
97  * \ingroup DemoFiles\r
98  * <HR>\r
99  */\r
100 \r
101 /*\r
102 Changes from V1.2.0:\r
103 \r
104         + The tasks that operate at the idle priority now use a lower expected\r
105           count than those running at a higher priority.  This prevents the low\r
106           priority tasks from signaling an error because they have not been \r
107           scheduled enough time for each of them to count the shared variable to\r
108           the high value.\r
109 \r
110 Changes from V2.0.0\r
111 \r
112         + Delay periods are now specified using variables and constants of\r
113           portTickType rather than unsigned long.\r
114 \r
115 Changes from V2.1.1\r
116 \r
117         + The stack size now uses configMINIMAL_STACK_SIZE.\r
118         + String constants made file scope to decrease stack depth on 8051 port.\r
119 */\r
120 \r
121 #include <stdlib.h>\r
122 \r
123 /* Scheduler include files. */\r
124 #include "FreeRTOS.h"\r
125 #include "task.h"\r
126 #include "semphr.h"\r
127 \r
128 /* Demo app include files. */\r
129 #include "semtest.h"\r
130 #include "print.h"\r
131 \r
132 /* The value to which the shared variables are counted. */\r
133 #define semtstBLOCKING_EXPECTED_VALUE           ( ( unsigned long ) 0xfff )\r
134 #define semtstNON_BLOCKING_EXPECTED_VALUE       ( ( unsigned long ) 0xff  )\r
135 \r
136 #define semtstSTACK_SIZE                        configMINIMAL_STACK_SIZE\r
137 \r
138 #define semtstNUM_TASKS                         ( 4 )\r
139 \r
140 #define semtstDELAY_FACTOR                      ( ( portTickType ) 10 )\r
141 \r
142 /* The task function as described at the top of the file. */\r
143 static void prvSemaphoreTest( void *pvParameters );\r
144 \r
145 /* Structure used to pass parameters to each task. */\r
146 typedef struct SEMAPHORE_PARAMETERS\r
147 {\r
148         xSemaphoreHandle xSemaphore;\r
149         volatile unsigned long *pulSharedVariable;\r
150         portTickType xBlockTime;\r
151 } xSemaphoreParameters;\r
152 \r
153 /* Variables used to check that all the tasks are still running without errors. */\r
154 static volatile short sCheckVariables[ semtstNUM_TASKS ] = { 0 };\r
155 static volatile short sNextCheckVariable = 0;\r
156 \r
157 /* Strings to print if USE_STDIO is defined. */\r
158 const char * const pcPollingSemaphoreTaskError = "Guarded shared variable in unexpected state.\r\n";\r
159 const char * const pcSemaphoreTaskStart = "Guarded shared variable task started.\r\n";\r
160 \r
161 /*-----------------------------------------------------------*/\r
162 \r
163 void vStartSemaphoreTasks( unsigned portBASE_TYPE uxPriority )\r
164 {\r
165 xSemaphoreParameters *pxFirstSemaphoreParameters, *pxSecondSemaphoreParameters;\r
166 const portTickType xBlockTime = ( portTickType ) 100;\r
167 \r
168         /* Create the structure used to pass parameters to the first two tasks. */\r
169         pxFirstSemaphoreParameters = ( xSemaphoreParameters * ) pvPortMalloc( sizeof( xSemaphoreParameters ) );\r
170 \r
171         if( pxFirstSemaphoreParameters != NULL )\r
172         {\r
173                 /* Create the semaphore used by the first two tasks. */\r
174                 vSemaphoreCreateBinary( pxFirstSemaphoreParameters->xSemaphore );\r
175 \r
176                 if( pxFirstSemaphoreParameters->xSemaphore != NULL )\r
177                 {\r
178                         /* Create the variable which is to be shared by the first two tasks. */\r
179                         pxFirstSemaphoreParameters->pulSharedVariable = ( unsigned long * ) pvPortMalloc( sizeof( unsigned long ) );\r
180 \r
181                         /* Initialise the share variable to the value the tasks expect. */\r
182                         *( pxFirstSemaphoreParameters->pulSharedVariable ) = semtstNON_BLOCKING_EXPECTED_VALUE;\r
183 \r
184                         /* The first two tasks do not block on semaphore calls. */\r
185                         pxFirstSemaphoreParameters->xBlockTime = ( portTickType ) 0;\r
186 \r
187                         /* Spawn the first two tasks.  As they poll they operate at the idle priority. */\r
188                         xTaskCreate( prvSemaphoreTest, "PolSEM1", semtstSTACK_SIZE, ( void * ) pxFirstSemaphoreParameters, tskIDLE_PRIORITY, ( xTaskHandle * ) NULL );\r
189                         xTaskCreate( prvSemaphoreTest, "PolSEM2", semtstSTACK_SIZE, ( void * ) pxFirstSemaphoreParameters, tskIDLE_PRIORITY, ( xTaskHandle * ) NULL );\r
190                 }\r
191         }\r
192 \r
193         /* Do exactly the same to create the second set of tasks, only this time \r
194         provide a block time for the semaphore calls. */\r
195         pxSecondSemaphoreParameters = ( xSemaphoreParameters * ) pvPortMalloc( sizeof( xSemaphoreParameters ) );\r
196         if( pxSecondSemaphoreParameters != NULL )\r
197         {\r
198                 vSemaphoreCreateBinary( pxSecondSemaphoreParameters->xSemaphore );\r
199 \r
200                 if( pxSecondSemaphoreParameters->xSemaphore != NULL )\r
201                 {\r
202                         pxSecondSemaphoreParameters->pulSharedVariable = ( unsigned long * ) pvPortMalloc( sizeof( unsigned long ) );\r
203                         *( pxSecondSemaphoreParameters->pulSharedVariable ) = semtstBLOCKING_EXPECTED_VALUE;\r
204                         pxSecondSemaphoreParameters->xBlockTime = xBlockTime / portTICK_RATE_MS;\r
205 \r
206                         xTaskCreate( prvSemaphoreTest, "BlkSEM1", semtstSTACK_SIZE, ( void * ) pxSecondSemaphoreParameters, uxPriority, ( xTaskHandle * ) NULL );\r
207                         xTaskCreate( prvSemaphoreTest, "BlkSEM2", semtstSTACK_SIZE, ( void * ) pxSecondSemaphoreParameters, uxPriority, ( xTaskHandle * ) NULL );\r
208                 }\r
209         }\r
210 }\r
211 /*-----------------------------------------------------------*/\r
212 \r
213 static void prvSemaphoreTest( void *pvParameters )\r
214 {\r
215 xSemaphoreParameters *pxParameters;\r
216 volatile unsigned long *pulSharedVariable, ulExpectedValue;\r
217 unsigned long ulCounter;\r
218 short sError = pdFALSE, sCheckVariableToUse;\r
219 \r
220         /* See which check variable to use.  sNextCheckVariable is not semaphore \r
221         protected! */\r
222         portENTER_CRITICAL();\r
223                 sCheckVariableToUse = sNextCheckVariable;\r
224                 sNextCheckVariable++;\r
225         portEXIT_CRITICAL();\r
226 \r
227         /* Queue a message for printing to say the task has started. */\r
228         vPrintDisplayMessage( &pcSemaphoreTaskStart );\r
229 \r
230         /* A structure is passed in as the parameter.  This contains the shared \r
231         variable being guarded. */\r
232         pxParameters = ( xSemaphoreParameters * ) pvParameters;\r
233         pulSharedVariable = pxParameters->pulSharedVariable;\r
234 \r
235         /* If we are blocking we use a much higher count to ensure loads of context\r
236         switches occur during the count. */\r
237         if( pxParameters->xBlockTime > ( portTickType ) 0 )\r
238         {\r
239                 ulExpectedValue = semtstBLOCKING_EXPECTED_VALUE;\r
240         }\r
241         else\r
242         {\r
243                 ulExpectedValue = semtstNON_BLOCKING_EXPECTED_VALUE;\r
244         }\r
245 \r
246         for( ;; )\r
247         {\r
248                 /* Try to obtain the semaphore. */\r
249                 if( xSemaphoreTake( pxParameters->xSemaphore, pxParameters->xBlockTime ) == pdPASS )\r
250                 {\r
251                         /* We have the semaphore and so expect any other tasks using the\r
252                         shared variable to have left it in the state we expect to find\r
253                         it. */\r
254                         if( *pulSharedVariable != ulExpectedValue )\r
255                         {\r
256                                 vPrintDisplayMessage( &pcPollingSemaphoreTaskError );\r
257                                 sError = pdTRUE;\r
258                         }\r
259                         \r
260                         /* Clear the variable, then count it back up to the expected value\r
261                         before releasing the semaphore.  Would expect a context switch or\r
262                         two during this time. */\r
263                         for( ulCounter = ( unsigned long ) 0; ulCounter <= ulExpectedValue; ulCounter++ )\r
264                         {\r
265                                 *pulSharedVariable = ulCounter;\r
266                                 if( *pulSharedVariable != ulCounter )\r
267                                 {\r
268                                         if( sError == pdFALSE )\r
269                                         {\r
270                                                 vPrintDisplayMessage( &pcPollingSemaphoreTaskError );\r
271                                         }\r
272                                         sError = pdTRUE;\r
273                                 }\r
274                         }\r
275 \r
276                         /* Release the semaphore, and if no errors have occurred increment the check\r
277                         variable. */\r
278                         if(     xSemaphoreGive( pxParameters->xSemaphore ) == pdFALSE )\r
279                         {\r
280                                 vPrintDisplayMessage( &pcPollingSemaphoreTaskError );\r
281                                 sError = pdTRUE;\r
282                         }\r
283 \r
284                         if( sError == pdFALSE )\r
285                         {\r
286                                 if( sCheckVariableToUse < semtstNUM_TASKS )\r
287                                 {\r
288                                         ( sCheckVariables[ sCheckVariableToUse ] )++;\r
289                                 }\r
290                         }\r
291 \r
292                         /* If we have a block time then we are running at a priority higher\r
293                         than the idle priority.  This task takes a long time to complete\r
294                         a cycle (deliberately so to test the guarding) so will be starving\r
295                         out lower priority tasks.  Block for some time to allow give lower\r
296                         priority tasks some processor time. */\r
297                         vTaskDelay( pxParameters->xBlockTime * semtstDELAY_FACTOR );\r
298                 }\r
299                 else\r
300                 {\r
301                         if( pxParameters->xBlockTime == ( portTickType ) 0 )\r
302                         {\r
303                                 /* We have not got the semaphore yet, so no point using the\r
304                                 processor.  We are not blocking when attempting to obtain the\r
305                                 semaphore. */\r
306                                 taskYIELD();\r
307                         }\r
308                 }\r
309         }\r
310 }\r
311 /*-----------------------------------------------------------*/\r
312 \r
313 /* This is called to check that all the created tasks are still running. */\r
314 portBASE_TYPE xAreSemaphoreTasksStillRunning( void )\r
315 {\r
316 static short sLastCheckVariables[ semtstNUM_TASKS ] = { 0 };\r
317 portBASE_TYPE xTask, xReturn = pdTRUE;\r
318 \r
319         for( xTask = 0; xTask < semtstNUM_TASKS; xTask++ )\r
320         {\r
321                 if( sLastCheckVariables[ xTask ] == sCheckVariables[ xTask ] )\r
322                 {\r
323                         xReturn = pdFALSE;\r
324                 }\r
325 \r
326                 sLastCheckVariables[ xTask ] = sCheckVariables[ xTask ];\r
327         }\r
328 \r
329         return xReturn;\r
330 }\r
331 \r
332 \r