From 8fe51ad8323262e3c6a9aa1460b38240ae21369a Mon Sep 17 00:00:00 2001 From: rtel Date: Thu, 28 Jan 2016 16:59:57 +0000 Subject: [PATCH] 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. git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@2410 1d2547de-c912-0410-9cb9-b8ca96c0e9e2 --- ...eeRTOS+TCP_and_FreeRTOS_FAT_in_the_lab.url | 5 + FreeRTOS/Demo/WIN32-MSVC/FreeRTOSConfig.h | 2 + FreeRTOS/Demo/WIN32-MSVC/main.c | 35 +- FreeRTOS/Demo/WIN32-MSVC/main_full.c | 63 ++- FreeRTOS/Source/include/FreeRTOS.h | 8 + FreeRTOS/Source/include/queue.h | 16 +- FreeRTOS/Source/include/semphr.h | 394 ++++++++++++++++-- FreeRTOS/Source/include/task.h | 84 +++- FreeRTOS/Source/include/timers.h | 16 +- FreeRTOS/Source/tasks.c | 343 +++++++++++---- FreeRTOS/Source/timers.c | 19 +- 11 files changed, 838 insertions(+), 147 deletions(-) create mode 100644 FreeRTOS-Plus/Demo/Also_See_FreeRTOS+TCP_and_FreeRTOS_FAT_in_the_lab.url diff --git a/FreeRTOS-Plus/Demo/Also_See_FreeRTOS+TCP_and_FreeRTOS_FAT_in_the_lab.url b/FreeRTOS-Plus/Demo/Also_See_FreeRTOS+TCP_and_FreeRTOS_FAT_in_the_lab.url new file mode 100644 index 000000000..dd4e3426b --- /dev/null +++ b/FreeRTOS-Plus/Demo/Also_See_FreeRTOS+TCP_and_FreeRTOS_FAT_in_the_lab.url @@ -0,0 +1,5 @@ +[{000214A0-0000-0000-C000-000000000046}] +Prop3=19,2 +[InternetShortcut] +URL=http://www.freertos.org/labs +IDList= diff --git a/FreeRTOS/Demo/WIN32-MSVC/FreeRTOSConfig.h b/FreeRTOS/Demo/WIN32-MSVC/FreeRTOSConfig.h index 37aaf9551..44b089297 100644 --- a/FreeRTOS/Demo/WIN32-MSVC/FreeRTOSConfig.h +++ b/FreeRTOS/Demo/WIN32-MSVC/FreeRTOSConfig.h @@ -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 diff --git a/FreeRTOS/Demo/WIN32-MSVC/main.c b/FreeRTOS/Demo/WIN32-MSVC/main.c index 53fd61a3e..44a935539 100644 --- a/FreeRTOS/Demo/WIN32-MSVC/main.c +++ b/FreeRTOS/Demo/WIN32-MSVC/main.c @@ -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 diff --git a/FreeRTOS/Demo/WIN32-MSVC/main_full.c b/FreeRTOS/Demo/WIN32-MSVC/main_full.c index a0ad433f6..d01969926 100644 --- a/FreeRTOS/Demo/WIN32-MSVC/main_full.c +++ b/FreeRTOS/Demo/WIN32-MSVC/main_full.c @@ -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). */ diff --git a/FreeRTOS/Source/include/FreeRTOS.h b/FreeRTOS/Source/include/FreeRTOS.h index ab0da0df5..33a4d79f1 100644 --- a/FreeRTOS/Source/include/FreeRTOS.h +++ b/FreeRTOS/Source/include/FreeRTOS.h @@ -171,6 +171,10 @@ extern "C" { #endif #endif +#ifndef configUSE_DAEMON_TASK_STARTUP_HOOK + #define configUSE_DAEMON_TASK_STARTUP_HOOK 0 +#endif + #ifndef INCLUDE_xTaskGetIdleTaskHandle #define INCLUDE_xTaskGetIdleTaskHandle 0 #endif @@ -191,6 +195,10 @@ extern "C" { #define INCLUDE_pcTaskGetTaskName 0 #endif +#ifndef INCLUDE_xTaskGetTaskHandle + #define INCLUDE_xTaskGetTaskHandle 0 +#endif + #ifndef configUSE_APPLICATION_TASK_TAG #define configUSE_APPLICATION_TASK_TAG 0 #endif diff --git a/FreeRTOS/Source/include/queue.h b/FreeRTOS/Source/include/queue.h index dfdc7e60e..aa15e325f 100644 --- a/FreeRTOS/Source/include/queue.h +++ b/FreeRTOS/Source/include/queue.h @@ -229,9 +229,13 @@ typedef void * QueueSetMemberHandle_t; * hold the queue's data structure, removing the need for the memory to be * allocated dynamically. * - * @return If the queue is successfully create then a handle to the newly - * created queue is returned. If the queue cannot be created then 0 is - * returned. + * @return If neither pucQueueStorageBuffer or pxQueueBuffer are NULL, then the + * function will not attempt any dynamic memory allocation, and a handle to the + * 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:
@@ -245,7 +249,7 @@ typedef void * QueueSetMemberHandle_t;
  #define ITEM_SIZE sizeof( uint32_t )
 
  // xQueueBuffer will hold the queue structure.
