www.freertos.org test on stm32f0

Fork of FreeRTOS by Rohit Grover

Revision:
0:8e57f3e9cc89
diff -r 000000000000 -r 8e57f3e9cc89 Source/croutine.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Source/croutine.c	Fri Jan 24 14:56:04 2014 +0000
@@ -0,0 +1,386 @@
+/*
+    FreeRTOS V7.6.0 - Copyright (C) 2013 Real Time Engineers Ltd.
+    All rights reserved
+
+    VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
+
+    ***************************************************************************
+     *                                                                       *
+     *    FreeRTOS provides completely free yet professionally developed,    *
+     *    robust, strictly quality controlled, supported, and cross          *
+     *    platform software that has become a de facto standard.             *
+     *                                                                       *
+     *    Help yourself get started quickly and support the FreeRTOS         *
+     *    project by purchasing a FreeRTOS tutorial book, reference          *
+     *    manual, or both from: http://www.FreeRTOS.org/Documentation        *
+     *                                                                       *
+     *    Thank you!                                                         *
+     *                                                                       *
+    ***************************************************************************
+
+    This file is part of the FreeRTOS distribution.
+
+    FreeRTOS is free software; you can redistribute it and/or modify it under
+    the terms of the GNU General Public License (version 2) as published by the
+    Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
+
+    >>! NOTE: The modification to the GPL is included to allow you to distribute
+    >>! a combined work that includes FreeRTOS without being obliged to provide
+    >>! the source code for proprietary components outside of the FreeRTOS
+    >>! kernel.
+
+    FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
+    WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+    FOR A PARTICULAR PURPOSE.  Full license text is available from the following
+    link: http://www.freertos.org/a00114.html
+
+    1 tab == 4 spaces!
+
+    ***************************************************************************
+     *                                                                       *
+     *    Having a problem?  Start by reading the FAQ "My application does   *
+     *    not run, what could be wrong?"                                     *
+     *                                                                       *
+     *    http://www.FreeRTOS.org/FAQHelp.html                               *
+     *                                                                       *
+    ***************************************************************************
+
+    http://www.FreeRTOS.org - Documentation, books, training, latest versions,
+    license and Real Time Engineers Ltd. contact details.
+
+    http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
+    including FreeRTOS+Trace - an indispensable productivity tool, a DOS
+    compatible FAT file system, and our tiny thread aware UDP/IP stack.
+
+    http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
+    Integrity Systems to sell under the OpenRTOS brand.  Low cost OpenRTOS
+    licenses offer ticketed support, indemnification and middleware.
+
+    http://www.SafeRTOS.com - High Integrity Systems also provide a safety
+    engineered and independently SIL3 certified version for use in safety and
+    mission critical applications that require provable dependability.
+
+    1 tab == 4 spaces!
+*/
+
+#include "FreeRTOS.h"
+#include "task.h"
+#include "croutine.h"
+
+/*
+ * Some kernel aware debuggers require data to be viewed to be global, rather
+ * than file scope.
+ */
+#ifdef portREMOVE_STATIC_QUALIFIER
+	#define static
+#endif
+
+
+/* Lists for ready and blocked co-routines. --------------------*/
+static xList pxReadyCoRoutineLists[ configMAX_CO_ROUTINE_PRIORITIES ];	/*< Prioritised ready co-routines. */
+static xList xDelayedCoRoutineList1;									/*< Delayed co-routines. */
+static xList xDelayedCoRoutineList2;									/*< Delayed co-routines (two lists are used - one for delays that have overflowed the current tick count. */
+static xList * pxDelayedCoRoutineList;									/*< Points to the delayed co-routine list currently being used. */
+static xList * pxOverflowDelayedCoRoutineList;							/*< Points to the delayed co-routine list currently being used to hold co-routines that have overflowed the current tick count. */
+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. */
+
+/* Other file private variables. --------------------------------*/
+corCRCB * pxCurrentCoRoutine = NULL;
+static unsigned portBASE_TYPE uxTopCoRoutineReadyPriority = 0;
+static portTickType xCoRoutineTickCount = 0, xLastTickCount = 0, xPassedTicks = 0;
+
+/* The initial state of the co-routine when it is created. */
+#define corINITIAL_STATE	( 0 )
+
+/*
+ * Place the co-routine represented by pxCRCB into the appropriate ready queue
+ * for the priority.  It is inserted at the end of the list.
+ *
+ * This macro accesses the co-routine ready lists and therefore must not be
+ * used from within an ISR.
+ */
+#define prvAddCoRoutineToReadyQueue( pxCRCB )																		\
+{																													\
+	if( pxCRCB->uxPriority > uxTopCoRoutineReadyPriority )															\
+	{																												\
+		uxTopCoRoutineReadyPriority = pxCRCB->uxPriority;															\
+	}																												\
+	vListInsertEnd( ( xList * ) &( pxReadyCoRoutineLists[ pxCRCB->uxPriority ] ), &( pxCRCB->xGenericListItem ) );	\
+}
+
+/*
+ * Utility to ready all the lists used by the scheduler.  This is called
+ * automatically upon the creation of the first co-routine.
+ */
+static void prvInitialiseCoRoutineLists( void );
+
+/*
+ * Co-routines that are readied by an interrupt cannot be placed directly into
+ * the ready lists (there is no mutual exclusion).  Instead they are placed in
+ * in the pending ready list in order that they can later be moved to the ready
+ * list by the co-routine scheduler.
+ */
+static void prvCheckPendingReadyList( void );
+
+/*
+ * Macro that looks at the list of co-routines that are currently delayed to
+ * see if any require waking.
+ *
+ * Co-routines are stored in the queue in the order of their wake time -
+ * meaning once one co-routine has been found whose timer has not expired
+ * we need not look any further down the list.
+ */
+static void prvCheckDelayedList( void );
+
+/*-----------------------------------------------------------*/
+
+signed portBASE_TYPE xCoRoutineCreate( crCOROUTINE_CODE pxCoRoutineCode, unsigned portBASE_TYPE uxPriority, unsigned portBASE_TYPE uxIndex )
+{
+signed portBASE_TYPE xReturn;
+corCRCB *pxCoRoutine;
+
+	/* Allocate the memory that will store the co-routine control block. */
+	pxCoRoutine = ( corCRCB * ) pvPortMalloc( sizeof( corCRCB ) );
+	if( pxCoRoutine )
+	{
+		/* If pxCurrentCoRoutine is NULL then this is the first co-routine to
+		be created and the co-routine data structures need initialising. */
+		if( pxCurrentCoRoutine == NULL )
+		{
+			pxCurrentCoRoutine = pxCoRoutine;
+			prvInitialiseCoRoutineLists();
+		}
+
+		/* Check the priority is within limits. */
+		if( uxPriority >= configMAX_CO_ROUTINE_PRIORITIES )
+		{
+			uxPriority = configMAX_CO_ROUTINE_PRIORITIES - 1;
+		}
+
+		/* Fill out the co-routine control block from the function parameters. */
+		pxCoRoutine->uxState = corINITIAL_STATE;
+		pxCoRoutine->uxPriority = uxPriority;
+		pxCoRoutine->uxIndex = uxIndex;
+		pxCoRoutine->pxCoRoutineFunction = pxCoRoutineCode;
+
+		/* Initialise all the other co-routine control block parameters. */
+		vListInitialiseItem( &( pxCoRoutine->xGenericListItem ) );
+		vListInitialiseItem( &( pxCoRoutine->xEventListItem ) );
+
+		/* Set the co-routine control block as a link back from the xListItem.
+		This is so we can get back to the containing CRCB from a generic item
+		in a list. */
+		listSET_LIST_ITEM_OWNER( &( pxCoRoutine->xGenericListItem ), pxCoRoutine );
+		listSET_LIST_ITEM_OWNER( &( pxCoRoutine->xEventListItem ), pxCoRoutine );
+
+		/* Event lists are always in priority order. */
+		listSET_LIST_ITEM_VALUE( &( pxCoRoutine->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) uxPriority );
+
+		/* Now the co-routine has been initialised it can be added to the ready
+		list at the correct priority. */
+		prvAddCoRoutineToReadyQueue( pxCoRoutine );
+
+		xReturn = pdPASS;
+	}
+	else
+	{
+		xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
+	}
+
+	return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+void vCoRoutineAddToDelayedList( portTickType xTicksToDelay, xList *pxEventList )
+{
+portTickType xTimeToWake;
+
+	/* Calculate the time to wake - this may overflow but this is
+	not a problem. */
+	xTimeToWake = xCoRoutineTickCount + xTicksToDelay;
+
+	/* We must remove ourselves from the ready list before adding
+	ourselves to the blocked list as the same list item is used for
+	both lists. */
+	( void ) uxListRemove( ( xListItem * ) &( pxCurrentCoRoutine->xGenericListItem ) );
+
+	/* The list item will be inserted in wake time order. */
+	listSET_LIST_ITEM_VALUE( &( pxCurrentCoRoutine->xGenericListItem ), xTimeToWake );
+
+	if( xTimeToWake < xCoRoutineTickCount )
+	{
+		/* Wake time has overflowed.  Place this item in the
+		overflow list. */
+		vListInsert( ( xList * ) pxOverflowDelayedCoRoutineList, ( xListItem * ) &( pxCurrentCoRoutine->xGenericListItem ) );
+	}
+	else
+	{
+		/* The wake time has not overflowed, so we can use the
+		current block list. */
+		vListInsert( ( xList * ) pxDelayedCoRoutineList, ( xListItem * ) &( pxCurrentCoRoutine->xGenericListItem ) );
+	}
+
+	if( pxEventList )
+	{
+		/* Also add the co-routine to an event list.  If this is done then the
+		function must be called with interrupts disabled. */
+		vListInsert( pxEventList, &( pxCurrentCoRoutine->xEventListItem ) );
+	}
+}
+/*-----------------------------------------------------------*/
+
+static void prvCheckPendingReadyList( void )
+{
+	/* Are there any co-routines waiting to get moved to the ready list?  These
+	are co-routines that have been readied by an ISR.  The ISR cannot access
+	the	ready lists itself. */
+	while( listLIST_IS_EMPTY( &xPendingReadyCoRoutineList ) == pdFALSE )
+	{
+		corCRCB *pxUnblockedCRCB;
+
+		/* The pending ready list can be accessed by an ISR. */
+		portDISABLE_INTERRUPTS();
+		{
+			pxUnblockedCRCB = ( corCRCB * ) listGET_OWNER_OF_HEAD_ENTRY( (&xPendingReadyCoRoutineList) );
+			( void ) uxListRemove( &( pxUnblockedCRCB->xEventListItem ) );
+		}
+		portENABLE_INTERRUPTS();
+
+		( void ) uxListRemove( &( pxUnblockedCRCB->xGenericListItem ) );
+		prvAddCoRoutineToReadyQueue( pxUnblockedCRCB );
+	}
+}
+/*-----------------------------------------------------------*/
+
+static void prvCheckDelayedList( void )
+{
+corCRCB *pxCRCB;
+
+	xPassedTicks = xTaskGetTickCount() - xLastTickCount;
+	while( xPassedTicks )
+	{
+		xCoRoutineTickCount++;
+		xPassedTicks--;
+
+		/* If the tick count has overflowed we need to swap the ready lists. */
+		if( xCoRoutineTickCount == 0 )
+		{
+			xList * pxTemp;
+
+			/* Tick count has overflowed so we need to swap the delay lists.  If there are
+			any items in pxDelayedCoRoutineList here then there is an error! */
+			pxTemp = pxDelayedCoRoutineList;
+			pxDelayedCoRoutineList = pxOverflowDelayedCoRoutineList;
+			pxOverflowDelayedCoRoutineList = pxTemp;
+		}
+
+		/* See if this tick has made a timeout expire. */
+		while( listLIST_IS_EMPTY( pxDelayedCoRoutineList ) == pdFALSE )
+		{
+			pxCRCB = ( corCRCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedCoRoutineList );
+
+			if( xCoRoutineTickCount < listGET_LIST_ITEM_VALUE( &( pxCRCB->xGenericListItem ) ) )
+			{
+				/* Timeout not yet expired. */
+				break;
+			}
+
+			portDISABLE_INTERRUPTS();
+			{
+				/* The event could have occurred just before this critical
+				section.  If this is the case then the generic list item will
+				have been moved to the pending ready list and the following
+				line is still valid.  Also the pvContainer parameter will have
+				been set to NULL so the following lines are also valid. */
+				uxListRemove( &( pxCRCB->xGenericListItem ) );
+
+				/* Is the co-routine waiting on an event also? */
+				if( pxCRCB->xEventListItem.pvContainer )
+				{
+					( void ) uxListRemove( &( pxCRCB->xEventListItem ) );
+				}
+			}
+			portENABLE_INTERRUPTS();
+
+			prvAddCoRoutineToReadyQueue( pxCRCB );
+		}
+	}
+
+	xLastTickCount = xCoRoutineTickCount;
+}
+/*-----------------------------------------------------------*/
+
+void vCoRoutineSchedule( void )
+{
+	/* See if any co-routines readied by events need moving to the ready lists. */
+	prvCheckPendingReadyList();
+
+	/* See if any delayed co-routines have timed out. */
+	prvCheckDelayedList();
+
+	/* Find the highest priority queue that contains ready co-routines. */
+	while( listLIST_IS_EMPTY( &( pxReadyCoRoutineLists[ uxTopCoRoutineReadyPriority ] ) ) )
+	{
+		if( uxTopCoRoutineReadyPriority == 0 )
+		{
+			/* No more co-routines to check. */
+			return;
+		}
+		--uxTopCoRoutineReadyPriority;
+	}
+
+	/* listGET_OWNER_OF_NEXT_ENTRY walks through the list, so the co-routines
+	 of the	same priority get an equal share of the processor time. */
+	listGET_OWNER_OF_NEXT_ENTRY( pxCurrentCoRoutine, &( pxReadyCoRoutineLists[ uxTopCoRoutineReadyPriority ] ) );
+
+	/* Call the co-routine. */
+	( pxCurrentCoRoutine->pxCoRoutineFunction )( pxCurrentCoRoutine, pxCurrentCoRoutine->uxIndex );
+
+	return;
+}
+/*-----------------------------------------------------------*/
+
+static void prvInitialiseCoRoutineLists( void )
+{
+unsigned portBASE_TYPE uxPriority;
+
+	for( uxPriority = 0; uxPriority < configMAX_CO_ROUTINE_PRIORITIES; uxPriority++ )
+	{
+		vListInitialise( ( xList * ) &( pxReadyCoRoutineLists[ uxPriority ] ) );
+	}
+
+	vListInitialise( ( xList * ) &xDelayedCoRoutineList1 );
+	vListInitialise( ( xList * ) &xDelayedCoRoutineList2 );
+	vListInitialise( ( xList * ) &xPendingReadyCoRoutineList );
+
+	/* Start with pxDelayedCoRoutineList using list1 and the
+	pxOverflowDelayedCoRoutineList using list2. */
+	pxDelayedCoRoutineList = &xDelayedCoRoutineList1;
+	pxOverflowDelayedCoRoutineList = &xDelayedCoRoutineList2;
+}
+/*-----------------------------------------------------------*/
+
+signed portBASE_TYPE xCoRoutineRemoveFromEventList( const xList *pxEventList )
+{
+corCRCB *pxUnblockedCRCB;
+signed portBASE_TYPE xReturn;
+
+	/* This function is called from within an interrupt.  It can only access
+	event lists and the pending ready list.  This function assumes that a
+	check has already been made to ensure pxEventList is not empty. */
+	pxUnblockedCRCB = ( corCRCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList );
+	( void ) uxListRemove( &( pxUnblockedCRCB->xEventListItem ) );
+	vListInsertEnd( ( xList * ) &( xPendingReadyCoRoutineList ), &( pxUnblockedCRCB->xEventListItem ) );
+
+	if( pxUnblockedCRCB->uxPriority >= pxCurrentCoRoutine->uxPriority )
+	{
+		xReturn = pdTRUE;
+	}
+	else
+	{
+		xReturn = pdFALSE;
+	}
+
+	return xReturn;
+}
+