croutine.c
Go to the documentation of this file.
1 /*
2  * FreeRTOS Kernel V10.0.0
3  * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of
6  * this software and associated documentation files (the "Software"), to deal in
7  * the Software without restriction, including without limitation the rights to
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9  * the Software, and to permit persons to whom the Software is furnished to do so,
10  * subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in all
13  * copies or substantial portions of the Software. If you wish to use our Amazon
14  * FreeRTOS name, please do so in a fair use way that does not cause confusion.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
18  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
19  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22  *
23  * http://www.FreeRTOS.org
24  * http://aws.amazon.com/freertos
25  *
26  * 1 tab == 4 spaces!
27  */
28 
29 #include "FreeRTOS.h"
30 #include "task.h"
31 #include "croutine.h"
32 
33 /* Remove the whole file is co-routines are not being used. */
34 #if( configUSE_CO_ROUTINES != 0 )
35 
36 /*
37  * Some kernel aware debuggers require data to be viewed to be global, rather
38  * than file scope.
39  */
40 #ifdef portREMOVE_STATIC_QUALIFIER
41  #define static
42 #endif
43 
44 
45 /* Lists for ready and blocked co-routines. --------------------*/
46 static List_t pxReadyCoRoutineLists[ configMAX_CO_ROUTINE_PRIORITIES ]; /*< Prioritised ready co-routines. */
47 static List_t xDelayedCoRoutineList1; /*< Delayed co-routines. */
48 static List_t xDelayedCoRoutineList2; /*< Delayed co-routines (two lists are used - one for delays that have overflowed the current tick count. */
49 static List_t * pxDelayedCoRoutineList; /*< Points to the delayed co-routine list currently being used. */
50 static List_t * pxOverflowDelayedCoRoutineList; /*< Points to the delayed co-routine list currently being used to hold co-routines that have overflowed the current tick count. */
51 static List_t 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. */
52 
53 /* Other file private variables. --------------------------------*/
54 CRCB_t * pxCurrentCoRoutine = NULL;
55 static UBaseType_t uxTopCoRoutineReadyPriority = 0;
56 static TickType_t xCoRoutineTickCount = 0, xLastTickCount = 0, xPassedTicks = 0;
57 
58 /* The initial state of the co-routine when it is created. */
59 #define corINITIAL_STATE ( 0 )
60 
61 /*
62  * Place the co-routine represented by pxCRCB into the appropriate ready queue
63  * for the priority. It is inserted at the end of the list.
64  *
65  * This macro accesses the co-routine ready lists and therefore must not be
66  * used from within an ISR.
67  */
68 #define prvAddCoRoutineToReadyQueue( pxCRCB ) \
69 { \
70  if( pxCRCB->uxPriority > uxTopCoRoutineReadyPriority ) \
71  { \
72  uxTopCoRoutineReadyPriority = pxCRCB->uxPriority; \
73  } \
74  vListInsertEnd( ( List_t * ) &( pxReadyCoRoutineLists[ pxCRCB->uxPriority ] ), &( pxCRCB->xGenericListItem ) ); \
75 }
76 
77 /*
78  * Utility to ready all the lists used by the scheduler. This is called
79  * automatically upon the creation of the first co-routine.
80  */
81 static void prvInitialiseCoRoutineLists( void );
82 
83 /*
84  * Co-routines that are readied by an interrupt cannot be placed directly into
85  * the ready lists (there is no mutual exclusion). Instead they are placed in
86  * in the pending ready list in order that they can later be moved to the ready
87  * list by the co-routine scheduler.
88  */
89 static void prvCheckPendingReadyList( void );
90 
91 /*
92  * Macro that looks at the list of co-routines that are currently delayed to
93  * see if any require waking.
94  *
95  * Co-routines are stored in the queue in the order of their wake time -
96  * meaning once one co-routine has been found whose timer has not expired
97  * we need not look any further down the list.
98  */
99 static void prvCheckDelayedList( void );
100 
101 /*-----------------------------------------------------------*/
102 
103 BaseType_t xCoRoutineCreate( crCOROUTINE_CODE pxCoRoutineCode, UBaseType_t uxPriority, UBaseType_t uxIndex )
104 {
105 BaseType_t xReturn;
106 CRCB_t *pxCoRoutine;
107 
108  /* Allocate the memory that will store the co-routine control block. */
109  pxCoRoutine = ( CRCB_t * ) pvPortMalloc( sizeof( CRCB_t ) );
110  if( pxCoRoutine )
111  {
112  /* If pxCurrentCoRoutine is NULL then this is the first co-routine to
113  be created and the co-routine data structures need initialising. */
114  if( pxCurrentCoRoutine == NULL )
115  {
116  pxCurrentCoRoutine = pxCoRoutine;
117  prvInitialiseCoRoutineLists();
118  }
119 
120  /* Check the priority is within limits. */
121  if( uxPriority >= configMAX_CO_ROUTINE_PRIORITIES )
122  {
123  uxPriority = configMAX_CO_ROUTINE_PRIORITIES - 1;
124  }
125 
126  /* Fill out the co-routine control block from the function parameters. */
127  pxCoRoutine->uxState = corINITIAL_STATE;
128  pxCoRoutine->uxPriority = uxPriority;
129  pxCoRoutine->uxIndex = uxIndex;
130  pxCoRoutine->pxCoRoutineFunction = pxCoRoutineCode;
131 
132  /* Initialise all the other co-routine control block parameters. */
133  vListInitialiseItem( &( pxCoRoutine->xGenericListItem ) );
134  vListInitialiseItem( &( pxCoRoutine->xEventListItem ) );
135 
136  /* Set the co-routine control block as a link back from the ListItem_t.
137  This is so we can get back to the containing CRCB from a generic item
138  in a list. */
139  listSET_LIST_ITEM_OWNER( &( pxCoRoutine->xGenericListItem ), pxCoRoutine );
140  listSET_LIST_ITEM_OWNER( &( pxCoRoutine->xEventListItem ), pxCoRoutine );
141 
142  /* Event lists are always in priority order. */
143  listSET_LIST_ITEM_VALUE( &( pxCoRoutine->xEventListItem ), ( ( TickType_t ) configMAX_CO_ROUTINE_PRIORITIES - ( TickType_t ) uxPriority ) );
144 
145  /* Now the co-routine has been initialised it can be added to the ready
146  list at the correct priority. */
147  prvAddCoRoutineToReadyQueue( pxCoRoutine );
148 
149  xReturn = pdPASS;
150  }
151  else
152  {
154  }
155 
156  return xReturn;
157 }
158 /*-----------------------------------------------------------*/
159 
160 void vCoRoutineAddToDelayedList( TickType_t xTicksToDelay, List_t *pxEventList )
161 {
162 TickType_t xTimeToWake;
163 
164  /* Calculate the time to wake - this may overflow but this is
165  not a problem. */
166  xTimeToWake = xCoRoutineTickCount + xTicksToDelay;
167 
168  /* We must remove ourselves from the ready list before adding
169  ourselves to the blocked list as the same list item is used for
170  both lists. */
171  ( void ) uxListRemove( ( ListItem_t * ) &( pxCurrentCoRoutine->xGenericListItem ) );
172 
173  /* The list item will be inserted in wake time order. */
174  listSET_LIST_ITEM_VALUE( &( pxCurrentCoRoutine->xGenericListItem ), xTimeToWake );
175 
176  if( xTimeToWake < xCoRoutineTickCount )
177  {
178  /* Wake time has overflowed. Place this item in the
179  overflow list. */
180  vListInsert( ( List_t * ) pxOverflowDelayedCoRoutineList, ( ListItem_t * ) &( pxCurrentCoRoutine->xGenericListItem ) );
181  }
182  else
183  {
184  /* The wake time has not overflowed, so we can use the
185  current block list. */
186  vListInsert( ( List_t * ) pxDelayedCoRoutineList, ( ListItem_t * ) &( pxCurrentCoRoutine->xGenericListItem ) );
187  }
188 
189  if( pxEventList )
190  {
191  /* Also add the co-routine to an event list. If this is done then the
192  function must be called with interrupts disabled. */
193  vListInsert( pxEventList, &( pxCurrentCoRoutine->xEventListItem ) );
194  }
195 }
196 /*-----------------------------------------------------------*/
197 
198 static void prvCheckPendingReadyList( void )
199 {
200  /* Are there any co-routines waiting to get moved to the ready list? These
201  are co-routines that have been readied by an ISR. The ISR cannot access
202  the ready lists itself. */
203  while( listLIST_IS_EMPTY( &xPendingReadyCoRoutineList ) == pdFALSE )
204  {
205  CRCB_t *pxUnblockedCRCB;
206 
207  /* The pending ready list can be accessed by an ISR. */
209  {
210  pxUnblockedCRCB = ( CRCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( (&xPendingReadyCoRoutineList) );
211  ( void ) uxListRemove( &( pxUnblockedCRCB->xEventListItem ) );
212  }
214 
215  ( void ) uxListRemove( &( pxUnblockedCRCB->xGenericListItem ) );
216  prvAddCoRoutineToReadyQueue( pxUnblockedCRCB );
217  }
218 }
219 /*-----------------------------------------------------------*/
220 
221 static void prvCheckDelayedList( void )
222 {
223 CRCB_t *pxCRCB;
224 
225  xPassedTicks = xTaskGetTickCount() - xLastTickCount;
226  while( xPassedTicks )
227  {
228  xCoRoutineTickCount++;
229  xPassedTicks--;
230 
231  /* If the tick count has overflowed we need to swap the ready lists. */
232  if( xCoRoutineTickCount == 0 )
233  {
234  List_t * pxTemp;
235 
236  /* Tick count has overflowed so we need to swap the delay lists. If there are
237  any items in pxDelayedCoRoutineList here then there is an error! */
238  pxTemp = pxDelayedCoRoutineList;
239  pxDelayedCoRoutineList = pxOverflowDelayedCoRoutineList;
240  pxOverflowDelayedCoRoutineList = pxTemp;
241  }
242 
243  /* See if this tick has made a timeout expire. */
244  while( listLIST_IS_EMPTY( pxDelayedCoRoutineList ) == pdFALSE )
245  {
246  pxCRCB = ( CRCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedCoRoutineList );
247 
248  if( xCoRoutineTickCount < listGET_LIST_ITEM_VALUE( &( pxCRCB->xGenericListItem ) ) )
249  {
250  /* Timeout not yet expired. */
251  break;
252  }
253 
255  {
256  /* The event could have occurred just before this critical
257  section. If this is the case then the generic list item will
258  have been moved to the pending ready list and the following
259  line is still valid. Also the pvContainer parameter will have
260  been set to NULL so the following lines are also valid. */
261  ( void ) uxListRemove( &( pxCRCB->xGenericListItem ) );
262 
263  /* Is the co-routine waiting on an event also? */
264  if( pxCRCB->xEventListItem.pvContainer )
265  {
266  ( void ) uxListRemove( &( pxCRCB->xEventListItem ) );
267  }
268  }
270 
271  prvAddCoRoutineToReadyQueue( pxCRCB );
272  }
273  }
274 
275  xLastTickCount = xCoRoutineTickCount;
276 }
277 /*-----------------------------------------------------------*/
278 
279 void vCoRoutineSchedule( void )
280 {
281  /* See if any co-routines readied by events need moving to the ready lists. */
282  prvCheckPendingReadyList();
283 
284  /* See if any delayed co-routines have timed out. */
285  prvCheckDelayedList();
286 
287  /* Find the highest priority queue that contains ready co-routines. */
288  while( listLIST_IS_EMPTY( &( pxReadyCoRoutineLists[ uxTopCoRoutineReadyPriority ] ) ) )
289  {
290  if( uxTopCoRoutineReadyPriority == 0 )
291  {
292  /* No more co-routines to check. */
293  return;
294  }
295  --uxTopCoRoutineReadyPriority;
296  }
297 
298  /* listGET_OWNER_OF_NEXT_ENTRY walks through the list, so the co-routines
299  of the same priority get an equal share of the processor time. */
300  listGET_OWNER_OF_NEXT_ENTRY( pxCurrentCoRoutine, &( pxReadyCoRoutineLists[ uxTopCoRoutineReadyPriority ] ) );
301 
302  /* Call the co-routine. */
303  ( pxCurrentCoRoutine->pxCoRoutineFunction )( pxCurrentCoRoutine, pxCurrentCoRoutine->uxIndex );
304 
305  return;
306 }
307 /*-----------------------------------------------------------*/
308 
309 static void prvInitialiseCoRoutineLists( void )
310 {
311 UBaseType_t uxPriority;
312 
313  for( uxPriority = 0; uxPriority < configMAX_CO_ROUTINE_PRIORITIES; uxPriority++ )
314  {
315  vListInitialise( ( List_t * ) &( pxReadyCoRoutineLists[ uxPriority ] ) );
316  }
317 
318  vListInitialise( ( List_t * ) &xDelayedCoRoutineList1 );
319  vListInitialise( ( List_t * ) &xDelayedCoRoutineList2 );
320  vListInitialise( ( List_t * ) &xPendingReadyCoRoutineList );
321 
322  /* Start with pxDelayedCoRoutineList using list1 and the
323  pxOverflowDelayedCoRoutineList using list2. */
324  pxDelayedCoRoutineList = &xDelayedCoRoutineList1;
325  pxOverflowDelayedCoRoutineList = &xDelayedCoRoutineList2;
326 }
327 /*-----------------------------------------------------------*/
328 
329 BaseType_t xCoRoutineRemoveFromEventList( const List_t *pxEventList )
330 {
331 CRCB_t *pxUnblockedCRCB;
332 BaseType_t xReturn;
333 
334  /* This function is called from within an interrupt. It can only access
335  event lists and the pending ready list. This function assumes that a
336  check has already been made to ensure pxEventList is not empty. */
337  pxUnblockedCRCB = ( CRCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList );
338  ( void ) uxListRemove( &( pxUnblockedCRCB->xEventListItem ) );
339  vListInsertEnd( ( List_t * ) &( xPendingReadyCoRoutineList ), &( pxUnblockedCRCB->xEventListItem ) );
340 
341  if( pxUnblockedCRCB->uxPriority >= pxCurrentCoRoutine->uxPriority )
342  {
343  xReturn = pdTRUE;
344  }
345  else
346  {
347  xReturn = pdFALSE;
348  }
349 
350  return xReturn;
351 }
352 
353 #endif /* configUSE_CO_ROUTINES == 0 */
354 
#define pdTRUE
Definition: projdefs.h:46
#define listGET_LIST_ITEM_VALUE(pxListItem)
Definition: list.h:208
#define listGET_OWNER_OF_NEXT_ENTRY(pxTCB, pxList)
Definition: list.h:277
Definition: list.h:164
void *configLIST_VOLATILE pvContainer
Definition: list.h:147
UBaseType_t uxListRemove(ListItem_t *const pxItemToRemove) PRIVILEGED_FUNCTION
Definition: list.c:171
ListItem_t xEventListItem
Definition: croutine.h:54
#define portENABLE_INTERRUPTS()
Definition: portmacro.h:103
#define portDISABLE_INTERRUPTS()
Definition: portmacro.h:102
BaseType_t xCoRoutineCreate(crCOROUTINE_CODE pxCoRoutineCode, UBaseType_t uxPriority, UBaseType_t uxIndex)
void vListInsertEnd(List_t *const pxList, ListItem_t *const pxNewListItem) PRIVILEGED_FUNCTION
Definition: list.c:75
void * pvPortMalloc(size_t xSize) PRIVILEGED_FUNCTION
Definition: heap_4.c:155
#define listSET_LIST_ITEM_VALUE(pxListItem, xValue)
Definition: list.h:198
#define NULL
Definition: nm_bsp.h:52
#define listLIST_IS_EMPTY(pxList)
Definition: list.h:250
unsigned long UBaseType_t
Definition: portmacro.h:58
uint32_t TickType_t
Definition: portmacro.h:64
#define listSET_LIST_ITEM_OWNER(pxListItem, pxOwner)
Definition: list.h:180
TickType_t xTaskGetTickCount(void) PRIVILEGED_FUNCTION
Definition: tasks.c:2217
#define errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY
Definition: projdefs.h:54
long BaseType_t
Definition: portmacro.h:57
#define pdPASS
Definition: projdefs.h:48
#define listGET_OWNER_OF_HEAD_ENTRY(pxList)
Definition: list.h:307
#define configMAX_CO_ROUTINE_PRIORITIES
void vCoRoutineSchedule(void)
void vCoRoutineAddToDelayedList(TickType_t xTicksToDelay, List_t *pxEventList)
void vListInsert(List_t *const pxList, ListItem_t *const pxNewListItem) PRIVILEGED_FUNCTION
Definition: list.c:104
#define pdFALSE
Definition: projdefs.h:45
UBaseType_t uxIndex
Definition: croutine.h:56
BaseType_t xCoRoutineRemoveFromEventList(const List_t *pxEventList)
crCOROUTINE_CODE pxCoRoutineFunction
Definition: croutine.h:52
ListItem_t xGenericListItem
Definition: croutine.h:53
void(* crCOROUTINE_CODE)(CoRoutineHandle_t, UBaseType_t)
Definition: croutine.h:48
void vListInitialise(List_t *const pxList) PRIVILEGED_FUNCTION
Definition: list.c:38
void vListInitialiseItem(ListItem_t *const pxItem) PRIVILEGED_FUNCTION
Definition: list.c:63
UBaseType_t uxPriority
Definition: croutine.h:55


inertial_sense_ros
Author(s):
autogenerated on Sun Feb 28 2021 03:17:57