root/webserver/example/freeRTOS/Demo/Common/Full/semtest.c

Revision 14, 11.4 kB (checked in by phil, 15 years ago)

added unmodified FreeRTOS package V5.4.1 with only web srv demo source for LPC2368 for CrossWorks?

Line 
1 /*
2         FreeRTOS V5.4.1 - Copyright (C) 2009 Real Time Engineers Ltd.
3
4         This file is part of the FreeRTOS distribution.
5
6         FreeRTOS is free software; you can redistribute it and/or modify it     under
7         the terms of the GNU General Public License (version 2) as published by the
8         Free Software Foundation and modified by the FreeRTOS exception.
9         **NOTE** The exception to the GPL is included to allow you to distribute a
10         combined work that includes FreeRTOS without being obliged to provide the
11         source code for proprietary components outside of the FreeRTOS kernel. 
12         Alternative commercial license and support terms are also available upon
13         request.  See the licensing section of http://www.FreeRTOS.org for full
14         license details.
15
16         FreeRTOS is distributed in the hope that it will be useful,     but WITHOUT
17         ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18         FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
19         more details.
20
21         You should have received a copy of the GNU General Public License along
22         with FreeRTOS; if not, write to the Free Software Foundation, Inc., 59
23         Temple Place, Suite 330, Boston, MA  02111-1307  USA.
24
25
26         ***************************************************************************
27         *                                                                         *
28         * Looking for a quick start?  Then check out the FreeRTOS eBook!          *
29         * See http://www.FreeRTOS.org/Documentation for details                   *
30         *                                                                         *
31         ***************************************************************************
32
33         1 tab == 4 spaces!
34
35         Please ensure to read the configuration and relevant port sections of the
36         online documentation.
37
38         http://www.FreeRTOS.org - Documentation, latest information, license and
39         contact details.
40
41         http://www.SafeRTOS.com - A version that is certified for use in safety
42         critical systems.
43
44         http://www.OpenRTOS.com - Commercial support, development, porting,
45         licensing and training services.
46 */
47
48 /**
49  * Creates two sets of two tasks.  The tasks within a set share a variable, access
50  * to which is guarded by a semaphore.
51  *
52  * Each task starts by attempting to obtain the semaphore.  On obtaining a
53  * semaphore a task checks to ensure that the guarded variable has an expected
54  * value.  It then clears the variable to zero before counting it back up to the
55  * expected value in increments of 1.  After each increment the variable is checked
56  * to ensure it contains the value to which it was just set. When the starting
57  * value is again reached the task releases the semaphore giving the other task in
58  * the set a chance to do exactly the same thing.  The starting value is high
59  * enough to ensure that a tick is likely to occur during the incrementing loop.
60  *
61  * An error is flagged if at any time during the process a shared variable is
62  * found to have a value other than that expected.  Such an occurrence would
63  * suggest an error in the mutual exclusion mechanism by which access to the
64  * variable is restricted.
65  *
66  * The first set of two tasks poll their semaphore.  The second set use blocking
67  * calls.
68  *
69  * \page SemTestC semtest.c
70  * \ingroup DemoFiles
71  * <HR>
72  */
73
74 /*
75 Changes from V1.2.0:
76
77         + The tasks that operate at the idle priority now use a lower expected
78           count than those running at a higher priority.  This prevents the low
79           priority tasks from signaling an error because they have not been
80           scheduled enough time for each of them to count the shared variable to
81           the high value.
82
83 Changes from V2.0.0
84
85         + Delay periods are now specified using variables and constants of
86           portTickType rather than unsigned portLONG.
87
88 Changes from V2.1.1
89
90         + The stack size now uses configMINIMAL_STACK_SIZE.
91         + String constants made file scope to decrease stack depth on 8051 port.
92 */
93
94 #include <stdlib.h>
95
96 /* Scheduler include files. */
97 #include "FreeRTOS.h"
98 #include "task.h"
99 #include "semphr.h"
100
101 /* Demo app include files. */
102 #include "semtest.h"
103 #include "print.h"
104
105 /* The value to which the shared variables are counted. */
106 #define semtstBLOCKING_EXPECTED_VALUE           ( ( unsigned portLONG ) 0xfff )
107 #define semtstNON_BLOCKING_EXPECTED_VALUE       ( ( unsigned portLONG ) 0xff  )
108
109 #define semtstSTACK_SIZE                        configMINIMAL_STACK_SIZE
110
111 #define semtstNUM_TASKS                         ( 4 )
112
113 #define semtstDELAY_FACTOR                      ( ( portTickType ) 10 )
114
115 /* The task function as described at the top of the file. */
116 static void prvSemaphoreTest( void *pvParameters );
117
118 /* Structure used to pass parameters to each task. */
119 typedef struct SEMAPHORE_PARAMETERS
120 {
121         xSemaphoreHandle xSemaphore;
122         volatile unsigned portLONG *pulSharedVariable;
123         portTickType xBlockTime;
124 } xSemaphoreParameters;
125
126 /* Variables used to check that all the tasks are still running without errors. */
127 static volatile portSHORT sCheckVariables[ semtstNUM_TASKS ] = { 0 };
128 static volatile portSHORT sNextCheckVariable = 0;
129
130 /* Strings to print if USE_STDIO is defined. */
131 const portCHAR * const pcPollingSemaphoreTaskError = "Guarded shared variable in unexpected state.\r\n";
132 const portCHAR * const pcSemaphoreTaskStart = "Guarded shared variable task started.\r\n";
133
134 /*-----------------------------------------------------------*/
135
136 void vStartSemaphoreTasks( unsigned portBASE_TYPE uxPriority )
137 {
138 xSemaphoreParameters *pxFirstSemaphoreParameters, *pxSecondSemaphoreParameters;
139 const portTickType xBlockTime = ( portTickType ) 100;
140
141         /* Create the structure used to pass parameters to the first two tasks. */
142         pxFirstSemaphoreParameters = ( xSemaphoreParameters * ) pvPortMalloc( sizeof( xSemaphoreParameters ) );
143
144         if( pxFirstSemaphoreParameters != NULL )
145         {
146                 /* Create the semaphore used by the first two tasks. */
147                 vSemaphoreCreateBinary( pxFirstSemaphoreParameters->xSemaphore );
148
149                 if( pxFirstSemaphoreParameters->xSemaphore != NULL )
150                 {
151                         /* Create the variable which is to be shared by the first two tasks. */
152                         pxFirstSemaphoreParameters->pulSharedVariable = ( unsigned portLONG * ) pvPortMalloc( sizeof( unsigned portLONG ) );
153
154                         /* Initialise the share variable to the value the tasks expect. */
155                         *( pxFirstSemaphoreParameters->pulSharedVariable ) = semtstNON_BLOCKING_EXPECTED_VALUE;
156
157                         /* The first two tasks do not block on semaphore calls. */
158                         pxFirstSemaphoreParameters->xBlockTime = ( portTickType ) 0;
159
160                         /* Spawn the first two tasks.  As they poll they operate at the idle priority. */
161                         xTaskCreate( prvSemaphoreTest, "PolSEM1", semtstSTACK_SIZE, ( void * ) pxFirstSemaphoreParameters, tskIDLE_PRIORITY, ( xTaskHandle * ) NULL );
162                         xTaskCreate( prvSemaphoreTest, "PolSEM2", semtstSTACK_SIZE, ( void * ) pxFirstSemaphoreParameters, tskIDLE_PRIORITY, ( xTaskHandle * ) NULL );
163                 }
164         }
165
166         /* Do exactly the same to create the second set of tasks, only this time
167         provide a block time for the semaphore calls. */
168         pxSecondSemaphoreParameters = ( xSemaphoreParameters * ) pvPortMalloc( sizeof( xSemaphoreParameters ) );
169         if( pxSecondSemaphoreParameters != NULL )
170         {
171                 vSemaphoreCreateBinary( pxSecondSemaphoreParameters->xSemaphore );
172
173                 if( pxSecondSemaphoreParameters->xSemaphore != NULL )
174                 {
175                         pxSecondSemaphoreParameters->pulSharedVariable = ( unsigned portLONG * ) pvPortMalloc( sizeof( unsigned portLONG ) );
176                         *( pxSecondSemaphoreParameters->pulSharedVariable ) = semtstBLOCKING_EXPECTED_VALUE;
177                         pxSecondSemaphoreParameters->xBlockTime = xBlockTime / portTICK_RATE_MS;
178
179                         xTaskCreate( prvSemaphoreTest, "BlkSEM1", semtstSTACK_SIZE, ( void * ) pxSecondSemaphoreParameters, uxPriority, ( xTaskHandle * ) NULL );
180                         xTaskCreate( prvSemaphoreTest, "BlkSEM2", semtstSTACK_SIZE, ( void * ) pxSecondSemaphoreParameters, uxPriority, ( xTaskHandle * ) NULL );
181                 }
182         }
183 }
184 /*-----------------------------------------------------------*/
185
186 static void prvSemaphoreTest( void *pvParameters )
187 {
188 xSemaphoreParameters *pxParameters;
189 volatile unsigned portLONG *pulSharedVariable, ulExpectedValue;
190 unsigned portLONG ulCounter;
191 portSHORT sError = pdFALSE, sCheckVariableToUse;
192
193         /* See which check variable to use.  sNextCheckVariable is not semaphore
194         protected! */
195         portENTER_CRITICAL();
196                 sCheckVariableToUse = sNextCheckVariable;
197                 sNextCheckVariable++;
198         portEXIT_CRITICAL();
199
200         /* Queue a message for printing to say the task has started. */
201         vPrintDisplayMessage( &pcSemaphoreTaskStart );
202
203         /* A structure is passed in as the parameter.  This contains the shared
204         variable being guarded. */
205         pxParameters = ( xSemaphoreParameters * ) pvParameters;
206         pulSharedVariable = pxParameters->pulSharedVariable;
207
208         /* If we are blocking we use a much higher count to ensure loads of context
209         switches occur during the count. */
210         if( pxParameters->xBlockTime > ( portTickType ) 0 )
211         {
212                 ulExpectedValue = semtstBLOCKING_EXPECTED_VALUE;
213         }
214         else
215         {
216                 ulExpectedValue = semtstNON_BLOCKING_EXPECTED_VALUE;
217         }
218
219         for( ;; )
220         {
221                 /* Try to obtain the semaphore. */
222                 if( xSemaphoreTake( pxParameters->xSemaphore, pxParameters->xBlockTime ) == pdPASS )
223                 {
224                         /* We have the semaphore and so expect any other tasks using the
225                         shared variable to have left it in the state we expect to find
226                         it. */
227                         if( *pulSharedVariable != ulExpectedValue )
228                         {
229                                 vPrintDisplayMessage( &pcPollingSemaphoreTaskError );
230                                 sError = pdTRUE;
231                         }
232                        
233                         /* Clear the variable, then count it back up to the expected value
234                         before releasing the semaphore.  Would expect a context switch or
235                         two during this time. */
236                         for( ulCounter = ( unsigned portLONG ) 0; ulCounter <= ulExpectedValue; ulCounter++ )
237                         {
238                                 *pulSharedVariable = ulCounter;
239                                 if( *pulSharedVariable != ulCounter )
240                                 {
241                                         if( sError == pdFALSE )
242                                         {
243                                                 vPrintDisplayMessage( &pcPollingSemaphoreTaskError );
244                                         }
245                                         sError = pdTRUE;
246                                 }
247                         }
248
249                         /* Release the semaphore, and if no errors have occurred increment the check
250                         variable. */
251                         if(     xSemaphoreGive( pxParameters->xSemaphore ) == pdFALSE )
252                         {
253                                 vPrintDisplayMessage( &pcPollingSemaphoreTaskError );
254                                 sError = pdTRUE;
255                         }
256
257                         if( sError == pdFALSE )
258                         {
259                                 if( sCheckVariableToUse < semtstNUM_TASKS )
260                                 {
261                                         ( sCheckVariables[ sCheckVariableToUse ] )++;
262                                 }
263                         }
264
265                         /* If we have a block time then we are running at a priority higher
266                         than the idle priority.  This task takes a long time to complete
267                         a cycle (deliberately so to test the guarding) so will be starving
268                         out lower priority tasks.  Block for some time to allow give lower
269                         priority tasks some processor time. */
270                         vTaskDelay( pxParameters->xBlockTime * semtstDELAY_FACTOR );
271                 }
272                 else
273                 {
274                         if( pxParameters->xBlockTime == ( portTickType ) 0 )
275                         {
276                                 /* We have not got the semaphore yet, so no point using the
277                                 processor.  We are not blocking when attempting to obtain the
278                                 semaphore. */
279                                 taskYIELD();
280                         }
281                 }
282         }
283 }
284 /*-----------------------------------------------------------*/
285
286 /* This is called to check that all the created tasks are still running. */
287 portBASE_TYPE xAreSemaphoreTasksStillRunning( void )
288 {
289 static portSHORT sLastCheckVariables[ semtstNUM_TASKS ] = { 0 };
290 portBASE_TYPE xTask, xReturn = pdTRUE;
291
292         for( xTask = 0; xTask < semtstNUM_TASKS; xTask++ )
293         {
294                 if( sLastCheckVariables[ xTask ] == sCheckVariables[ xTask ] )
295                 {
296                         xReturn = pdFALSE;
297                 }
298
299                 sLastCheckVariables[ xTask ] = sCheckVariables[ xTask ];
300         }
301
302         return xReturn;
303 }
304
305
Note: See TracBrowser for help on using the browser.