- StaticQueue_t xQueueBuffer; 
+ StaticQueue_t xQueueBuffer;
 
  // ucQueueStorage will hold the items posted to the queue.  Must be at least
  // [(queue length) * ( queue item size)] bytes long.
@@ -267,7 +271,7 @@ typedef void * QueueSetMemberHandle_t;
 	// ... Rest of task code.
  }
  
- * \defgroup xQueueCreate xQueueCreate + * \defgroup xQueueCreateStatic xQueueCreateStatic * \ingroup QueueManagement */ #if( configSUPPORT_STATIC_ALLOCATION == 1 ) @@ -1649,7 +1653,7 @@ BaseType_t xQueueGiveMutexRecursive( QueueHandle_t pxMutex ) PRIVILEGED_FUNCTION * returned. */ #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 /* diff --git a/FreeRTOS/Source/include/semphr.h b/FreeRTOS/Source/include/semphr.h index 4f5b7fd71..fe31007c7 100644 --- a/FreeRTOS/Source/include/semphr.h +++ b/FreeRTOS/Source/include/semphr.h @@ -145,10 +145,23 @@ typedef QueueHandle_t SemaphoreHandle_t; * semphr. h *
SemaphoreHandle_t xSemaphoreCreateBinary( void )
* + * 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 * 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. + * * The old vSemaphoreCreateBinary() macro is now deprecated in favour of this * xSemaphoreCreateBinary() function. Note that binary semaphores created using * 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 * 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 * 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 @@ -168,7 +176,8 @@ typedef QueueHandle_t SemaphoreHandle_t; * semaphore does not use a priority inheritance mechanism. For an alternative * 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:
@@ -176,7 +185,7 @@ typedef QueueHandle_t SemaphoreHandle_t;
 
  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.
     xSemaphore = xSemaphoreCreateBinary();
 
@@ -187,13 +196,78 @@ typedef QueueHandle_t SemaphoreHandle_t;
     }
  }
  
