From 670d172cfcbbbf54cfd91ea6a43fe23cedd1e974 Mon Sep 17 00:00:00 2001 From: Richard Barry Date: Sun, 23 Sep 2012 14:35:12 +0000 Subject: [PATCH] Introduced configUSE_PORT_OPTIMISED_TASK_SELECTION, and updated the MSVC simulator port as the first implementation. --- FreeRTOS/Demo/WIN32-MSVC/FreeRTOSConfig.h | 7 +- FreeRTOS/Source/include/FreeRTOS.h | 4 + .../Source/portable/MSVC-MingW/portmacro.h | 24 +++++ FreeRTOS/Source/tasks.c | 94 +++++++++++++++---- 4 files changed, 112 insertions(+), 17 deletions(-) diff --git a/FreeRTOS/Demo/WIN32-MSVC/FreeRTOSConfig.h b/FreeRTOS/Demo/WIN32-MSVC/FreeRTOSConfig.h index 77e9362e8..c03e2b29c 100644 --- a/FreeRTOS/Demo/WIN32-MSVC/FreeRTOSConfig.h +++ b/FreeRTOS/Demo/WIN32-MSVC/FreeRTOSConfig.h @@ -104,7 +104,7 @@ #define configTIMER_QUEUE_LENGTH 20 #define configTIMER_TASK_STACK_DEPTH ( configMINIMAL_STACK_SIZE * 2 ) -#define configMAX_PRIORITIES ( ( unsigned portBASE_TYPE ) 7 ) +#define configMAX_PRIORITIES ( 7 ) #define configMAX_CO_ROUTINE_PRIORITIES ( 2 ) @@ -132,4 +132,9 @@ to exclude the API function. */ extern void vAssertCalled( void ); #define configASSERT( x ) if( ( x ) == 0 ) vAssertCalled() +/* configUSE_PORT_OPTIMISED_TASK_SELECTION is only available in the MSVC +version of the Win32 simulator projects. It will be ignored in the GCC +version. */ +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 + #endif /* FREERTOS_CONFIG_H */ diff --git a/FreeRTOS/Source/include/FreeRTOS.h b/FreeRTOS/Source/include/FreeRTOS.h index 17c5c682d..ab58749be 100644 --- a/FreeRTOS/Source/include/FreeRTOS.h +++ b/FreeRTOS/Source/include/FreeRTOS.h @@ -165,6 +165,10 @@ typedef portBASE_TYPE (*pdTASK_HOOK_CODE)( void * ); #define INCLUDE_uxTaskGetStackHighWaterMark 0 #endif +#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION + #define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 +#endif + #ifndef INCLUDE_cTaskStateGet #define INCLUDE_cTaskStateGet 0 #endif diff --git a/FreeRTOS/Source/portable/MSVC-MingW/portmacro.h b/FreeRTOS/Source/portable/MSVC-MingW/portmacro.h index 484aac5d2..9a991ab6f 100644 --- a/FreeRTOS/Source/portable/MSVC-MingW/portmacro.h +++ b/FreeRTOS/Source/portable/MSVC-MingW/portmacro.h @@ -108,6 +108,30 @@ void vPortExitCritical( void ); #define portENTER_CRITICAL() vPortEnterCritical() #define portEXIT_CRITICAL() vPortExitCritical() +#ifndef __GNUC__ + #if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1 + + /* Check the configuration. */ + #if( configMAX_PRIORITIES >= 32 ) + #error configUSE_PORT_OPTIMISED_TASK_SELECTION can only be set to 1 when configMAX_PRIORITIES is less than or equal to 32. It is very rare that a system requires more than 10 to 15 difference priorities as tasks that share a priority will time slice. + #endif + + /* Store/clear the ready priorities in a bit map. */ + #define portRECORD_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) |= ( 1UL << ( uxPriority ) ) + #define portRESET_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) &= ~( 1UL << ( uxPriority ) ) + + + /*-----------------------------------------------------------*/ + + /* BitScanReverse returns the bit position of the most significant '1' + in the word. */ + #define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) _BitScanReverse( ( DWORD * ) &( uxTopPriority ), ( uxReadyPriorities ) ) + + #endif /* taskRECORD_READY_PRIORITY */ +#endif /* __GNUC__ */ + + + /* Task function macros as described on the FreeRTOS.org WEB site. */ #define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void * pvParameters ) #define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void * pvParameters ) diff --git a/FreeRTOS/Source/tasks.c b/FreeRTOS/Source/tasks.c index 8d622939b..9e0649a21 100644 --- a/FreeRTOS/Source/tasks.c +++ b/FreeRTOS/Source/tasks.c @@ -210,6 +210,72 @@ PRIVILEGED_DATA static portTickType xNextTaskUnblockTime = ( portTickType ) /*-----------------------------------------------------------*/ +#if configUSE_PORT_OPTIMISED_TASK_SELECTION == 0 + /* + * uxTopReadyPriority holds the priority of the highest priority ready + * state task. + */ + #define taskRECORD_READY_PRIORITY( uxPriority ) \ + { \ + if( ( uxPriority ) > uxTopReadyPriority ) \ + { \ + uxTopReadyPriority = ( uxPriority ); \ + } \ + } /* taskRECORD_READY_PRIORITY */ + + /*-----------------------------------------------------------*/ + + #define taskSELECT_HIGHEST_PRIORITY_TASK() \ + { \ + /* Find the highest priority queue that contains ready tasks. */ \ + while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxTopReadyPriority ] ) ) ) \ + { \ + configASSERT( uxTopReadyPriority ); \ + --uxTopReadyPriority; \ + } \ + \ + /* listGET_OWNER_OF_NEXT_ENTRY indexes through the list, so the tasks of \ + the same priority get an equal share of the processor time. */ \ + listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopReadyPriority ] ) ); \ + } /* taskSELECT_HIGHEST_PRIORITY_TASK */ + + /*-----------------------------------------------------------*/ + + /* Define away taskCHECK_READY_LIST() as it is not required in this + configuration. */ + #define taskCHECK_READY_LIST( uxPriority ) + +#else /* configUSE_PORT_OPTIMISED_TASK_SELECTION */ + + /* A port optimised version is provided. Call the port defined macros. */ + #define taskRECORD_READY_PRIORITY( uxPriority ) portRECORD_READY_PRIORITY( uxPriority, uxTopReadyPriority ) + + /*-----------------------------------------------------------*/ + + #define taskSELECT_HIGHEST_PRIORITY_TASK() \ + { \ + unsigned portBASE_TYPE uxTopPriority; \ + \ + /* Find the highest priority queue that contains ready tasks. */ \ + portGET_HIGHEST_PRIORITY( uxTopPriority, uxTopReadyPriority ); \ + listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ] ) ); \ + } /* taskSELECT_HIGHEST_PRIORITY_TASK() */ + + /*-----------------------------------------------------------*/ + + /* Let the port layer know if the ready list is empty so + taskSELECT_HIGHEST_PRIORITY_TASK() can function correctly. */ + #define taskCHECK_READY_LIST( uxPriority ) \ + { \ + if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ ( uxPriority ) ] ) ) == 0 ) \ + { \ + portRESET_READY_PRIORITY( ( uxPriority ), uxTopReadyPriority ); \ + } \ + } /* taskCHECK_READY_LIST() */ + + +#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */ + /* * Place the task represented by pxTCB into the appropriate ready queue for * the task. It is inserted at the end of the list. One quirk of this is @@ -219,10 +285,7 @@ PRIVILEGED_DATA static portTickType xNextTaskUnblockTime = ( portTickType ) */ #define prvAddTaskToReadyQueue( pxTCB ) \ traceMOVED_TASK_TO_READY_STATE( pxTCB ) \ - if( ( pxTCB )->uxPriority > uxTopReadyPriority ) \ - { \ - uxTopReadyPriority = ( pxTCB )->uxPriority; \ - } \ + taskRECORD_READY_PRIORITY( ( pxTCB )->uxPriority ); \ vListInsertEnd( ( xList * ) &( pxReadyTasksLists[ ( pxTCB )->uxPriority ] ), &( ( pxTCB )->xGenericListItem ) ) /*-----------------------------------------------------------*/ @@ -579,6 +642,7 @@ tskTCB * pxNewTCB; the termination list and free up any memory allocated by the scheduler for the TCB and stack. */ vListRemove( &( pxTCB->xGenericListItem ) ); + taskCHECK_READY_LIST( pxTCB->uxPriority ); /* Is the task waiting on an event also? */ if( pxTCB->xEventListItem.pvContainer != NULL ) @@ -671,6 +735,7 @@ tskTCB * pxNewTCB; ourselves to the blocked list as the same list item is used for both lists. */ vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) ); + taskCHECK_READY_LIST( pxCurrentTCB->uxPriority ); prvAddCurrentTaskToDelayedList( xTimeToWake ); } } @@ -717,6 +782,7 @@ tskTCB * pxNewTCB; ourselves to the blocked list as the same list item is used for both lists. */ vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) ); + taskCHECK_READY_LIST( pxCurrentTCB->uxPriority ); prvAddCurrentTaskToDelayedList( xTimeToWake ); } xAlreadyYielded = xTaskResumeAll(); @@ -910,6 +976,7 @@ tskTCB * pxNewTCB; it to it's new ready list. As we are in a critical section we can do this even if the scheduler is suspended. */ vListRemove( &( pxTCB->xGenericListItem ) ); + taskCHECK_READY_LIST( uxCurrentPriority ); prvAddTaskToReadyQueue( pxTCB ); } @@ -947,6 +1014,7 @@ tskTCB * pxNewTCB; /* Remove task from the ready/delayed list and place in the suspended list. */ vListRemove( &( pxTCB->xGenericListItem ) ); + taskCHECK_READY_LIST( pxTCB->uxPriority ); /* Is the task waiting on an event also? */ if( pxTCB->xEventListItem.pvContainer != NULL ) @@ -1690,17 +1758,8 @@ void vTaskSwitchContext( void ) taskFIRST_CHECK_FOR_STACK_OVERFLOW(); taskSECOND_CHECK_FOR_STACK_OVERFLOW(); - /* Find the highest priority queue that contains ready tasks. */ - while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxTopReadyPriority ] ) ) ) - { - configASSERT( uxTopReadyPriority ); - --uxTopReadyPriority; - } - - /* listGET_OWNER_OF_NEXT_ENTRY walks through the list, so the tasks of the - same priority get an equal share of the processor time. */ - listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopReadyPriority ] ) ); - + taskSELECT_HIGHEST_PRIORITY_TASK(); + traceTASK_SWITCHED_IN(); } } @@ -1724,7 +1783,7 @@ portTickType xTimeToWake; to the blocked list as the same list item is used for both lists. We have exclusive access to the ready lists as the scheduler is locked. */ vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) ); - + taskCHECK_READY_LIST( pxCurrentTCB->uxPriority ); #if ( INCLUDE_vTaskSuspend == 1 ) { @@ -1778,6 +1837,7 @@ portTickType xTimeToWake; blocked list as the same list item is used for both lists. This function is called form a critical section. */ vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) ); + taskCHECK_READY_LIST( pxCurrentTCB->uxPriority ); /* Calculate the time at which the task should be woken if the event does not occur. This may overflow but this doesn't matter. */ @@ -2458,6 +2518,7 @@ tskTCB *pxNewTCB; if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxTCB->uxPriority ] ), &( pxTCB->xGenericListItem ) ) != pdFALSE ) { vListRemove( &( pxTCB->xGenericListItem ) ); + taskCHECK_READY_LIST( pxTCB->uxPriority ); /* Inherit the priority before being moved into the new list. */ pxTCB->uxPriority = pxCurrentTCB->uxPriority; @@ -2490,6 +2551,7 @@ tskTCB *pxNewTCB; /* We must be the running task to be able to give the mutex back. Remove ourselves from the ready list we currently appear in. */ vListRemove( &( pxTCB->xGenericListItem ) ); + taskCHECK_READY_LIST( pxTCB->uxPriority ); /* Disinherit the priority before adding the task into the new ready list. */