Add vTaskGetTaskInfo() function that allows a TaskStatus_t structure to be returned for an individual task (previously information could only be obtained for all the tasks at once).

Add a member to the TaskStatus_t structure that is used to return the base address of the stack used by the task being queried.
Add xTaskGetTaskHandle() that allows the handle of a task to be looked up from the task's text name.
Continue to document the macros that allow RTOS objects to be created using statically allocated memory.
Introduced vApplicationDaemonTaskStartupHook(), which allows initialisation that that needs to be executed after the scheduler has been started to be executed from the RTOS daemon task.
Call prvResetNextTaskUnblockTime() in xTaskResumeAll() if a task is moved from the pending ready list - this can prevent an unnecessary wake from sleep mode if a task is unblocked by an interrupt while in a low power tickless state.
This commit is contained in:
Richard Barry 2016-01-28 16:59:57 +00:00
parent b514f4fa4e
commit 802af0150c
11 changed files with 838 additions and 147 deletions

View file

@ -86,6 +86,7 @@
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
#define configUSE_IDLE_HOOK 1
#define configUSE_TICK_HOOK 1
#define configUSE_DAEMON_TASK_STARTUP_HOOK 1
#define configTICK_RATE_HZ ( 1000 ) /* In this non-real time simulated environment the tick frequency has to be at least a multiple of the Win32 tick frequency, and therefore very slow. */
#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 50 ) /* In this simulated case, the stack only has to hold one small structure as the real stack is part of the win32 thread. */
#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 24 * 1024 ) )
@ -145,6 +146,7 @@ functions anyway. */
#define INCLUDE_xTimerGetTimerDaemonTaskHandle 1
#define INCLUDE_xTaskGetIdleTaskHandle 1
#define INCLUDE_pcTaskGetTaskName 1
#define INCLUDE_xTaskGetTaskHandle 1
#define INCLUDE_eTaskGetState 1
#define INCLUDE_xSemaphoreGetMutexHolder 1
#define INCLUDE_xTimerPendFunctionCall 1

View file