- * \defgroup vSemaphoreCreateBinary vSemaphoreCreateBinary + * \defgroup xSemaphoreCreateBinary xSemaphoreCreateBinary * \ingroup Semaphores */ #define xSemaphoreCreateBinary() xQueueGenericCreate( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, NULL, NULL, queueQUEUE_TYPE_BINARY_SEMAPHORE ) +/** + * semphr. h + *
SemaphoreHandle_t xSemaphoreCreateBinaryStatic( StaticSemaphore_t *pxSemaphoreBuffer )
+ * + * 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: +
+ 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.
+ }
+ 
+ * \defgroup xSemaphoreCreateBinaryStatic xSemaphoreCreateBinaryStatic + * \ingroup Semaphores + */ #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 */ /** @@ -204,7 +278,7 @@ typedef QueueHandle_t SemaphoreHandle_t; * ) * * Macro 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(). * * @param xSemaphore A handle to the semaphore being taken - obtained when @@ -227,7 +301,7 @@ typedef QueueHandle_t SemaphoreHandle_t; void vATask( void * pvParameters ) { // Create the semaphore to guard a shared resource. - vSemaphoreCreateBinary( xSemaphore ); + xSemaphore = xSemaphoreCreateBinary(); } // A task that uses the semaphore. @@ -376,7 +450,7 @@ typedef QueueHandle_t SemaphoreHandle_t; *
xSemaphoreGive( SemaphoreHandle_t xSemaphore )
* * Macro 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(). * * 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 ) { // Create the semaphore to guard a shared resource. - vSemaphoreCreateBinary( xSemaphore ); + xSemaphore = vSemaphoreCreateBinary(); if( xSemaphore != NULL ) { @@ -541,7 +615,7 @@ typedef QueueHandle_t SemaphoreHandle_t; ) * * Macro 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()) * must not be used with this macro. @@ -632,7 +706,7 @@ typedef QueueHandle_t SemaphoreHandle_t; ) * * Macro 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(). * * Mutex type semaphores (those created using a call to xSemaphoreCreateMutex()) @@ -661,12 +735,22 @@ typedef QueueHandle_t SemaphoreHandle_t; * semphr. h *
SemaphoreHandle_t xSemaphoreCreateMutex( void )
* - * Macro that implements a mutex semaphore by using the existing queue - * mechanism. + * Creates a new mutex type semaphore instance, and returns a handle by which + * 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 - * xSemaphoreGiveRecursive() macros should not be used. + * 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 @@ -674,13 +758,14 @@ typedef QueueHandle_t SemaphoreHandle_t; * * 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 * semaphore and another always 'takes' the semaphore) and from within interrupt * service routines. * - * @return xSemaphore Handle to the created mutex semaphore. Should be of type - * SemaphoreHandle_t. + * @return If the mutex was successfully created then a handle to the created + * semaphore is returned. If there was not enough heap to allocate the mutex + * data structures then NULL is returned. * * Example usage:
@@ -699,13 +784,75 @@ typedef QueueHandle_t SemaphoreHandle_t;
     }
  }
  
- * \defgroup vSemaphoreCreateMutex vSemaphoreCreateMutex + * \defgroup xSemaphoreCreateMutex xSemaphoreCreateMutex * \ingroup Semaphores */ #define xSemaphoreCreateMutex() xQueueCreateMutex( queueQUEUE_TYPE_MUTEX, NULL ) -#if( configSUPPORT_STATIC_ALLOCATION == 1 ) - #define xSemaphoreCreateMutexStatic( pxStaticQueue ) xQueueCreateMutex( queueQUEUE_TYPE_MUTEX, ( pxStaticQueue ) ) +/** + * semphr. h + *
SemaphoreHandle_t xSemaphoreCreateMutexStatic( StaticSemaphore_t *pxMutexBuffer )
+ * + * 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: +
+ 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.
+ }
+ 
+ * \defgroup xSemaphoreCreateMutexStatic xSemaphoreCreateMutexStatic + * \ingroup Semaphores + */ + #if( configSUPPORT_STATIC_ALLOCATION == 1 ) + #define xSemaphoreCreateMutexStatic( pxMutexBuffer ) xQueueCreateMutex( queueQUEUE_TYPE_MUTEX, ( pxMutexBuffer ) ) #endif /* configSUPPORT_STATIC_ALLOCATION */ @@ -713,12 +860,23 @@ typedef QueueHandle_t SemaphoreHandle_t; * semphr. h *
SemaphoreHandle_t xSemaphoreCreateRecursiveMutex( void )
* - * Macro that implements a recursive mutex by using the existing queue - * mechanism. + * 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 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 * doesn't become available again until the owner has called @@ -733,13 +891,13 @@ typedef QueueHandle_t SemaphoreHandle_t; * * 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 * semaphore and another always 'takes' the semaphore) and from within interrupt * service routines. * * @return xSemaphore Handle to the created mutex semaphore. Should be of type - * SemaphoreHandle_t. + * SemaphoreHandle_t. * * Example usage:
@@ -758,11 +916,85 @@ typedef QueueHandle_t SemaphoreHandle_t;
     }
  }
  
