pw_thread_threadx: Keep walking tasks on error
Changes behavior of the thread iterator to continue iteration over all
threads when an error is encountered.
Change-Id: I6ef8a0565165c0720f2c47d6982ff0031e33757f
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/53661
Commit-Queue: Armando Montanez <amontanez@google.com>
Pigweed-Auto-Submit: Armando Montanez <amontanez@google.com>
Reviewed-by: Ewout van Bekkum <ewout@google.com>
diff --git a/pw_thread_threadx/BUILD.gn b/pw_thread_threadx/BUILD.gn
index dd7d7b3..1eba6dc 100644
--- a/pw_thread_threadx/BUILD.gn
+++ b/pw_thread_threadx/BUILD.gn
@@ -158,6 +158,7 @@
"$dir_pw_thread:snapshot",
dir_pw_bytes,
dir_pw_function,
+ dir_pw_log,
dir_pw_protobuf,
dir_pw_status,
]
diff --git a/pw_thread_threadx/docs.rst b/pw_thread_threadx/docs.rst
index 5cfd84f..df27220 100644
--- a/pw_thread_threadx/docs.rst
+++ b/pw_thread_threadx/docs.rst
@@ -33,6 +33,15 @@
``ForEachThread()`` can be used to iterate over all the created thread TCBs.
Note that it's only safe to use this while the scheduler is disabled.
+An ``Aborted`` error status is returned if the provided callback returns
+``false`` to request an early termination of thread iteration.
+
+Return values
+=============
+
+* ``Aborted``: The callback requested an early-termination of thread iteration.
+* ``OkStatus``: The callback has been successfully run with every thread.
+
--------------------
Snapshot integration
--------------------
@@ -42,7 +51,7 @@
SnapshotThread()/SnapshotThreads()
==================================
``SnapshotThread()`` captures the thread name, state, and stack information for
-the provided RTX TCB to a ``pw::thread::Thread`` protobuf encoder. To ensure
+the provided ThreadX TCB to a ``pw::thread::Thread`` protobuf encoder. To ensure
the most up-to-date information is captured, the stack pointer for the currently
running thread must be provided for cases where the running thread is being
captured. For ARM Cortex-M CPUs, you can do something like this:
diff --git a/pw_thread_threadx/public/pw_thread_threadx/util.h b/pw_thread_threadx/public/pw_thread_threadx/util.h
index ed0c1e1..34c4299 100644
--- a/pw_thread_threadx/public/pw_thread_threadx/util.h
+++ b/pw_thread_threadx/public/pw_thread_threadx/util.h
@@ -19,12 +19,18 @@
namespace pw::thread::threadx {
-// A callback that is executed for each thread when using ForEachThread().
-using ThreadCallback = pw::Function<Status(const TX_THREAD&)>;
+// A callback that is executed for each thread when using ForEachThread(). The
+// callback should return true if thread iteration should continue. When this
+// callback returns false, ForEachThread() will cease iteration of threads and
+// return an `Aborted` error code.
+using ThreadCallback = pw::Function<bool(const TX_THREAD&)>;
// Iterates through all threads that haven't been deleted, calling the provided
-// callback on each thread. If the callback fails on one thread, the iteration
-// stops.
+// callback on each thread.
+//
+// Returns:
+// Aborted - The callback requested an early-termination of thread iteration.
+// OkStatus - Successfully iterated over all threads.
//
// Warning: This is only safe to use when the scheduler is disabled.
Status ForEachThread(ThreadCallback& cb);
diff --git a/pw_thread_threadx/snapshot.cc b/pw_thread_threadx/snapshot.cc
index 0333714..48d0f4f 100644
--- a/pw_thread_threadx/snapshot.cc
+++ b/pw_thread_threadx/snapshot.cc
@@ -16,6 +16,7 @@
#include <string_view>
#include "pw_function/function.h"
+#include "pw_log/log.h"
#include "pw_protobuf/encoder.h"
#include "pw_status/status.h"
#include "pw_thread/snapshot.h"
@@ -79,20 +80,29 @@
void* running_thread_stack_pointer;
SnapshotThreadInfo::StreamEncoder* encoder;
ProcessThreadStackCallback* stack_dumper;
+ Status thread_capture_status;
} ctx;
ctx.running_thread_stack_pointer = running_thread_stack_pointer;
ctx.encoder = &encoder;
ctx.stack_dumper = &stack_dumper;
- ThreadCallback thread_capture_cb([&ctx](const TX_THREAD& thread) -> Status {
+ ThreadCallback thread_capture_cb([&ctx](const TX_THREAD& thread) -> bool {
Thread::StreamEncoder thread_encoder = ctx.encoder->GetThreadsEncoder();
- return SnapshotThread(thread,
- ctx.running_thread_stack_pointer,
- thread_encoder,
- *ctx.stack_dumper);
+ ctx.thread_capture_status.Update(
+ SnapshotThread(thread,
+ ctx.running_thread_stack_pointer,
+ thread_encoder,
+ *ctx.stack_dumper));
+ // Always iterate all threads.
+ return true;
});
- return ForEachThread(thread_capture_cb);
+ if (Status status = ForEachThread(thread_capture_cb); !status.ok()) {
+ PW_LOG_ERROR("Failed to iterate threads during snapshot capture: %d",
+ static_cast<int>(status.code()));
+ }
+
+ return ctx.thread_capture_status;
}
Status SnapshotThread(const TX_THREAD& thread,
diff --git a/pw_thread_threadx/util.cc b/pw_thread_threadx/util.cc
index 0d9c5e5..078a51a 100644
--- a/pw_thread_threadx/util.cc
+++ b/pw_thread_threadx/util.cc
@@ -15,7 +15,6 @@
#include "pw_function/function.h"
#include "pw_status/status.h"
-#include "pw_status/try.h"
#include "tx_api.h"
#include "tx_thread.h"
@@ -24,11 +23,14 @@
namespace internal {
// Iterates through all threads that haven't been deleted, calling the provided
-// call
+// callback.
Status ForEachThread(const TX_THREAD& starting_thread, ThreadCallback& cb) {
const TX_THREAD* thread = &starting_thread;
do {
- PW_TRY(cb(*thread));
+ if (!cb(*thread)) {
+ // Early-terminate iteration if requested by the callback.
+ return Status::Aborted();
+ }
thread = thread->tx_thread_created_next;
} while (thread != &starting_thread);