pw_thread_freertos: Fix extra wakeups when detaching threads

vTaskResume() is known to cause premature return from blocking APIs,
since it will indiscriminately call prvAddTaskToReadyList().

Instead, use vTaskSuspendAll() / xTaskResumeAll(), which will not wake
up any tasks which weren't already running (and weren't signalled during
scheduler suspension).

This also fixes a latent bug where, in the existing fallback case of
using vTaskSuspendAll(), the new task scheduler state will be
taskSCHEDULER_SUSPENDED, causing the subsequent xTaskResumeAll() to be
skipped.

Bug: b/303885539
Change-Id: I4d09400e133b4d44353d601d07e13917e096a3eb
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/175310
Reviewed-by: Ewout van Bekkum <ewout@google.com>
Reviewed-by: Christoph Klee <chklee@google.com>
Commit-Queue: Auto-Submit <auto-submit@pigweed-service-accounts.iam.gserviceaccount.com>
Pigweed-Auto-Submit: Austin Foxley <afoxley@google.com>
Reviewed-by: Jonathon Reinhart <jrreinhart@google.com>
This commit is contained in:
Austin Foxley 2023-10-09 19:49:46 +00:00 committed by CQ Bot Account
parent 0e403d6a58
commit 754739c7d5

View File

@ -193,22 +193,20 @@ Thread::Thread(const thread::Options& facade_options,
void Thread::detach() {
PW_CHECK(joinable());
if (xTaskGetSchedulerState() == taskSCHEDULER_RUNNING) {
#if (INCLUDE_vTaskSuspend == 1)
// No need to suspend extra tasks.
vTaskSuspend(native_type_->task_handle());
#else
// xTaskResumeAll() can only be used after the scheduler has been started.
const bool scheduler_initialized =
xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED;
if (scheduler_initialized) {
// We don't want to individually suspend and resume this task using
// vTaskResume() as that can cause tasks to prematurely wake up and return
// from blocking APIs (b/303885539).
vTaskSuspendAll();
#endif // INCLUDE_vTaskSuspend == 1
}
native_type_->set_detached();
const bool thread_done = native_type_->thread_done();
if (xTaskGetSchedulerState() == taskSCHEDULER_RUNNING) {
#if (INCLUDE_vTaskSuspend == 1)
vTaskResume(native_type_->task_handle());
#else
if (scheduler_initialized) {
xTaskResumeAll();
#endif // INCLUDE_vTaskSuspend == 1
}
if (thread_done) {