- * \defgroup vSemaphoreCreateMutex vSemaphoreCreateMutex + * \defgroup xSemaphoreCreateRecursiveMutex xSemaphoreCreateRecursiveMutex * \ingroup Semaphores */ #define xSemaphoreCreateRecursiveMutex() xQueueCreateMutex( queueQUEUE_TYPE_RECURSIVE_MUTEX, NULL ) +/** + * semphr. h + *
SemaphoreHandle_t xSemaphoreCreateRecursiveMutexStatic( StaticSemaphore_t *pxMutexBuffer )
+ * + * 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: +
+ 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.
+ }
+ 
+ * \defgroup xSemaphoreCreateRecursiveMutexStatic xSemaphoreCreateRecursiveMutexStatic + * \ingroup Semaphores + */ #if( configSUPPORT_STATIC_ALLOCATION == 1 ) #define xSemaphoreCreateRecursiveMutexStatic( pxStaticSemaphore ) xQueueCreateMutex( queueQUEUE_TYPE_RECURSIVE_MUTEX, pxStaticSemaphore ) #endif /* configSUPPORT_STATIC_ALLOCATION */ @@ -771,8 +1003,19 @@ typedef QueueHandle_t SemaphoreHandle_t; * semphr. h *
SemaphoreHandle_t xSemaphoreCreateCounting( UBaseType_t uxMaxCount, UBaseType_t uxInitialCount )
* - * Macro that creates a counting semaphore by using the existing - * queue mechanism. + * 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: * @@ -830,8 +1073,91 @@ typedef QueueHandle_t SemaphoreHandle_t; */ #define xSemaphoreCreateCounting( uxMaxCount, uxInitialCount ) xQueueCreateCountingSemaphore( ( uxMaxCount ), ( uxInitialCount ), ( NULL ) ) +/** + * semphr. h + *
SemaphoreHandle_t xSemaphoreCreateCountingStatic( UBaseType_t uxMaxCount, UBaseType_t uxInitialCount, StaticSemaphore_t *pxSemaphoreBuffer )
+ * + * 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: +
+ 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.
+ }
+ 
+ * \defgroup xSemaphoreCreateCountingStatic xSemaphoreCreateCountingStatic + * \ingroup Semaphores + */ #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 */ /** diff --git a/FreeRTOS/Source/include/task.h b/FreeRTOS/Source/include/task.h index 223446b62..b736b6010 100644 --- a/FreeRTOS/Source/include/task.h +++ b/FreeRTOS/Source/include/task.h @@ -115,7 +115,8 @@ typedef enum eReady, /* The task being queried is in a read or pending ready list. */ 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. */ - 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; /* 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 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. */ + 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. */ } TaskStatus_t; @@ -426,8 +428,12 @@ is used in assert() statements. */ * task's data structures, removing the need for the memory to be allocated * dynamically. * - * @return pdPASS if the task was successfully created and added to a ready - * list, otherwise an error code defined in the file projdefs.h + * @return If neither pxStackBuffer or pxTaskBuffer are NULL, then the function + * 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:
@@ -819,6 +825,62 @@ UBaseType_t uxTaskPriorityGetFromISR( TaskHandle_t xTask ) PRIVILEGED_FUNCTION;
  */
 eTaskState eTaskGetState( TaskHandle_t xTask ) PRIVILEGED_FUNCTION;
 
