Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: Nucleo freertos_test FreeRTOS_test freertos_bluetooth ... more
croutine.c
00001 /* 00002 FreeRTOS V7.6.0 - Copyright (C) 2013 Real Time Engineers Ltd. 00003 All rights reserved 00004 00005 VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. 00006 00007 *************************************************************************** 00008 * * 00009 * FreeRTOS provides completely free yet professionally developed, * 00010 * robust, strictly quality controlled, supported, and cross * 00011 * platform software that has become a de facto standard. * 00012 * * 00013 * Help yourself get started quickly and support the FreeRTOS * 00014 * project by purchasing a FreeRTOS tutorial book, reference * 00015 * manual, or both from: http://www.FreeRTOS.org/Documentation * 00016 * * 00017 * Thank you! * 00018 * * 00019 *************************************************************************** 00020 00021 This file is part of the FreeRTOS distribution. 00022 00023 FreeRTOS is free software; you can redistribute it and/or modify it under 00024 the terms of the GNU General Public License (version 2) as published by the 00025 Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. 00026 00027 >>! NOTE: The modification to the GPL is included to allow you to distribute 00028 >>! a combined work that includes FreeRTOS without being obliged to provide 00029 >>! the source code for proprietary components outside of the FreeRTOS 00030 >>! kernel. 00031 00032 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY 00033 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 00034 FOR A PARTICULAR PURPOSE. Full license text is available from the following 00035 link: http://www.freertos.org/a00114.html 00036 00037 1 tab == 4 spaces! 00038 00039 *************************************************************************** 00040 * * 00041 * Having a problem? Start by reading the FAQ "My application does * 00042 * not run, what could be wrong?" * 00043 * * 00044 * http://www.FreeRTOS.org/FAQHelp.html * 00045 * * 00046 *************************************************************************** 00047 00048 http://www.FreeRTOS.org - Documentation, books, training, latest versions, 00049 license and Real Time Engineers Ltd. contact details. 00050 00051 http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, 00052 including FreeRTOS+Trace - an indispensable productivity tool, a DOS 00053 compatible FAT file system, and our tiny thread aware UDP/IP stack. 00054 00055 http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High 00056 Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS 00057 licenses offer ticketed support, indemnification and middleware. 00058 00059 http://www.SafeRTOS.com - High Integrity Systems also provide a safety 00060 engineered and independently SIL3 certified version for use in safety and 00061 mission critical applications that require provable dependability. 00062 00063 1 tab == 4 spaces! 00064 */ 00065 00066 #include "FreeRTOS.h" 00067 #include "task.h" 00068 #include "croutine.h" 00069 00070 /* 00071 * Some kernel aware debuggers require data to be viewed to be global, rather 00072 * than file scope. 00073 */ 00074 #ifdef portREMOVE_STATIC_QUALIFIER 00075 #define static 00076 #endif 00077 00078 00079 /* Lists for ready and blocked co-routines. --------------------*/ 00080 static xList pxReadyCoRoutineLists[ configMAX_CO_ROUTINE_PRIORITIES ]; /*< Prioritised ready co-routines. */ 00081 static xList xDelayedCoRoutineList1; /*< Delayed co-routines. */ 00082 static xList xDelayedCoRoutineList2; /*< Delayed co-routines (two lists are used - one for delays that have overflowed the current tick count. */ 00083 static xList * pxDelayedCoRoutineList; /*< Points to the delayed co-routine list currently being used. */ 00084 static xList * pxOverflowDelayedCoRoutineList; /*< Points to the delayed co-routine list currently being used to hold co-routines that have overflowed the current tick count. */ 00085 static xList xPendingReadyCoRoutineList; /*< Holds co-routines that have been readied by an external event. They cannot be added directly to the ready lists as the ready lists cannot be accessed by interrupts. */ 00086 00087 /* Other file private variables. --------------------------------*/ 00088 corCRCB * pxCurrentCoRoutine = NULL; 00089 static unsigned portBASE_TYPE uxTopCoRoutineReadyPriority = 0; 00090 static portTickType xCoRoutineTickCount = 0, xLastTickCount = 0, xPassedTicks = 0; 00091 00092 /* The initial state of the co-routine when it is created. */ 00093 #define corINITIAL_STATE ( 0 ) 00094 00095 /* 00096 * Place the co-routine represented by pxCRCB into the appropriate ready queue 00097 * for the priority. It is inserted at the end of the list. 00098 * 00099 * This macro accesses the co-routine ready lists and therefore must not be 00100 * used from within an ISR. 00101 */ 00102 #define prvAddCoRoutineToReadyQueue( pxCRCB ) \ 00103 { \ 00104 if( pxCRCB->uxPriority > uxTopCoRoutineReadyPriority ) \ 00105 { \ 00106 uxTopCoRoutineReadyPriority = pxCRCB->uxPriority; \ 00107 } \ 00108 vListInsertEnd( ( xList * ) &( pxReadyCoRoutineLists[ pxCRCB->uxPriority ] ), &( pxCRCB->xGenericListItem ) ); \ 00109 } 00110 00111 /* 00112 * Utility to ready all the lists used by the scheduler. This is called 00113 * automatically upon the creation of the first co-routine. 00114 */ 00115 static void prvInitialiseCoRoutineLists( void ); 00116 00117 /* 00118 * Co-routines that are readied by an interrupt cannot be placed directly into 00119 * the ready lists (there is no mutual exclusion). Instead they are placed in 00120 * in the pending ready list in order that they can later be moved to the ready 00121 * list by the co-routine scheduler. 00122 */ 00123 static void prvCheckPendingReadyList( void ); 00124 00125 /* 00126 * Macro that looks at the list of co-routines that are currently delayed to 00127 * see if any require waking. 00128 * 00129 * Co-routines are stored in the queue in the order of their wake time - 00130 * meaning once one co-routine has been found whose timer has not expired 00131 * we need not look any further down the list. 00132 */ 00133 static void prvCheckDelayedList( void ); 00134 00135 /*-----------------------------------------------------------*/ 00136 00137 signed portBASE_TYPE xCoRoutineCreate( crCOROUTINE_CODE pxCoRoutineCode, unsigned portBASE_TYPE uxPriority, unsigned portBASE_TYPE uxIndex ) 00138 { 00139 signed portBASE_TYPE xReturn; 00140 corCRCB *pxCoRoutine; 00141 00142 /* Allocate the memory that will store the co-routine control block. */ 00143 pxCoRoutine = ( corCRCB * ) pvPortMalloc( sizeof( corCRCB ) ); 00144 if( pxCoRoutine ) 00145 { 00146 /* If pxCurrentCoRoutine is NULL then this is the first co-routine to 00147 be created and the co-routine data structures need initialising. */ 00148 if( pxCurrentCoRoutine == NULL ) 00149 { 00150 pxCurrentCoRoutine = pxCoRoutine; 00151 prvInitialiseCoRoutineLists(); 00152 } 00153 00154 /* Check the priority is within limits. */ 00155 if( uxPriority >= configMAX_CO_ROUTINE_PRIORITIES ) 00156 { 00157 uxPriority = configMAX_CO_ROUTINE_PRIORITIES - 1; 00158 } 00159 00160 /* Fill out the co-routine control block from the function parameters. */ 00161 pxCoRoutine->uxState = corINITIAL_STATE; 00162 pxCoRoutine->uxPriority = uxPriority; 00163 pxCoRoutine->uxIndex = uxIndex; 00164 pxCoRoutine->pxCoRoutineFunction = pxCoRoutineCode; 00165 00166 /* Initialise all the other co-routine control block parameters. */ 00167 vListInitialiseItem( &( pxCoRoutine->xGenericListItem ) ); 00168 vListInitialiseItem( &( pxCoRoutine->xEventListItem ) ); 00169 00170 /* Set the co-routine control block as a link back from the xListItem. 00171 This is so we can get back to the containing CRCB from a generic item 00172 in a list. */ 00173 listSET_LIST_ITEM_OWNER( &( pxCoRoutine->xGenericListItem ), pxCoRoutine ); 00174 listSET_LIST_ITEM_OWNER( &( pxCoRoutine->xEventListItem ), pxCoRoutine ); 00175 00176 /* Event lists are always in priority order. */ 00177 listSET_LIST_ITEM_VALUE( &( pxCoRoutine->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) uxPriority ); 00178 00179 /* Now the co-routine has been initialised it can be added to the ready 00180 list at the correct priority. */ 00181 prvAddCoRoutineToReadyQueue( pxCoRoutine ); 00182 00183 xReturn = pdPASS; 00184 } 00185 else 00186 { 00187 xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY; 00188 } 00189 00190 return xReturn; 00191 } 00192 /*-----------------------------------------------------------*/ 00193 00194 void vCoRoutineAddToDelayedList( portTickType xTicksToDelay, xList *pxEventList ) 00195 { 00196 portTickType xTimeToWake; 00197 00198 /* Calculate the time to wake - this may overflow but this is 00199 not a problem. */ 00200 xTimeToWake = xCoRoutineTickCount + xTicksToDelay; 00201 00202 /* We must remove ourselves from the ready list before adding 00203 ourselves to the blocked list as the same list item is used for 00204 both lists. */ 00205 ( void ) uxListRemove( ( xListItem * ) &( pxCurrentCoRoutine->xGenericListItem ) ); 00206 00207 /* The list item will be inserted in wake time order. */ 00208 listSET_LIST_ITEM_VALUE( &( pxCurrentCoRoutine->xGenericListItem ), xTimeToWake ); 00209 00210 if( xTimeToWake < xCoRoutineTickCount ) 00211 { 00212 /* Wake time has overflowed. Place this item in the 00213 overflow list. */ 00214 vListInsert( ( xList * ) pxOverflowDelayedCoRoutineList, ( xListItem * ) &( pxCurrentCoRoutine->xGenericListItem ) ); 00215 } 00216 else 00217 { 00218 /* The wake time has not overflowed, so we can use the 00219 current block list. */ 00220 vListInsert( ( xList * ) pxDelayedCoRoutineList, ( xListItem * ) &( pxCurrentCoRoutine->xGenericListItem ) ); 00221 } 00222 00223 if( pxEventList ) 00224 { 00225 /* Also add the co-routine to an event list. If this is done then the 00226 function must be called with interrupts disabled. */ 00227 vListInsert( pxEventList, &( pxCurrentCoRoutine->xEventListItem ) ); 00228 } 00229 } 00230 /*-----------------------------------------------------------*/ 00231 00232 static void prvCheckPendingReadyList( void ) 00233 { 00234 /* Are there any co-routines waiting to get moved to the ready list? These 00235 are co-routines that have been readied by an ISR. The ISR cannot access 00236 the ready lists itself. */ 00237 while( listLIST_IS_EMPTY( &xPendingReadyCoRoutineList ) == pdFALSE ) 00238 { 00239 corCRCB *pxUnblockedCRCB; 00240 00241 /* The pending ready list can be accessed by an ISR. */ 00242 portDISABLE_INTERRUPTS(); 00243 { 00244 pxUnblockedCRCB = ( corCRCB * ) listGET_OWNER_OF_HEAD_ENTRY( (&xPendingReadyCoRoutineList) ); 00245 ( void ) uxListRemove( &( pxUnblockedCRCB->xEventListItem ) ); 00246 } 00247 portENABLE_INTERRUPTS(); 00248 00249 ( void ) uxListRemove( &( pxUnblockedCRCB->xGenericListItem ) ); 00250 prvAddCoRoutineToReadyQueue( pxUnblockedCRCB ); 00251 } 00252 } 00253 /*-----------------------------------------------------------*/ 00254 00255 static void prvCheckDelayedList( void ) 00256 { 00257 corCRCB *pxCRCB; 00258 00259 xPassedTicks = xTaskGetTickCount() - xLastTickCount; 00260 while( xPassedTicks ) 00261 { 00262 xCoRoutineTickCount++; 00263 xPassedTicks--; 00264 00265 /* If the tick count has overflowed we need to swap the ready lists. */ 00266 if( xCoRoutineTickCount == 0 ) 00267 { 00268 xList * pxTemp; 00269 00270 /* Tick count has overflowed so we need to swap the delay lists. If there are 00271 any items in pxDelayedCoRoutineList here then there is an error! */ 00272 pxTemp = pxDelayedCoRoutineList; 00273 pxDelayedCoRoutineList = pxOverflowDelayedCoRoutineList; 00274 pxOverflowDelayedCoRoutineList = pxTemp; 00275 } 00276 00277 /* See if this tick has made a timeout expire. */ 00278 while( listLIST_IS_EMPTY( pxDelayedCoRoutineList ) == pdFALSE ) 00279 { 00280 pxCRCB = ( corCRCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedCoRoutineList ); 00281 00282 if( xCoRoutineTickCount < listGET_LIST_ITEM_VALUE( &( pxCRCB->xGenericListItem ) ) ) 00283 { 00284 /* Timeout not yet expired. */ 00285 break; 00286 } 00287 00288 portDISABLE_INTERRUPTS(); 00289 { 00290 /* The event could have occurred just before this critical 00291 section. If this is the case then the generic list item will 00292 have been moved to the pending ready list and the following 00293 line is still valid. Also the pvContainer parameter will have 00294 been set to NULL so the following lines are also valid. */ 00295 uxListRemove( &( pxCRCB->xGenericListItem ) ); 00296 00297 /* Is the co-routine waiting on an event also? */ 00298 if( pxCRCB->xEventListItem.pvContainer ) 00299 { 00300 ( void ) uxListRemove( &( pxCRCB->xEventListItem ) ); 00301 } 00302 } 00303 portENABLE_INTERRUPTS(); 00304 00305 prvAddCoRoutineToReadyQueue( pxCRCB ); 00306 } 00307 } 00308 00309 xLastTickCount = xCoRoutineTickCount; 00310 } 00311 /*-----------------------------------------------------------*/ 00312 00313 void vCoRoutineSchedule( void ) 00314 { 00315 /* See if any co-routines readied by events need moving to the ready lists. */ 00316 prvCheckPendingReadyList(); 00317 00318 /* See if any delayed co-routines have timed out. */ 00319 prvCheckDelayedList(); 00320 00321 /* Find the highest priority queue that contains ready co-routines. */ 00322 while( listLIST_IS_EMPTY( &( pxReadyCoRoutineLists[ uxTopCoRoutineReadyPriority ] ) ) ) 00323 { 00324 if( uxTopCoRoutineReadyPriority == 0 ) 00325 { 00326 /* No more co-routines to check. */ 00327 return; 00328 } 00329 --uxTopCoRoutineReadyPriority; 00330 } 00331 00332 /* listGET_OWNER_OF_NEXT_ENTRY walks through the list, so the co-routines 00333 of the same priority get an equal share of the processor time. */ 00334 listGET_OWNER_OF_NEXT_ENTRY( pxCurrentCoRoutine, &( pxReadyCoRoutineLists[ uxTopCoRoutineReadyPriority ] ) ); 00335 00336 /* Call the co-routine. */ 00337 ( pxCurrentCoRoutine->pxCoRoutineFunction )( pxCurrentCoRoutine, pxCurrentCoRoutine->uxIndex ); 00338 00339 return; 00340 } 00341 /*-----------------------------------------------------------*/ 00342 00343 static void prvInitialiseCoRoutineLists( void ) 00344 { 00345 unsigned portBASE_TYPE uxPriority; 00346 00347 for( uxPriority = 0; uxPriority < configMAX_CO_ROUTINE_PRIORITIES; uxPriority++ ) 00348 { 00349 vListInitialise( ( xList * ) &( pxReadyCoRoutineLists[ uxPriority ] ) ); 00350 } 00351 00352 vListInitialise( ( xList * ) &xDelayedCoRoutineList1 ); 00353 vListInitialise( ( xList * ) &xDelayedCoRoutineList2 ); 00354 vListInitialise( ( xList * ) &xPendingReadyCoRoutineList ); 00355 00356 /* Start with pxDelayedCoRoutineList using list1 and the 00357 pxOverflowDelayedCoRoutineList using list2. */ 00358 pxDelayedCoRoutineList = &xDelayedCoRoutineList1; 00359 pxOverflowDelayedCoRoutineList = &xDelayedCoRoutineList2; 00360 } 00361 /*-----------------------------------------------------------*/ 00362 00363 signed portBASE_TYPE xCoRoutineRemoveFromEventList( const xList *pxEventList ) 00364 { 00365 corCRCB *pxUnblockedCRCB; 00366 signed portBASE_TYPE xReturn; 00367 00368 /* This function is called from within an interrupt. It can only access 00369 event lists and the pending ready list. This function assumes that a 00370 check has already been made to ensure pxEventList is not empty. */ 00371 pxUnblockedCRCB = ( corCRCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList ); 00372 ( void ) uxListRemove( &( pxUnblockedCRCB->xEventListItem ) ); 00373 vListInsertEnd( ( xList * ) &( xPendingReadyCoRoutineList ), &( pxUnblockedCRCB->xEventListItem ) ); 00374 00375 if( pxUnblockedCRCB->uxPriority >= pxCurrentCoRoutine->uxPriority ) 00376 { 00377 xReturn = pdTRUE; 00378 } 00379 else 00380 { 00381 xReturn = pdFALSE; 00382 } 00383 00384 return xReturn; 00385 } 00386
Generated on Tue Jul 12 2022 11:36:40 by
1.7.2