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

@ -0,0 +1,5 @@
[{000214A0-0000-0000-C000-000000000046}]
Prop3=19,2
[InternetShortcut]
URL=http://www.freertos.org/labs
IDList=

View File

@ -86,6 +86,7 @@
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 #define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
#define configUSE_IDLE_HOOK 1 #define configUSE_IDLE_HOOK 1
#define configUSE_TICK_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 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 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 ) ) #define configTOTAL_HEAP_SIZE ( ( size_t ) ( 24 * 1024 ) )
@ -145,6 +146,7 @@ functions anyway. */
#define INCLUDE_xTimerGetTimerDaemonTaskHandle 1 #define INCLUDE_xTimerGetTimerDaemonTaskHandle 1
#define INCLUDE_xTaskGetIdleTaskHandle 1 #define INCLUDE_xTaskGetIdleTaskHandle 1
#define INCLUDE_pcTaskGetTaskName 1 #define INCLUDE_pcTaskGetTaskName 1
#define INCLUDE_xTaskGetTaskHandle 1
#define INCLUDE_eTaskGetState 1 #define INCLUDE_eTaskGetState 1
#define INCLUDE_xSemaphoreGetMutexHolder 1 #define INCLUDE_xSemaphoreGetMutexHolder 1
#define INCLUDE_xTimerPendFunctionCall 1 #define INCLUDE_xTimerPendFunctionCall 1

View File

