blob: aef4860fd319f8b1584ee5d430f9473fe6433e39 [file]
// Copyright 2025 The Pigweed Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
#include "pw_async2/dispatcher_for_test.h"
#include "pw_sync/thread_notification.h"
#include "pw_thread/sleep.h"
#include "pw_thread/test_thread_context.h"
#include "pw_thread/thread.h"
#include "pw_unit_test/framework.h"
namespace {
using namespace std::chrono_literals;
using pw::async2::Context;
using pw::async2::DispatcherForTest;
using pw::async2::Pending;
using pw::async2::Poll;
using pw::async2::Ready;
using pw::async2::Task;
using pw::async2::Waker;
class BlockingTask : public Task {
public:
explicit BlockingTask() : Task(PW_ASYNC_TASK_NAME("BlockingTask")) {}
Poll<> DoPend(Context& cx) override {
if (first_run_) {
first_run_ = false;
PW_ASYNC_STORE_WAKER(cx, waker_, "BlockingTask::Wake()");
running_.release();
return Pending();
}
return Ready();
}
void WaitUntilRunning() { running_.acquire(); }
void Wake() { waker_.Wake(); }
private:
pw::sync::ThreadNotification running_;
Waker waker_;
bool first_run_ = true;
};
TEST(DispatcherForTest, RunToCompletionWaitsForTaskToWake) {
DispatcherForTest dispatcher;
BlockingTask task;
dispatcher.Post(task);
pw::thread::test::TestThreadContext context;
pw::Thread thread(context.options(), [&task] {
task.WaitUntilRunning();
task.Wake();
});
dispatcher.AllowBlocking();
dispatcher.RunToCompletion();
EXPECT_FALSE(task.IsRegistered());
thread.join();
}
TEST(DispatcherForTest, RunToCompletionUntilReleased) {
DispatcherForTest dispatcher;
pw::thread::test::TestThreadContext context;
pw::Thread thread(context.options(), [&dispatcher] {
pw::this_thread::sleep_for(10ms);
dispatcher.Release();
});
dispatcher.RunToCompletionUntilReleased();
thread.join();
}
TEST(DispatcherForTest, RunToCompletionUntilReleasedMultipleTimes) {
DispatcherForTest dispatcher;
pw::thread::test::TestThreadContext context;
for (int i = 0; i < 3; ++i) {
pw::Thread thread(context.options(),
[&dispatcher] { dispatcher.Release(); });
dispatcher.RunToCompletionUntilReleased();
thread.join();
}
}
} // namespace