1 /*
2  * SPDX-FileCopyrightText: 2017-2021 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include "freertos/FreeRTOS.h"
8 #include "freertos/task_snapshot.h"
9 
10 #ifndef DIM
11 #define DIM(t) (sizeof(t)/ sizeof(*(t)))
12 #endif
13 
14 #if ( configENABLE_TASK_SNAPSHOT == 1 )
15 
prvTaskGetSnapshot(TaskSnapshot_t * pxTaskSnapshotArray,UBaseType_t * uxTask,void * pxTCB)16 	static void prvTaskGetSnapshot( TaskSnapshot_t *pxTaskSnapshotArray, UBaseType_t *uxTask, void *pxTCB )
17 	{
18 		if (pxTCB == NULL) {
19 			return;
20 		}
21 		pxTaskSnapshotArray[ *uxTask ].pxTCB = pxTCB;
22 		pxTaskSnapshotArray[ *uxTask ].pxTopOfStack = (StackType_t *) pxTCBGetTopOfStack(pxTCB);
23 		#if( portSTACK_GROWTH < 0 )
24 		{
25 			pxTaskSnapshotArray[ *uxTask ].pxEndOfStack = pxTCBGetEndOfStack(pxTCB);
26 		}
27 		#else
28 		{
29 			pxTaskSnapshotArray[ *uxTask ].pxEndOfStack = pxTCBGetStartOfStack(pxTCB);
30 		}
31 		#endif
32 		(*uxTask)++;
33 	}
34 
prvTaskGetSnapshotsFromList(TaskSnapshot_t * pxTaskSnapshotArray,UBaseType_t * uxTask,const UBaseType_t uxArraySize,List_t * pxList)35 	static void prvTaskGetSnapshotsFromList( TaskSnapshot_t *pxTaskSnapshotArray, UBaseType_t *uxTask, const UBaseType_t uxArraySize, List_t *pxList )
36 	{
37 		void *pxNextTCB = NULL;
38 		void *pxFirstTCB = NULL;
39 
40 		if( listCURRENT_LIST_LENGTH( pxList ) > ( UBaseType_t ) 0 )
41 		{
42 			listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList );
43 			do
44 			{
45 				if( *uxTask >= uxArraySize ) {
46 					break;
47 				}
48 
49 				listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList );
50 				prvTaskGetSnapshot( pxTaskSnapshotArray, uxTask, pxNextTCB );
51 			} while( pxNextTCB != pxFirstTCB );
52 		}
53 		else
54 		{
55 			mtCOVERAGE_TEST_MARKER();
56 		}
57 	}
58 
uxTaskGetSnapshotAll(TaskSnapshot_t * const pxTaskSnapshotArray,const UBaseType_t uxArraySize,UBaseType_t * const pxTcbSz)59 	UBaseType_t uxTaskGetSnapshotAll( TaskSnapshot_t * const pxTaskSnapshotArray, const UBaseType_t uxArraySize, UBaseType_t * const pxTcbSz )
60 	{
61 		UBaseType_t uxTask = 0;
62 		UBaseType_t i = 0;
63 
64 
65 		*pxTcbSz = pxTCBGetSize();
66 		/* Fill in an TaskStatus_t structure with information on each
67 		task in the Ready state. */
68 		i = configMAX_PRIORITIES;
69 		do
70 		{
71 			i--;
72 			prvTaskGetSnapshotsFromList( pxTaskSnapshotArray, &uxTask, uxArraySize, pxListGetReadyTask(i) );
73 		} while( i > ( UBaseType_t ) tskIDLE_PRIORITY ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
74 
75 		/* Fill in an TaskStatus_t structure with information on each
76 		task in the Blocked state. */
77 		prvTaskGetSnapshotsFromList( pxTaskSnapshotArray, &uxTask, uxArraySize, pxGetDelayedTaskList() );
78 		prvTaskGetSnapshotsFromList( pxTaskSnapshotArray, &uxTask, uxArraySize, pxGetOverflowDelayedTaskList() );
79 		for (i = 0; i < configNUM_CORES; i++) {
80 			if( uxTask >= uxArraySize ) {
81 				break;
82 			}
83 			prvTaskGetSnapshotsFromList( pxTaskSnapshotArray, &uxTask, uxArraySize, pxListGetReadyPendingTask(i) );
84 		}
85 
86 		#if( INCLUDE_vTaskDelete == 1 )
87 		{
88 			prvTaskGetSnapshotsFromList( pxTaskSnapshotArray, &uxTask, uxArraySize, pxGetTasksWaitingTermination() );
89 		}
90 		#endif
91 
92 		#if ( INCLUDE_vTaskSuspend == 1 )
93 		{
94 			prvTaskGetSnapshotsFromList( pxTaskSnapshotArray, &uxTask, uxArraySize, pxGetSuspendedTaskList() );
95 		}
96 		#endif
97 		return uxTask;
98 	}
99 
prvFirstTaskGet(List_t * pxList)100 	static void *prvFirstTaskGet( List_t *pxList )
101 	{
102 		ListItem_t *pxListItem = listGET_HEAD_ENTRY( pxList );
103 		if( pxListItem != listGET_END_MARKER( pxList ) ) {
104 			return listGET_LIST_ITEM_OWNER( pxListItem );
105 		}
106 		return NULL;
107 	}
108 
prvNextTaskGet(void * pxTCB)109 	static void *prvNextTaskGet( void *pxTCB )
110 	{
111 		List_t *pxList = listLIST_ITEM_CONTAINER( pxTCBGetStateListItem(pxTCB) );
112 		ListItem_t *pxListItem = listGET_NEXT( pxTCBGetStateListItem(pxTCB) );
113 		if( pxListItem != listGET_END_MARKER( pxList ) ) {
114 			return listGET_LIST_ITEM_OWNER( pxListItem );
115 		}
116 		return NULL;
117 	}
118 
vTaskGetSnapshot(TaskHandle_t pxTask,TaskSnapshot_t * pxTaskSnapshot)119 	void vTaskGetSnapshot( TaskHandle_t pxTask, TaskSnapshot_t *pxTaskSnapshot )
120 	{
121 		configASSERT( portVALID_TCB_MEM(pxTask) );
122 		configASSERT( pxTaskSnapshot != NULL );
123 		pxTaskSnapshot->pxTCB = (void*) pxTask;
124 		pxTaskSnapshot->pxTopOfStack = pxTCBGetTopOfStack((void*) pxTask);
125 		pxTaskSnapshot->pxEndOfStack = pxTCBGetEndOfStack((void*) pxTask);
126 	}
127 
pxTaskGetNext(TaskHandle_t pxTask)128 	TaskHandle_t pxTaskGetNext( TaskHandle_t pxTask )
129 	{
130 		void *pxTCB = pxTask;
131 		List_t *pxTaskList = NULL;
132 		UBaseType_t i = configMAX_PRIORITIES;
133 		UBaseType_t bCurTaskListFound = pdFALSE;
134 		List_t *task_lists[] = {
135 			pxGetDelayedTaskList(),
136 			pxGetOverflowDelayedTaskList(),
137 		#if( INCLUDE_vTaskDelete == 1 )
138 			pxGetTasksWaitingTermination(),
139 		#endif
140 		#if( INCLUDE_vTaskSuspend == 1 )
141 			pxGetSuspendedTaskList()
142 		#endif
143 		};
144 
145 		if( pxTask != NULL && !portVALID_TCB_MEM(pxTask) ) {
146 			return NULL;
147 		}
148 
149 		if( pxTCB != NULL ) {
150 			pxTCB = prvNextTaskGet( pxTCB );
151 			if( pxTCB != NULL ) {
152 				// take care not to return garbage
153 				return portVALID_TCB_MEM(pxTCB) ? pxTCB : NULL;
154 			}
155 			pxTaskList = listLIST_ITEM_CONTAINER( pxTCBGetStateListItem(pxTask) );
156 		}
157 		/* ready tasks lists */
158 		do
159 		{
160 			i--;
161 			List_t *pxList = pxListGetReadyTask(i);
162 			if( bCurTaskListFound == pdFALSE && pxTaskList != NULL ) {
163 				/* need to find list the current task item from */
164 				if( pxTaskList == pxList ) {
165 					bCurTaskListFound = pdTRUE;
166 				}
167 				continue; /* go to the next 'ready list' */
168 			}
169 			pxTCB = prvFirstTaskGet( pxList );
170 			if( pxTCB != NULL ) {
171 				// take care not to return garbage
172 				return portVALID_TCB_MEM(pxTCB) ? pxTCB : NULL;
173 		}
174 		}
175 		while( i > tskIDLE_PRIORITY );
176 		/* pending ready tasks lists */
177 		for (i = 0; i < configNUM_CORES; i++) {
178 			List_t *pxList = pxListGetReadyPendingTask(i);
179 			if( bCurTaskListFound == pdFALSE && pxTaskList != NULL ) {
180 				/* need to find list the current task item from */
181 				if( pxTaskList == pxList ) {
182 					bCurTaskListFound = pdTRUE;
183 				}
184 				continue; /* go to the next 'ready list' */
185 			}
186 			pxTCB = prvFirstTaskGet( pxList );
187 			if( pxTCB != NULL ) {
188 				// take care not to return garbage
189 				return portVALID_TCB_MEM(pxTCB) ? pxTCB : NULL;
190 			}
191 		}
192 		/* other tasks lists */
193 		for (i = 0; i < DIM(task_lists); i++) {
194 			List_t *pxList = task_lists[ i ];
195 			if( bCurTaskListFound == pdFALSE && pxTaskList != NULL ) {
196 				/* need to find list the current task item from */
197 				if( pxTaskList == pxList ) {
198 					bCurTaskListFound = pdTRUE;
199 				}
200 				continue; /* go to the next 'ready list' */
201 			}
202 			pxTCB = prvFirstTaskGet( pxList );
203 			if( pxTCB != NULL ) {
204 				// take care not to return garbage
205 				return portVALID_TCB_MEM(pxTCB) ? pxTCB : NULL;
206 			}
207 		}
208 
209 		return NULL;
210 	}
211 
212 #endif
213