1 // Copyright 2024 The Pigweed Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not 4 // use this file except in compliance with the License. You may obtain a copy of 5 // the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 // License for the specific language governing permissions and limitations under 13 // the License. 14 15 #include <atomic> 16 17 #include "gtest/gtest.h" 18 #include "pw_async2/dispatcher.h" 19 #include "pw_function/function.h" 20 #include "pw_thread/sleep.h" 21 #include "pw_thread/thread.h" 22 #include "pw_thread_stl/options.h" 23 24 namespace pw::async2 { 25 namespace { 26 27 using namespace std::chrono_literals; 28 29 class MockTask : public Task { 30 public: 31 std::atomic_bool should_complete = false; 32 std::atomic_int polled = 0; 33 std::atomic_int destroyed = 0; 34 Waker last_waker; 35 36 private: DoPend(Context & cx)37 Poll<> DoPend(Context& cx) override { 38 ++polled; 39 last_waker = cx.GetWaker(WaitReason::Unspecified()); 40 if (should_complete) { 41 return Ready(); 42 } else { 43 return Pending(); 44 } 45 } DoDestroy()46 void DoDestroy() override { ++destroyed; } 47 }; 48 49 class FunctionThread : public thread::ThreadCore { 50 public: FunctionThread(Closure func)51 explicit FunctionThread(Closure func) : func_(std::move(func)) {} 52 53 private: Run()54 void Run() override { func_(); } 55 56 Closure func_; 57 }; 58 TEST(Dispatcher,RunToCompletion_SleepsUntilWoken)59TEST(Dispatcher, RunToCompletion_SleepsUntilWoken) { 60 MockTask task; 61 task.should_complete = false; 62 Dispatcher dispatcher; 63 dispatcher.Post(task); 64 65 FunctionThread delayed_wake([&task]() { 66 this_thread::sleep_for(100ms); 67 task.should_complete = true; 68 std::move(task.last_waker).Wake(); 69 }); 70 71 thread::Thread work_thread(thread::stl::Options(), delayed_wake); 72 73 dispatcher.RunToCompletion(task); 74 75 work_thread.join(); 76 77 // Poll once when sleeping then once when woken. 78 EXPECT_EQ(task.polled, 2); 79 EXPECT_EQ(task.destroyed, 1); 80 } 81 82 } // namespace 83 } // namespace pw::async2 84