esp32: SEGGER SystemView Tracing Support

Implements support for system level traces compatible with SEGGER
SystemView tool on top of ESP32 application tracing module.
That kind of traces can help to analyse program's behaviour.
SystemView can show timeline of tasks/ISRs execution, context switches,
statistics related to the CPUs' load distribution etc.

Also this commit adds useful feature to ESP32 application tracing module:
 - Trace data buffering is implemented to handle temporary peaks of events load
This commit is contained in:
Alexey Gerenkov
2017-06-27 20:52:43 +03:00
parent 8eeaef6eb6
commit 8d43859b6a
51 changed files with 7769 additions and 600 deletions
+3
View File
@@ -6,3 +6,6 @@ COMPONENT_ADD_LDFLAGS = -l$(COMPONENT_NAME) -Wl,--undefined=uxTopUsedPriority
COMPONENT_ADD_INCLUDEDIRS := include
COMPONENT_PRIV_INCLUDEDIRS := include/freertos
#ifdef CONFIG_SYSVIEW_ENABLE
#COMPONENT_ADD_INCLUDEDIRS += app_trace
#endif
@@ -204,6 +204,10 @@ extern "C" {
#define INCLUDE_uxTaskGetStackHighWaterMark 0
#endif
#ifndef INCLUDE_pxTaskGetStackStart
#define INCLUDE_pxTaskGetStackStart 0
#endif
#ifndef INCLUDE_eTaskGetState
#define INCLUDE_eTaskGetState 0
#endif
@@ -406,6 +410,22 @@ extern "C" {
#define traceMOVED_TASK_TO_READY_STATE( pxTCB )
#endif
#ifndef traceREADDED_TASK_TO_READY_STATE
#define traceREADDED_TASK_TO_READY_STATE( pxTCB ) traceMOVED_TASK_TO_READY_STATE( pxTCB )
#endif
#ifndef traceMOVED_TASK_TO_DELAYED_LIST
#define traceMOVED_TASK_TO_DELAYED_LIST()
#endif
#ifndef traceMOVED_TASK_TO_OVERFLOW_DELAYED_LIST
#define traceMOVED_TASK_TO_OVERFLOW_DELAYED_LIST()
#endif
#ifndef traceMOVED_TASK_TO_SUSPENDED_LIST
#define traceMOVED_TASK_TO_SUSPENDED_LIST( pxTCB )
#endif
#ifndef traceQUEUE_CREATE
#define traceQUEUE_CREATE( pxNewQueue )
#endif
@@ -618,6 +638,22 @@ extern "C" {
#define traceQUEUE_REGISTRY_ADD(xQueue, pcQueueName)
#endif
#ifndef traceTASK_NOTIFY_GIVE_FROM_ISR
#define traceTASK_NOTIFY_GIVE_FROM_ISR()
#endif
#ifndef traceISR_EXIT_TO_SCHEDULER
#define traceISR_EXIT_TO_SCHEDULER()
#endif
#ifndef traceISR_EXIT
#define traceISR_EXIT()
#endif
#ifndef traceISR_ENTER
#define traceISR_ENTER(_n_)
#endif
#ifndef configGENERATE_RUN_TIME_STATS
#define configGENERATE_RUN_TIME_STATS 0
#endif
@@ -227,6 +227,7 @@
#define INCLUDE_vTaskDelay 1
#define INCLUDE_uxTaskGetStackHighWaterMark 1
#define INCLUDE_pcTaskGetTaskName 1
#define INCLUDE_xTaskGetIdleTaskHandle 1
#if CONFIG_ENABLE_MEMORY_DEBUG
#define configENABLE_MEMORY_DEBUG 1
@@ -276,6 +277,12 @@ extern void vPortCleanUpTCB ( void *pxTCB );
#define configENABLE_TASK_SNAPSHOT 1
#endif
#if CONFIG_SYSVIEW_ENABLE
#ifndef __ASSEMBLER__
#include "SEGGER_SYSVIEW_FreeRTOS.h"
#undef INLINE // to avoid redefinition
#endif /* def __ASSEMBLER__ */
#endif
#endif /* FREERTOS_CONFIG_H */
@@ -268,7 +268,7 @@ static inline void uxPortCompareSet(volatile uint32_t *addr, uint32_t compare, u
void vPortYield( void );
void _frxt_setup_switch( void );
#define portYIELD() vPortYield()
#define portYIELD_FROM_ISR() _frxt_setup_switch()
#define portYIELD_FROM_ISR() {traceISR_EXIT_TO_SCHEDULER(); _frxt_setup_switch();}
static inline uint32_t xPortGetCoreID();
@@ -1297,6 +1297,25 @@ char *pcTaskGetTaskName( TaskHandle_t xTaskToQuery ) PRIVILEGED_FUNCTION; /*lint
*/
UBaseType_t uxTaskGetStackHighWaterMark( TaskHandle_t xTask ) PRIVILEGED_FUNCTION;
/**
* task.h
* <PRE>uint8_t* pxTaskGetStackStart( TaskHandle_t xTask);</PRE>
*
* INCLUDE_pxTaskGetStackStart must be set to 1 in FreeRTOSConfig.h for
* this function to be available.
*
* Returns the start of the stack associated with xTask. That is,
* the highest stack memory address on architectures where the stack grows down
* from high memory, and the lowest memory address on architectures where the
* stack grows up from low memory.
*
* @param xTask Handle of the task associated with the stack returned.
* Set xTask to NULL to return the stack of the calling task.
*
* @return A pointer to the start of the stack.
*/
uint8_t* pxTaskGetStackStart( TaskHandle_t xTask) PRIVILEGED_FUNCTION;
/* When using trace macros it is sometimes necessary to include task.h before
FreeRTOS.h. When this is done TaskHookFunction_t will not yet have been defined,
so the following two prototypes will cause a compilation error. This can be
@@ -117,6 +117,14 @@ static inline void xt_set_intclear(unsigned int arg)
xthal_set_intclear(arg);
}
/*
-------------------------------------------------------------------------------
Call this function to get handler's argument for the specified interrupt.
n - Interrupt number.
-------------------------------------------------------------------------------
*/
extern void * xt_get_interrupt_handler_arg(int n);
#endif /* __XTENSA_API_H__ */
+13 -2
View File
@@ -105,6 +105,8 @@
#include "esp_crosscore_int.h"
#include "esp_intr_alloc.h"
/* Defined in portasm.h */
extern void _frxt_tick_timer_init(void);
@@ -112,6 +114,13 @@ extern void _frxt_tick_timer_init(void);
extern void _xt_coproc_init(void);
#if CONFIG_FREERTOS_CORETIMER_0
#define SYSTICK_INTR_ID (ETS_INTERNAL_TIMER0_INTR_SOURCE+ETS_INTERNAL_INTR_SOURCE_OFF)
#endif
#if CONFIG_FREERTOS_CORETIMER_1
#define SYSTICK_INTR_ID (ETS_INTERNAL_TIMER1_INTR_SOURCE+ETS_INTERNAL_INTR_SOURCE_OFF)
#endif
/*-----------------------------------------------------------*/
unsigned port_xSchedulerRunning[portNUM_PROCESSORS] = {0}; // Duplicate of inaccessible xSchedulerRunning; needed at startup to avoid counting nesting
@@ -122,7 +131,7 @@ unsigned port_interruptNesting[portNUM_PROCESSORS] = {0}; // Interrupt nesting
// User exception dispatcher when exiting
void _xt_user_exit(void);
/*
/*
* Stack initialization
*/
#if portUSING_MPU_WRAPPERS
@@ -222,12 +231,14 @@ BaseType_t xPortSysTickHandler( void )
BaseType_t ret;
portbenchmarkIntLatency();
traceISR_ENTER(SYSTICK_INTR_ID);
ret = xTaskIncrementTick();
if( ret != pdFALSE )
{
portYIELD_FROM_ISR();
} else {
traceISR_EXIT();
}
return ret;
}
+1 -1
View File
@@ -30,7 +30,6 @@
.extern pxCurrentTCB
/*
*******************************************************************************
* Interrupt stack. The size of the interrupt stack is determined by the config
@@ -42,6 +41,7 @@
.align 16
.global port_IntStack
.global port_IntStackTop
.global port_switch_flag
port_IntStack:
.space configISR_STACK_SIZE*portNUM_PROCESSORS /* This allocates stacks for each individual CPU. */
port_IntStackTop:
+4 -4
View File
@@ -70,7 +70,7 @@
/*
ToDo: The multicore implementation of this uses taskENTER_CRITICAL etc to make sure the
ToDo: The multicore implementation of this uses taskENTER_CRITICAL etc to make sure the
queue structures aren't accessed by another processor or core. It would be useful to have
IRQs be able to schedule stuff while doing task-related stuff, meaning we have to convert
the taskENTER_CRITICAL stuff to a lock + a scheduler suspend instead.
@@ -262,7 +262,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
configASSERT( pxQueue );
if ( xNewQueue == pdTRUE )
if ( xNewQueue == pdTRUE )
{
vPortCPUInitializeMutex(&pxQueue->mux);
}
@@ -1181,7 +1181,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
if( ( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) || ( xCopyPosition == queueOVERWRITE ) )
{
traceQUEUE_SEND_FROM_ISR( pxQueue );
/* A task can only have an inherited priority if it is a mutex
holder - and if there is a mutex holder then the mutex cannot be
given from an ISR. Therefore, unlike the xQueueGenericGive()
@@ -2315,7 +2315,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
void vQueueAddToRegistry( QueueHandle_t xQueue, const char *pcQueueName ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
{
UBaseType_t ux;
UNTESTED_FUNCTION();
/* See if there is an empty space in the registry. A NULL name denotes
a free slot. */
+114 -73
View File
@@ -277,7 +277,7 @@ PRIVILEGED_DATA static List_t xPendingReadyList[ portNUM_PROCESSORS ]; /*<
#if ( INCLUDE_xTaskGetIdleTaskHandle == 1 )
PRIVILEGED_DATA static TaskHandle_t xIdleTaskHandle = NULL; /*< Holds the handle of the idle task. The idle task is created automatically when the scheduler is started. */
PRIVILEGED_DATA static TaskHandle_t xIdleTaskHandle[portNUM_PROCESSORS] = {NULL}; /*< Holds the handle of the idle task. The idle task is created automatically when the scheduler is started. */
#endif
@@ -314,6 +314,12 @@ PRIVILEGED_DATA static portMUX_TYPE xTickCountMutex = portMUX_INITIALIZER_UNLOCK
#endif
// per-CPU flags indicating that we are doing context switch, it is used by apptrace and sysview modules
// in order to avoid calls of vPortYield from traceTASK_SWITCHED_IN/OUT when waiting
// for locks to be free or for host to read full trace buffer
PRIVILEGED_DATA static volatile BaseType_t xSwitchingContext[ portNUM_PROCESSORS ] = { pdFALSE };
/*lint +e956 */
/* Debugging and trace facilities private variables and macros. ------------*/
@@ -436,12 +442,20 @@ count overflows. */
* the task. It is inserted at the end of the list.
*/
#define prvAddTaskToReadyList( pxTCB ) \
traceMOVED_TASK_TO_READY_STATE( pxTCB ) \
traceMOVED_TASK_TO_READY_STATE( pxTCB ); \
taskRECORD_READY_PRIORITY( ( pxTCB )->uxPriority ); \
vListInsertEnd( &( pxReadyTasksLists[ ( pxTCB )->uxPriority ] ), &( ( pxTCB )->xGenericListItem ) )
/*
* Place the task represented by pxTCB which has been in a ready list before
* into the appropriate ready list for the task.
* It is inserted at the end of the list.
*/
#define prvReaddTaskToReadyList( pxTCB ) \
traceREADDED_TASK_TO_READY_STATE( pxTCB ); \
taskRECORD_READY_PRIORITY( ( pxTCB )->uxPriority ); \
vListInsertEnd( &( pxReadyTasksLists[ ( pxTCB )->uxPriority ] ), &( ( pxTCB )->xGenericListItem ) )
/*-----------------------------------------------------------*/
#define tskCAN_RUN_HERE( cpuid ) ( cpuid==xPortGetCoreID() || cpuid==tskNO_AFFINITY )
/*
@@ -621,7 +635,7 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode
/*
* This routine tries to send an interrupt to another core if needed to make it execute a task
* of higher priority. We try to figure out if needed first by inspecting the pxTCB of the
* of higher priority. We try to figure out if needed first by inspecting the pxTCB of the
* other CPU first. Specifically for Xtensa, we can do this because pxTCB is an atomic pointer. It
* is possible that it is inaccurate because the other CPU just did a task switch, but in that case
* at most a superfluous interrupt is generated.
@@ -1046,8 +1060,8 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode
{
TCB_t *curTCB, *tcb0, *tcb1;
/* Assure that xCoreID is valid or we'll have an out-of-bounds on pxCurrentTCB
You will assert here if e.g. you only have one CPU enabled in menuconfig and
/* Assure that xCoreID is valid or we'll have an out-of-bounds on pxCurrentTCB
You will assert here if e.g. you only have one CPU enabled in menuconfig and
are trying to start a task on core 1. */
configASSERT( xCoreID == tskNO_AFFINITY || xCoreID < portNUM_PROCESSORS);
@@ -1609,7 +1623,7 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode
{
xYieldRequired = pdTRUE;
}
else if ( pxTCB->xCoreID != xPortGetCoreID() )
else if ( pxTCB->xCoreID != xPortGetCoreID() )
{
taskYIELD_OTHER_CORE( pxTCB->xCoreID, uxNewPriority );
}
@@ -1697,7 +1711,7 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode
{
mtCOVERAGE_TEST_MARKER();
}
prvAddTaskToReadyList( pxTCB );
prvReaddTaskToReadyList( pxTCB );
}
else
{
@@ -1758,7 +1772,7 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode
{
mtCOVERAGE_TEST_MARKER();
}
traceMOVED_TASK_TO_SUSPENDED_LIST(pxTCB);
vListInsertEnd( &xSuspendedTaskList, &( pxTCB->xGenericListItem ) );
curTCB = pxCurrentTCB[ xPortGetCoreID() ];
}
@@ -2064,7 +2078,7 @@ void vTaskEndScheduler( void )
#if ( configUSE_NEWLIB_REENTRANT == 1 )
//Return global reent struct if FreeRTOS isn't running,
//Return global reent struct if FreeRTOS isn't running,
struct _reent* __getreent() {
//No lock needed because if this changes, we won't be running anymore.
TCB_t *currTask=xTaskGetCurrentTaskHandle();
@@ -2353,8 +2367,8 @@ UBaseType_t uxTaskGetNumberOfTasks( void )
{
/* If xTaskGetIdleTaskHandle() is called before the scheduler has been
started, then xIdleTaskHandle will be NULL. */
configASSERT( ( xIdleTaskHandle != NULL ) );
return xIdleTaskHandle;
configASSERT( ( xIdleTaskHandle[ xPortGetCoreID() ] != NULL ) );
return xIdleTaskHandle[ xPortGetCoreID() ];
}
#endif /* INCLUDE_xTaskGetIdleTaskHandle */
@@ -2393,7 +2407,7 @@ BaseType_t xSwitchRequired = pdFALSE;
/* Only let core 0 increase the tick count, to keep accurate track of time. */
/* ToDo: This doesn't really play nice with the logic below: it means when core 1 is
running a low-priority task, it will keep running it until there is a context
running a low-priority task, it will keep running it until there is a context
switch, even when this routine (running on core 0) unblocks a bunch of high-priority
tasks... this is less than optimal -- JD. */
if ( xPortGetCoreID()!=0 ) {
@@ -2688,6 +2702,7 @@ void vTaskSwitchContext( void )
else
{
xYieldPending[ xPortGetCoreID() ] = pdFALSE;
xSwitchingContext[ xPortGetCoreID() ] = pdTRUE;
traceTASK_SWITCHED_OUT();
#if ( configGENERATE_RUN_TIME_STATS == 1 )
@@ -2724,7 +2739,7 @@ void vTaskSwitchContext( void )
taskSECOND_CHECK_FOR_STACK_OVERFLOW();
/* Select a new task to run */
/*
We cannot do taskENTER_CRITICAL_ISR(&xTaskQueueMutex); here because it saves the interrupt context to the task tcb, and we're
swapping that out here. Instead, we're going to do the work here ourselves. Because interrupts are already disabled, we only
@@ -2735,11 +2750,11 @@ void vTaskSwitchContext( void )
#else
vPortCPUAcquireMutex( &xTaskQueueMutex );
#endif
unsigned portBASE_TYPE foundNonExecutingWaiter = pdFALSE, ableToSchedule = pdFALSE, resetListHead;
portBASE_TYPE uxDynamicTopReady = uxTopReadyPriority;
unsigned portBASE_TYPE holdTop=pdFALSE;
/*
* ToDo: This scheduler doesn't correctly implement the round-robin scheduling as done in the single-core
* FreeRTOS stack when multiple tasks have the same priority and are all ready; it just keeps grabbing the
@@ -2747,21 +2762,21 @@ void vTaskSwitchContext( void )
* (Is this still true? if any, there's the issue with one core skipping over the processes for the other
* core, potentially not giving the skipped-over processes any time.)
*/
while ( ableToSchedule == pdFALSE && uxDynamicTopReady >= 0 )
{
resetListHead = pdFALSE;
// Nothing to do for empty lists
if (!listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxDynamicTopReady ] ) )) {
ableToSchedule = pdFALSE;
tskTCB * pxRefTCB;
/* Remember the current list item so that we
can detect if all items have been inspected.
Once this happens, we move on to a lower
priority list (assuming nothing is suitable
for scheduling). Note: This can return NULL if
for scheduling). Note: This can return NULL if
the list index is at the listItem */
pxRefTCB = pxReadyTasksLists[ uxDynamicTopReady ].pxIndex->pvOwner;
@@ -2769,7 +2784,7 @@ void vTaskSwitchContext( void )
//pxIndex points to the list end marker. Skip that and just get the next item.
listGET_OWNER_OF_NEXT_ENTRY( pxRefTCB, &( pxReadyTasksLists[ uxDynamicTopReady ] ) );
}
do {
listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &( pxReadyTasksLists[ uxDynamicTopReady ] ) );
/* Find out if the next task in the list is
@@ -2785,7 +2800,7 @@ void vTaskSwitchContext( void )
break;
}
}
if (foundNonExecutingWaiter == pdTRUE) {
/* If the task is not being executed
by another core and its affinity is
@@ -2804,7 +2819,7 @@ void vTaskSwitchContext( void )
} else {
ableToSchedule = pdFALSE;
}
if (ableToSchedule == pdFALSE) {
resetListHead = pdTRUE;
} else if ((ableToSchedule == pdTRUE) && (resetListHead == pdTRUE)) {
@@ -2821,6 +2836,7 @@ void vTaskSwitchContext( void )
}
traceTASK_SWITCHED_IN();
xSwitchingContext[ xPortGetCoreID() ] = pdFALSE;
//Exit critical region manually as well: release the mux now, interrupts will be re-enabled when we
//exit the function.
@@ -2834,7 +2850,6 @@ void vTaskSwitchContext( void )
vPortSetStackWatchpoint(pxCurrentTCB[xPortGetCoreID()]->pxStack);
#endif
}
portEXIT_CRITICAL_NESTED(irqstate);
}
@@ -2875,6 +2890,7 @@ TickType_t xTimeToWake;
/* Add the task to the suspended task list instead of a delayed task
list to ensure the task is not woken by a timing event. It will
block indefinitely. */
traceMOVED_TASK_TO_SUSPENDED_LIST(pxCurrentTCB);
vListInsertEnd( &xSuspendedTaskList, &( pxCurrentTCB[ xPortGetCoreID() ]->xGenericListItem ) );
}
else
@@ -3567,7 +3583,7 @@ static void prvCheckTasksWaitingTermination( void )
break;
}
}
#if ( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 ) && ( configTHREAD_LOCAL_STORAGE_DELETE_CALLBACKS )
{
int x;
@@ -3586,7 +3602,7 @@ static void prvCheckTasksWaitingTermination( void )
{
mtCOVERAGE_TEST_MARKER();
}
}
}
taskEXIT_CRITICAL(&xTaskQueueMutex);
}
#endif /* vTaskDelete */
@@ -3601,11 +3617,13 @@ static void prvAddCurrentTaskToDelayedList( const BaseType_t xCoreID, const Tick
if( xTimeToWake < xTickCount )
{
traceMOVED_TASK_TO_OVERFLOW_DELAYED_LIST();
/* Wake time has overflowed. Place this item in the overflow list. */
vListInsert( pxOverflowDelayedTaskList, &( pxCurrentTCB[ xCoreID ]->xGenericListItem ) );
}
else
{
traceMOVED_TASK_TO_DELAYED_LIST();
/* The wake time has not overflowed, so the current block list is used. */
vListInsert( pxDelayedTaskList, &( pxCurrentTCB[ xCoreID ]->xGenericListItem ) );
@@ -3749,7 +3767,6 @@ BaseType_t xTaskGetAffinity( TaskHandle_t xTask )
uint8_t *pucEndOfStack;
UBaseType_t uxReturn;
UNTESTED_FUNCTION();
pxTCB = prvGetTCBFromHandle( xTask );
#if portSTACK_GROWTH < 0
@@ -3770,6 +3787,19 @@ BaseType_t xTaskGetAffinity( TaskHandle_t xTask )
#endif /* INCLUDE_uxTaskGetStackHighWaterMark */
/*-----------------------------------------------------------*/
#if (INCLUDE_pxTaskGetStackStart == 1)
uint8_t* pxTaskGetStackStart( TaskHandle_t xTask)
{
TCB_t *pxTCB;
UBaseType_t uxReturn;
pxTCB = prvGetTCBFromHandle( xTask );
return ( uint8_t * ) pxTCB->pxStack;
}
#endif /* INCLUDE_pxTaskGetStackStart */
/*-----------------------------------------------------------*/
#if ( INCLUDE_vTaskDelete == 1 )
@@ -3954,7 +3984,7 @@ TCB_t *pxTCB;
/* Inherit the priority before being moved into the new list. */
pxTCB->uxPriority = pxCurrentTCB[ xPortGetCoreID() ]->uxPriority;
prvAddTaskToReadyList( pxTCB );
prvReaddTaskToReadyList( pxTCB );
}
else
{
@@ -4025,7 +4055,7 @@ TCB_t *pxTCB;
any other purpose if this task is running, and it must be
running to give back the mutex. */
listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxTCB->uxPriority ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
prvAddTaskToReadyList( pxTCB );
prvReaddTaskToReadyList( pxTCB );
/* Return true to indicate that a context switch is required.
This is only actually required in the corner case whereby
@@ -4066,7 +4096,7 @@ TCB_t *pxTCB;
/* Gotcha (which seems to be deliberate in FreeRTOS, according to
http://www.freertos.org/FreeRTOS_Support_Forum_Archive/December_2012/freertos_PIC32_Bug_-_vTaskEnterCritical_6400806.html
) is that calling vTaskEnterCritical followed by vTaskExitCritical will leave the interrupts DISABLED when the scheduler
is not running. Re-enabling the scheduler will re-enable the interrupts instead.
is not running. Re-enabling the scheduler will re-enable the interrupts instead.
For ESP32 FreeRTOS, vTaskEnterCritical implements both portENTER_CRITICAL and portENTER_CRITICAL_ISR.
*/
@@ -4112,11 +4142,11 @@ For ESP32 FreeRTOS, vTaskEnterCritical implements both portENTER_CRITICAL and po
protect against recursive calls if the assert function also uses a
critical section. */
/* DISABLED in the esp32 port - because of SMP, For ESP32
FreeRTOS, vTaskEnterCritical implements both
/* DISABLED in the esp32 port - because of SMP, For ESP32
FreeRTOS, vTaskEnterCritical implements both
portENTER_CRITICAL and portENTER_CRITICAL_ISR. vTaskEnterCritical
has to be used in way more places than before, and some are called
both from ISR as well as non-ISR code, thus we re-organized
both from ISR as well as non-ISR code, thus we re-organized
vTaskEnterCritical to also work in ISRs. */
#if 0
if( pxCurrentTCB[ xPortGetCoreID() ]->uxCriticalNesting == 1 )
@@ -4177,7 +4207,7 @@ For ESP32 FreeRTOS, vTaskExitCritical implements both portEXIT_CRITICAL and port
mtCOVERAGE_TEST_MARKER();
}
}
#endif /* portCRITICAL_NESTING_IN_TCB */
/*-----------------------------------------------------------*/
@@ -4508,6 +4538,7 @@ TickType_t uxReturn;
of a delayed task list to ensure the task is not
woken by a timing event. It will block
indefinitely. */
traceMOVED_TASK_TO_SUSPENDED_LIST(pxCurrentTCB);
vListInsertEnd( &xSuspendedTaskList, &( pxCurrentTCB[ xPortGetCoreID() ]->xGenericListItem ) );
}
else
@@ -4624,6 +4655,7 @@ TickType_t uxReturn;
of a delayed task list to ensure the task is not
woken by a timing event. It will block
indefinitely. */
traceMOVED_TASK_TO_SUSPENDED_LIST(pxCurrentTCB);
vListInsertEnd( &xSuspendedTaskList, &( pxCurrentTCB[ xPortGetCoreID() ]->xGenericListItem ) );
}
else
@@ -4929,7 +4961,7 @@ TickType_t uxReturn;
this task pending until the scheduler is resumed. */
vListInsertEnd( &( xPendingReadyList[ xPortGetCoreID() ] ), &( pxTCB->xEventListItem ) );
}
if( tskCAN_RUN_HERE(pxTCB->xCoreID) && pxTCB->uxPriority > pxCurrentTCB[ xPortGetCoreID() ]->uxPriority )
{
/* The notified task has a priority above the currently
@@ -4956,6 +4988,22 @@ TickType_t uxReturn;
#if ( configENABLE_TASK_SNAPSHOT == 1 )
static void prvTaskGetSnapshot( TaskSnapshot_t *pxTaskSnapshotArray, UBaseType_t *uxTask, TCB_t *pxTCB )
{
pxTaskSnapshotArray[ *uxTask ].pxTCB = pxTCB;
pxTaskSnapshotArray[ *uxTask ].pxTopOfStack = (StackType_t *)pxTCB->pxTopOfStack;
#if( portSTACK_GROWTH < 0 )
{
pxTaskSnapshotArray[ *uxTask ].pxEndOfStack = pxTCB->pxEndOfStack;
}
#else
{
pxTaskSnapshotArray[ *uxTask ].pxEndOfStack = pxTCB->pxStack;
}
#endif
(*uxTask)++;
}
static void prvTaskGetSnapshotsFromList( TaskSnapshot_t *pxTaskSnapshotArray, UBaseType_t *uxTask, const UBaseType_t uxArraySize, List_t *pxList )
{
TCB_t *pxNextTCB, *pxFirstTCB;
@@ -4970,20 +5018,7 @@ TickType_t uxReturn;
if( *uxTask >= uxArraySize )
break;
pxTaskSnapshotArray[ *uxTask ].pxTCB = pxNextTCB;
pxTaskSnapshotArray[ *uxTask ].pxTopOfStack = (StackType_t *)pxNextTCB->pxTopOfStack;
#if( portSTACK_GROWTH < 0 )
{
pxTaskSnapshotArray[ *uxTask ].pxEndOfStack = pxNextTCB->pxEndOfStack;
}
#else
{
pxTaskSnapshotArray[ *uxTask ].pxEndOfStack = pxNextTCB->pxStack;
}
#endif
(*uxTask)++;
prvTaskGetSnapshot( pxTaskSnapshotArray, uxTask, pxNextTCB );
} while( pxNextTCB != pxFirstTCB );
}
else
@@ -4996,35 +5031,41 @@ TickType_t uxReturn;
{
UBaseType_t uxTask = 0, i = 0;
PRIVILEGED_DATA TCB_t * volatile pxCurrentTCB[ portNUM_PROCESSORS ] = { NULL };
*pxTcbSz = sizeof(TCB_t);
/* Fill in an TaskStatus_t structure with information on each
task in the Ready state. */
i = configMAX_PRIORITIES;
do
{
/* Fill in an TaskStatus_t structure with information on each
task in the Ready state. */
i = configMAX_PRIORITIES;
do
{
i--;
prvTaskGetSnapshotsFromList( pxTaskSnapshotArray, &uxTask, uxArraySize, &( pxReadyTasksLists[ i ] ) );
} while( i > ( UBaseType_t ) tskIDLE_PRIORITY ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
i--;
prvTaskGetSnapshotsFromList( pxTaskSnapshotArray, &uxTask, uxArraySize, &( pxReadyTasksLists[ i ] ) );
} while( i > ( 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. */
prvTaskGetSnapshotsFromList( pxTaskSnapshotArray, &uxTask, uxArraySize, ( List_t * ) pxDelayedTaskList );
prvTaskGetSnapshotsFromList( pxTaskSnapshotArray, &uxTask, uxArraySize, ( List_t * ) pxOverflowDelayedTaskList );
/* Fill in an TaskStatus_t structure with information on each
task in the Blocked state. */
prvTaskGetSnapshotsFromList( pxTaskSnapshotArray, &uxTask, uxArraySize, ( List_t * ) pxDelayedTaskList );
prvTaskGetSnapshotsFromList( pxTaskSnapshotArray, &uxTask, uxArraySize, ( List_t * ) pxOverflowDelayedTaskList );
for (i = 0; i < portNUM_PROCESSORS; i++) {
if( uxTask >= uxArraySize )
break;
prvTaskGetSnapshot( pxTaskSnapshotArray, &uxTask, pxCurrentTCB[ i ] );
prvTaskGetSnapshotsFromList( pxTaskSnapshotArray, &uxTask, uxArraySize, &( xPendingReadyList[ i ] ) );
}
#if( INCLUDE_vTaskDelete == 1 )
{
prvTaskGetSnapshotsFromList( pxTaskSnapshotArray, &uxTask, uxArraySize, &xTasksWaitingTermination );
}
#endif
#if ( INCLUDE_vTaskSuspend == 1 )
{
prvTaskGetSnapshotsFromList( pxTaskSnapshotArray, &uxTask, uxArraySize, &xSuspendedTaskList );
}
#endif
#if( INCLUDE_vTaskDelete == 1 )
{
prvTaskGetSnapshotsFromList( pxTaskSnapshotArray, &uxTask, uxArraySize, &xTasksWaitingTermination );
}
#endif
#if ( INCLUDE_vTaskSuspend == 1 )
{
prvTaskGetSnapshotsFromList( pxTaskSnapshotArray, &uxTask, uxArraySize, &xSuspendedTaskList );
}
#endif
return uxTask;
}
+2 -2
View File
@@ -780,9 +780,9 @@ static void prvCheckForValidListAndQueue( void )
/* Check that the list from which active timers are referenced, and the
queue used to communicate with the timer service, have been
initialised. */
/* Erm, yes, this is a problem. We can't lock until the lock is initialized, and we can't initialize the lock
atomically because we don't have a lock yet... I'm pretty sure doubly-initializing a lock on 2 cpus
atomically because we don't have a lock yet... I'm pretty sure doubly-initializing a lock on 2 cpus
is no problem in the current implementation, but this is not a nice way to solve things. ToDo - improve. */
if( xTimerQueue == NULL ) vPortCPUInitializeMutex( &xTimerMux );
+15
View File
@@ -138,6 +138,21 @@ xt_handler xt_set_interrupt_handler(int n, xt_handler f, void * arg)
return ((old == &xt_unhandled_interrupt) ? 0 : old);
}
#if CONFIG_SYSVIEW_ENABLE
void * xt_get_interrupt_handler_arg(int n)
{
xt_handler_table_entry * entry;
if( n < 0 || n >= XCHAL_NUM_INTERRUPTS )
return 0; /* invalid interrupt number */
/* Convert exception number to _xt_exception_table name */
n = n * portNUM_PROCESSORS + xPortGetCoreID();
entry = _xt_interrupt_table + n;
return entry->arg;
}
#endif
#endif /* XCHAL_HAVE_INTERRUPTS */