xref: /aosp_15_r20/external/pigweed/pw_thread_freertos/util.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1*61c4878aSAndroid Build Coastguard Worker // Copyright 2021 The Pigweed Authors
2*61c4878aSAndroid Build Coastguard Worker //
3*61c4878aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4*61c4878aSAndroid Build Coastguard Worker // use this file except in compliance with the License. You may obtain a copy of
5*61c4878aSAndroid Build Coastguard Worker // the License at
6*61c4878aSAndroid Build Coastguard Worker //
7*61c4878aSAndroid Build Coastguard Worker //     https://www.apache.org/licenses/LICENSE-2.0
8*61c4878aSAndroid Build Coastguard Worker //
9*61c4878aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*61c4878aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11*61c4878aSAndroid Build Coastguard Worker // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12*61c4878aSAndroid Build Coastguard Worker // License for the specific language governing permissions and limitations under
13*61c4878aSAndroid Build Coastguard Worker // the License.
14*61c4878aSAndroid Build Coastguard Worker #include "pw_thread_freertos/util.h"
15*61c4878aSAndroid Build Coastguard Worker 
16*61c4878aSAndroid Build Coastguard Worker #include "FreeRTOS.h"
17*61c4878aSAndroid Build Coastguard Worker #include "list.h"
18*61c4878aSAndroid Build Coastguard Worker #include "pw_function/function.h"
19*61c4878aSAndroid Build Coastguard Worker #include "pw_log/log.h"
20*61c4878aSAndroid Build Coastguard Worker #include "pw_status/status.h"
21*61c4878aSAndroid Build Coastguard Worker #include "pw_status/try.h"
22*61c4878aSAndroid Build Coastguard Worker #include "task.h"
23*61c4878aSAndroid Build Coastguard Worker 
24*61c4878aSAndroid Build Coastguard Worker // The externed symbols below are all internal FreeRTOS kernel variables from
25*61c4878aSAndroid Build Coastguard Worker // FreeRTOS/Source/tasks.c needed in order to iterate through all of the threads
26*61c4878aSAndroid Build Coastguard Worker // from interrupts which the native APIs do not permit.
27*61c4878aSAndroid Build Coastguard Worker //
28*61c4878aSAndroid Build Coastguard Worker // NOTE: FreeRTOS declares these symbols as `static`, so they are not normally
29*61c4878aSAndroid Build Coastguard Worker // accessible outside of their translation unit. The `static` keyword must be
30*61c4878aSAndroid Build Coastguard Worker // removed by setting `pw_third_party_freertos_DISABLE_TASKS_STATICS` in the
31*61c4878aSAndroid Build Coastguard Worker // builds. See https://pigweed.dev/pw_thread_freertos/#thread-iteration-backend.
32*61c4878aSAndroid Build Coastguard Worker 
33*61c4878aSAndroid Build Coastguard Worker extern "C" PRIVILEGED_DATA volatile BaseType_t xSchedulerRunning;
34*61c4878aSAndroid Build Coastguard Worker 
35*61c4878aSAndroid Build Coastguard Worker extern "C" PRIVILEGED_DATA TaskHandle_t volatile pxCurrentTCB;
36*61c4878aSAndroid Build Coastguard Worker 
37*61c4878aSAndroid Build Coastguard Worker // Prioritised ready tasks.
38*61c4878aSAndroid Build Coastguard Worker extern "C" PRIVILEGED_DATA List_t pxReadyTasksLists[configMAX_PRIORITIES];
39*61c4878aSAndroid Build Coastguard Worker 
40*61c4878aSAndroid Build Coastguard Worker // Points to the delayed task list currently being used.
41*61c4878aSAndroid Build Coastguard Worker extern "C" PRIVILEGED_DATA List_t* volatile pxDelayedTaskList;
42*61c4878aSAndroid Build Coastguard Worker 
43*61c4878aSAndroid Build Coastguard Worker // Points to the delayed task list currently being used to hold tasks that have
44*61c4878aSAndroid Build Coastguard Worker // overflowed the current tick count.
45*61c4878aSAndroid Build Coastguard Worker extern "C" PRIVILEGED_DATA List_t* volatile pxOverflowDelayedTaskList;
46*61c4878aSAndroid Build Coastguard Worker 
47*61c4878aSAndroid Build Coastguard Worker #if INCLUDE_vTaskDelete == 1
48*61c4878aSAndroid Build Coastguard Worker // Tasks that have been deleted - but their memory not yet freed.
49*61c4878aSAndroid Build Coastguard Worker extern "C" PRIVILEGED_DATA List_t xTasksWaitingTermination;
50*61c4878aSAndroid Build Coastguard Worker #endif  // INCLUDE_vTaskDelete == 1
51*61c4878aSAndroid Build Coastguard Worker 
52*61c4878aSAndroid Build Coastguard Worker #if INCLUDE_vTaskSuspend == 1
53*61c4878aSAndroid Build Coastguard Worker // Tasks that are currently suspended.
54*61c4878aSAndroid Build Coastguard Worker extern "C" PRIVILEGED_DATA List_t xSuspendedTaskList;
55*61c4878aSAndroid Build Coastguard Worker #endif  // INCLUDE_vTaskSuspend == 1
56*61c4878aSAndroid Build Coastguard Worker 
57*61c4878aSAndroid Build Coastguard Worker namespace pw::thread::freertos {
58*61c4878aSAndroid Build Coastguard Worker namespace {
59*61c4878aSAndroid Build Coastguard Worker 
ForEachThreadInList(List_t * list,const eTaskState default_list_state,const ThreadCallback & cb)60*61c4878aSAndroid Build Coastguard Worker Status ForEachThreadInList(List_t* list,
61*61c4878aSAndroid Build Coastguard Worker                            const eTaskState default_list_state,
62*61c4878aSAndroid Build Coastguard Worker                            const ThreadCallback& cb) {
63*61c4878aSAndroid Build Coastguard Worker   if (listCURRENT_LIST_LENGTH(list) == 0) {
64*61c4878aSAndroid Build Coastguard Worker     return OkStatus();
65*61c4878aSAndroid Build Coastguard Worker   }
66*61c4878aSAndroid Build Coastguard Worker 
67*61c4878aSAndroid Build Coastguard Worker   Status status = OkStatus();
68*61c4878aSAndroid Build Coastguard Worker   // Note that these are pointers to the thread control blocks, however the
69*61c4878aSAndroid Build Coastguard Worker   // list macros from FreeRTOS do not cast the types and ergo we use void *.
70*61c4878aSAndroid Build Coastguard Worker   void* current_thread;
71*61c4878aSAndroid Build Coastguard Worker   void* first_thread_in_list;
72*61c4878aSAndroid Build Coastguard Worker   listGET_OWNER_OF_NEXT_ENTRY(first_thread_in_list, list);
73*61c4878aSAndroid Build Coastguard Worker   do {
74*61c4878aSAndroid Build Coastguard Worker     listGET_OWNER_OF_NEXT_ENTRY(current_thread, list);
75*61c4878aSAndroid Build Coastguard Worker     // We must finish the list iteration to restore the list state, but
76*61c4878aSAndroid Build Coastguard Worker     // we want to stop invoking callbacks upon the first failure.
77*61c4878aSAndroid Build Coastguard Worker     if (status.ok()) {
78*61c4878aSAndroid Build Coastguard Worker       // Note that the lists do not contain the running state, so instead
79*61c4878aSAndroid Build Coastguard Worker       // check for each thread whether it is currently running.
80*61c4878aSAndroid Build Coastguard Worker       const TaskHandle_t current_thread_handle =
81*61c4878aSAndroid Build Coastguard Worker           reinterpret_cast<TaskHandle_t>(current_thread);
82*61c4878aSAndroid Build Coastguard Worker       if (!cb(current_thread_handle,
83*61c4878aSAndroid Build Coastguard Worker               current_thread_handle == pxCurrentTCB ? eRunning
84*61c4878aSAndroid Build Coastguard Worker                                                     : default_list_state)) {
85*61c4878aSAndroid Build Coastguard Worker         status = Status::Aborted();
86*61c4878aSAndroid Build Coastguard Worker       }
87*61c4878aSAndroid Build Coastguard Worker     }
88*61c4878aSAndroid Build Coastguard Worker   } while (current_thread != first_thread_in_list);
89*61c4878aSAndroid Build Coastguard Worker   return status;
90*61c4878aSAndroid Build Coastguard Worker }
91*61c4878aSAndroid Build Coastguard Worker 
92*61c4878aSAndroid Build Coastguard Worker }  // namespace
93*61c4878aSAndroid Build Coastguard Worker 
ForEachThread(const ThreadCallback & cb)94*61c4878aSAndroid Build Coastguard Worker Status ForEachThread(const ThreadCallback& cb) {
95*61c4878aSAndroid Build Coastguard Worker   if (xSchedulerRunning == pdFALSE) {
96*61c4878aSAndroid Build Coastguard Worker     return Status::FailedPrecondition();
97*61c4878aSAndroid Build Coastguard Worker   }
98*61c4878aSAndroid Build Coastguard Worker 
99*61c4878aSAndroid Build Coastguard Worker   for (size_t i = 0; i < configMAX_PRIORITIES; ++i) {
100*61c4878aSAndroid Build Coastguard Worker     PW_TRY(ForEachThreadInList(&pxReadyTasksLists[i], eReady, cb));
101*61c4878aSAndroid Build Coastguard Worker   }
102*61c4878aSAndroid Build Coastguard Worker   PW_TRY(ForEachThreadInList(pxDelayedTaskList, eBlocked, cb));
103*61c4878aSAndroid Build Coastguard Worker   PW_TRY(ForEachThreadInList(pxOverflowDelayedTaskList, eBlocked, cb));
104*61c4878aSAndroid Build Coastguard Worker #if INCLUDE_vTaskDelete == 1
105*61c4878aSAndroid Build Coastguard Worker   PW_TRY(ForEachThreadInList(&xTasksWaitingTermination, eDeleted, cb));
106*61c4878aSAndroid Build Coastguard Worker #endif  // INCLUDE_vTaskDelete == 1
107*61c4878aSAndroid Build Coastguard Worker #if INCLUDE_vTaskSuspend == 1
108*61c4878aSAndroid Build Coastguard Worker   PW_TRY(ForEachThreadInList(&xSuspendedTaskList, eSuspended, cb));
109*61c4878aSAndroid Build Coastguard Worker #endif  // INCLUDE_vTaskSuspend == 1
110*61c4878aSAndroid Build Coastguard Worker   return OkStatus();
111*61c4878aSAndroid Build Coastguard Worker }
112*61c4878aSAndroid Build Coastguard Worker 
113*61c4878aSAndroid Build Coastguard Worker }  // namespace pw::thread::freertos
114