root/webserver/example/freeRTOS/Source/croutine.c

Revision 14, 13.5 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 #include "FreeRTOS.h"
49 #include "task.h"
50 #include "croutine.h"
51
52 /*
53  * Some kernel aware debuggers require data to be viewed to be global, rather
54  * than file scope.
55  */
56 #ifdef portREMOVE_STATIC_QUALIFIER
57         #define static
58 #endif
59
60
61 /* Lists for ready and blocked co-routines. --------------------*/
62 static xList pxReadyCoRoutineLists[ configMAX_CO_ROUTINE_PRIORITIES ];  /*< Prioritised ready co-routines. */
63 static xList xDelayedCoRoutineList1;                                                                    /*< Delayed co-routines. */
64 static xList xDelayedCoRoutineList2;                                                                    /*< Delayed co-routines (two lists are used - one for delays that have overflowed the current tick count. */
65 static xList * pxDelayedCoRoutineList;                                                                  /*< Points to the delayed co-routine list currently being used. */
66 static xList * pxOverflowDelayedCoRoutineList;                                                  /*< Points to the delayed co-routine list currently being used to hold co-routines that have overflowed the current tick count. */
67 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. */
68
69 /* Other file private variables. --------------------------------*/
70 corCRCB * pxCurrentCoRoutine = NULL;
71 static unsigned portBASE_TYPE uxTopCoRoutineReadyPriority = 0;
72 static portTickType xCoRoutineTickCount = 0, xLastTickCount = 0, xPassedTicks = 0;
73
74 /* The initial state of the co-routine when it is created. */
75 #define corINITIAL_STATE        ( 0 )
76
77 /*
78  * Place the co-routine represented by pxCRCB into the appropriate ready queue
79  * for the priority.  It is inserted at the end of the list.
80  *
81  * This macro accesses the co-routine ready lists and therefore must not be
82  * used from within an ISR.
83  */
84 #define prvAddCoRoutineToReadyQueue( pxCRCB )                                                                                                                                           \
85 {                                                                                                                                                                                                                                       \
86         if( pxCRCB->uxPriority > uxTopCoRoutineReadyPriority )                                                                                                                  \
87         {                                                                                                                                                                                                                               \
88                 uxTopCoRoutineReadyPriority = pxCRCB->uxPriority;                                                                                                                       \
89         }                                                                                                                                                                                                                               \
90         vListInsertEnd( ( xList * ) &( pxReadyCoRoutineLists[ pxCRCB->uxPriority ] ), &( pxCRCB->xGenericListItem ) );  \
91 }       
92
93 /*
94  * Utility to ready all the lists used by the scheduler.  This is called
95  * automatically upon the creation of the first co-routine.
96  */
97 static void prvInitialiseCoRoutineLists( void );
98
99 /*
100  * Co-routines that are readied by an interrupt cannot be placed directly into
101  * the ready lists (there is no mutual exclusion).  Instead they are placed in
102  * in the pending ready list in order that they can later be moved to the ready
103  * list by the co-routine scheduler.
104  */
105 static void prvCheckPendingReadyList( void );
106
107 /*
108  * Macro that looks at the list of co-routines that are currently delayed to
109  * see if any require waking.
110  *
111  * Co-routines are stored in the queue in the order of their wake time -
112  * meaning once one co-routine has been found whose timer has not expired
113  * we need not look any further down the list.
114  */
115 static void prvCheckDelayedList( void );
116
117 /*-----------------------------------------------------------*/
118
119 signed portBASE_TYPE xCoRoutineCreate( crCOROUTINE_CODE pxCoRoutineCode, unsigned portBASE_TYPE uxPriority, unsigned portBASE_TYPE uxIndex )
120 {
121 signed portBASE_TYPE xReturn;
122 corCRCB *pxCoRoutine;
123
124         /* Allocate the memory that will store the co-routine control block. */
125         pxCoRoutine = ( corCRCB * ) pvPortMalloc( sizeof( corCRCB ) );
126         if( pxCoRoutine )
127         {
128                 /* If pxCurrentCoRoutine is NULL then this is the first co-routine to
129                 be created and the co-routine data structures need initialising. */
130                 if( pxCurrentCoRoutine == NULL )
131                 {
132                         pxCurrentCoRoutine = pxCoRoutine;
133                         prvInitialiseCoRoutineLists();
134                 }
135
136                 /* Check the priority is within limits. */
137                 if( uxPriority >= configMAX_CO_ROUTINE_PRIORITIES )
138                 {
139                         uxPriority = configMAX_CO_ROUTINE_PRIORITIES - 1;
140                 }
141
142                 /* Fill out the co-routine control block from the function parameters. */
143                 pxCoRoutine->uxState = corINITIAL_STATE;
144                 pxCoRoutine->uxPriority = uxPriority;
145                 pxCoRoutine->uxIndex = uxIndex;
146                 pxCoRoutine->pxCoRoutineFunction = pxCoRoutineCode;
147
148                 /* Initialise all the other co-routine control block parameters. */
149                 vListInitialiseItem( &( pxCoRoutine->xGenericListItem ) );
150                 vListInitialiseItem( &( pxCoRoutine->xEventListItem ) );
151
152                 /* Set the co-routine control block as a link back from the xListItem.
153                 This is so we can get back to the containing CRCB from a generic item
154                 in a list. */
155                 listSET_LIST_ITEM_OWNER( &( pxCoRoutine->xGenericListItem ), pxCoRoutine );
156                 listSET_LIST_ITEM_OWNER( &( pxCoRoutine->xEventListItem ), pxCoRoutine );
157        
158                 /* Event lists are always in priority order. */
159                 listSET_LIST_ITEM_VALUE( &( pxCoRoutine->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) uxPriority );
160                
161                 /* Now the co-routine has been initialised it can be added to the ready
162                 list at the correct priority. */
163                 prvAddCoRoutineToReadyQueue( pxCoRoutine );
164
165                 xReturn = pdPASS;
166         }
167         else
168         {               
169                 xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
170         }
171        
172         return xReturn;
173 }
174 /*-----------------------------------------------------------*/
175
176 void vCoRoutineAddToDelayedList( portTickType xTicksToDelay, xList *pxEventList )
177 {
178 portTickType xTimeToWake;
179
180         /* Calculate the time to wake - this may overflow but this is
181         not a problem. */
182         xTimeToWake = xCoRoutineTickCount + xTicksToDelay;
183
184         /* We must remove ourselves from the ready list before adding
185         ourselves to the blocked list as the same list item is used for
186         both lists. */
187         vListRemove( ( xListItem * ) &( pxCurrentCoRoutine->xGenericListItem ) );
188
189         /* The list item will be inserted in wake time order. */
190         listSET_LIST_ITEM_VALUE( &( pxCurrentCoRoutine->xGenericListItem ), xTimeToWake );
191
192         if( xTimeToWake < xCoRoutineTickCount )
193         {
194                 /* Wake time has overflowed.  Place this item in the
195                 overflow list. */
196                 vListInsert( ( xList * ) pxOverflowDelayedCoRoutineList, ( xListItem * ) &( pxCurrentCoRoutine->xGenericListItem ) );
197         }
198         else
199         {
200                 /* The wake time has not overflowed, so we can use the
201                 current block list. */
202                 vListInsert( ( xList * ) pxDelayedCoRoutineList, ( xListItem * ) &( pxCurrentCoRoutine->xGenericListItem ) );
203         }
204
205         if( pxEventList )
206         {
207                 /* Also add the co-routine to an event list.  If this is done then the
208                 function must be called with interrupts disabled. */
209                 vListInsert( pxEventList, &( pxCurrentCoRoutine->xEventListItem ) );
210         }
211 }
212 /*-----------------------------------------------------------*/
213
214 static void prvCheckPendingReadyList( void )
215 {
216         /* Are there any co-routines waiting to get moved to the ready list?  These
217         are co-routines that have been readied by an ISR.  The ISR cannot access
218         the     ready lists itself. */
219         while( !listLIST_IS_EMPTY( &xPendingReadyCoRoutineList ) )
220         {
221                 corCRCB *pxUnblockedCRCB;
222
223                 /* The pending ready list can be accessed by an ISR. */
224                 portDISABLE_INTERRUPTS();
225                 {       
226                         pxUnblockedCRCB = ( corCRCB * ) listGET_OWNER_OF_HEAD_ENTRY( (&xPendingReadyCoRoutineList) );                   
227                         vListRemove( &( pxUnblockedCRCB->xEventListItem ) );
228                 }
229                 portENABLE_INTERRUPTS();
230
231                 vListRemove( &( pxUnblockedCRCB->xGenericListItem ) );
232                 prvAddCoRoutineToReadyQueue( pxUnblockedCRCB );
233         }
234 }
235 /*-----------------------------------------------------------*/
236
237 static void prvCheckDelayedList( void )
238 {
239 corCRCB *pxCRCB;
240
241         xPassedTicks = xTaskGetTickCount() - xLastTickCount;
242         while( xPassedTicks )
243         {
244                 xCoRoutineTickCount++;
245                 xPassedTicks--;
246
247                 /* If the tick count has overflowed we need to swap the ready lists. */
248                 if( xCoRoutineTickCount == 0 )
249                 {
250                         xList * pxTemp;
251
252                         /* Tick count has overflowed so we need to swap the delay lists.  If there are
253                         any items in pxDelayedCoRoutineList here then there is an error! */
254                         pxTemp = pxDelayedCoRoutineList;
255                         pxDelayedCoRoutineList = pxOverflowDelayedCoRoutineList;
256                         pxOverflowDelayedCoRoutineList = pxTemp;
257                 }
258
259                 /* See if this tick has made a timeout expire. */
260                 while( ( pxCRCB = ( corCRCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedCoRoutineList ) ) != NULL )
261                 {       
262                         if( xCoRoutineTickCount < listGET_LIST_ITEM_VALUE( &( pxCRCB->xGenericListItem ) ) )                           
263                         {                       
264                                 /* Timeout not yet expired. */                                                                                                                                                 
265                                 break;                                                                                                                                                         
266                         }                                                                                                                                                                               
267
268                         portDISABLE_INTERRUPTS();
269                         {
270                                 /* The event could have occurred just before this critical
271                                 section.  If this is the case then the generic list item will
272                                 have been moved to the pending ready list and the following
273                                 line is still valid.  Also the pvContainer parameter will have
274                                 been set to NULL so the following lines are also valid. */
275                                 vListRemove( &( pxCRCB->xGenericListItem ) );                                                                                   
276
277                                 /* Is the co-routine waiting on an event also? */                                                                                               
278                                 if( pxCRCB->xEventListItem.pvContainer )                                                                                                       
279                                 {                                                                                                                       
280                                         vListRemove( &( pxCRCB->xEventListItem ) );                                                                                     
281                                 }
282                         }
283                         portENABLE_INTERRUPTS();
284
285                         prvAddCoRoutineToReadyQueue( pxCRCB );                                                                                                 
286                 }                                                                                                                                                                                                       
287         }
288
289         xLastTickCount = xCoRoutineTickCount;
290 }
291 /*-----------------------------------------------------------*/
292
293 void vCoRoutineSchedule( void )
294 {
295         /* See if any co-routines readied by events need moving to the ready lists. */
296         prvCheckPendingReadyList();
297
298         /* See if any delayed co-routines have timed out. */
299         prvCheckDelayedList();
300
301         /* Find the highest priority queue that contains ready co-routines. */
302         while( listLIST_IS_EMPTY( &( pxReadyCoRoutineLists[ uxTopCoRoutineReadyPriority ] ) ) )
303         {
304                 if( uxTopCoRoutineReadyPriority == 0 )
305                 {
306                         /* No more co-routines to check. */
307                         return;
308                 }
309                 --uxTopCoRoutineReadyPriority;
310         }
311
312         /* listGET_OWNER_OF_NEXT_ENTRY walks through the list, so the co-routines
313          of the same priority get an equal share of the processor time. */
314         listGET_OWNER_OF_NEXT_ENTRY( pxCurrentCoRoutine, &( pxReadyCoRoutineLists[ uxTopCoRoutineReadyPriority ] ) );
315
316         /* Call the co-routine. */
317         ( pxCurrentCoRoutine->pxCoRoutineFunction )( pxCurrentCoRoutine, pxCurrentCoRoutine->uxIndex );
318
319         return;
320 }
321 /*-----------------------------------------------------------*/
322
323 static void prvInitialiseCoRoutineLists( void )
324 {
325 unsigned portBASE_TYPE uxPriority;
326
327         for( uxPriority = 0; uxPriority < configMAX_CO_ROUTINE_PRIORITIES; uxPriority++ )
328         {
329                 vListInitialise( ( xList * ) &( pxReadyCoRoutineLists[ uxPriority ] ) );
330         }
331
332         vListInitialise( ( xList * ) &xDelayedCoRoutineList1 );
333         vListInitialise( ( xList * ) &xDelayedCoRoutineList2 );
334         vListInitialise( ( xList * ) &xPendingReadyCoRoutineList );
335
336         /* Start with pxDelayedCoRoutineList using list1 and the
337         pxOverflowDelayedCoRoutineList using list2. */
338         pxDelayedCoRoutineList = &xDelayedCoRoutineList1;
339         pxOverflowDelayedCoRoutineList = &xDelayedCoRoutineList2;
340 }
341 /*-----------------------------------------------------------*/
342
343 signed portBASE_TYPE xCoRoutineRemoveFromEventList( const xList *pxEventList )
344 {
345 corCRCB *pxUnblockedCRCB;
346 signed portBASE_TYPE xReturn;
347
348         /* This function is called from within an interrupt.  It can only access
349         event lists and the pending ready list. */
350         pxUnblockedCRCB = ( corCRCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList );
351         vListRemove( &( pxUnblockedCRCB->xEventListItem ) );
352         vListInsertEnd( ( xList * ) &( xPendingReadyCoRoutineList ), &( pxUnblockedCRCB->xEventListItem ) );
353
354         if( pxUnblockedCRCB->uxPriority >= pxCurrentCoRoutine->uxPriority )
355         {
356                 xReturn = pdTRUE;
357         }
358         else
359         {
360                 xReturn = pdFALSE;
361         }
362
363         return xReturn;
364 }
365
Note: See TracBrowser for help on using the browser.