@ -154,8 +154,8 @@ void vApplicationMallocFailedHook( void );
void vApplicationIdleHook( void ); void vApplicationIdleHook( void );
void vApplicationStackOverflowHook( TaskHandle_t pxTask, char *pcTaskName ); void vApplicationStackOverflowHook( TaskHandle_t pxTask, char *pcTaskName );
void vApplicationTickHook( void ); void vApplicationTickHook( void );
void vApplicationGetIdleTaskMemory( DummyTCB_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint16_t *pusIdleTaskStackSize ); void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint16_t *pusIdleTaskStackSize );
void vApplicationGetTimerTaskMemory( DummyTCB_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint16_t *pusTimerTaskStackSize ); void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint16_t *pusTimerTaskStackSize );
/* /*
* Writes trace data to a disk file when the trace recording is stopped. * 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 ); 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. /* 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 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 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 ) void vAssertCalled( unsigned long ulLine, const char * const pcFileName )
{ {
static portBASE_TYPE xPrinted = pdFALSE; 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 /* The buffers used by the idle task must be static so they are persistent, and
so exist after this function returns. */ so exist after this function returns. */
static DummyTCB_t xIdleTaskTCB; static StaticTask_t xIdleTaskTCB;
static StackType_t uxIdleTaskStack[ configMINIMAL_STACK_SIZE ]; static StackType_t uxIdleTaskStack[ configMINIMAL_STACK_SIZE ];
/* configUSE_STATIC_ALLOCATION is set to 1, so the application has the /* 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 /* The buffers used by the Timer/Daemon task must be static so they are
persistent, and so exist after this function returns. */ persistent, and so exist after this function returns. The stack buffer is
static DummyTCB_t xTimerTaskTCB; not declared here, but globally, as it is checked by a test in a different
static StackType_t uxTimerTaskStack[ configTIMER_TASK_STACK_DEPTH ]; file. */
static StaticTask_t xTimerTaskTCB;
/* configUSE_STATIC_ALLOCATION is set to 1, so the application has the /* 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 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(); vStartInterruptSemaphoreTasks();
vStartQueueSetPollingTask(); vStartQueueSetPollingTask();
xTaskCreate( prvDemoQueueSpaceFunctions, "QSpace", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL ); xTaskCreate( prvDemoQueueSpaceFunctions, "QSpace", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
{
vStartStaticallyAllocatedTasks(); vStartStaticallyAllocatedTasks();
}
#endif
#if( configUSE_PREEMPTION != 0 ) #if( configUSE_PREEMPTION != 0 )
{ {
@ -339,10 +344,13 @@ const TickType_t xCycleFrequency = pdMS_TO_TICKS( 2500UL );
{ {
pcStatusMessage = "Error: Queue set polling"; pcStatusMessage = "Error: Queue set polling";
} }
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
else if( xAreStaticAllocationTasksStillRunning() != pdPASS ) else if( xAreStaticAllocationTasksStillRunning() != pdPASS )
{ {
pcStatusMessage = "Error: Static allocation"; pcStatusMessage = "Error: Static allocation";
} }
#endif /* configSUPPORT_STATIC_ALLOCATION */
/* This is the only task that uses stdout so its ok to call printf() /* This is the only task that uses stdout so its ok to call printf()
directly. */ directly. */
@ -396,6 +404,16 @@ void *pvAllocated;
that has tasks blocked on it. */ that has tasks blocked on it. */
if( xMutexToDelete != NULL ) 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 ); vSemaphoreDelete( xMutexToDelete );
xMutexToDelete = NULL; xMutexToDelete = NULL;
} }
@ -482,6 +500,8 @@ TaskHandle_t xIdleTaskHandle, xTimerTaskHandle;
char *pcTaskName; char *pcTaskName;
static portBASE_TYPE xPerformedOneShotTests = pdFALSE; static portBASE_TYPE xPerformedOneShotTests = pdFALSE;
TaskHandle_t xTestTask; TaskHandle_t xTestTask;
TaskStatus_t xTaskInfo;
extern StackType_t uxTimerTaskStack[];
/* Demonstrate the use of the xTimerGetTimerDaemonTaskHandle() and /* Demonstrate the use of the xTimerGetTimerDaemonTaskHandle() and
xTaskGetIdleTaskHandle() functions. Also try using the function that sets xTaskGetIdleTaskHandle() functions. Also try using the function that sets
@ -496,6 +516,18 @@ TaskHandle_t xTestTask;
pcStatusMessage = "Error: Returned idle task handle was incorrect"; 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. */ /* Check the timer task handle was returned correctly. */
pcTaskName = pcTaskGetTaskName( xTimerTaskHandle ); pcTaskName = pcTaskGetTaskName( xTimerTaskHandle );
if( strcmp( pcTaskName, "Tmr Svc" ) != 0 ) if( strcmp( pcTaskName, "Tmr Svc" ) != 0 )
@ -503,6 +535,11 @@ TaskHandle_t xTestTask;
pcStatusMessage = "Error: Returned timer task handle was incorrect"; 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. */ /* This task is running, make sure it's state is returned as running. */
if( eTaskStateGet( xIdleTaskHandle ) != eRunning ) if( eTaskStateGet( xIdleTaskHandle ) != eRunning )
{ {
@ -515,6 +552,22 @@ TaskHandle_t xTestTask;
pcStatusMessage = "Error: Returned timer task state was incorrect"; 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 /* 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 is not created on each iteration because to do so would cause the death
task to report an error (too many tasks running). */ task to report an error (too many tasks running). */

View File

@ -171,6 +171,10 @@ extern "C" {
#endif #endif
#endif #endif
#ifndef configUSE_DAEMON_TASK_STARTUP_HOOK
#define configUSE_DAEMON_TASK_STARTUP_HOOK 0
#endif
#ifndef INCLUDE_xTaskGetIdleTaskHandle #ifndef INCLUDE_xTaskGetIdleTaskHandle
#define INCLUDE_xTaskGetIdleTaskHandle 0 #define INCLUDE_xTaskGetIdleTaskHandle 0
#endif #endif
@ -191,6 +195,10 @@ extern "C" {
#define INCLUDE_pcTaskGetTaskName 0 #define INCLUDE_pcTaskGetTaskName 0
#endif #endif
#ifndef INCLUDE_xTaskGetTaskHandle
#define INCLUDE_xTaskGetTaskHandle 0
#endif
#ifndef configUSE_APPLICATION_TASK_TAG #ifndef configUSE_APPLICATION_TASK_TAG
#define configUSE_APPLICATION_TASK_TAG 0 #define configUSE_APPLICATION_TASK_TAG 0
#endif #endif

View File

@ -229,9 +229,13 @@ typedef void * QueueSetMemberHandle_t;
* hold the queue's data structure, removing the need for the memory to be * hold the queue's data structure, removing the need for the memory to be
* allocated dynamically. * allocated dynamically.
* *
* @return If the queue is successfully create then a handle to the newly * @return If neither pucQueueStorageBuffer or pxQueueBuffer are NULL, then the
* created queue is returned. If the queue cannot be created then 0 is * function will not attempt any dynamic memory allocation, and a handle to the
* returned. * created queue will always be returned. If pucQueueStorageBuffer or
* pxQueueBuffer is NULL then the function will attempt to dynamically allocate
* one of both buffers. In this case, if the allocation succeeds then a handle
* to the created queue will be returned, and if one of the the allocation fails
* NULL will be returned.
* *
* Example usage: * Example usage:
<pre> <pre>
@ -267,7 +271,7 @@ typedef void * QueueSetMemberHandle_t;
// ... Rest of task code. // ... Rest of task code.
} }
</pre> </pre>
* \defgroup xQueueCreate xQueueCreate * \defgroup xQueueCreateStatic xQueueCreateStatic
* \ingroup QueueManagement * \ingroup QueueManagement
*/ */
#if( configSUPPORT_STATIC_ALLOCATION == 1 ) #if( configSUPPORT_STATIC_ALLOCATION == 1 )
@ -1649,7 +1653,7 @@ BaseType_t xQueueGiveMutexRecursive( QueueHandle_t pxMutex ) PRIVILEGED_FUNCTION
* returned. * returned.
*/ */
#if( configQUEUE_REGISTRY_SIZE > 0 ) #if( configQUEUE_REGISTRY_SIZE > 0 )
const char *pcQueueGetQueueName( QueueHandle_t xQueue ); const char *pcQueueGetQueueName( QueueHandle_t xQueue ); /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
#endif #endif
/* /*

View File

@ -145,10 +145,23 @@ typedef QueueHandle_t SemaphoreHandle_t;
* semphr. h * semphr. h
* <pre>SemaphoreHandle_t xSemaphoreCreateBinary( void )</pre> * <pre>SemaphoreHandle_t xSemaphoreCreateBinary( void )</pre>
* *
* Creates a new binary semaphore instance, and returns a handle by which the
* new semaphore can be referenced.
*
* In many usage scenarios it is faster and more memory efficient to use a * In many usage scenarios it is faster and more memory efficient to use a
* direct to task notification in place of a binary semaphore! * direct to task notification in place of a binary semaphore!
* http://www.freertos.org/RTOS-task-notifications.html * http://www.freertos.org/RTOS-task-notifications.html
* *
* Internally, within the FreeRTOS implementation, binary semaphores use a block
* of memory, in which the semaphore structure is stored. If a binary semaphore
* is created using xSemaphoreCreateBinary() then the required memory is
* automatically dynamically allocated inside the xSemaphoreCreateBinary()
* function. (see http://www.freertos.org/a00111.html). If a binary semaphore
* is created using xSemaphoreCreateBinaryStatic() then the application writer
* can instead optionally provide the memory that will get used by the binary
* semaphore. xSemaphoreCreateBinaryStatic() therefore allows a binary
* semaphore to be created without using any dynamic memory allocation.
*
* The old vSemaphoreCreateBinary() macro is now deprecated in favour of this * The old vSemaphoreCreateBinary() macro is now deprecated in favour of this
* xSemaphoreCreateBinary() function. Note that binary semaphores created using * xSemaphoreCreateBinary() function. Note that binary semaphores created using
* the vSemaphoreCreateBinary() macro are created in a state such that the * the vSemaphoreCreateBinary() macro are created in a state such that the
@ -156,11 +169,6 @@ typedef QueueHandle_t SemaphoreHandle_t;
* created using xSemaphoreCreateBinary() are created in a state such that the * created using xSemaphoreCreateBinary() are created in a state such that the
* the semaphore must first be 'given' before it can be 'taken'. * the semaphore must first be 'given' before it can be 'taken'.
* *
* Function that creates a semaphore by using the existing queue mechanism.
* The queue length is 1 as this is a binary semaphore. The data size is 0
* as nothing is actually stored - all that is important is whether the queue is
* empty or full (the binary semaphore is available or not).
*
* This type of semaphore can be used for pure synchronisation between tasks or * This type of semaphore can be used for pure synchronisation between tasks or
* between an interrupt and a task. The semaphore need not be given back once * between an interrupt and a task. The semaphore need not be given back once
* obtained, so one task/interrupt can continuously 'give' the semaphore while * obtained, so one task/interrupt can continuously 'give' the semaphore while
@ -168,7 +176,8 @@ typedef QueueHandle_t SemaphoreHandle_t;
* semaphore does not use a priority inheritance mechanism. For an alternative * semaphore does not use a priority inheritance mechanism. For an alternative
* that does use priority inheritance see xSemaphoreCreateMutex(). * that does use priority inheritance see xSemaphoreCreateMutex().
* *
* @return Handle to the created semaphore. * @return Handle to the created semaphore, or NULL if the memory required to
* hold the semaphore's data structures could not be allocated.
* *
* Example usage: * Example usage:
<pre> <pre>
@ -176,7 +185,7 @@ typedef QueueHandle_t SemaphoreHandle_t;
void vATask( void * pvParameters ) void vATask( void * pvParameters )
{ {
// Semaphore cannot be used before a call to vSemaphoreCreateBinary (). // Semaphore cannot be used before a call to xSemaphoreCreateBinary().
// This is a macro so pass the variable in directly. // This is a macro so pass the variable in directly.
xSemaphore = xSemaphoreCreateBinary(); xSemaphore = xSemaphoreCreateBinary();
@ -187,13 +196,78 @@ typedef QueueHandle_t SemaphoreHandle_t;
} }
} }
</pre> </pre>
* \defgroup vSemaphoreCreateBinary vSemaphoreCreateBinary * \defgroup xSemaphoreCreateBinary xSemaphoreCreateBinary
* \ingroup Semaphores * \ingroup Semaphores
*/ */
#define xSemaphoreCreateBinary() xQueueGenericCreate( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, NULL, NULL, queueQUEUE_TYPE_BINARY_SEMAPHORE ) #define xSemaphoreCreateBinary() xQueueGenericCreate( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, NULL, NULL, queueQUEUE_TYPE_BINARY_SEMAPHORE )
/**
* semphr. h
* <pre>SemaphoreHandle_t xSemaphoreCreateBinaryStatic( StaticSemaphore_t *pxSemaphoreBuffer )</pre>
*
* Creates a new binary semaphore instance, and returns a handle by which the
* new semaphore can be referenced.
*
* NOTE: In many usage scenarios it is faster and more memory efficient to use a
* direct to task notification in place of a binary semaphore!
* http://www.freertos.org/RTOS-task-notifications.html
*
* Internally, within the FreeRTOS implementation, binary semaphores use a block
* of memory, in which the semaphore structure is stored. If a binary semaphore
* is created using xSemaphoreCreateBinary() then the required memory is
* automatically dynamically allocated inside the xSemaphoreCreateBinary()
* function. (see http://www.freertos.org/a00111.html). If a binary semaphore
* is created using xSemaphoreCreateBinaryStatic() then the application writer
* can instead optionally provide the memory that will get used by the binary
* semaphore. xSemaphoreCreateBinaryStatic() therefore allows a binary
* semaphore to be created without using any dynamic memory allocation.
*
* This type of semaphore can be used for pure synchronisation between tasks or
* between an interrupt and a task. The semaphore need not be given back once
* obtained, so one task/interrupt can continuously 'give' the semaphore while
* another continuously 'takes' the semaphore. For this reason this type of
* semaphore does not use a priority inheritance mechanism. For an alternative
* that does use priority inheritance see xSemaphoreCreateMutex().
*
* @param pxSemaphoreBuffer If pxSemaphoreBuffer is NULL then the memory
* required to hold the semaphore's data structures will be allocated
* dynamically, just as when a semaphore is created using
* xSemaphoreCreateBinary(). If pxSemaphoreBuffer is not NULL then it must
* point to a variable of type StaticSemaphore_t, which will then be used to
* hold the semaphore's data structure, removing the need for the memory to be
* allocated dynamically.
*
* @return If pxSemaphoreBuffer is not NULL then the function will not attempt
* any dynamic memory allocation, and a handle to the created semaphore will
* always be returned. If pxSemaphoreBuffer is NULL then the function will
* attempt to dynamically allocate the memory required to hold the semaphore's
* data structures. In this case, if the allocation succeeds then a handle to
* the created semaphore will be returned, and if the allocation fails NULL will
* be returned.
*
* Example usage:
<pre>
SemaphoreHandle_t xSemaphore = NULL;
StaticSemaphore_t xSemaphoreBuffer;
void vATask( void * pvParameters )
{
// Semaphore cannot be used before a call to xSemaphoreCreateBinary().
// The semaphore's data structures will be placed in the xSemaphoreBuffer
// variable, the address of which is passed into the function. The
// function's parameter is not NULL, so the function will not attempt any
// dynamic memory allocation, and therefore the function will not return
// return NULL.
xSemaphore = xSemaphoreCreateBinary( &xSemaphoreBuffer );
// Rest of task code goes here.
}
</pre>
* \defgroup xSemaphoreCreateBinaryStatic xSemaphoreCreateBinaryStatic
* \ingroup Semaphores
*/
#if( configSUPPORT_STATIC_ALLOCATION == 1 ) #if( configSUPPORT_STATIC_ALLOCATION == 1 )
#define xSemaphoreCreateBinaryStatic( pxStaticQueue ) xQueueGenericCreate( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, NULL, pxStaticQueue, queueQUEUE_TYPE_BINARY_SEMAPHORE ) #define xSemaphoreCreateBinaryStatic( pxStaticSemaphore ) xQueueGenericCreate( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, NULL, pxStaticSemaphore, queueQUEUE_TYPE_BINARY_SEMAPHORE )
#endif /* configSUPPORT_STATIC_ALLOCATION */ #endif /* configSUPPORT_STATIC_ALLOCATION */
/** /**
@ -204,7 +278,7 @@ typedef QueueHandle_t SemaphoreHandle_t;
* )</pre> * )</pre>
* *
* <i>Macro</i> to obtain a semaphore. The semaphore must have previously been * <i>Macro</i> to obtain a semaphore. The semaphore must have previously been
* created with a call to vSemaphoreCreateBinary(), xSemaphoreCreateMutex() or * created with a call to xSemaphoreCreateBinary(), xSemaphoreCreateMutex() or
* xSemaphoreCreateCounting(). * xSemaphoreCreateCounting().
* *
* @param xSemaphore A handle to the semaphore being taken - obtained when * @param xSemaphore A handle to the semaphore being taken - obtained when
@ -227,7 +301,7 @@ typedef QueueHandle_t SemaphoreHandle_t;
void vATask( void * pvParameters ) void vATask( void * pvParameters )
{ {
// Create the semaphore to guard a shared resource. // Create the semaphore to guard a shared resource.
vSemaphoreCreateBinary( xSemaphore ); xSemaphore = xSemaphoreCreateBinary();
} }
// A task that uses the semaphore. // A task that uses the semaphore.
@ -376,7 +450,7 @@ typedef QueueHandle_t SemaphoreHandle_t;
* <pre>xSemaphoreGive( SemaphoreHandle_t xSemaphore )</pre> * <pre>xSemaphoreGive( SemaphoreHandle_t xSemaphore )</pre>
* *
* <i>Macro</i> to release a semaphore. The semaphore must have previously been * <i>Macro</i> to release a semaphore. The semaphore must have previously been
* created with a call to vSemaphoreCreateBinary(), xSemaphoreCreateMutex() or * created with a call to xSemaphoreCreateBinary(), xSemaphoreCreateMutex() or
* xSemaphoreCreateCounting(). and obtained using sSemaphoreTake(). * xSemaphoreCreateCounting(). and obtained using sSemaphoreTake().
* *
* This macro must not be used from an ISR. See xSemaphoreGiveFromISR () for * This macro must not be used from an ISR. See xSemaphoreGiveFromISR () for
@ -400,7 +474,7 @@ typedef QueueHandle_t SemaphoreHandle_t;
void vATask( void * pvParameters ) void vATask( void * pvParameters )
{ {
// Create the semaphore to guard a shared resource. // Create the semaphore to guard a shared resource.
vSemaphoreCreateBinary( xSemaphore ); xSemaphore = vSemaphoreCreateBinary();
if( xSemaphore != NULL ) if( xSemaphore != NULL )
{ {
@ -541,7 +615,7 @@ typedef QueueHandle_t SemaphoreHandle_t;
)</pre> )</pre>
* *
* <i>Macro</i> to release a semaphore. The semaphore must have previously been * <i>Macro</i> to release a semaphore. The semaphore must have previously been
* created with a call to vSemaphoreCreateBinary() or xSemaphoreCreateCounting(). * created with a call to xSemaphoreCreateBinary() or xSemaphoreCreateCounting().
* *
* Mutex type semaphores (those created using a call to xSemaphoreCreateMutex()) * Mutex type semaphores (those created using a call to xSemaphoreCreateMutex())
* must not be used with this macro. * must not be used with this macro.
@ -632,7 +706,7 @@ typedef QueueHandle_t SemaphoreHandle_t;
)</pre> )</pre>
* *
* <i>Macro</i> to take a semaphore from an ISR. The semaphore must have * <i>Macro</i> to take a semaphore from an ISR. The semaphore must have
* previously been created with a call to vSemaphoreCreateBinary() or * previously been created with a call to xSemaphoreCreateBinary() or
* xSemaphoreCreateCounting(). * xSemaphoreCreateCounting().
* *
* Mutex type semaphores (those created using a call to xSemaphoreCreateMutex()) * Mutex type semaphores (those created using a call to xSemaphoreCreateMutex())
@ -661,12 +735,22 @@ typedef QueueHandle_t SemaphoreHandle_t;
* semphr. h * semphr. h
* <pre>SemaphoreHandle_t xSemaphoreCreateMutex( void )</pre> * <pre>SemaphoreHandle_t xSemaphoreCreateMutex( void )</pre>
* *
* <i>Macro</i> that implements a mutex semaphore by using the existing queue * Creates a new mutex type semaphore instance, and returns a handle by which
* mechanism. * the new mutex can be referenced.
* *
* Mutexes created using this macro can be accessed using the xSemaphoreTake() * Internally, within the FreeRTOS implementation, mutex semaphores use a block
* of memory, in which the mutex structure is stored. If a mutex is created
* using xSemaphoreCreateMutex() then the required memory is automatically
* dynamically allocated inside the xSemaphoreCreateMutex() function. (see
* http://www.freertos.org/a00111.html). If a mutex is created using
* xSemaphoreCreateMutexStatic() then the application writer can instead
* optionally provide the memory that will get used by the mutex.
* xSemaphoreCreateMutexStatic() therefore allows a mutex to be created without
* using any dynamic memory allocation.
*
* Mutexes created using this function can be accessed using the xSemaphoreTake()
* and xSemaphoreGive() macros. The xSemaphoreTakeRecursive() and * and xSemaphoreGive() macros. The xSemaphoreTakeRecursive() and
* xSemaphoreGiveRecursive() macros should not be used. * xSemaphoreGiveRecursive() macros must not be used.
* *
* This type of semaphore uses a priority inheritance mechanism so a task * This type of semaphore uses a priority inheritance mechanism so a task
* 'taking' a semaphore MUST ALWAYS 'give' the semaphore back once the * 'taking' a semaphore MUST ALWAYS 'give' the semaphore back once the
@ -674,13 +758,14 @@ typedef QueueHandle_t SemaphoreHandle_t;
* *
* Mutex type semaphores cannot be used from within interrupt service routines. * Mutex type semaphores cannot be used from within interrupt service routines.
* *
* See vSemaphoreCreateBinary() for an alternative implementation that can be * See xSemaphoreCreateBinary() for an alternative implementation that can be
* used for pure synchronisation (where one task or interrupt always 'gives' the * used for pure synchronisation (where one task or interrupt always 'gives' the
* semaphore and another always 'takes' the semaphore) and from within interrupt * semaphore and another always 'takes' the semaphore) and from within interrupt
* service routines. * service routines.
* *
* @return xSemaphore Handle to the created mutex semaphore. Should be of type * @return If the mutex was successfully created then a handle to the created
* SemaphoreHandle_t. * semaphore is returned. If there was not enough heap to allocate the mutex
* data structures then NULL is returned.
* *
* Example usage: * Example usage:
<pre> <pre>
@ -699,13 +784,75 @@ typedef QueueHandle_t SemaphoreHandle_t;
} }
} }
</pre> </pre>
* \defgroup vSemaphoreCreateMutex vSemaphoreCreateMutex * \defgroup xSemaphoreCreateMutex xSemaphoreCreateMutex
* \ingroup Semaphores * \ingroup Semaphores
*/ */
#define xSemaphoreCreateMutex() xQueueCreateMutex( queueQUEUE_TYPE_MUTEX, NULL ) #define xSemaphoreCreateMutex() xQueueCreateMutex( queueQUEUE_TYPE_MUTEX, NULL )
#if( configSUPPORT_STATIC_ALLOCATION == 1 ) /**
#define xSemaphoreCreateMutexStatic( pxStaticQueue ) xQueueCreateMutex( queueQUEUE_TYPE_MUTEX, ( pxStaticQueue ) ) * semphr. h
* <pre>SemaphoreHandle_t xSemaphoreCreateMutexStatic( StaticSemaphore_t *pxMutexBuffer )</pre>
*
* Creates a new mutex type semaphore instance, and returns a handle by which
* the new mutex can be referenced.
*
* Internally, within the FreeRTOS implementation, mutex semaphores use a block
* of memory, in which the mutex structure is stored. If a mutex is created
* using xSemaphoreCreateMutex() then the required memory is automatically
* dynamically allocated inside the xSemaphoreCreateMutex() function. (see
* http://www.freertos.org/a00111.html). If a mutex is created using
* xSemaphoreCreateMutexStatic() then the application writer can instead
* optionally provide the memory that will get used by the mutex.
* xSemaphoreCreateMutexStatic() therefore allows a mutex to be created without
* using any dynamic memory allocation.
*
* Mutexes created using this function can be accessed using the xSemaphoreTake()
* and xSemaphoreGive() macros. The xSemaphoreTakeRecursive() and
* xSemaphoreGiveRecursive() macros must not be used.
*
* This type of semaphore uses a priority inheritance mechanism so a task
* 'taking' a semaphore MUST ALWAYS 'give' the semaphore back once the
* semaphore it is no longer required.
*
* Mutex type semaphores cannot be used from within interrupt service routines.
*
* See xSemaphoreCreateBinary() for an alternative implementation that can be
* used for pure synchronisation (where one task or interrupt always 'gives' the
* semaphore and another always 'takes' the semaphore) and from within interrupt
* service routines.
*
* @param pxMutexBuffer If pxMutexBuffer is NULL then the memory required to
* hold the mutex's data structures will be allocated dynamically, just as when
* a mutex is created using xSemaphoreCreateMutex(). If pxMutexBuffer is not
* NULL then it must point to a variable of type StaticSemaphore_t, which will
* then be used to hold the mutex's data structure, removing the need for
* the memory to be allocated dynamically.
*
* @return If the mutex was successfully created then a handle to the created
* mutex is returned. If pxMutexBuffer was NULL, and there was not enough
* heap to allocate the mutex data structures, then NULL is returned.
*
* Example usage:
<pre>
SemaphoreHandle_t xSemaphore;
StaticSemaphore_t xMutexBuffer;
void vATask( void * pvParameters )
{
// A mutex cannot be used before it has been created. xMutexBuffer is
// into xSemaphoreCreateMutexStatic() so no dynamic memory allocation is
// attempted.
xSemaphore = xSemaphoreCreateMutexStatic( &xMutexBuffer );
// As no dynamic memory allocation was performed, xSemaphore cannot be NULL,
// so there is no need to check it.
}
</pre>
* \defgroup xSemaphoreCreateMutexStatic xSemaphoreCreateMutexStatic
* \ingroup Semaphores
*/
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
#define xSemaphoreCreateMutexStatic( pxMutexBuffer ) xQueueCreateMutex( queueQUEUE_TYPE_MUTEX, ( pxMutexBuffer ) )
#endif /* configSUPPORT_STATIC_ALLOCATION */ #endif /* configSUPPORT_STATIC_ALLOCATION */
@ -713,12 +860,23 @@ typedef QueueHandle_t SemaphoreHandle_t;
* semphr. h * semphr. h
* <pre>SemaphoreHandle_t xSemaphoreCreateRecursiveMutex( void )</pre> * <pre>SemaphoreHandle_t xSemaphoreCreateRecursiveMutex( void )</pre>
* *
* <i>Macro</i> that implements a recursive mutex by using the existing queue * Creates a new recursive mutex type semaphore instance, and returns a handle
* mechanism. * by which the new recursive mutex can be referenced.
*
* Internally, within the FreeRTOS implementation, recursive mutexs use a block
* of memory, in which the mutex structure is stored. If a recursive mutex is
* created using xSemaphoreCreateRecursiveMutex() then the required memory is
* automatically dynamically allocated inside the
* xSemaphoreCreateRecursiveMutex() function. (see
* http://www.freertos.org/a00111.html). If a recursive mutex is created using
* xSemaphoreCreateRecursiveMutexStatic() then the application writer can
* instead optionally provide the memory that will get used by the mutex.
* xSemaphoreCreateRecursiveMutexStatic() therefore allows a recursive mutex to
* be created without using any dynamic memory allocation.
* *
* Mutexes created using this macro can be accessed using the * Mutexes created using this macro can be accessed using the
* xSemaphoreTakeRecursive() and xSemaphoreGiveRecursive() macros. The * xSemaphoreTakeRecursive() and xSemaphoreGiveRecursive() macros. The
* xSemaphoreTake() and xSemaphoreGive() macros should not be used. * xSemaphoreTake() and xSemaphoreGive() macros must not be used.
* *
* A mutex used recursively can be 'taken' repeatedly by the owner. The mutex * A mutex used recursively can be 'taken' repeatedly by the owner. The mutex
* doesn't become available again until the owner has called * doesn't become available again until the owner has called
@ -733,7 +891,7 @@ typedef QueueHandle_t SemaphoreHandle_t;
* *
* Mutex type semaphores cannot be used from within interrupt service routines. * Mutex type semaphores cannot be used from within interrupt service routines.
* *
* See vSemaphoreCreateBinary() for an alternative implementation that can be * See xSemaphoreCreateBinary() for an alternative implementation that can be
* used for pure synchronisation (where one task or interrupt always 'gives' the * used for pure synchronisation (where one task or interrupt always 'gives' the
* semaphore and another always 'takes' the semaphore) and from within interrupt * semaphore and another always 'takes' the semaphore) and from within interrupt
* service routines. * service routines.
@ -758,11 +916,85 @@ typedef QueueHandle_t SemaphoreHandle_t;
} }
} }
</pre> </pre>
* \defgroup vSemaphoreCreateMutex vSemaphoreCreateMutex * \defgroup xSemaphoreCreateRecursiveMutex xSemaphoreCreateRecursiveMutex
* \ingroup Semaphores * \ingroup Semaphores
*/ */
#define xSemaphoreCreateRecursiveMutex() xQueueCreateMutex( queueQUEUE_TYPE_RECURSIVE_MUTEX, NULL ) #define xSemaphoreCreateRecursiveMutex() xQueueCreateMutex( queueQUEUE_TYPE_RECURSIVE_MUTEX, NULL )
/**
* semphr. h
* <pre>SemaphoreHandle_t xSemaphoreCreateRecursiveMutexStatic( StaticSemaphore_t *pxMutexBuffer )</pre>
*
* Creates a new recursive mutex type semaphore instance, and returns a handle
* by which the new recursive mutex can be referenced.
*
* Internally, within the FreeRTOS implementation, recursive mutexs use a block
* of memory, in which the mutex structure is stored. If a recursive mutex is
* created using xSemaphoreCreateRecursiveMutex() then the required memory is
* automatically dynamically allocated inside the
* xSemaphoreCreateRecursiveMutex() function. (see
* http://www.freertos.org/a00111.html). If a recursive mutex is created using
* xSemaphoreCreateRecursiveMutexStatic() then the application writer can
* instead optionally provide the memory that will get used by the mutex.
* xSemaphoreCreateRecursiveMutexStatic() therefore allows a recursive mutex to
* be created without using any dynamic memory allocation.
*
* Mutexes created using this macro can be accessed using the
* xSemaphoreTakeRecursive() and xSemaphoreGiveRecursive() macros. The
* xSemaphoreTake() and xSemaphoreGive() macros must not be used.
*
* A mutex used recursively can be 'taken' repeatedly by the owner. The mutex
* doesn't become available again until the owner has called
* xSemaphoreGiveRecursive() for each successful 'take' request. For example,
* if a task successfully 'takes' the same mutex 5 times then the mutex will
* not be available to any other task until it has also 'given' the mutex back
* exactly five times.
*
* This type of semaphore uses a priority inheritance mechanism so a task
* 'taking' a semaphore MUST ALWAYS 'give' the semaphore back once the
* semaphore it is no longer required.
*
* Mutex type semaphores cannot be used from within interrupt service routines.
*
* See xSemaphoreCreateBinary() for an alternative implementation that can be
* used for pure synchronisation (where one task or interrupt always 'gives' the
* semaphore and another always 'takes' the semaphore) and from within interrupt
* service routines.
*
* @param pxMutexBuffer If pxMutexBuffer is NULL then the memory required to
* hold the recursive mutex's data structures will be allocated dynamically,
* just as when a recursive mutex is created using
* xSemaphoreCreateRecursiveMutex(). If pxMutexBuffer is not NULL then it must
* point to a variable of type StaticSemaphore_t, which will then be used to
* hold the recursive mutex's data structure, removing the need for the memory
* to be allocated dynamically.
*
* @return If the recursive mutex was successfully created then a handle to the
* created recursive mutex is returned. If pxMutexBuffer was NULL, and there
* was not enough heap to allocate the mutex data structures, then NULL is
* returned.
*
* Example usage:
<pre>
SemaphoreHandle_t xSemaphore;
StaticSemaphore_t xMutexBuffer;
void vATask( void * pvParameters )
{
// A recursive semaphore cannot be used before it is created. Here a
// recursive mutex is created using xSemaphoreCreateRecursiveMutexStatic().
// The address of xMutexBuffer is passed into the function, and will hold
// the mutexes data structures - so no dynamic memory allocation will be
// attempted.
xSemaphore = xSemaphoreCreateRecursiveMutexStatic( &xMutexBuffer );
// As no dynamic memory allocation was performed, xSemaphore cannot be NULL,
// so there is no need to check it.
}
</pre>
* \defgroup xSemaphoreCreateRecursiveMutexStatic xSemaphoreCreateRecursiveMutexStatic
* \ingroup Semaphores
*/
#if( configSUPPORT_STATIC_ALLOCATION == 1 ) #if( configSUPPORT_STATIC_ALLOCATION == 1 )
#define xSemaphoreCreateRecursiveMutexStatic( pxStaticSemaphore ) xQueueCreateMutex( queueQUEUE_TYPE_RECURSIVE_MUTEX, pxStaticSemaphore ) #define xSemaphoreCreateRecursiveMutexStatic( pxStaticSemaphore ) xQueueCreateMutex( queueQUEUE_TYPE_RECURSIVE_MUTEX, pxStaticSemaphore )
#endif /* configSUPPORT_STATIC_ALLOCATION */ #endif /* configSUPPORT_STATIC_ALLOCATION */
@ -771,8 +1003,19 @@ typedef QueueHandle_t SemaphoreHandle_t;
* semphr. h * semphr. h
* <pre>SemaphoreHandle_t xSemaphoreCreateCounting( UBaseType_t uxMaxCount, UBaseType_t uxInitialCount )</pre> * <pre>SemaphoreHandle_t xSemaphoreCreateCounting( UBaseType_t uxMaxCount, UBaseType_t uxInitialCount )</pre>
* *
* <i>Macro</i> that creates a counting semaphore by using the existing * Creates a new counting semaphore instance, and returns a handle by which the
* queue mechanism. * new counting semaphore can be referenced.
*
* Internally, within the FreeRTOS implementation, counting semaphores use a
* block of memory, in which the counting semaphore structure is stored. If a
* counting semaphore is created using xSemaphoreCreateCounting() then the
* required memory is automatically dynamically allocated inside the
* xSemaphoreCreateCounting() function. (see
* http://www.freertos.org/a00111.html). If a counting semaphore is created
* using xSemaphoreCreateCountingStatic() then the application writer can
* instead optionally provide the memory that will get used by the counting
* semaphore. xSemaphoreCreateCountingStatic() therefore allows a counting
* semaphore to be created without using any dynamic memory allocation.
* *
* Counting semaphores are typically used for two things: * Counting semaphores are typically used for two things:
* *
@ -830,8 +1073,91 @@ typedef QueueHandle_t SemaphoreHandle_t;
*/ */
#define xSemaphoreCreateCounting( uxMaxCount, uxInitialCount ) xQueueCreateCountingSemaphore( ( uxMaxCount ), ( uxInitialCount ), ( NULL ) ) #define xSemaphoreCreateCounting( uxMaxCount, uxInitialCount ) xQueueCreateCountingSemaphore( ( uxMaxCount ), ( uxInitialCount ), ( NULL ) )
/**
* semphr. h
* <pre>SemaphoreHandle_t xSemaphoreCreateCountingStatic( UBaseType_t uxMaxCount, UBaseType_t uxInitialCount, StaticSemaphore_t *pxSemaphoreBuffer )</pre>
*
* Creates a new counting semaphore instance, and returns a handle by which the
* new counting semaphore can be referenced.
*
* Internally, within the FreeRTOS implementation, counting semaphores use a
* block of memory, in which the counting semaphore structure is stored. If a
* counting semaphore is created using xSemaphoreCreateCounting() then the
* required memory is automatically dynamically allocated inside the
* xSemaphoreCreateCounting() function. (see
* http://www.freertos.org/a00111.html). If a counting semaphore is created
* using xSemaphoreCreateCountingStatic() then the application writer can
* instead optionally provide the memory that will get used by the counting
* semaphore. xSemaphoreCreateCountingStatic() therefore allows a counting
* semaphore to be created without using any dynamic memory allocation.
*
* Counting semaphores are typically used for two things:
*
* 1) Counting events.
*
* In this usage scenario an event handler will 'give' a semaphore each time
* an event occurs (incrementing the semaphore count value), and a handler
* task will 'take' a semaphore each time it processes an event
* (decrementing the semaphore count value). The count value is therefore
* the difference between the number of events that have occurred and the
* number that have been processed. In this case it is desirable for the
* initial count value to be zero.
*
* 2) Resource management.
*
* In this usage scenario the count value indicates the number of resources
* available. To obtain control of a resource a task must first obtain a
* semaphore - decrementing the semaphore count value. When the count value
* reaches zero there are no free resources. When a task finishes with the
* resource it 'gives' the semaphore back - incrementing the semaphore count
* value. In this case it is desirable for the initial count value to be
* equal to the maximum count value, indicating that all resources are free.
*
* @param uxMaxCount The maximum count value that can be reached. When the
* semaphore reaches this value it can no longer be 'given'.
*
* @param uxInitialCount The count value assigned to the semaphore when it is
* created.
*
* @param pxSemaphoreBuffer If pxSemaphoreBuffer is NULL then the memory
* required to hold the semaphore's data structures will be allocated
* dynamically, just as when a counting semaphore is created using
* xSemaphoreCreateCounting(). If pxSemaphoreBuffer is not NULL then it must
* point to a variable of type StaticSemaphore_t, which will then be used to
* hold the semaphore's data structure, removing the need for the memory
* to be allocated dynamically.
*
* @return If the counting semaphore was successfully created then a handle to
* the created counting semaphore is returned. If pxSemaphoreBuffer was NULL,
* and there was not enough heap to allocate the counting semaphore data
* structures, then NULL is returned.
*
* Example usage:
<pre>
SemaphoreHandle_t xSemaphore;
StaticSemaphore_t xSemaphoreBuffer;
void vATask( void * pvParameters )
{
SemaphoreHandle_t xSemaphore = NULL;
// Counting semaphore cannot be used before they have been created. Create
// a counting semaphore using xSemaphoreCreateCountingStatic(). The max
// value to which the semaphore can count is 10, and the initial value
// assigned to the count will be 0. The address of xSemaphoreBuffer is
// passed in and will be used to hold the semaphore structure, so no dynamic
// memory allocation will be used.
xSemaphore = xSemaphoreCreateCounting( 10, 0, &xSemaphoreBuffer );
// No memory allocation was attempted so xSemaphore cannot be NULL, so there
// is no need to check its value.
}
</pre>
* \defgroup xSemaphoreCreateCountingStatic xSemaphoreCreateCountingStatic
* \ingroup Semaphores
*/
#if( configSUPPORT_STATIC_ALLOCATION == 1 ) #if( configSUPPORT_STATIC_ALLOCATION == 1 )
#define xSemaphoreCreateCountingStatic( uxMaxCount, uxInitialCount, pxStaticSemaphore ) xQueueCreateCountingSemaphore( ( uxMaxCount ), ( uxInitialCount ), ( pxStaticSemaphore ) ) #define xSemaphoreCreateCountingStatic( uxMaxCount, uxInitialCount, pxSemaphoreBuffer ) xQueueCreateCountingSemaphore( ( uxMaxCount ), ( uxInitialCount ), ( pxSemaphoreBuffer ) )
#endif /* configSUPPORT_STATIC_ALLOCATION */ #endif /* configSUPPORT_STATIC_ALLOCATION */
/** /**

View File

@ -115,7 +115,8 @@ typedef enum
eReady, /* The task being queried is in a read or pending ready list. */ eReady, /* The task being queried is in a read or pending ready list. */
eBlocked, /* The task being queried is in the Blocked state. */ eBlocked, /* The task being queried is in the Blocked state. */
eSuspended, /* The task being queried is in the Suspended state, or is in the Blocked state with an infinite time out. */ eSuspended, /* The task being queried is in the Suspended state, or is in the Blocked state with an infinite time out. */
eDeleted /* The task being queried has been deleted, but its TCB has not yet been freed. */ eDeleted, /* The task being queried has been deleted, but its TCB has not yet been freed. */
eInvalid /* Used as an 'invalid state' value. */
} eTaskState; } eTaskState;
/* Actions that can be performed when vTaskNotify() is called. */ /* Actions that can be performed when vTaskNotify() is called. */
@ -172,6 +173,7 @@ typedef struct xTASK_STATUS
UBaseType_t uxCurrentPriority; /* The priority at which the task was running (may be inherited) when the structure was populated. */ UBaseType_t uxCurrentPriority; /* The priority at which the task was running (may be inherited) when the structure was populated. */
UBaseType_t uxBasePriority; /* The priority to which the task will return if the task's current priority has been inherited to avoid unbounded priority inversion when obtaining a mutex. Only valid if configUSE_MUTEXES is defined as 1 in FreeRTOSConfig.h. */ UBaseType_t uxBasePriority; /* The priority to which the task will return if the task's current priority has been inherited to avoid unbounded priority inversion when obtaining a mutex. Only valid if configUSE_MUTEXES is defined as 1 in FreeRTOSConfig.h. */
uint32_t ulRunTimeCounter; /* The total run time allocated to the task so far, as defined by the run time stats clock. See http://www.freertos.org/rtos-run-time-stats.html. Only valid when configGENERATE_RUN_TIME_STATS is defined as 1 in FreeRTOSConfig.h. */ uint32_t ulRunTimeCounter; /* The total run time allocated to the task so far, as defined by the run time stats clock. See http://www.freertos.org/rtos-run-time-stats.html. Only valid when configGENERATE_RUN_TIME_STATS is defined as 1 in FreeRTOSConfig.h. */
StackType_t *pxStackBase; /* Points to the lowest address of the task's stack area. */
uint16_t usStackHighWaterMark; /* The minimum amount of stack space that has remained for the task since the task was created. The closer this value is to zero the closer the task has come to overflowing its stack. */ uint16_t usStackHighWaterMark; /* The minimum amount of stack space that has remained for the task since the task was created. The closer this value is to zero the closer the task has come to overflowing its stack. */
} TaskStatus_t; } TaskStatus_t;
@ -426,8 +428,12 @@ is used in assert() statements. */
* task's data structures, removing the need for the memory to be allocated * task's data structures, removing the need for the memory to be allocated
* dynamically. * dynamically.
* *
* @return pdPASS if the task was successfully created and added to a ready * @return If neither pxStackBuffer or pxTaskBuffer are NULL, then the function
* list, otherwise an error code defined in the file projdefs.h * will not attempt any dynamic memory allocation, and pdPASS will always be
* returned. If pxStackBuffer or pxTaskBuffer is NULL then the function will
* attempt to dynamically allocate one of both buffers. In this case, if the
* allocation succeeds then pdPASS will be returned, and if the allocation fails
* then an error code defined in projdefs.h is returned.
* *
* Example usage: * Example usage:
<pre> <pre>
@ -819,6 +825,62 @@ UBaseType_t uxTaskPriorityGetFromISR( TaskHandle_t xTask ) PRIVILEGED_FUNCTION;
*/ */
eTaskState eTaskGetState( TaskHandle_t xTask ) PRIVILEGED_FUNCTION; eTaskState eTaskGetState( TaskHandle_t xTask ) PRIVILEGED_FUNCTION;
/**
* task. h
* <pre>void vTaskGetTaskInfo( TaskHandle_t xTask, TaskStatus_t *pxTaskStatus, BaseType_t xGetFreeStackSpace, eTaskState eState );</pre>
*
* configUSE_TRACE_FACILITY must be defined as 1 for this function to be
* available. See the configuration section for more information.
*
* Populates a TaskStatus_t structure with information about a task.
*
* @param xTask Handle of the task being queried. If xTask is NULL then
* information will be returned about the calling task.
*
* @param pxTaskStatus A pointer to the TaskStatus_t structure that will be
* filled with information about the task referenced by the handle passed using
* the xTask parameter.
*
* @xGetFreeStackSpace The TaskStatus_t structure contains a member to report
* the stack high water mark of the task being queried. Calculating the stack
* high water mark takes a relatively long time, and can make the system
* temporarily unresponsive - so the xGetFreeStackSpace parameter is provided to
* allow the high water mark checking to be skipped. The high watermark value
* will only be written to the TaskStatus_t structure if xGetFreeStackSpace is
* not set to pdFALSE;
*
* @param eState The TaskStatus_t structure contains a member to report the
* state of the task being queried. Obtaining the task state is not as fast as
* a simple assignment - so the eState parameter is provided to allow the state
* information to be omitted from the TaskStatus_t structure. To obtain state
* information then set eState to eInvalid - otherwise the value passed in
* eState will be reported as the task state in the TaskStatus_t structure.
*
* Example usage:
<pre>
void vAFunction( void )
{
TaskHandle_t xHandle;
TaskStatus_t xTaskDetails;
// Obtain the handle of a task from its name.
xHandle = xTaskGetTaskHandle( "Task_Name" );
// Check the handle is not NULL.
configASSERT( xHandle );
// Use the handle to obtain further information about the task.
vTaskGetTaskInfo( xHandle,
&xTaskDetails,
pdTRUE, // Include the high water mark in xTaskDetails.
eInvalid ); // Include the task state in xTaskDetails.
}
</pre>
* \defgroup vTaskGetTaskInfo vTaskGetTaskInfo
* \ingroup TaskCtrl
*/
void vTaskGetTaskInfo( TaskHandle_t xTask, TaskStatus_t *pxTaskStatus, BaseType_t xGetFreeStackSpace, eTaskState eState );
/** /**
* task. h * task. h
* <pre>void vTaskPrioritySet( TaskHandle_t xTask, UBaseType_t uxNewPriority );</pre> * <pre>void vTaskPrioritySet( TaskHandle_t xTask, UBaseType_t uxNewPriority );</pre>
@ -1243,6 +1305,22 @@ UBaseType_t uxTaskGetNumberOfTasks( void ) PRIVILEGED_FUNCTION;
*/ */
char *pcTaskGetTaskName( TaskHandle_t xTaskToQuery ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ char *pcTaskGetTaskName( TaskHandle_t xTaskToQuery ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
/**
* task. h
* <PRE>TaskHandle_t xTaskGetTaskHandle( const char *pcNameToQuery );</PRE>
*
* NOTE: This function takes a relatively long time to complete and should be
* used sparingly.
*
* @return The handle of the task that has the human readable name pcNameToQuery.
* NULL is returned if no matching name is found. INCLUDE_xTaskGetTaskHandle
* must be set to 1 in FreeRTOSConfig.h for pcTaskGetTaskHandle() to be available.
*
* \defgroup pcTaskGetTaskHandle pcTaskGetTaskHandle
* \ingroup TaskUtils
*/
TaskHandle_t xTaskGetTaskHandle( const char *pcNameToQuery ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
/** /**
* task.h * task.h
* <PRE>UBaseType_t uxTaskGetStackHighWaterMark( TaskHandle_t xTask );</PRE> * <PRE>UBaseType_t uxTaskGetStackHighWaterMark( TaskHandle_t xTask );</PRE>

View File

@ -145,8 +145,8 @@ typedef void (*PendedFunction_t)( void *, uint32_t );
* http://www.freertos.org/a00111.html). If a software timer is created using * http://www.freertos.org/a00111.html). If a software timer is created using
* xTimerCreateStatic() then the application writer can instead optionally * xTimerCreateStatic() then the application writer can instead optionally
* provide the memory that will get used by the software timer. * provide the memory that will get used by the software timer.
* xTimerCreateStatic() therefore allows a software to be created without using * xTimerCreateStatic() therefore allows a software timer to be created without
* any dynamic memory allocation. * using any dynamic memory allocation.
* *
* Timers are created in the dormant state. The xTimerStart(), xTimerReset(), * Timers are created in the dormant state. The xTimerStart(), xTimerReset(),
* xTimerStartFromISR(), xTimerResetFromISR(), xTimerChangePeriod() and * xTimerStartFromISR(), xTimerResetFromISR(), xTimerChangePeriod() and
@ -327,10 +327,12 @@ typedef void (*PendedFunction_t)( void *, uint32_t );
* will be then be used to hold the software timer's data structures, removing * will be then be used to hold the software timer's data structures, removing
* the need for the memory to be allocated dynamically. * the need for the memory to be allocated dynamically.
* *
* @return If the timer is successfully created then a handle to the newly * @return If pxTimerBuffer is not NULL then the function will not attempt
* created timer is returned. If the timer cannot be created (because either * any dynamic memory allocation, and a handle to the created timer will always
* there is insufficient FreeRTOS heap remaining to allocate the timer * be returned. If pxTimerBuffer is NULL then the function will attempt to
* structures, or the timer period was set to 0) then NULL is returned. * dynamically allocate the memory required to hold the timer's data structures.
* In this case, if the allocation succeeds then a handle to the created timer
* will be returned, and if the allocation fails NULL will be returned.
* *
* Example usage: * Example usage:
* @verbatim * @verbatim
@ -1277,7 +1279,7 @@ const char * pcTimerGetTimerName( TimerHandle_t xTimer ) PRIVILEGED_FUNCTION; /*
*/ */
BaseType_t xTimerCreateTimerTask( void ) PRIVILEGED_FUNCTION; BaseType_t xTimerCreateTimerTask( void ) PRIVILEGED_FUNCTION;
BaseType_t xTimerGenericCommand( TimerHandle_t xTimer, const BaseType_t xCommandID, const TickType_t xOptionalValue, BaseType_t * const pxHigherPriorityTaskWoken, const TickType_t xTicksToWait ) PRIVILEGED_FUNCTION; BaseType_t xTimerGenericCommand( TimerHandle_t xTimer, const BaseType_t xCommandID, const TickType_t xOptionalValue, BaseType_t * const pxHigherPriorityTaskWoken, const TickType_t xTicksToWait ) PRIVILEGED_FUNCTION;
TimerHandle_t xTimerGenericCreate( const char * const pcTimerName, const TickType_t xTimerPeriodInTicks, const UBaseType_t uxAutoReload, void * const pvTimerID, TimerCallbackFunction_t pxCallbackFunction, StaticTimer_t *pxTimerBuffer ) PRIVILEGED_FUNCTION; TimerHandle_t xTimerGenericCreate( const char * const pcTimerName, const TickType_t xTimerPeriodInTicks, const UBaseType_t uxAutoReload, void * const pvTimerID, TimerCallbackFunction_t pxCallbackFunction, StaticTimer_t *pxTimerBuffer ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -507,7 +507,17 @@ static TCB_t *prvAllocateTCBAndStack( const uint16_t usStackDepth, StackType_t *
*/ */
#if ( configUSE_TRACE_FACILITY == 1 ) #if ( configUSE_TRACE_FACILITY == 1 )
static UBaseType_t prvListTaskWithinSingleList( TaskStatus_t *pxTaskStatusArray, List_t *pxList, eTaskState eState ) PRIVILEGED_FUNCTION; static UBaseType_t prvListTasksWithinSingleList( TaskStatus_t *pxTaskStatusArray, List_t *pxList, eTaskState eState ) PRIVILEGED_FUNCTION;
#endif
/*
* Searches pxList for a task with name pcNameToQuery - returning a handle to
* the task if it is found, or NULL if the task is not found.
*/
#if ( INCLUDE_xTaskGetTaskHandle == 1 )
static TCB_t *prvSearchForNameWithinSingleList( List_t *pxList, const char pcNameToQuery[] );
#endif #endif
@ -985,7 +995,7 @@ StackType_t *pxTopOfStack;
#endif /* INCLUDE_vTaskDelay */ #endif /* INCLUDE_vTaskDelay */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#if ( INCLUDE_eTaskGetState == 1 ) #if( ( INCLUDE_eTaskGetState == 1 ) || ( configUSE_TRACE_FACILITY == 1 ) )
eTaskState eTaskGetState( TaskHandle_t xTask ) eTaskState eTaskGetState( TaskHandle_t xTask )
{ {
@ -1321,6 +1331,21 @@ StackType_t *pxTopOfStack;
} }
taskEXIT_CRITICAL(); taskEXIT_CRITICAL();
if( xSchedulerRunning != pdFALSE )
{
/* Reset the next expected unblock time in case it referred to the
task that is now in the Suspended state. */
taskENTER_CRITICAL();
{
prvResetNextTaskUnblockTime();
}
taskEXIT_CRITICAL();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
if( pxTCB == pxCurrentTCB ) if( pxTCB == pxCurrentTCB )
{ {
if( xSchedulerRunning != pdFALSE ) if( xSchedulerRunning != pdFALSE )
@ -1349,24 +1374,10 @@ StackType_t *pxTopOfStack;
} }
} }
else else
{
if( xSchedulerRunning != pdFALSE )
{
/* A task other than the currently running task was suspended,
reset the next expected unblock time in case it referred to the
task that is now in the Suspended state. */
taskENTER_CRITICAL();
{
prvResetNextTaskUnblockTime();
}
taskEXIT_CRITICAL();
}
else
{ {
mtCOVERAGE_TEST_MARKER(); mtCOVERAGE_TEST_MARKER();
} }
} }
}
#endif /* INCLUDE_vTaskSuspend */ #endif /* INCLUDE_vTaskSuspend */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -1710,7 +1721,7 @@ void vTaskSuspendAll( void )
BaseType_t xTaskResumeAll( void ) BaseType_t xTaskResumeAll( void )
{ {
TCB_t *pxTCB; TCB_t *pxTCB = NULL;
BaseType_t xAlreadyYielded = pdFALSE; BaseType_t xAlreadyYielded = pdFALSE;
/* If uxSchedulerSuspended is zero then this function does not match a /* If uxSchedulerSuspended is zero then this function does not match a
@ -1751,6 +1762,17 @@ BaseType_t xAlreadyYielded = pdFALSE;
} }
} }
if( pxTCB != NULL )
{
/* A task was unblocked while the scheduler was suspended,
which may have prevented the next unblock time from being
re-calculated, in which case re-calculate it now. Mainly
important for low power tickless implementations, where
this can prevent an unnecessary exit from low power
state. */
prvResetNextTaskUnblockTime();
}
/* If any ticks occurred while the scheduler was suspended then /* If any ticks occurred while the scheduler was suspended then
they should be processed now. This ensures the tick count does they should be processed now. This ensures the tick count does
not slip, and that any delayed tasks are resumed at the correct not slip, and that any delayed tasks are resumed at the correct
@ -1861,7 +1883,8 @@ UBaseType_t uxTaskGetNumberOfTasks( void )
{ {
TCB_t *pxTCB; TCB_t *pxTCB;
/* If null is passed in here then the name of the calling task is being queried. */ /* If null is passed in here then the name of the calling task is being
queried. */
pxTCB = prvGetTCBFromHandle( xTaskToQuery ); pxTCB = prvGetTCBFromHandle( xTaskToQuery );
configASSERT( pxTCB ); configASSERT( pxTCB );
return &( pxTCB->pcTaskName[ 0 ] ); return &( pxTCB->pcTaskName[ 0 ] );
@ -1870,6 +1893,129 @@ UBaseType_t uxTaskGetNumberOfTasks( void )
#endif /* INCLUDE_pcTaskGetTaskName */ #endif /* INCLUDE_pcTaskGetTaskName */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#if ( INCLUDE_xTaskGetTaskHandle == 1 )
static TCB_t *prvSearchForNameWithinSingleList( List_t *pxList, const char pcNameToQuery[] )
{
TCB_t *pxNextTCB, *pxFirstTCB, *pxReturn = NULL;
UBaseType_t x;
char cNextChar;
/* This function is called with the scheduler suspended. */
if( listCURRENT_LIST_LENGTH( pxList ) > ( UBaseType_t ) 0 )
{
listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList );
do
{
listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList );
/* Check each character in the name looking for a match or
mismatch. */
for( x = ( UBaseType_t ) 0; x < ( UBaseType_t ) configMAX_TASK_NAME_LEN; x++ )
{
cNextChar = pxNextTCB->pcTaskName[ x ];
if( cNextChar != pcNameToQuery[ x ] )
{
/* Characters didn't match. */
break;
}
else if( cNextChar == 0x00 )
{
/* Both strings terminated, a match must have been
found. */
pxReturn = pxNextTCB;
break;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
if( pxReturn != NULL )
{
/* The handle has been found. */
break;
}
} while( pxNextTCB != pxFirstTCB );
}
else
{
mtCOVERAGE_TEST_MARKER();
}
return pxReturn;
}
#endif /* INCLUDE_xTaskGetTaskHandle */
/*-----------------------------------------------------------*/
#if ( INCLUDE_xTaskGetTaskHandle == 1 )
TaskHandle_t xTaskGetTaskHandle( const char *pcNameToQuery ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
{
UBaseType_t uxQueue = configMAX_PRIORITIES;
TCB_t* pxTCB;
vTaskSuspendAll();
{
/* Search the ready lists. */
do
{
uxQueue--;
pxTCB = prvSearchForNameWithinSingleList( ( List_t * ) &( pxReadyTasksLists[ uxQueue ] ), pcNameToQuery );
if( pxTCB != NULL )
{
/* Found the handle. */
break;
}
} while( uxQueue > ( UBaseType_t ) tskIDLE_PRIORITY ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
/* Search the delayed lists. */
if( pxTCB == NULL )
{
pxTCB = prvSearchForNameWithinSingleList( ( List_t * ) pxDelayedTaskList, pcNameToQuery );
}
if( pxTCB == NULL )
{
pxTCB = prvSearchForNameWithinSingleList( ( List_t * ) pxOverflowDelayedTaskList, pcNameToQuery );
}
#if ( INCLUDE_vTaskSuspend == 1 )
{
if( pxTCB == NULL )
{
/* Search the suspended list. */
pxTCB = prvSearchForNameWithinSingleList( &xSuspendedTaskList, pcNameToQuery );
}
}
#endif
#if( INCLUDE_vTaskDelete == 1 )
{
if( pxTCB == NULL )
{
/* Search the deleted list. */
pxTCB = prvSearchForNameWithinSingleList( &xTasksWaitingTermination, pcNameToQuery );
}
}
#endif
}
( void ) xTaskResumeAll();
return ( TaskHandle_t ) pxTCB;
}
#endif /* INCLUDE_xTaskGetTaskHandle */
/*-----------------------------------------------------------*/
#if ( configUSE_TRACE_FACILITY == 1 ) #if ( configUSE_TRACE_FACILITY == 1 )
UBaseType_t uxTaskGetSystemState( TaskStatus_t * const pxTaskStatusArray, const UBaseType_t uxArraySize, uint32_t * const pulTotalRunTime ) UBaseType_t uxTaskGetSystemState( TaskStatus_t * const pxTaskStatusArray, const UBaseType_t uxArraySize, uint32_t * const pulTotalRunTime )
@ -1886,20 +2032,20 @@ UBaseType_t uxTaskGetNumberOfTasks( void )
do do
{ {
uxQueue--; uxQueue--;
uxTask += prvListTaskWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &( pxReadyTasksLists[ uxQueue ] ), eReady ); uxTask += prvListTasksWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &( pxReadyTasksLists[ uxQueue ] ), eReady );
} while( uxQueue > ( UBaseType_t ) tskIDLE_PRIORITY ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ } while( uxQueue > ( UBaseType_t ) tskIDLE_PRIORITY ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
/* Fill in an TaskStatus_t structure with information on each /* Fill in an TaskStatus_t structure with information on each
task in the Blocked state. */ task in the Blocked state. */
uxTask += prvListTaskWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), ( List_t * ) pxDelayedTaskList, eBlocked ); uxTask += prvListTasksWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), ( List_t * ) pxDelayedTaskList, eBlocked );
uxTask += prvListTaskWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), ( List_t * ) pxOverflowDelayedTaskList, eBlocked ); uxTask += prvListTasksWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), ( List_t * ) pxOverflowDelayedTaskList, eBlocked );
#if( INCLUDE_vTaskDelete == 1 ) #if( INCLUDE_vTaskDelete == 1 )
{ {
/* Fill in an TaskStatus_t structure with information on /* Fill in an TaskStatus_t structure with information on
each task that has been deleted but not yet cleaned up. */ each task that has been deleted but not yet cleaned up. */
uxTask += prvListTaskWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &xTasksWaitingTermination, eDeleted ); uxTask += prvListTasksWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &xTasksWaitingTermination, eDeleted );
} }
#endif #endif
@ -1907,7 +2053,7 @@ UBaseType_t uxTaskGetNumberOfTasks( void )
{ {
/* Fill in an TaskStatus_t structure with information on /* Fill in an TaskStatus_t structure with information on
each task in the Suspended state. */ each task in the Suspended state. */
uxTask += prvListTaskWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &xSuspendedTaskList, eSuspended ); uxTask += prvListTasksWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &xSuspendedTaskList, eSuspended );
} }
#endif #endif
@ -3268,9 +3414,98 @@ TCB_t *pxNewTCB;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#if( configUSE_TRACE_FACILITY == 1 )
void vTaskGetTaskInfo( TaskHandle_t xTask, TaskStatus_t *pxTaskStatus, BaseType_t xGetFreeStackSpace, eTaskState eState )
{
TCB_t *pxTCB;
/* xTask is NULL then get the state of the calling task. */
pxTCB = prvGetTCBFromHandle( xTask );
pxTaskStatus->xHandle = ( TaskHandle_t ) pxTCB;
pxTaskStatus->pcTaskName = ( const char * ) &( pxTCB->pcTaskName [ 0 ] );
pxTaskStatus->uxCurrentPriority = pxTCB->uxPriority;
pxTaskStatus->pxStackBase = pxTCB->pxStack;
pxTaskStatus->xTaskNumber = pxTCB->uxTCBNumber;
#if ( INCLUDE_vTaskSuspend == 1 )
{
/* If the task is in the suspended list then there is a chance it is
actually just blocked indefinitely - so really it should be reported as
being in the Blocked state. */
if( pxTaskStatus->eCurrentState == eSuspended )
{
vTaskSuspendAll();
{
if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
{
pxTaskStatus->eCurrentState = eBlocked;
}
}
xTaskResumeAll();
}
}
#endif /* INCLUDE_vTaskSuspend */
#if ( configUSE_MUTEXES == 1 )
{
pxTaskStatus->uxBasePriority = pxTCB->uxBasePriority;
}
#else
{
pxTaskStatus->uxBasePriority = 0;
}
#endif
#if ( configGENERATE_RUN_TIME_STATS == 1 )
{
pxTaskStatus->ulRunTimeCounter = pxTCB->ulRunTimeCounter;
}
#else
{
pxTaskStatus->ulRunTimeCounter = 0;
}
#endif
/* Obtaining the task state is a little fiddly, so is only done if the value
of eState passed into this function is eInvalid - otherwise the state is
just set to whatever is passed in. */
if( eState != eInvalid )
{
pxTaskStatus->eCurrentState = eState;
}
else
{
pxTaskStatus->eCurrentState = eTaskGetState( xTask );
}
/* Obtaining the stack space takes some time, so the xGetFreeStackSpace
parameter is provided to allow it to be skipped. */
if( xGetFreeStackSpace != pdFALSE )
{
#if ( portSTACK_GROWTH > 0 )
{
pxTaskStatus->usStackHighWaterMark = prvTaskCheckFreeStackSpace( ( uint8_t * ) pxTCB->pxEndOfStack );
}
#else
{
pxTaskStatus->usStackHighWaterMark = prvTaskCheckFreeStackSpace( ( uint8_t * ) pxTCB->pxStack );
}
#endif
}
else
{
pxTaskStatus->usStackHighWaterMark = 0;
}
}
#endif /* INCLUDE_eTaskGetState */
/*-----------------------------------------------------------*/
#if ( configUSE_TRACE_FACILITY == 1 ) #if ( configUSE_TRACE_FACILITY == 1 )
static UBaseType_t prvListTaskWithinSingleList( TaskStatus_t *pxTaskStatusArray, List_t *pxList, eTaskState eState ) static UBaseType_t prvListTasksWithinSingleList( TaskStatus_t *pxTaskStatusArray, List_t *pxList, eTaskState eState )
{ {
volatile TCB_t *pxNextTCB, *pxFirstTCB; volatile TCB_t *pxNextTCB, *pxFirstTCB;
UBaseType_t uxTask = 0; UBaseType_t uxTask = 0;
@ -3286,60 +3521,8 @@ TCB_t *pxNewTCB;
do do
{ {
listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList ); listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList );
vTaskGetTaskInfo( ( TaskHandle_t ) pxNextTCB, &( pxTaskStatusArray[ uxTask ] ), pdTRUE, eState );
pxTaskStatusArray[ uxTask ].xHandle = ( TaskHandle_t ) pxNextTCB;
pxTaskStatusArray[ uxTask ].pcTaskName = ( const char * ) &( pxNextTCB->pcTaskName [ 0 ] );
pxTaskStatusArray[ uxTask ].xTaskNumber = pxNextTCB->uxTCBNumber;
pxTaskStatusArray[ uxTask ].eCurrentState = eState;
pxTaskStatusArray[ uxTask ].uxCurrentPriority = pxNextTCB->uxPriority;
#if ( INCLUDE_vTaskSuspend == 1 )
{
/* If the task is in the suspended list then there is a chance
it is actually just blocked indefinitely - so really it should
be reported as being in the Blocked state. */
if( eState == eSuspended )
{
if( listLIST_ITEM_CONTAINER( &( pxNextTCB->xEventListItem ) ) != NULL )
{
pxTaskStatusArray[ uxTask ].eCurrentState = eBlocked;
}
}
}
#endif /* INCLUDE_vTaskSuspend */
#if ( configUSE_MUTEXES == 1 )
{
pxTaskStatusArray[ uxTask ].uxBasePriority = pxNextTCB->uxBasePriority;
}
#else
{
pxTaskStatusArray[ uxTask ].uxBasePriority = 0;
}
#endif
#if ( configGENERATE_RUN_TIME_STATS == 1 )
{
pxTaskStatusArray[ uxTask ].ulRunTimeCounter = pxNextTCB->ulRunTimeCounter;
}
#else
{
pxTaskStatusArray[ uxTask ].ulRunTimeCounter = 0;
}
#endif
#if ( portSTACK_GROWTH > 0 )
{
pxTaskStatusArray[ uxTask ].usStackHighWaterMark = prvTaskCheckFreeStackSpace( ( uint8_t * ) pxNextTCB->pxEndOfStack );
}
#else
{
pxTaskStatusArray[ uxTask ].usStackHighWaterMark = prvTaskCheckFreeStackSpace( ( uint8_t * ) pxNextTCB->pxStack );
}
#endif
uxTask++; uxTask++;
} while( pxNextTCB != pxFirstTCB ); } while( pxNextTCB != pxFirstTCB );
} }
else else
@ -3422,7 +3605,7 @@ TCB_t *pxNewTCB;
{ {
/* Only free the stack and TCB if they were allocated dynamically in /* Only free the stack and TCB if they were allocated dynamically in
the first place. */ the first place. */
if( ( pxTCB->ucStaticAllocationFlags & taskSTATICALLY_ALLOCATED_STACK ) == ( UBaseType_t ) 0 ) if( ( pxTCB->ucStaticAllocationFlags & taskSTATICALLY_ALLOCATED_STACK ) == ( uint8_t ) 0 )
{ {
vPortFreeAligned( pxTCB->pxStack ); vPortFreeAligned( pxTCB->pxStack );
} }
@ -3431,7 +3614,7 @@ TCB_t *pxNewTCB;
mtCOVERAGE_TEST_MARKER(); mtCOVERAGE_TEST_MARKER();
} }
if( ( pxTCB->ucStaticAllocationFlags & taskSTATICALLY_ALLOCATED_TCB ) == ( UBaseType_t ) 0 ) if( ( pxTCB->ucStaticAllocationFlags & taskSTATICALLY_ALLOCATED_TCB ) == ( uint8_t ) 0 )
{ {
vPortFreeAligned( pxTCB ); vPortFreeAligned( pxTCB );
} }