@ -154,8 +154,8 @@ void vApplicationMallocFailedHook( void );
void vApplicationIdleHook( void );
void vApplicationStackOverflowHook( TaskHandle_t pxTask, char *pcTaskName );
void vApplicationTickHook( void );
void vApplicationGetIdleTaskMemory( DummyTCB_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint16_t *pusIdleTaskStackSize );
void vApplicationGetTimerTaskMemory( DummyTCB_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint16_t *pusTimerTaskStackSize );
void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint16_t *pusIdleTaskStackSize );
void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint16_t *pusTimerTaskStackSize );
/*
* Writes trace data to a disk file when the trace recording is stopped.
@ -163,6 +163,15 @@ void vApplicationGetTimerTaskMemory( DummyTCB_t **ppxTimerTaskTCBBuffer, StackTy
*/
static void prvSaveTraceFile( void );
/*-----------------------------------------------------------*/
/* When configSUPPORT_STATIC_ALLOCATION is set to 1 the application writer can
use a callback function to optionally provide the memory required by the idle
and timer tasks. This is the stack that will be used by the timer task. It is
declared here, as a global, so it can be checked by a test that is implemented
in a different file. */
StackType_t uxTimerTaskStack[ configTIMER_TASK_STACK_DEPTH ];
/* The user trace event posted to the trace recording on each tick interrupt.
Note: This project runs under Windows, and Windows will not be executing the
RTOS threads continuously. Therefore tick events will not appear with a regular
@ -299,6 +308,15 @@ void vApplicationTickHook( void )
}
/*-----------------------------------------------------------*/
void vApplicationDaemonTaskStartupHook( void )
{
/* This function will be called once only, when the daemon task starts to
execute (sometimes called the timer task). This is useful if the
application includes initialisation code that would benefit from executing
after the scheduler has been started. */
}
/*-----------------------------------------------------------*/
void vAssertCalled( unsigned long ulLine, const char * const pcFileName )
{
static portBASE_TYPE xPrinted = pdFALSE;
@ -392,11 +410,11 @@ const HeapRegion_t xHeapRegions[] =
}
/*-----------------------------------------------------------*/
void vApplicationGetIdleTaskMemory( DummyTCB_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint16_t *pusIdleTaskStackSize )
void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint16_t *pusIdleTaskStackSize )
{
/* The buffers used by the idle task must be static so they are persistent, and
so exist after this function returns. */
static DummyTCB_t xIdleTaskTCB;
static StaticTask_t xIdleTaskTCB;
static StackType_t uxIdleTaskStack[ configMINIMAL_STACK_SIZE ];
/* configUSE_STATIC_ALLOCATION is set to 1, so the application has the
@ -409,12 +427,13 @@ static StackType_t uxIdleTaskStack[ configMINIMAL_STACK_SIZE ];
}
/*-----------------------------------------------------------*/
void vApplicationGetTimerTaskMemory( DummyTCB_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint16_t *pusTimerTaskStackSize )
void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint16_t *pusTimerTaskStackSize )
{
/* The buffers used by the Timer/Daemon task must be static so they are
persistent, and so exist after this function returns. */
static DummyTCB_t xTimerTaskTCB;
static StackType_t uxTimerTaskStack[ configTIMER_TASK_STACK_DEPTH ];
persistent, and so exist after this function returns. The stack buffer is
not declared here, but globally, as it is checked by a test in a different
file. */
static StaticTask_t xTimerTaskTCB;
/* configUSE_STATIC_ALLOCATION is set to 1, so the application has the
opportunity to supply the buffers that will be used by the Timer/RTOS daemon

View file

@ -215,7 +215,12 @@ int main_full( void )
vStartInterruptSemaphoreTasks();
vStartQueueSetPollingTask();
xTaskCreate( prvDemoQueueSpaceFunctions, "QSpace", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
vStartStaticallyAllocatedTasks();
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
{
vStartStaticallyAllocatedTasks();
}
#endif
#if( configUSE_PREEMPTION != 0 )
{
@ -339,10 +344,13 @@ const TickType_t xCycleFrequency = pdMS_TO_TICKS( 2500UL );
{
pcStatusMessage = "Error: Queue set polling";
}
else if( xAreStaticAllocationTasksStillRunning() != pdPASS )
{
pcStatusMessage = "Error: Static allocation";
}
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
else if( xAreStaticAllocationTasksStillRunning() != pdPASS )
{
pcStatusMessage = "Error: Static allocation";
}
#endif /* configSUPPORT_STATIC_ALLOCATION */
/* This is the only task that uses stdout so its ok to call printf()
directly. */
@ -396,6 +404,16 @@ void *pvAllocated;
that has tasks blocked on it. */
if( xMutexToDelete != NULL )
{
/* For test purposes, add the mutex to the registry, then remove it
again, before it is deleted - checking its name is as expected before
and after the assertion into the registry and its removal from the
registry. */
configASSERT( pcQueueGetQueueName( xMutexToDelete ) == NULL );
vQueueAddToRegistry( xMutexToDelete, "Test_Mutex" );
configASSERT( strcmp( pcQueueGetQueueName( xMutexToDelete ), "Test_Mutex" ) == 0 );
vQueueUnregisterQueue( xMutexToDelete );
configASSERT( pcQueueGetQueueName( xMutexToDelete ) == NULL );
vSemaphoreDelete( xMutexToDelete );
xMutexToDelete = NULL;
}
@ -482,6 +500,8 @@ TaskHandle_t xIdleTaskHandle, xTimerTaskHandle;
char *pcTaskName;
static portBASE_TYPE xPerformedOneShotTests = pdFALSE;
TaskHandle_t xTestTask;
TaskStatus_t xTaskInfo;
extern StackType_t uxTimerTaskStack[];
/* Demonstrate the use of the xTimerGetTimerDaemonTaskHandle() and
xTaskGetIdleTaskHandle() functions. Also try using the function that sets
@ -496,6 +516,18 @@ TaskHandle_t xTestTask;
pcStatusMessage = "Error: Returned idle task handle was incorrect";
}
/* Check the same handle is obtained using the idle task's name. First try
with the wrong name, then the right name. */
if( xTaskGetTaskHandle( "Idle" ) == xIdleTaskHandle )
{
pcStatusMessage = "Error: Returned handle for name Idle was incorrect";
}
if( xTaskGetTaskHandle( "IDLE" ) != xIdleTaskHandle )
{
pcStatusMessage = "Error: Returned handle for name Idle was incorrect";
}
/* Check the timer task handle was returned correctly. */
pcTaskName = pcTaskGetTaskName( xTimerTaskHandle );
if( strcmp( pcTaskName, "Tmr Svc" ) != 0 )
@ -503,6 +535,11 @@ TaskHandle_t xTestTask;
pcStatusMessage = "Error: Returned timer task handle was incorrect";
}
if( xTaskGetTaskHandle( "Tmr Svc" ) != xTimerTaskHandle )
{
pcStatusMessage = "Error: Returned handle for name Tmr Svc was incorrect";
}
/* This task is running, make sure it's state is returned as running. */
if( eTaskStateGet( xIdleTaskHandle ) != eRunning )
{
@ -515,6 +552,22 @@ TaskHandle_t xTestTask;
pcStatusMessage = "Error: Returned timer task state was incorrect";
}
/* Also with the vTaskGetTaskInfo() function. */
vTaskGetTaskInfo( xTimerTaskHandle, /* The task being queried. */
&xTaskInfo, /* The structure into which information on the task will be written. */
pdTRUE, /* Include the task's high watermark in the structure. */
eInvalid ); /* Include the task state in the structure. */
/* Check the information returned by vTaskGetTaskInfo() is as expected. */
if( ( xTaskInfo.eCurrentState != eBlocked ) ||
( strcmp( xTaskInfo.pcTaskName, "Tmr Svc" ) != 0 ) ||
( xTaskInfo.uxCurrentPriority != configTIMER_TASK_PRIORITY ) ||
( xTaskInfo.pxStackBase != uxTimerTaskStack ) ||
( xTaskInfo.xHandle != xTimerTaskHandle ) )
{
pcStatusMessage = "Error: vTaskGetTaskInfo() returned incorrect information about the timer task";
}
/* Other tests that should only be performed once follow. The test task
is not created on each iteration because to do so would cause the death
task to report an error (too many tasks running). */