+/**
+ * task. h
+ * 
void vTaskGetTaskInfo( TaskHandle_t xTask, TaskStatus_t *pxTaskStatus, BaseType_t xGetFreeStackSpace, eTaskState eState );
+ * + * 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: +
+ 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.
+ }
+   
+ * \defgroup vTaskGetTaskInfo vTaskGetTaskInfo + * \ingroup TaskCtrl + */ +void vTaskGetTaskInfo( TaskHandle_t xTask, TaskStatus_t *pxTaskStatus, BaseType_t xGetFreeStackSpace, eTaskState eState ); + /** * task. h *
void vTaskPrioritySet( TaskHandle_t xTask, UBaseType_t uxNewPriority );
@@ -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. */ +/** + * task. h + *
TaskHandle_t xTaskGetTaskHandle( const char *pcNameToQuery );
+ * + * 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 *
UBaseType_t uxTaskGetStackHighWaterMark( TaskHandle_t xTask );
diff --git a/FreeRTOS/Source/include/timers.h b/FreeRTOS/Source/include/timers.h index e5e5c137c..210a40c04 100644 --- a/FreeRTOS/Source/include/timers.h +++ b/FreeRTOS/Source/include/timers.h @@ -145,8 +145,8 @@ typedef void (*PendedFunction_t)( void *, uint32_t ); * http://www.freertos.org/a00111.html). If a software timer is created using * xTimerCreateStatic() then the application writer can instead optionally * provide the memory that will get used by the software timer. - * xTimerCreateStatic() therefore allows a software to be created without using - * any dynamic memory allocation. + * xTimerCreateStatic() therefore allows a software timer to be created without + * using any dynamic memory allocation. * * Timers are created in the dormant state. The xTimerStart(), xTimerReset(), * 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 * the need for the memory to be allocated dynamically. * - * @return If the timer is successfully created then a handle to the newly - * created timer is returned. If the timer cannot be created (because either - * there is insufficient FreeRTOS heap remaining to allocate the timer - * structures, or the timer period was set to 0) then NULL is returned. + * @return If pxTimerBuffer is not NULL then the function will not attempt + * any dynamic memory allocation, and a handle to the created timer will always + * be returned. If pxTimerBuffer is NULL then the function will attempt to + * 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: * @verbatim @@ -1277,7 +1279,7 @@ const char * pcTimerGetTimerName( TimerHandle_t xTimer ) 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; -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 } diff --git a/FreeRTOS/Source/tasks.c b/FreeRTOS/Source/tasks.c index d73f8d277..b9b17576a 100644 --- a/FreeRTOS/Source/tasks.c +++ b/FreeRTOS/Source/tasks.c @@ -507,7 +507,17 @@ static TCB_t *prvAllocateTCBAndStack( const uint16_t usStackDepth, StackType_t * */ #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 @@ -985,7 +995,7 @@ StackType_t *pxTopOfStack; #endif /* INCLUDE_vTaskDelay */ /*-----------------------------------------------------------*/ -#if ( INCLUDE_eTaskGetState == 1 ) +#if( ( INCLUDE_eTaskGetState == 1 ) || ( configUSE_TRACE_FACILITY == 1 ) ) eTaskState eTaskGetState( TaskHandle_t xTask ) { @@ -1321,6 +1331,21 @@ StackType_t *pxTopOfStack; } 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( xSchedulerRunning != pdFALSE ) @@ -1350,21 +1375,7 @@ StackType_t *pxTopOfStack; } 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(); } } @@ -1710,7 +1721,7 @@ void vTaskSuspendAll( void ) BaseType_t xTaskResumeAll( void ) { -TCB_t *pxTCB; +TCB_t *pxTCB = NULL; BaseType_t xAlreadyYielded = pdFALSE; /* 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 they should be processed now. This ensures the tick count does not slip, and that any delayed tasks are resumed at the correct @@ -1861,7 +1883,8 @@ UBaseType_t uxTaskGetNumberOfTasks( void ) { 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 ); configASSERT( pxTCB ); return &( pxTCB->pcTaskName[ 0 ] ); @@ -1870,6 +1893,129 @@ UBaseType_t uxTaskGetNumberOfTasks( void ) #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 ) UBaseType_t uxTaskGetSystemState( TaskStatus_t * const pxTaskStatusArray, const UBaseType_t uxArraySize, uint32_t * const pulTotalRunTime ) @@ -1886,20 +2032,20 @@ UBaseType_t uxTaskGetNumberOfTasks( void ) do { 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. */ /* Fill in an TaskStatus_t structure with information on each task in the Blocked state. */ - uxTask += prvListTaskWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), ( List_t * ) pxDelayedTaskList, eBlocked ); - uxTask += prvListTaskWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), ( List_t * ) pxOverflowDelayedTaskList, eBlocked ); + uxTask += prvListTasksWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), ( List_t * ) pxDelayedTaskList, eBlocked ); + uxTask += prvListTasksWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), ( List_t * ) pxOverflowDelayedTaskList, eBlocked ); #if( INCLUDE_vTaskDelete == 1 ) { /* Fill in an TaskStatus_t structure with information on each task that has been deleted but not yet cleaned up. */ - uxTask += prvListTaskWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &xTasksWaitingTermination, eDeleted ); + uxTask += prvListTasksWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &xTasksWaitingTermination, eDeleted ); } #endif @@ -1907,7 +2053,7 @@ UBaseType_t uxTaskGetNumberOfTasks( void ) { /* Fill in an TaskStatus_t structure with information on each task in the Suspended state. */ - uxTask += prvListTaskWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &xSuspendedTaskList, eSuspended ); + uxTask += prvListTasksWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &xSuspendedTaskList, eSuspended ); } #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 ) - 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; UBaseType_t uxTask = 0; @@ -3286,60 +3521,8 @@ TCB_t *pxNewTCB; do { listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList ); - - 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 - + vTaskGetTaskInfo( ( TaskHandle_t ) pxNextTCB, &( pxTaskStatusArray[ uxTask ] ), pdTRUE, eState ); uxTask++; - } while( pxNextTCB != pxFirstTCB ); } else @@ -3422,7 +3605,7 @@ TCB_t *pxNewTCB; { /* Only free the stack and TCB if they were allocated dynamically in the first place. */ - if( ( pxTCB->ucStaticAllocationFlags & taskSTATICALLY_ALLOCATED_STACK ) == ( UBaseType_t ) 0 ) + if( ( pxTCB->ucStaticAllocationFlags & taskSTATICALLY_ALLOCATED_STACK ) == ( uint8_t ) 0 ) { vPortFreeAligned( pxTCB->pxStack ); } @@ -3431,7 +3614,7 @@ TCB_t *pxNewTCB; mtCOVERAGE_TEST_MARKER(); } - if( ( pxTCB->ucStaticAllocationFlags & taskSTATICALLY_ALLOCATED_TCB ) == ( UBaseType_t ) 0 ) + if( ( pxTCB->ucStaticAllocationFlags & taskSTATICALLY_ALLOCATED_TCB ) == ( uint8_t ) 0 ) { vPortFreeAligned( pxTCB ); } diff --git a/FreeRTOS/Source/timers.c b/FreeRTOS/Source/timers.c index 1dd62ef58..25d816715 100644 --- a/FreeRTOS/Source/timers.c +++ b/FreeRTOS/Source/timers.c @@ -274,7 +274,6 @@ uint16_t usTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH; } #endif /* configSUPPORT_STATIC_ALLOCATION */ - #if ( INCLUDE_xTimerGetTimerDaemonTaskHandle == 1 ) { /* Create the timer task, storing its handle in xTimerTaskHandle so @@ -327,7 +326,7 @@ Timer_t *pxNewTimer; } 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 ) @@ -429,7 +428,7 @@ DaemonTaskMessage_t xMessage; #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; @@ -486,6 +485,18 @@ BaseType_t xListWasEmpty; /* Just to avoid compiler warnings. */ ( 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( ;; ) { /* Query the timers list to see if it contains any timers, and if so, @@ -769,7 +780,7 @@ TickType_t xTimeNow; allocated. */ #if( configSUPPORT_STATIC_ALLOCATION == 1 ) { - if( pxTimer->ucStaticallyAllocated == pdFALSE ) + if( pxTimer->ucStaticallyAllocated == ( uint8_t ) pdFALSE ) { vPortFree( pxTimer ); } -- 2.39.5