]> begriffs open source - freertos/blob - Demo/Common/Minimal/semtest.c
Updated to V4.0.5
[freertos] / Demo / Common / Minimal / semtest.c
1 /*\r
2         FreeRTOS.org V4.0.5 - Copyright (C) 2003-2006 Richard Barry.\r
3 \r
4         This file is part of the FreeRTOS.org distribution.\r
5 \r
6         FreeRTOS.org is free software; you can redistribute it and/or modify\r
7         it under the terms of the GNU General Public License as published by\r
8         the Free Software Foundation; either version 2 of the License, or\r
9         (at your option) any later version.\r
10 \r
11         FreeRTOS.org is distributed in the hope that it will be useful,\r
12         but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
14         GNU General Public License for more details.\r
15 \r
16         You should have received a copy of the GNU General Public License\r
17         along with FreeRTOS.org; if not, write to the Free Software\r
18         Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
19 \r
20         A special exception to the GPL can be applied should you wish to distribute\r
21         a combined work that includes FreeRTOS.org, without being obliged to provide\r
22         the source code for any proprietary components.  See the licensing section \r
23         of http://www.FreeRTOS.org for full details of how and when the exception\r
24         can be applied.\r
25 \r
26         ***************************************************************************\r
27         See http://www.FreeRTOS.org for documentation, latest information, license \r
28         and contact details.  Please ensure to read the configuration and relevant \r
29         port sections of the online documentation.\r
30         ***************************************************************************\r
31 */\r
32 \r
33 /*\r
34  * Creates two sets of two tasks.  The tasks within a set share a variable, access \r
35  * to which is guarded by a semaphore.\r
36  * \r
37  * Each task starts by attempting to obtain the semaphore.  On obtaining a \r
38  * semaphore a task checks to ensure that the guarded variable has an expected \r
39  * value.  It then clears the variable to zero before counting it back up to the \r
40  * expected value in increments of 1.  After each increment the variable is checked \r
41  * to ensure it contains the value to which it was just set. When the starting \r
42  * value is again reached the task releases the semaphore giving the other task in \r
43  * the set a chance to do exactly the same thing.  The starting value is high \r
44  * enough to ensure that a tick is likely to occur during the incrementing loop.\r
45  *\r
46  * An error is flagged if at any time during the process a shared variable is \r
47  * found to have a value other than that expected.  Such an occurrence would \r
48  * suggest an error in the mutual exclusion mechanism by which access to the \r
49  * variable is restricted.\r
50  *\r
51  * The first set of two tasks poll their semaphore.  The second set use blocking \r
52  * calls.\r
53  *\r
54  */\r
55 \r
56 \r
57 #include <stdlib.h>\r
58 \r
59 /* Scheduler include files. */\r
60 #include "FreeRTOS.h"\r
61 #include "task.h"\r
62 #include "semphr.h"\r
63 \r
64 /* Demo app include files. */\r
65 #include "semtest.h"\r
66 \r
67 /* The value to which the shared variables are counted. */\r
68 #define semtstBLOCKING_EXPECTED_VALUE           ( ( unsigned portLONG ) 0xfff )\r
69 #define semtstNON_BLOCKING_EXPECTED_VALUE       ( ( unsigned portLONG ) 0xff  )\r
70 \r
71 #define semtstSTACK_SIZE                        configMINIMAL_STACK_SIZE\r
72 \r
73 #define semtstNUM_TASKS                         ( 4 )\r
74 \r
75 #define semtstDELAY_FACTOR                      ( ( portTickType ) 10 )\r
76 \r
77 /* The task function as described at the top of the file. */\r
78 static portTASK_FUNCTION_PROTO( prvSemaphoreTest, pvParameters );\r
79 \r
80 /* Structure used to pass parameters to each task. */\r
81 typedef struct SEMAPHORE_PARAMETERS\r
82 {\r
83         xSemaphoreHandle xSemaphore;\r
84         volatile unsigned portLONG *pulSharedVariable;\r
85         portTickType xBlockTime;\r
86 } xSemaphoreParameters;\r
87 \r
88 /* Variables used to check that all the tasks are still running without errors. */\r
89 static volatile portSHORT sCheckVariables[ semtstNUM_TASKS ] = { 0 };\r
90 static volatile portSHORT sNextCheckVariable = 0;\r
91 \r
92 /*-----------------------------------------------------------*/\r
93 \r
94 void vStartSemaphoreTasks( unsigned portBASE_TYPE uxPriority )\r
95 {\r
96 xSemaphoreParameters *pxFirstSemaphoreParameters, *pxSecondSemaphoreParameters;\r
97 const portTickType xBlockTime = ( portTickType ) 100;\r
98 \r
99         /* Create the structure used to pass parameters to the first two tasks. */\r
100         pxFirstSemaphoreParameters = ( xSemaphoreParameters * ) pvPortMalloc( sizeof( xSemaphoreParameters ) );\r
101 \r
102         if( pxFirstSemaphoreParameters != NULL )\r
103         {\r
104                 /* Create the semaphore used by the first two tasks. */\r
105                 vSemaphoreCreateBinary( pxFirstSemaphoreParameters->xSemaphore );\r
106 \r
107                 if( pxFirstSemaphoreParameters->xSemaphore != NULL )\r
108                 {\r
109                         /* Create the variable which is to be shared by the first two tasks. */\r
110                         pxFirstSemaphoreParameters->pulSharedVariable = ( unsigned portLONG * ) pvPortMalloc( sizeof( unsigned portLONG ) );\r
111 \r
112                         /* Initialise the share variable to the value the tasks expect. */\r
113                         *( pxFirstSemaphoreParameters->pulSharedVariable ) = semtstNON_BLOCKING_EXPECTED_VALUE;\r
114 \r
115                         /* The first two tasks do not block on semaphore calls. */\r
116                         pxFirstSemaphoreParameters->xBlockTime = ( portTickType ) 0;\r
117 \r
118                         /* Spawn the first two tasks.  As they poll they operate at the idle priority. */\r
119                         xTaskCreate( prvSemaphoreTest, ( signed portCHAR * ) "PolSEM1", semtstSTACK_SIZE, ( void * ) pxFirstSemaphoreParameters, tskIDLE_PRIORITY, ( xTaskHandle * ) NULL );\r
120                         xTaskCreate( prvSemaphoreTest, ( signed portCHAR * ) "PolSEM2", semtstSTACK_SIZE, ( void * ) pxFirstSemaphoreParameters, tskIDLE_PRIORITY, ( xTaskHandle * ) NULL );\r
121                 }\r
122         }\r
123 \r
124         /* Do exactly the same to create the second set of tasks, only this time \r
125         provide a block time for the semaphore calls. */\r
126         pxSecondSemaphoreParameters = ( xSemaphoreParameters * ) pvPortMalloc( sizeof( xSemaphoreParameters ) );\r
127         if( pxSecondSemaphoreParameters != NULL )\r
128         {\r
129                 vSemaphoreCreateBinary( pxSecondSemaphoreParameters->xSemaphore );\r
130 \r
131                 if( pxSecondSemaphoreParameters->xSemaphore != NULL )\r
132                 {\r
133                         pxSecondSemaphoreParameters->pulSharedVariable = ( unsigned portLONG * ) pvPortMalloc( sizeof( unsigned portLONG ) );\r
134                         *( pxSecondSemaphoreParameters->pulSharedVariable ) = semtstBLOCKING_EXPECTED_VALUE;\r
135                         pxSecondSemaphoreParameters->xBlockTime = xBlockTime / portTICK_RATE_MS;\r
136 \r
137                         xTaskCreate( prvSemaphoreTest, ( signed portCHAR * ) "BlkSEM1", semtstSTACK_SIZE, ( void * ) pxSecondSemaphoreParameters, uxPriority, ( xTaskHandle * ) NULL );\r
138                         xTaskCreate( prvSemaphoreTest, ( signed portCHAR * ) "BlkSEM2", semtstSTACK_SIZE, ( void * ) pxSecondSemaphoreParameters, uxPriority, ( xTaskHandle * ) NULL );\r
139                 }\r
140         }\r
141 }\r
142 /*-----------------------------------------------------------*/\r
143 \r
144 static portTASK_FUNCTION( prvSemaphoreTest, pvParameters )\r
145 {\r
146 xSemaphoreParameters *pxParameters;\r
147 volatile unsigned portLONG *pulSharedVariable, ulExpectedValue;\r
148 unsigned portLONG ulCounter;\r
149 portSHORT sError = pdFALSE, sCheckVariableToUse;\r
150 \r
151         /* See which check variable to use.  sNextCheckVariable is not semaphore \r
152         protected! */\r
153         portENTER_CRITICAL();\r
154                 sCheckVariableToUse = sNextCheckVariable;\r
155                 sNextCheckVariable++;\r
156         portEXIT_CRITICAL();\r
157 \r
158         /* A structure is passed in as the parameter.  This contains the shared \r
159         variable being guarded. */\r
160         pxParameters = ( xSemaphoreParameters * ) pvParameters;\r
161         pulSharedVariable = pxParameters->pulSharedVariable;\r
162 \r
163         /* If we are blocking we use a much higher count to ensure loads of context\r
164         switches occur during the count. */\r
165         if( pxParameters->xBlockTime > ( portTickType ) 0 )\r
166         {\r
167                 ulExpectedValue = semtstBLOCKING_EXPECTED_VALUE;\r
168         }\r
169         else\r
170         {\r
171                 ulExpectedValue = semtstNON_BLOCKING_EXPECTED_VALUE;\r
172         }\r
173 \r
174         for( ;; )\r
175         {\r
176                 /* Try to obtain the semaphore. */\r
177                 if( xSemaphoreTake( pxParameters->xSemaphore, pxParameters->xBlockTime ) == pdPASS )\r
178                 {\r
179                         /* We have the semaphore and so expect any other tasks using the\r
180                         shared variable to have left it in the state we expect to find\r
181                         it. */\r
182                         if( *pulSharedVariable != ulExpectedValue )\r
183                         {\r
184                                 sError = pdTRUE;\r
185                         }\r
186                         \r
187                         /* Clear the variable, then count it back up to the expected value\r
188                         before releasing the semaphore.  Would expect a context switch or\r
189                         two during this time. */\r
190                         for( ulCounter = ( unsigned portLONG ) 0; ulCounter <= ulExpectedValue; ulCounter++ )\r
191                         {\r
192                                 *pulSharedVariable = ulCounter;\r
193                                 if( *pulSharedVariable != ulCounter )\r
194                                 {\r
195                                         sError = pdTRUE;\r
196                                 }\r
197                         }\r
198 \r
199                         /* Release the semaphore, and if no errors have occurred increment the check\r
200                         variable. */\r
201                         if(     xSemaphoreGive( pxParameters->xSemaphore ) == pdFALSE )\r
202                         {\r
203                                 sError = pdTRUE;\r
204                         }\r
205 \r
206                         if( sError == pdFALSE )\r
207                         {\r
208                                 if( sCheckVariableToUse < semtstNUM_TASKS )\r
209                                 {\r
210                                         ( sCheckVariables[ sCheckVariableToUse ] )++;\r
211                                 }\r
212                         }\r
213 \r
214                         /* If we have a block time then we are running at a priority higher\r
215                         than the idle priority.  This task takes a long time to complete\r
216                         a cycle (deliberately so to test the guarding) so will be starving\r
217                         out lower priority tasks.  Block for some time to allow give lower\r
218                         priority tasks some processor time. */\r
219                         vTaskDelay( pxParameters->xBlockTime * semtstDELAY_FACTOR );\r
220                 }\r
221                 else\r
222                 {\r
223                         if( pxParameters->xBlockTime == ( portTickType ) 0 )\r
224                         {\r
225                                 /* We have not got the semaphore yet, so no point using the\r
226                                 processor.  We are not blocking when attempting to obtain the\r
227                                 semaphore. */\r
228                                 taskYIELD();\r
229                         }\r
230                 }\r
231         }\r
232 }\r
233 /*-----------------------------------------------------------*/\r
234 \r
235 /* This is called to check that all the created tasks are still running. */\r
236 portBASE_TYPE xAreSemaphoreTasksStillRunning( void )\r
237 {\r
238 static portSHORT sLastCheckVariables[ semtstNUM_TASKS ] = { 0 };\r
239 portBASE_TYPE xTask, xReturn = pdTRUE;\r
240 \r
241         for( xTask = 0; xTask < semtstNUM_TASKS; xTask++ )\r
242         {\r
243                 if( sLastCheckVariables[ xTask ] == sCheckVariables[ xTask ] )\r
244                 {\r
245                         xReturn = pdFALSE;\r
246                 }\r
247 \r
248                 sLastCheckVariables[ xTask ] = sCheckVariables[ xTask ];\r
249         }\r
250 \r
251         return xReturn;\r
252 }\r
253 \r
254 \r