From a79c161476546ec571feabcb5c6dc3e88df1cd5e Mon Sep 17 00:00:00 2001 From: rtel Date: Sun, 14 Feb 2016 11:58:11 +0000 Subject: [PATCH] Core kernel code changes: + Added xTaskAbortDelay() function, which causes a task to exit the Blocked state even before the timeout has expired or the event the task is waiting for has occurred. + For efficiency and code size reasons on some architectures, replace many instances of "== pdTRUE" with "!= pdFALSE". git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@2416 1d2547de-c912-0410-9cb9-b8ca96c0e9e2 --- FreeRTOS/Source/include/task.h | 25 ++++ FreeRTOS/Source/portable/MemMang/ReadMe.url | 5 + FreeRTOS/Source/portable/readme.txt | 5 +- FreeRTOS/Source/queue.c | 27 ++-- FreeRTOS/Source/tasks.c | 137 +++++++++++++++++--- FreeRTOS/Source/timers.c | 4 +- 6 files changed, 171 insertions(+), 32 deletions(-) create mode 100644 FreeRTOS/Source/portable/MemMang/ReadMe.url diff --git a/FreeRTOS/Source/include/task.h b/FreeRTOS/Source/include/task.h index 182d35912..df352eb95 100644 --- a/FreeRTOS/Source/include/task.h +++ b/FreeRTOS/Source/include/task.h @@ -744,6 +744,31 @@ void vTaskDelay( const TickType_t xTicksToDelay ) PRIVILEGED_FUNCTION; */ void vTaskDelayUntil( TickType_t * const pxPreviousWakeTime, const TickType_t xTimeIncrement ) PRIVILEGED_FUNCTION; +/** + * task. h + *
BaseType_t xTaskAbortDelay( TaskHandle_t xTask );
+ * + * INCLUDE_xTaskAbortDelay must be defined as 1 in FreeRTOSConfig.h for this + * function to be available. + * + * A task will enter the Blocked state when it is waiting for an event. The + * event it is waiting for can be a temporal event (waiting for a time), such + * as when vTaskDelay() is called, or an event on an object, such as when + * xQueueReceive() or ulTaskNotifyTake() is called. If the handle of a task + * that is in the Blocked state is used in a call to xTaskAbortDelay() then the + * task will leave the Blocked state, and return from whichever function call + * placed the task into the Blocked state. + * + * @param xTask The handle of the task to remove from the Blocked state. + * + * @return If the task referenced by xTask was not in the Blocked state then + * pdFAIL is returned. Otherwise pdPASS is returned. + * + * \defgroup xTaskAbortDelay xTaskAbortDelay + * \ingroup TaskCtrl + */ +BaseType_t xTaskAbortDelay( TaskHandle_t xTask ); + /** * task. h *
UBaseType_t uxTaskPriorityGet( TaskHandle_t xTask );
diff --git a/FreeRTOS/Source/portable/MemMang/ReadMe.url b/FreeRTOS/Source/portable/MemMang/ReadMe.url new file mode 100644 index 000000000..b04bfe3e5 --- /dev/null +++ b/FreeRTOS/Source/portable/MemMang/ReadMe.url @@ -0,0 +1,5 @@ +[{000214A0-0000-0000-C000-000000000046}] +Prop3=19,2 +[InternetShortcut] +URL=http://www.freertos.org/a00111.html +IDList= diff --git a/FreeRTOS/Source/portable/readme.txt b/FreeRTOS/Source/portable/readme.txt index a259d267b..b22b36bf1 100644 --- a/FreeRTOS/Source/portable/readme.txt +++ b/FreeRTOS/Source/portable/readme.txt @@ -3,11 +3,12 @@ components and are common to every port, and one or more files that are specific to a particular microcontroller and/or compiler. -+ The FreeRTOS/Source/Portable/MemMang directory contains the three sample ++ The FreeRTOS/Source/Portable/MemMang directory contains the five sample memory allocators as described on the http://www.FreeRTOS.org WEB site. + The other directories each contain files specific to a particular -microcontroller or compiler. +microcontroller or compiler, where the directory name denotes the compiler +specific files the directory contains. diff --git a/FreeRTOS/Source/queue.c b/FreeRTOS/Source/queue.c index 57bdcdbde..3a6aea92a 100644 --- a/FreeRTOS/Source/queue.c +++ b/FreeRTOS/Source/queue.c @@ -303,7 +303,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; it will be possible to write to it. */ if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) { - if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) == pdTRUE ) + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE ) { queueYIELD_IF_USING_PREEMPTION(); } @@ -651,7 +651,7 @@ Queue_t *pxNewQueue; /* pdPASS will only be returned if the mutex was successfully obtained. The calling task may have entered the Blocked state before reaching here. */ - if( xReturn == pdPASS ) + if( xReturn != pdFAIL ) { ( pxMutex->u.uxRecursiveCallCount )++; } @@ -732,7 +732,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; { if( pxQueue->pxQueueSetContainer != NULL ) { - if( prvNotifyQueueSetContainer( pxQueue, xCopyPosition ) == pdTRUE ) + if( prvNotifyQueueSetContainer( pxQueue, xCopyPosition ) != pdFALSE ) { /* The queue is a member of a queue set, and posting to the queue set caused a higher priority task to @@ -750,7 +750,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; queue then unblock it now. */ if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) { - if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) == pdTRUE ) + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) { /* The unblocked task has a priority higher than our own so yield immediately. Yes it is ok to @@ -783,7 +783,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; queue then unblock it now. */ if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) { - if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) == pdTRUE ) + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) { /* The unblocked task has a priority higher than our own so yield immediately. Yes it is ok to do @@ -920,7 +920,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; queue then unblock it now. */ if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) { - if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) == pdTRUE ) + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) { /* The unblocked task has a priority higher than our own so yield immediately. */ @@ -1031,7 +1031,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) { - if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) == pdTRUE ) + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE ) { portYIELD_WITHIN_API(); } @@ -1191,7 +1191,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; { if( pxQueue->pxQueueSetContainer != NULL ) { - if( prvNotifyQueueSetContainer( pxQueue, xCopyPosition ) == pdTRUE ) + if( prvNotifyQueueSetContainer( pxQueue, xCopyPosition ) != pdFALSE ) { /* The queue is a member of a queue set, and posting to the queue set caused a higher priority task to @@ -1352,7 +1352,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; { if( pxQueue->pxQueueSetContainer != NULL ) { - if( prvNotifyQueueSetContainer( pxQueue, queueSEND_TO_BACK ) == pdTRUE ) + if( prvNotifyQueueSetContainer( pxQueue, queueSEND_TO_BACK ) != pdFALSE ) { /* The semaphore is a member of a queue set, and posting to the queue set caused a higher priority @@ -1506,7 +1506,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) { - if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) == pdTRUE ) + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE ) { queueYIELD_IF_USING_PREEMPTION(); } @@ -2019,7 +2019,7 @@ static void prvUnlockQueue( Queue_t * const pxQueue ) { if( pxQueue->pxQueueSetContainer != NULL ) { - if( prvNotifyQueueSetContainer( pxQueue, queueSEND_TO_BACK ) == pdTRUE ) + if( prvNotifyQueueSetContainer( pxQueue, queueSEND_TO_BACK ) != pdFALSE ) { /* The queue is a member of a queue set, and posting to the queue set caused a higher priority task to unblock. @@ -2033,8 +2033,9 @@ static void prvUnlockQueue( Queue_t * const pxQueue ) } else { - /* Tasks that are removed from the event list will get added to - the pending ready list as the scheduler is still suspended. */ + /* Tasks that are removed from the event list will get + added to the pending ready list as the scheduler is still + suspended. */ if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) { if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) diff --git a/FreeRTOS/Source/tasks.c b/FreeRTOS/Source/tasks.c index 3dcb0049e..4f2c29bad 100644 --- a/FreeRTOS/Source/tasks.c +++ b/FreeRTOS/Source/tasks.c @@ -199,8 +199,12 @@ typedef struct tskTaskControlBlock volatile uint8_t ucNotifyState; #endif - #if ( configSUPPORT_STATIC_ALLOCATION == 1 ) - uint8_t ucStaticAllocationFlags; /* Set to pdTRUE if the stack is a statically allocated array, and pdFALSE if the stack is dynamically allocated. */ + #if( configSUPPORT_STATIC_ALLOCATION == 1 ) + uint8_t ucStaticAllocationFlags; /* Set to pdTRUE if the stack is a statically allocated array, and pdFALSE if the stack is dynamically allocated. */ + #endif + + #if( INCLUDE_xTaskAbortDelay == 1 ) + uint8_t ucDelayAborted; #endif } tskTCB; @@ -210,8 +214,8 @@ below to enable the use of older kernel aware debuggers. */ typedef tskTCB TCB_t; /* - * Some kernel aware debuggers require the data the debugger needs access to to - * be global, rather than file scope. + * Some kernel aware debuggers require the data the debugger needs access to be + * global, rather than file scope. */ #ifdef portREMOVE_STATIC_QUALIFIER #define static @@ -1244,7 +1248,7 @@ StackType_t *pxTopOfStack; mtCOVERAGE_TEST_MARKER(); } - if( xYieldRequired == pdTRUE ) + if( xYieldRequired != pdFALSE ) { taskYIELD_IF_USING_PREEMPTION(); } @@ -1415,7 +1419,7 @@ StackType_t *pxTopOfStack; { taskENTER_CRITICAL(); { - if( prvTaskIsTaskSuspended( pxTCB ) == pdTRUE ) + if( prvTaskIsTaskSuspended( pxTCB ) != pdFALSE ) { traceTASK_RESUME( pxTCB ); @@ -1484,7 +1488,7 @@ StackType_t *pxTopOfStack; uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); { - if( prvTaskIsTaskSuspended( pxTCB ) == pdTRUE ) + if( prvTaskIsTaskSuspended( pxTCB ) != pdFALSE ) { traceTASK_RESUME_FROM_ISR( pxTCB ); @@ -1769,7 +1773,7 @@ BaseType_t xAlreadyYielded = pdFALSE; mtCOVERAGE_TEST_MARKER(); } - if( xYieldPending == pdTRUE ) + if( xYieldPending != pdFALSE ) { #if( configUSE_PREEMPTION != 0 ) { @@ -1933,6 +1937,9 @@ UBaseType_t uxTaskGetNumberOfTasks( void ) UBaseType_t uxQueue = configMAX_PRIORITIES; TCB_t* pxTCB; + /* Task names will be truncated to configMAX_TASK_NAME_LEN - 1 bytes. */ + configASSERT( strlen( pcNameToQuery ) < configMAX_TASK_NAME_LEN ); + vTaskSuspendAll(); { /* Search the ready lists. */ @@ -2094,6 +2101,80 @@ implementations require configUSE_TICKLESS_IDLE to be set to a value other than #endif /* configUSE_TICKLESS_IDLE */ /*----------------------------------------------------------*/ +#if ( INCLUDE_xTaskAbortDelay == 1 ) + + BaseType_t xTaskAbortDelay( TaskHandle_t xTask ) + { + TCB_t *pxTCB = ( TCB_t * ) xTask; + BaseType_t xReturn = pdFALSE; + + configASSERT( pxTCB ); + + vTaskSuspendAll(); + { + /* A task can only be prematurely removed from the Blocked state if + it is actually in the Blocked state. */ + if( eTaskGetState( xTask ) == eBlocked ) + { + /* Remove the reference to the task from the blocked list. An + interrupt won't touch the xGenericListItem because the + scheduler is suspended. */ + ( void ) uxListRemove( &( pxTCB->xGenericListItem ) ); + + /* Is the task waiting on an event also? If so remove it from + the event list too. Interrupts can touch the event list item, + even though the scheduler is suspended, so a critical section + is used. */ + taskENTER_CRITICAL(); + { + if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL ) + { + ( void ) uxListRemove( &( pxTCB->xEventListItem ) ); + pxTCB->ucDelayAborted = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + taskEXIT_CRITICAL(); + + /* Place the unblocked task into the appropriate ready list. */ + prvAddTaskToReadyList( pxTCB ); + + /* A task being unblocked cannot cause an immediate context + switch if preemption is turned off. */ + #if ( configUSE_PREEMPTION == 1 ) + { + /* Preemption is on, but a context switch should only be + performed if the unblocked task has a priority that is + equal to or higher than the currently executing task. */ + if( pxTCB->uxPriority > pxCurrentTCB->uxPriority ) + { + /* Pend the yield to be performed when the scheduler + is unsuspended. */ + xYieldPending = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + #endif /* configUSE_PREEMPTION */ + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + xTaskResumeAll(); + + return xReturn; + } + +#endif /* INCLUDE_xTaskAbortDelay */ +/*----------------------------------------------------------*/ + BaseType_t xTaskIncrementTick( void ) { TCB_t * pxTCB; @@ -2479,7 +2560,7 @@ void vTaskPlaceOnUnorderedEventList( List_t * pxEventList, const TickType_t xIte /* If the task should block indefinitely then set the block time to a value that will be recognised as an indefinite delay inside the prvAddCurrentTaskToDelayedList() function. */ - if( xWaitIndefinitely == pdTRUE ) + if( xWaitIndefinitely != pdFALSE ) { xTicksToWait = portMAX_DELAY; } @@ -2624,15 +2705,26 @@ BaseType_t xReturn; /* Minor optimisation. The tick count cannot change in this block. */ const TickType_t xConstTickCount = xTickCount; + #if( INCLUDE_xTaskAbortDelay == 1 ) + if( pxCurrentTCB->ucDelayAborted != pdFALSE ) + { + /* The delay was aborted, which is not the same as a time out, + but has the same result. */ + pxCurrentTCB->ucDelayAborted = pdFALSE; + xReturn = pdTRUE; + } + else + #endif + #if ( INCLUDE_vTaskSuspend == 1 ) - /* If INCLUDE_vTaskSuspend is set to 1 and the block time specified - is the maximum block time then the task should block indefinitely, - and therefore never time out. */ if( *pxTicksToWait == portMAX_DELAY ) { + /* If INCLUDE_vTaskSuspend is set to 1 and the block time + specified is the maximum block time then the task should block + indefinitely, and therefore never time out. */ xReturn = pdFALSE; } - else /* We are not blocking indefinitely, perform the checks below. */ + else #endif if( ( xNumOfOverflows != pxTimeOut->xOverflowCount ) && ( xConstTickCount >= pxTimeOut->xTimeOnEntering ) ) /*lint !e525 Indentation preferred as is to make code within pre-processor directives clearer. */ @@ -2644,7 +2736,7 @@ BaseType_t xReturn; was called. */ xReturn = pdTRUE; } - else if( ( ( TickType_t ) ( xConstTickCount - pxTimeOut->xTimeOnEntering ) ) < *pxTicksToWait ) + else if( ( ( TickType_t ) ( xConstTickCount - pxTimeOut->xTimeOnEntering ) ) < *pxTicksToWait ) /*lint !e961 Explicit casting is only redundant with some compilers, whereas others require it to prevent integer conversion errors. */ { /* Not a genuine timeout. Adjust parameters for time remaining. */ *pxTicksToWait -= ( xConstTickCount - pxTimeOut->xTimeOnEntering ); @@ -2971,6 +3063,12 @@ UBaseType_t x; _REENT_INIT_PTR( ( &( pxTCB->xNewLib_reent ) ) ); } #endif + + #if( INCLUDE_xTaskAbortDelay == 1 ) + { + pxTCB->ucDelayAborted = pdFALSE; + } + #endif } /*-----------------------------------------------------------*/ @@ -4499,10 +4597,19 @@ TickType_t uxReturn; /*-----------------------------------------------------------*/ -static void prvAddCurrentTaskToDelayedList( TickType_t xTicksToWait, BaseType_t xCanBlockIndefinitely ) +static void prvAddCurrentTaskToDelayedList( TickType_t xTicksToWait, const BaseType_t xCanBlockIndefinitely ) { TickType_t xTimeToWake; + #if( INCLUDE_xTaskAbortDelay == 1 ) + { + /* About to enter a delayed list, so ensure the ucDelayAborted flag is + reset to pdFALSE so it can be detected as having been set to pdTRUE + when the task leaves the Blocked state. */ + pxCurrentTCB->ucDelayAborted = pdFALSE; + } + #endif + /* Remove the task from the ready list before adding it to the blocked list as the same list item is used for both lists. */ if( uxListRemove( &( pxCurrentTCB->xGenericListItem ) ) == ( UBaseType_t ) 0 ) diff --git a/FreeRTOS/Source/timers.c b/FreeRTOS/Source/timers.c index c56d3bf21..50645ea19 100644 --- a/FreeRTOS/Source/timers.c +++ b/FreeRTOS/Source/timers.c @@ -454,7 +454,7 @@ Timer_t * const pxTimer = ( Timer_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxCurrentTi /* The timer is inserted into a list using a time relative to anything other than the current time. It will therefore be inserted into the correct list relative to the time this task thinks it is now. */ - if( prvInsertTimerInActiveList( pxTimer, ( xNextExpireTime + pxTimer->xTimerPeriodInTicks ), xTimeNow, xNextExpireTime ) == pdTRUE ) + if( prvInsertTimerInActiveList( pxTimer, ( xNextExpireTime + pxTimer->xTimerPeriodInTicks ), xTimeNow, xNextExpireTime ) != pdFALSE ) { /* The timer expired before it was added to the active timer list. Reload it now. */ @@ -730,7 +730,7 @@ TickType_t xTimeNow; case tmrCOMMAND_RESET_FROM_ISR : case tmrCOMMAND_START_DONT_TRACE : /* Start or restart a timer. */ - if( prvInsertTimerInActiveList( pxTimer, xMessage.u.xTimerParameters.xMessageValue + pxTimer->xTimerPeriodInTicks, xTimeNow, xMessage.u.xTimerParameters.xMessageValue ) == pdTRUE ) + if( prvInsertTimerInActiveList( pxTimer, xMessage.u.xTimerParameters.xMessageValue + pxTimer->xTimerPeriodInTicks, xTimeNow, xMessage.u.xTimerParameters.xMessageValue ) != pdFALSE ) { /* The timer expired before it was added to the active timer list. Process it now. */ -- 2.39.2