1 /*
2  * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #pragma once
8 
9 #include "sdkconfig.h"
10 
11 /**
12  * This file will be included in `tasks.c` file, thus, it must NOT be included
13  * by any (other) file.
14  * The functions below only consist in getters for the static variables in
15  * `tasks.c` file.
16  * The only source files that should call these functions are the ones in
17  * `/additions` directory.
18  */
19 
20 /* ----------------------------------------------------- Newlib --------------------------------------------------------
21  *
22  * ------------------------------------------------------------------------------------------------------------------ */
23 
24 #if ( configUSE_NEWLIB_REENTRANT == 1 )
25 /**
26  * @brief Get reentrancy structure of the current task
27  *
28  * - This funciton is required by newlib (when __DYNAMIC_REENT__ is enabled)
29  * - It will return a pointer to the current task's reent struct
30  * - If FreeRTOS is not running, it will return the global reent struct
31  *
32  * @return Pointer to a the (current taks's)/(globa) reent struct
33  */
__getreent(void)34 struct _reent *__getreent(void)
35 {
36     // No lock needed because if this changes, we won't be running anymore.
37     struct _reent *ret;
38 #if !defined CONFIG_IDF_RTOS_RTTHREAD
39     TCB_t *pxCurTask = xTaskGetCurrentTaskHandle();
40     if (pxCurTask == NULL) {
41         // No task running. Return global struct.
42         ret = _GLOBAL_REENT;
43     } else {
44         // We have a task; return its reentrant struct.
45         ret = &pxCurTask->xNewLib_reent;
46     }
47 #else
48     ret = _GLOBAL_REENT;
49 #endif
50     return ret;
51 }
52 #endif // configUSE_NEWLIB_REENTRANT == 1
53 
54 /* -------------------------------------------------- Task Snapshot ----------------------------------------------------
55  *
56  * ------------------------------------------------------------------------------------------------------------------ */
57 
58 #if CONFIG_FREERTOS_ENABLE_TASK_SNAPSHOT
59 
60 #include "task_snapshot.h"
61 
62 /**
63  * @brief List of all task lists in FreeRTOS
64  *
65  * @note There are currently differing number of task list between SMP FreeRTOS and ESP-IDF FreeRTOS
66  */
67 static List_t *non_ready_task_lists[] = {
68     #ifdef CONFIG_FREERTOS_SMP
69         &xPendingReadyList,
70     #else
71         &xPendingReadyList[0],
72         #ifndef CONFIG_FREERTOS_UNICORE
73             &xPendingReadyList[1],
74         #endif // CONFIG_FREERTOS_UNICORE
75     #endif //CONFIG_FREERTOS_SMP
76     &xDelayedTaskList1,
77     &xDelayedTaskList2,
78     #if( INCLUDE_vTaskDelete == 1 )
79         &xTasksWaitingTermination,
80     #endif
81     #if( INCLUDE_vTaskSuspend == 1 )
82         &xSuspendedTaskList,
83     #endif
84 };
85 
86 /**
87  * @brief Get the next task list to traverse
88  *
89  * - Given a particular task list, this function returns the next task to traverse.
90  * - The task lists are returned in the following precedence
91  *      - Ready lists (highest to lowers priority)
92  *      - Pending ready list(s)
93  *      - Delayed list 1
94  *      - Delayed list 2
95  *      - Waiting termination list
96  *      - Suspended list
97  *
98  * @param pxCurTaskList Previously traversed task list (or NULL if obtaining the first task list)
99  * @return List_t* The next task list to traverse (or NULL of all task lists have been traversed)
100  */
pxGetNextTaskList(List_t * pxCurTaskList)101 static List_t *pxGetNextTaskList(List_t *pxCurTaskList)
102 {
103     List_t *pxNextTaskList = NULL;
104 
105     // No Current List. Start from the highest priority ready task list
106     if (pxCurTaskList == NULL)
107     {
108         pxNextTaskList = &pxReadyTasksLists[configMAX_PRIORITIES - 1];
109     }
110     // Current list is one of the ready task lists. Find the current priority, and return the next lower priority ready task list
111     else if (pxCurTaskList >= &pxReadyTasksLists[0] && pxCurTaskList <= &pxReadyTasksLists[configMAX_PRIORITIES - 1] )
112     {
113         // Find the current priority
114         int cur_priority;
115         for (cur_priority = configMAX_PRIORITIES - 1; cur_priority >= 0; cur_priority--) {
116             if (pxCurTaskList == &pxReadyTasksLists[cur_priority]) {
117                 break;
118             }
119         }
120         // Return the ready task list at (cur_priority - 1), or the pending ready task list
121         if (cur_priority > 0)
122         {
123             pxNextTaskList = &pxReadyTasksLists[cur_priority - 1];
124         }
125         // We've reached the end of the Ready Task Lists.  We get the next list from the non-ready task lists
126         else if (cur_priority == 0)
127         {
128             pxNextTaskList = non_ready_task_lists[0];
129         }
130         else
131         {
132             abort();    // This should never occur
133         }
134     }
135 
136     // Current list is one of the non-ready task lists. Fetch the next non-ready task list
137     if (pxNextTaskList == NULL) {
138         int cur_list_idx;
139         const int num_non_ready_task_lists = (sizeof(non_ready_task_lists) / sizeof(List_t *));
140         // Note: - 1 so that if the current list is the last on non_ready_task_lists[], the next list will return NULL
141         for (cur_list_idx = 0; cur_list_idx < num_non_ready_task_lists - 1; cur_list_idx++) {
142             if (pxCurTaskList == non_ready_task_lists[cur_list_idx]) {
143                 pxNextTaskList = non_ready_task_lists[cur_list_idx + 1];
144                 break;
145             }
146         }
147     }
148 
149     return pxNextTaskList;
150 }
151 
pxTaskGetNext(TaskHandle_t pxTask)152 TaskHandle_t pxTaskGetNext( TaskHandle_t pxTask )
153 {
154     TCB_t *pxTCB = (TCB_t *)pxTask;
155     // Check current task is valid
156     if (pxTCB != NULL && !portVALID_TCB_MEM(pxTCB)) {
157         return NULL;
158     }
159 
160     List_t *pxCurTaskList;
161     const ListItem_t *pxCurListItem;
162     if (pxTCB == NULL) {
163         // Starting traversal for the first time
164         pxCurTaskList = pxGetNextTaskList(NULL);
165         pxCurListItem = listGET_END_MARKER(pxCurTaskList);
166     } else {
167         // Continuing traversal
168         pxCurTaskList = listLIST_ITEM_CONTAINER(&pxTCB->xStateListItem);
169         pxCurListItem = &pxTCB->xStateListItem;
170     }
171 
172     ListItem_t *pxNextListItem = NULL;
173     if (pxCurListItem->pxNext == listGET_END_MARKER(pxCurTaskList)) {
174         List_t *pxNextTaskList = pxGetNextTaskList(pxCurTaskList);
175         while (pxNextTaskList != NULL) {
176             if (!listLIST_IS_EMPTY(pxNextTaskList)) {
177                 // Get the first item in the next task list
178                 pxNextListItem = listGET_HEAD_ENTRY(pxNextTaskList);
179                 break;
180             }
181             // Task list is empty. Get the next task list
182             pxNextTaskList = pxGetNextTaskList(pxNextTaskList);
183         }
184     } else {
185         //There are still more items in the current task list. Get the next item
186         pxNextListItem = listGET_NEXT(pxCurListItem);
187     }
188 
189     TCB_t *pxNextTCB;
190     if (pxNextListItem == NULL) {
191         pxNextTCB = NULL;
192     } else {
193         pxNextTCB = (TCB_t *)listGET_LIST_ITEM_OWNER(pxNextListItem);
194     }
195 
196     return pxNextTCB;
197 }
198 
vTaskGetSnapshot(TaskHandle_t pxTask,TaskSnapshot_t * pxTaskSnapshot)199 BaseType_t vTaskGetSnapshot( TaskHandle_t pxTask, TaskSnapshot_t *pxTaskSnapshot )
200 {
201     if (portVALID_TCB_MEM(pxTask) == false || pxTaskSnapshot == NULL) {
202         return pdFALSE;
203     }
204 
205     TCB_t *pxTCB = (TCB_t *)pxTask;
206     pxTaskSnapshot->pxTCB = pxTCB;
207     pxTaskSnapshot->pxTopOfStack = (StackType_t *)pxTCB->pxTopOfStack;
208     pxTaskSnapshot->pxEndOfStack = (StackType_t *)pxTCB->pxEndOfStack;
209     return pdTRUE;
210 }
211 
uxTaskGetSnapshotAll(TaskSnapshot_t * const pxTaskSnapshotArray,const UBaseType_t uxArrayLength,UBaseType_t * const pxTCBSize)212 UBaseType_t uxTaskGetSnapshotAll( TaskSnapshot_t * const pxTaskSnapshotArray, const UBaseType_t uxArrayLength, UBaseType_t * const pxTCBSize )
213 {
214     UBaseType_t uxArrayNumFilled = 0;
215 
216     //Traverse all of the tasks lists
217     List_t *pxCurTaskList = pxGetNextTaskList(NULL);    //Get the first task list
218     while (pxCurTaskList != NULL && uxArrayNumFilled < uxArrayLength) {
219         if (!listLIST_IS_EMPTY(pxCurTaskList)) {
220             const ListItem_t *pxCurListItem;
221             //Walk each task on the current task list
222             pxCurListItem = listGET_HEAD_ENTRY(pxCurTaskList);
223             while (pxCurListItem != listGET_END_MARKER(pxCurTaskList)) {
224                 TCB_t *pxTCB = (TCB_t *)listGET_LIST_ITEM_OWNER(pxCurListItem);
225                 vTaskGetSnapshot((TaskHandle_t)pxTCB, &pxTaskSnapshotArray[uxArrayNumFilled]);
226                 uxArrayNumFilled++;
227                 if (!(uxArrayNumFilled < uxArrayLength)) {
228                     break;
229                 }
230                 pxCurListItem = listGET_NEXT(pxCurListItem);
231             }
232         }
233         //Get the next task list
234         pxCurTaskList = pxGetNextTaskList(pxCurTaskList);
235     }
236 
237     *pxTCBSize = sizeof(TCB_t);
238     return uxArrayNumFilled;
239 }
240 #endif // CONFIG_FREERTOS_ENABLE_TASK_SNAPSHOT
241 
242 /* ----------------------------------------------------- OpenOCD -------------------------------------------------------
243  *
244  * ------------------------------------------------------------------------------------------------------------------ */
245 
246 #if ( configENABLE_FREERTOS_DEBUG_OCDAWARE == 1 )
247 
248 /**
249  * Debug param indexes. DO NOT change the order. OpenOCD uses the same indexes
250  * Entries in FreeRTOS_openocd_params must match the order of these indexes
251  */
252 enum {
253     ESP_FREERTOS_DEBUG_TABLE_SIZE = 0,
254     ESP_FREERTOS_DEBUG_TABLE_VERSION,
255     ESP_FREERTOS_DEBUG_KERNEL_VER_MAJOR,
256     ESP_FREERTOS_DEBUG_KERNEL_VER_MINOR,
257     ESP_FREERTOS_DEBUG_KERNEL_VER_BUILD,
258     ESP_FREERTOS_DEBUG_UX_TOP_USED_PIORITY,
259     ESP_FREERTOS_DEBUG_PX_TOP_OF_STACK,
260     ESP_FREERTOS_DEBUG_PC_TASK_NAME,
261     /* New entries must be inserted here */
262     ESP_FREERTOS_DEBUG_TABLE_END,
263 };
264 
265 const DRAM_ATTR uint8_t FreeRTOS_openocd_params[ESP_FREERTOS_DEBUG_TABLE_END]  = {
266     ESP_FREERTOS_DEBUG_TABLE_END,       /* table size */
267     1,                                  /* table version */
268     tskKERNEL_VERSION_MAJOR,
269     tskKERNEL_VERSION_MINOR,
270     tskKERNEL_VERSION_BUILD,
271     configMAX_PRIORITIES - 1,           /* uxTopUsedPriority */
272     offsetof(TCB_t, pxTopOfStack),      /* thread_stack_offset; */
273     offsetof(TCB_t, pcTaskName),        /* thread_name_offset; */
274 };
275 
276 #endif // configENABLE_FREERTOS_DEBUG_OCDAWARE == 1
277 
278 /* -------------------------------------------- FreeRTOS IDF API Additions ---------------------------------------------
279  * FreeRTOS related API that were added by IDF
280  * ------------------------------------------------------------------------------------------------------------------ */
281 
282 #if CONFIG_FREERTOS_SMP
283 _Static_assert(tskNO_AFFINITY == CONFIG_FREERTOS_NO_AFFINITY, "CONFIG_FREERTOS_NO_AFFINITY must be the same as tskNO_AFFINITY");
284 
xTaskCreatePinnedToCore(TaskFunction_t pxTaskCode,const char * const pcName,const uint32_t usStackDepth,void * const pvParameters,UBaseType_t uxPriority,TaskHandle_t * const pxCreatedTask,const BaseType_t xCoreID)285 BaseType_t xTaskCreatePinnedToCore( TaskFunction_t pxTaskCode,
286                                     const char * const pcName,
287                                     const uint32_t usStackDepth,
288                                     void * const pvParameters,
289                                     UBaseType_t uxPriority,
290                                     TaskHandle_t * const pxCreatedTask,
291                                     const BaseType_t xCoreID)
292 {
293     BaseType_t ret;
294     #if ( ( configUSE_CORE_AFFINITY == 1 ) && ( configNUM_CORES > 1 ) )
295         {
296             // Convert xCoreID into an affinity mask
297             UBaseType_t uxCoreAffinityMask;
298             if (xCoreID == tskNO_AFFINITY) {
299                 uxCoreAffinityMask = tskNO_AFFINITY;
300             } else {
301                 uxCoreAffinityMask = (1 << xCoreID);
302             }
303             ret = xTaskCreateAffinitySet(pxTaskCode, pcName, usStackDepth, pvParameters, uxPriority, uxCoreAffinityMask, pxCreatedTask);
304         }
305     #else /* ( ( configUSE_CORE_AFFINITY == 1 ) && ( configNUM_CORES > 1 ) ) */
306         {
307             ret = xTaskCreate(pxTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask);
308         }
309     #endif /* ( ( configUSE_CORE_AFFINITY == 1 ) && ( configNUM_CORES > 1 ) ) */
310     return ret;
311 }
312 
313 #if ( configSUPPORT_STATIC_ALLOCATION == 1 )
xTaskCreateStaticPinnedToCore(TaskFunction_t pxTaskCode,const char * const pcName,const uint32_t ulStackDepth,void * const pvParameters,UBaseType_t uxPriority,StackType_t * const puxStackBuffer,StaticTask_t * const pxTaskBuffer,const BaseType_t xCoreID)314 TaskHandle_t xTaskCreateStaticPinnedToCore( TaskFunction_t pxTaskCode,
315                                             const char * const pcName,
316                                             const uint32_t ulStackDepth,
317                                             void * const pvParameters,
318                                             UBaseType_t uxPriority,
319                                             StackType_t * const puxStackBuffer,
320                                             StaticTask_t * const pxTaskBuffer,
321                                             const BaseType_t xCoreID)
322 {
323     TaskHandle_t ret;
324     #if ( ( configUSE_CORE_AFFINITY == 1 ) && ( configNUM_CORES > 1 ) )
325         {
326             // Convert xCoreID into an affinity mask
327             UBaseType_t uxCoreAffinityMask;
328             if (xCoreID == tskNO_AFFINITY) {
329                 uxCoreAffinityMask = tskNO_AFFINITY;
330             } else {
331                 uxCoreAffinityMask = (1 << xCoreID);
332             }
333             ret = xTaskCreateStaticAffinitySet(pxTaskCode, pcName, ulStackDepth, pvParameters, uxPriority, puxStackBuffer, pxTaskBuffer, uxCoreAffinityMask);
334         }
335     #else /* ( ( configUSE_CORE_AFFINITY == 1 ) && ( configNUM_CORES > 1 ) ) */
336         {
337             ret = xTaskCreateStatic(pxTaskCode, pcName, ulStackDepth, pvParameters, uxPriority, puxStackBuffer, pxTaskBuffer);
338         }
339     #endif /* ( ( configUSE_CORE_AFFINITY == 1 ) && ( configNUM_CORES > 1 ) ) */
340     return ret;
341 }
342 #endif /* configSUPPORT_STATIC_ALLOCATION */
343 
xTaskGetCurrentTaskHandleForCPU(BaseType_t xCoreID)344 TaskHandle_t xTaskGetCurrentTaskHandleForCPU( BaseType_t xCoreID )
345 {
346     TaskHandle_t xTaskHandleTemp;
347     assert(xCoreID >= 0 && xCoreID < configNUM_CORES);
348     taskENTER_CRITICAL();
349     xTaskHandleTemp = (TaskHandle_t) pxCurrentTCBs[xCoreID];
350     taskEXIT_CRITICAL();
351     return xTaskHandleTemp;
352 }
353 
xTaskGetIdleTaskHandleForCPU(BaseType_t xCoreID)354 TaskHandle_t xTaskGetIdleTaskHandleForCPU( BaseType_t xCoreID )
355 {
356     assert(xCoreID >= 0 && xCoreID < configNUM_CORES);
357     return (TaskHandle_t) xIdleTaskHandle[xCoreID];
358 }
359 
xTaskGetAffinity(TaskHandle_t xTask)360 BaseType_t xTaskGetAffinity( TaskHandle_t xTask )
361 {
362     taskENTER_CRITICAL();
363     UBaseType_t uxCoreAffinityMask;
364 #if ( configUSE_CORE_AFFINITY == 1 && configNUM_CORES > 1 )
365     TCB_t *pxTCB = prvGetTCBFromHandle( xTask );
366     uxCoreAffinityMask = pxTCB->uxCoreAffinityMask;
367 #else
368     uxCoreAffinityMask = tskNO_AFFINITY;
369 #endif
370     taskEXIT_CRITICAL();
371     BaseType_t ret;
372     // If the task is not pinned to a particular core, treat it as tskNO_AFFINITY
373     if (uxCoreAffinityMask & (uxCoreAffinityMask - 1)) {    // If more than one bit set
374         ret = tskNO_AFFINITY;
375     } else {
376         int index_plus_one = __builtin_ffs(uxCoreAffinityMask);
377         assert(index_plus_one >= 1);
378         ret = index_plus_one - 1;
379     }
380     return ret;
381 }
382 
383 #if ( CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS )
vTaskSetThreadLocalStoragePointerAndDelCallback(TaskHandle_t xTaskToSet,BaseType_t xIndex,void * pvValue,TlsDeleteCallbackFunction_t pvDelCallback)384 void vTaskSetThreadLocalStoragePointerAndDelCallback( TaskHandle_t xTaskToSet, BaseType_t xIndex, void *pvValue, TlsDeleteCallbackFunction_t pvDelCallback)
385     {
386         // Verify that the offsets of pvThreadLocalStoragePointers and pvDummy15 match.
387         // pvDummy15 is part of the StaticTask_t struct and is used to access the TLSPs
388         // while deletion.
389         _Static_assert(offsetof( StaticTask_t, pvDummy15 ) == offsetof( TCB_t, pvThreadLocalStoragePointers ), "Offset of pvDummy15 must match the offset of pvThreadLocalStoragePointers");
390 
391         //Set the local storage pointer first
392         vTaskSetThreadLocalStoragePointer( xTaskToSet, xIndex, pvValue );
393 
394         //Set the deletion callback at an offset of configNUM_THREAD_LOCAL_STORAGE_POINTERS/2
395         vTaskSetThreadLocalStoragePointer( xTaskToSet, ( xIndex + ( configNUM_THREAD_LOCAL_STORAGE_POINTERS / 2 ) ), pvDelCallback );
396     }
397 #endif // CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS
398 
399 #endif // CONFIG_FREERTOS_SMP
400