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