|
|
@@ -0,0 +1,220 @@
|
|
|
+// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD
|
|
|
+//
|
|
|
+// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
+// you may not use this file except in compliance with the License.
|
|
|
+// You may obtain a copy of the License at
|
|
|
+//
|
|
|
+// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
+//
|
|
|
+// Unless required by applicable law or agreed to in writing, software
|
|
|
+// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
+// See the License for the specific language governing permissions and
|
|
|
+// limitations under the License.
|
|
|
+
|
|
|
+#include "freertos/FreeRTOS.h"
|
|
|
+#include "freertos/task_snapshot.h"
|
|
|
+
|
|
|
+#ifndef DIM
|
|
|
+#define DIM(t) (sizeof(t)/ sizeof(*(t)))
|
|
|
+#endif
|
|
|
+
|
|
|
+#if ( configENABLE_TASK_SNAPSHOT == 1 )
|
|
|
+
|
|
|
+ static void prvTaskGetSnapshot( TaskSnapshot_t *pxTaskSnapshotArray, UBaseType_t *uxTask, void *pxTCB )
|
|
|
+ {
|
|
|
+ if (pxTCB == NULL) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ pxTaskSnapshotArray[ *uxTask ].pxTCB = pxTCB;
|
|
|
+ pxTaskSnapshotArray[ *uxTask ].pxTopOfStack = (StackType_t *) pxTCBGetTopOfStack(pxTCB);
|
|
|
+ #if( portSTACK_GROWTH < 0 )
|
|
|
+ {
|
|
|
+ pxTaskSnapshotArray[ *uxTask ].pxEndOfStack = pxTCBGetEndOfStack(pxTCB);
|
|
|
+ }
|
|
|
+ #else
|
|
|
+ {
|
|
|
+ pxTaskSnapshotArray[ *uxTask ].pxEndOfStack = pxTCBGetStartOfStack(pxTCB);
|
|
|
+ }
|
|
|
+ #endif
|
|
|
+ (*uxTask)++;
|
|
|
+ }
|
|
|
+
|
|
|
+ static void prvTaskGetSnapshotsFromList( TaskSnapshot_t *pxTaskSnapshotArray, UBaseType_t *uxTask, const UBaseType_t uxArraySize, List_t *pxList )
|
|
|
+ {
|
|
|
+ void *pxNextTCB = NULL;
|
|
|
+ void *pxFirstTCB = NULL;
|
|
|
+
|
|
|
+ if( listCURRENT_LIST_LENGTH( pxList ) > ( UBaseType_t ) 0 )
|
|
|
+ {
|
|
|
+ listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList );
|
|
|
+ do
|
|
|
+ {
|
|
|
+ if( *uxTask >= uxArraySize ) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList );
|
|
|
+ prvTaskGetSnapshot( pxTaskSnapshotArray, uxTask, pxNextTCB );
|
|
|
+ } while( pxNextTCB != pxFirstTCB );
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ mtCOVERAGE_TEST_MARKER();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ UBaseType_t uxTaskGetSnapshotAll( TaskSnapshot_t * const pxTaskSnapshotArray, const UBaseType_t uxArraySize, UBaseType_t * const pxTcbSz )
|
|
|
+ {
|
|
|
+ UBaseType_t uxTask = 0;
|
|
|
+ UBaseType_t i = 0;
|
|
|
+
|
|
|
+
|
|
|
+ *pxTcbSz = pxTCBGetSize();
|
|
|
+ /* Fill in an TaskStatus_t structure with information on each
|
|
|
+ task in the Ready state. */
|
|
|
+ i = configMAX_PRIORITIES;
|
|
|
+ do
|
|
|
+ {
|
|
|
+ i--;
|
|
|
+ prvTaskGetSnapshotsFromList( pxTaskSnapshotArray, &uxTask, uxArraySize, pxListGetReadyTask(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, pxGetDelayedTaskList() );
|
|
|
+ prvTaskGetSnapshotsFromList( pxTaskSnapshotArray, &uxTask, uxArraySize, pxGetOverflowDelayedTaskList() );
|
|
|
+ for (i = 0; i < portNUM_PROCESSORS; i++) {
|
|
|
+ if( uxTask >= uxArraySize ) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ prvTaskGetSnapshotsFromList( pxTaskSnapshotArray, &uxTask, uxArraySize, pxListGetReadyPendingTask(i) );
|
|
|
+ }
|
|
|
+
|
|
|
+ #if( INCLUDE_vTaskDelete == 1 )
|
|
|
+ {
|
|
|
+ prvTaskGetSnapshotsFromList( pxTaskSnapshotArray, &uxTask, uxArraySize, pxGetTasksWaitingTermination() );
|
|
|
+ }
|
|
|
+ #endif
|
|
|
+
|
|
|
+ #if ( INCLUDE_vTaskSuspend == 1 )
|
|
|
+ {
|
|
|
+ prvTaskGetSnapshotsFromList( pxTaskSnapshotArray, &uxTask, uxArraySize, pxGetSuspendedTaskList() );
|
|
|
+ }
|
|
|
+ #endif
|
|
|
+ return uxTask;
|
|
|
+ }
|
|
|
+
|
|
|
+ static void *prvFirstTaskGet( List_t *pxList )
|
|
|
+ {
|
|
|
+ ListItem_t *pxListItem = listGET_HEAD_ENTRY( pxList );
|
|
|
+ if( pxListItem != listGET_END_MARKER( pxList ) ) {
|
|
|
+ return listGET_LIST_ITEM_OWNER( pxListItem );
|
|
|
+ }
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ static void *prvNextTaskGet( void *pxTCB )
|
|
|
+ {
|
|
|
+ List_t *pxList = listLIST_ITEM_CONTAINER( pxTCBGetStateListItem(pxTCB) );
|
|
|
+ ListItem_t *pxListItem = listGET_NEXT( pxTCBGetStateListItem(pxTCB) );
|
|
|
+ if( pxListItem != listGET_END_MARKER( pxList ) ) {
|
|
|
+ return listGET_LIST_ITEM_OWNER( pxListItem );
|
|
|
+ }
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ void vTaskGetSnapshot( TaskHandle_t pxTask, TaskSnapshot_t *pxTaskSnapshot )
|
|
|
+ {
|
|
|
+ configASSERT( portVALID_TCB_MEM(pxTask) );
|
|
|
+ configASSERT( pxTaskSnapshot != NULL );
|
|
|
+ pxTaskSnapshot->pxTCB = (void*) pxTask;
|
|
|
+ pxTaskSnapshot->pxTopOfStack = pxTCBGetTopOfStack((void*) pxTask);
|
|
|
+ pxTaskSnapshot->pxEndOfStack = pxTCBGetEndOfStack((void*) pxTask);
|
|
|
+ }
|
|
|
+
|
|
|
+ TaskHandle_t pxTaskGetNext( TaskHandle_t pxTask )
|
|
|
+ {
|
|
|
+ void *pxTCB = pxTask;
|
|
|
+ List_t *pxTaskList = NULL;
|
|
|
+ UBaseType_t i = configMAX_PRIORITIES;
|
|
|
+ UBaseType_t bCurTaskListFound = pdFALSE;
|
|
|
+ List_t *task_lists[] = {
|
|
|
+ pxGetDelayedTaskList(),
|
|
|
+ pxGetOverflowDelayedTaskList(),
|
|
|
+ #if( INCLUDE_vTaskDelete == 1 )
|
|
|
+ pxGetTasksWaitingTermination(),
|
|
|
+ #endif
|
|
|
+ #if( INCLUDE_vTaskSuspend == 1 )
|
|
|
+ pxGetSuspendedTaskList()
|
|
|
+ #endif
|
|
|
+ };
|
|
|
+
|
|
|
+ if( pxTask != NULL && !portVALID_TCB_MEM(pxTask) ) {
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ if( pxTCB != NULL ) {
|
|
|
+ pxTCB = prvNextTaskGet( pxTCB );
|
|
|
+ if( pxTCB != NULL ) {
|
|
|
+ // take care not to return garbage
|
|
|
+ return portVALID_TCB_MEM(pxTCB) ? pxTCB : NULL;
|
|
|
+ }
|
|
|
+ pxTaskList = listLIST_ITEM_CONTAINER( pxTCBGetStateListItem(pxTask) );
|
|
|
+ }
|
|
|
+ /* ready tasks lists */
|
|
|
+ do
|
|
|
+ {
|
|
|
+ i--;
|
|
|
+ List_t *pxList = pxListGetReadyTask(i);
|
|
|
+ if( bCurTaskListFound == pdFALSE && pxTaskList != NULL ) {
|
|
|
+ /* need to find list the current task item from */
|
|
|
+ if( pxTaskList == pxList ) {
|
|
|
+ bCurTaskListFound = pdTRUE;
|
|
|
+ }
|
|
|
+ continue; /* go to the next 'ready list' */
|
|
|
+ }
|
|
|
+ pxTCB = prvFirstTaskGet( pxList );
|
|
|
+ if( pxTCB != NULL ) {
|
|
|
+ // take care not to return garbage
|
|
|
+ return portVALID_TCB_MEM(pxTCB) ? pxTCB : NULL;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ while( i > tskIDLE_PRIORITY );
|
|
|
+ /* pending ready tasks lists */
|
|
|
+ for (i = 0; i < portNUM_PROCESSORS; i++) {
|
|
|
+ List_t *pxList = pxListGetReadyPendingTask(i);
|
|
|
+ if( bCurTaskListFound == pdFALSE && pxTaskList != NULL ) {
|
|
|
+ /* need to find list the current task item from */
|
|
|
+ if( pxTaskList == pxList ) {
|
|
|
+ bCurTaskListFound = pdTRUE;
|
|
|
+ }
|
|
|
+ continue; /* go to the next 'ready list' */
|
|
|
+ }
|
|
|
+ pxTCB = prvFirstTaskGet( pxList );
|
|
|
+ if( pxTCB != NULL ) {
|
|
|
+ // take care not to return garbage
|
|
|
+ return portVALID_TCB_MEM(pxTCB) ? pxTCB : NULL;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /* other tasks lists */
|
|
|
+ for (i = 0; i < DIM(task_lists); i++) {
|
|
|
+ List_t *pxList = task_lists[ i ];
|
|
|
+ if( bCurTaskListFound == pdFALSE && pxTaskList != NULL ) {
|
|
|
+ /* need to find list the current task item from */
|
|
|
+ if( pxTaskList == pxList ) {
|
|
|
+ bCurTaskListFound = pdTRUE;
|
|
|
+ }
|
|
|
+ continue; /* go to the next 'ready list' */
|
|
|
+ }
|
|
|
+ pxTCB = prvFirstTaskGet( pxList );
|
|
|
+ if( pxTCB != NULL ) {
|
|
|
+ // take care not to return garbage
|
|
|
+ return portVALID_TCB_MEM(pxTCB) ? pxTCB : NULL;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+#endif
|