View File

@ -274,7 +274,6 @@ uint16_t usTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
} }
#endif /* configSUPPORT_STATIC_ALLOCATION */ #endif /* configSUPPORT_STATIC_ALLOCATION */
#if ( INCLUDE_xTimerGetTimerDaemonTaskHandle == 1 ) #if ( INCLUDE_xTimerGetTimerDaemonTaskHandle == 1 )
{ {
/* Create the timer task, storing its handle in xTimerTaskHandle so /* Create the timer task, storing its handle in xTimerTaskHandle so
@ -327,7 +326,7 @@ Timer_t *pxNewTimer;
} }
else else
{ {
pxNewTimer = ( Timer_t * ) pxTimerBuffer; pxNewTimer = ( Timer_t * ) pxTimerBuffer; /*lint !e740 Unusual cast is ok as the structures are designed to have the same alignment, and the size is checked by an assert. */
} }
if( pxNewTimer != NULL ) if( pxNewTimer != NULL )
@ -429,7 +428,7 @@ DaemonTaskMessage_t xMessage;
#endif #endif
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
const char * pcTimerGetTimerName( TimerHandle_t xTimer ) const char * pcTimerGetTimerName( TimerHandle_t xTimer ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
{ {
Timer_t *pxTimer = ( Timer_t * ) xTimer; Timer_t *pxTimer = ( Timer_t * ) xTimer;
@ -486,6 +485,18 @@ BaseType_t xListWasEmpty;
/* Just to avoid compiler warnings. */ /* Just to avoid compiler warnings. */
( void ) pvParameters; ( void ) pvParameters;
#if( configUSE_DAEMON_TASK_STARTUP_HOOK == 1 )
{
extern void vApplicationDaemonTaskStartupHook( void );
/* Allow the application writer to execute some code in the context of
this task at the point the task starts executing. This is useful if the
application includes initialisation code that would benefit from
executing after the scheduler has been started. */
vApplicationDaemonTaskStartupHook();
}
#endif /* configUSE_DAEMON_TASK_STARTUP_HOOK */
for( ;; ) for( ;; )
{ {
/* Query the timers list to see if it contains any timers, and if so, /* Query the timers list to see if it contains any timers, and if so,
@ -769,7 +780,7 @@ TickType_t xTimeNow;
allocated. */ allocated. */
#if( configSUPPORT_STATIC_ALLOCATION == 1 ) #if( configSUPPORT_STATIC_ALLOCATION == 1 )
{ {
if( pxTimer->ucStaticallyAllocated == pdFALSE ) if( pxTimer->ucStaticallyAllocated == ( uint8_t ) pdFALSE )
{ {
vPortFree( pxTimer ); vPortFree( pxTimer );
} }