brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame^] | 1 | /* |
| 2 | FreeRTOS V6.0.5 - Copyright (C) 2010 Real Time Engineers Ltd. |
| 3 | |
| 4 | *************************************************************************** |
| 5 | * * |
| 6 | * If you are: * |
| 7 | * * |
| 8 | * + New to FreeRTOS, * |
| 9 | * + Wanting to learn FreeRTOS or multitasking in general quickly * |
| 10 | * + Looking for basic training, * |
| 11 | * + Wanting to improve your FreeRTOS skills and productivity * |
| 12 | * * |
| 13 | * then take a look at the FreeRTOS eBook * |
| 14 | * * |
| 15 | * "Using the FreeRTOS Real Time Kernel - a Practical Guide" * |
| 16 | * http://www.FreeRTOS.org/Documentation * |
| 17 | * * |
| 18 | * A pdf reference manual is also available. Both are usually delivered * |
| 19 | * to your inbox within 20 minutes to two hours when purchased between 8am * |
| 20 | * and 8pm GMT (although please allow up to 24 hours in case of * |
| 21 | * exceptional circumstances). Thank you for your support! * |
| 22 | * * |
| 23 | *************************************************************************** |
| 24 | |
| 25 | This file is part of the FreeRTOS distribution. |
| 26 | |
| 27 | FreeRTOS is free software; you can redistribute it and/or modify it under |
| 28 | the terms of the GNU General Public License (version 2) as published by the |
| 29 | Free Software Foundation AND MODIFIED BY the FreeRTOS exception. |
| 30 | ***NOTE*** The exception to the GPL is included to allow you to distribute |
| 31 | a combined work that includes FreeRTOS without being obliged to provide the |
| 32 | source code for proprietary components outside of the FreeRTOS kernel. |
| 33 | FreeRTOS is distributed in the hope that it will be useful, but WITHOUT |
| 34 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| 35 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
| 36 | more details. You should have received a copy of the GNU General Public |
| 37 | License and the FreeRTOS license exception along with FreeRTOS; if not it |
| 38 | can be viewed here: http://www.freertos.org/a00114.html and also obtained |
| 39 | by writing to Richard Barry, contact details for whom are available on the |
| 40 | FreeRTOS WEB site. |
| 41 | |
| 42 | 1 tab == 4 spaces! |
| 43 | |
| 44 | http://www.FreeRTOS.org - Documentation, latest information, license and |
| 45 | contact details. |
| 46 | |
| 47 | http://www.SafeRTOS.com - A version that is certified for use in safety |
| 48 | critical systems. |
| 49 | |
| 50 | http://www.OpenRTOS.com - Commercial support, development, porting, |
| 51 | licensing and training services. |
| 52 | */ |
| 53 | |
| 54 | /* |
| 55 | * Creates two sets of two tasks. The tasks within a set share a variable, access |
| 56 | * to which is guarded by a semaphore. |
| 57 | * |
| 58 | * Each task starts by attempting to obtain the semaphore. On obtaining a |
| 59 | * semaphore a task checks to ensure that the guarded variable has an expected |
| 60 | * value. It then clears the variable to zero before counting it back up to the |
| 61 | * expected value in increments of 1. After each increment the variable is checked |
| 62 | * to ensure it contains the value to which it was just set. When the starting |
| 63 | * value is again reached the task releases the semaphore giving the other task in |
| 64 | * the set a chance to do exactly the same thing. The starting value is high |
| 65 | * enough to ensure that a tick is likely to occur during the incrementing loop. |
| 66 | * |
| 67 | * An error is flagged if at any time during the process a shared variable is |
| 68 | * found to have a value other than that expected. Such an occurrence would |
| 69 | * suggest an error in the mutual exclusion mechanism by which access to the |
| 70 | * variable is restricted. |
| 71 | * |
| 72 | * The first set of two tasks poll their semaphore. The second set use blocking |
| 73 | * calls. |
| 74 | * |
| 75 | */ |
| 76 | |
| 77 | |
| 78 | #include <stdlib.h> |
| 79 | |
| 80 | /* Scheduler include files. */ |
| 81 | #include "FreeRTOS.h" |
| 82 | #include "task.h" |
| 83 | #include "semphr.h" |
| 84 | |
| 85 | /* Demo app include files. */ |
| 86 | #include "semtest.h" |
| 87 | |
| 88 | /* The value to which the shared variables are counted. */ |
| 89 | #define semtstBLOCKING_EXPECTED_VALUE ( ( unsigned long ) 0xfff ) |
| 90 | #define semtstNON_BLOCKING_EXPECTED_VALUE ( ( unsigned long ) 0xff ) |
| 91 | |
| 92 | #define semtstSTACK_SIZE configMINIMAL_STACK_SIZE |
| 93 | |
| 94 | #define semtstNUM_TASKS ( 4 ) |
| 95 | |
| 96 | #define semtstDELAY_FACTOR ( ( portTickType ) 10 ) |
| 97 | |
| 98 | /* The task function as described at the top of the file. */ |
| 99 | static portTASK_FUNCTION_PROTO(prvSemaphoreTest, pvParameters); |
| 100 | |
| 101 | /* Structure used to pass parameters to each task. */ |
| 102 | typedef struct SEMAPHORE_PARAMETERS { |
| 103 | xSemaphoreHandle xSemaphore; |
| 104 | volatile unsigned long *pulSharedVariable; |
| 105 | portTickType xBlockTime; |
| 106 | } xSemaphoreParameters; |
| 107 | |
| 108 | /* Variables used to check that all the tasks are still running without errors. */ |
| 109 | static volatile short sCheckVariables[ semtstNUM_TASKS ] = { 0 }; |
| 110 | static volatile short sNextCheckVariable = 0; |
| 111 | |
| 112 | /*-----------------------------------------------------------*/ |
| 113 | |
| 114 | void vStartSemaphoreTasks(unsigned portBASE_TYPE uxPriority) |
| 115 | { |
| 116 | xSemaphoreParameters *pxFirstSemaphoreParameters, *pxSecondSemaphoreParameters; |
| 117 | const portTickType xBlockTime = (portTickType) 100; |
| 118 | |
| 119 | /* Create the structure used to pass parameters to the first two tasks. */ |
| 120 | pxFirstSemaphoreParameters = (xSemaphoreParameters *) pvPortMalloc(sizeof(xSemaphoreParameters)); |
| 121 | |
| 122 | if (pxFirstSemaphoreParameters != NULL) { |
| 123 | /* Create the semaphore used by the first two tasks. */ |
| 124 | vSemaphoreCreateBinary(pxFirstSemaphoreParameters->xSemaphore); |
| 125 | |
| 126 | if (pxFirstSemaphoreParameters->xSemaphore != NULL) { |
| 127 | /* Create the variable which is to be shared by the first two tasks. */ |
| 128 | pxFirstSemaphoreParameters->pulSharedVariable = (unsigned long *) pvPortMalloc(sizeof(unsigned long)); |
| 129 | |
| 130 | /* Initialise the share variable to the value the tasks expect. */ |
| 131 | *(pxFirstSemaphoreParameters->pulSharedVariable) = semtstNON_BLOCKING_EXPECTED_VALUE; |
| 132 | |
| 133 | /* The first two tasks do not block on semaphore calls. */ |
| 134 | pxFirstSemaphoreParameters->xBlockTime = (portTickType) 0; |
| 135 | |
| 136 | /* Spawn the first two tasks. As they poll they operate at the idle priority. */ |
| 137 | xTaskCreate(prvSemaphoreTest, (signed char *) "PolSEM1", semtstSTACK_SIZE, (void *) pxFirstSemaphoreParameters, tskIDLE_PRIORITY, (xTaskHandle *) NULL); |
| 138 | xTaskCreate(prvSemaphoreTest, (signed char *) "PolSEM2", semtstSTACK_SIZE, (void *) pxFirstSemaphoreParameters, tskIDLE_PRIORITY, (xTaskHandle *) NULL); |
| 139 | } |
| 140 | } |
| 141 | |
| 142 | /* Do exactly the same to create the second set of tasks, only this time |
| 143 | provide a block time for the semaphore calls. */ |
| 144 | pxSecondSemaphoreParameters = (xSemaphoreParameters *) pvPortMalloc(sizeof(xSemaphoreParameters)); |
| 145 | if (pxSecondSemaphoreParameters != NULL) { |
| 146 | vSemaphoreCreateBinary(pxSecondSemaphoreParameters->xSemaphore); |
| 147 | |
| 148 | if (pxSecondSemaphoreParameters->xSemaphore != NULL) { |
| 149 | pxSecondSemaphoreParameters->pulSharedVariable = (unsigned long *) pvPortMalloc(sizeof(unsigned long)); |
| 150 | *(pxSecondSemaphoreParameters->pulSharedVariable) = semtstBLOCKING_EXPECTED_VALUE; |
| 151 | pxSecondSemaphoreParameters->xBlockTime = xBlockTime / portTICK_RATE_MS; |
| 152 | |
| 153 | xTaskCreate(prvSemaphoreTest, (signed char *) "BlkSEM1", semtstSTACK_SIZE, (void *) pxSecondSemaphoreParameters, uxPriority, (xTaskHandle *) NULL); |
| 154 | xTaskCreate(prvSemaphoreTest, (signed char *) "BlkSEM2", semtstSTACK_SIZE, (void *) pxSecondSemaphoreParameters, uxPriority, (xTaskHandle *) NULL); |
| 155 | } |
| 156 | } |
| 157 | |
| 158 | /* vQueueAddToRegistry() adds the semaphore to the registry, if one is |
| 159 | in use. The registry is provided as a means for kernel aware |
| 160 | debuggers to locate semaphores and has no purpose if a kernel aware debugger |
| 161 | is not being used. The call to vQueueAddToRegistry() will be removed |
| 162 | by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is |
| 163 | defined to be less than 1. */ |
| 164 | vQueueAddToRegistry((xQueueHandle) pxFirstSemaphoreParameters->xSemaphore, (signed char *) "Counting_Sem_1"); |
| 165 | vQueueAddToRegistry((xQueueHandle) pxSecondSemaphoreParameters->xSemaphore, (signed char *) "Counting_Sem_2"); |
| 166 | } |
| 167 | /*-----------------------------------------------------------*/ |
| 168 | |
| 169 | static portTASK_FUNCTION(prvSemaphoreTest, pvParameters) |
| 170 | { |
| 171 | xSemaphoreParameters *pxParameters; |
| 172 | volatile unsigned long *pulSharedVariable, ulExpectedValue; |
| 173 | unsigned long ulCounter; |
| 174 | short sError = pdFALSE, sCheckVariableToUse; |
| 175 | |
| 176 | /* See which check variable to use. sNextCheckVariable is not semaphore |
| 177 | protected! */ |
| 178 | portENTER_CRITICAL(); |
| 179 | sCheckVariableToUse = sNextCheckVariable; |
| 180 | sNextCheckVariable++; |
| 181 | portEXIT_CRITICAL(); |
| 182 | |
| 183 | /* A structure is passed in as the parameter. This contains the shared |
| 184 | variable being guarded. */ |
| 185 | pxParameters = (xSemaphoreParameters *) pvParameters; |
| 186 | pulSharedVariable = pxParameters->pulSharedVariable; |
| 187 | |
| 188 | /* If we are blocking we use a much higher count to ensure loads of context |
| 189 | switches occur during the count. */ |
| 190 | if (pxParameters->xBlockTime > (portTickType) 0) { |
| 191 | ulExpectedValue = semtstBLOCKING_EXPECTED_VALUE; |
| 192 | } else { |
| 193 | ulExpectedValue = semtstNON_BLOCKING_EXPECTED_VALUE; |
| 194 | } |
| 195 | |
| 196 | for (;;) { |
| 197 | /* Try to obtain the semaphore. */ |
| 198 | if (xSemaphoreTake(pxParameters->xSemaphore, pxParameters->xBlockTime) == pdPASS) { |
| 199 | /* We have the semaphore and so expect any other tasks using the |
| 200 | shared variable to have left it in the state we expect to find |
| 201 | it. */ |
| 202 | if (*pulSharedVariable != ulExpectedValue) { |
| 203 | sError = pdTRUE; |
| 204 | } |
| 205 | |
| 206 | /* Clear the variable, then count it back up to the expected value |
| 207 | before releasing the semaphore. Would expect a context switch or |
| 208 | two during this time. */ |
| 209 | for (ulCounter = (unsigned long) 0; ulCounter <= ulExpectedValue; ulCounter++) { |
| 210 | *pulSharedVariable = ulCounter; |
| 211 | if (*pulSharedVariable != ulCounter) { |
| 212 | sError = pdTRUE; |
| 213 | } |
| 214 | } |
| 215 | |
| 216 | /* Release the semaphore, and if no errors have occurred increment the check |
| 217 | variable. */ |
| 218 | if (xSemaphoreGive(pxParameters->xSemaphore) == pdFALSE) { |
| 219 | sError = pdTRUE; |
| 220 | } |
| 221 | |
| 222 | if (sError == pdFALSE) { |
| 223 | if (sCheckVariableToUse < semtstNUM_TASKS) { |
| 224 | (sCheckVariables[ sCheckVariableToUse ])++; |
| 225 | } |
| 226 | } |
| 227 | |
| 228 | /* If we have a block time then we are running at a priority higher |
| 229 | than the idle priority. This task takes a long time to complete |
| 230 | a cycle (deliberately so to test the guarding) so will be starving |
| 231 | out lower priority tasks. Block for some time to allow give lower |
| 232 | priority tasks some processor time. */ |
| 233 | vTaskDelay(pxParameters->xBlockTime * semtstDELAY_FACTOR); |
| 234 | } else { |
| 235 | if (pxParameters->xBlockTime == (portTickType) 0) { |
| 236 | /* We have not got the semaphore yet, so no point using the |
| 237 | processor. We are not blocking when attempting to obtain the |
| 238 | semaphore. */ |
| 239 | taskYIELD(); |
| 240 | } |
| 241 | } |
| 242 | } |
| 243 | } |
| 244 | /*-----------------------------------------------------------*/ |
| 245 | |
| 246 | /* This is called to check that all the created tasks are still running. */ |
| 247 | portBASE_TYPE xAreSemaphoreTasksStillRunning(void) |
| 248 | { |
| 249 | static short sLastCheckVariables[ semtstNUM_TASKS ] = { 0 }; |
| 250 | portBASE_TYPE xTask, xReturn = pdTRUE; |
| 251 | |
| 252 | for (xTask = 0; xTask < semtstNUM_TASKS; xTask++) { |
| 253 | if (sLastCheckVariables[ xTask ] == sCheckVariables[ xTask ]) { |
| 254 | xReturn = pdFALSE; |
| 255 | } |
| 256 | |
| 257 | sLastCheckVariables[ xTask ] = sCheckVariables[ xTask ]; |
| 258 | } |
| 259 | |
| 260 | return xReturn; |
| 261 | } |
| 262 | |
| 263 | |