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 #pragma once 15 16 #include <lib/async-loop/loop.h> 17 #include <zircon/assert.h> 18 #include <zircon/listnode.h> 19 20 #include "pw_async/task.h" 21 22 namespace pw::async::test::backend { 23 24 class NativeFakeDispatcher { 25 public: 26 explicit NativeFakeDispatcher(Dispatcher& test_dispatcher); ~NativeFakeDispatcher()27 ~NativeFakeDispatcher() { DestroyLoop(); } 28 RequestStop()29 void RequestStop() { stop_requested_ = true; } 30 31 // Synchronously destroys the loop, runs pending tasks with a cancelled 32 // status, and frees the loop memory. Returns true if any task was invoked. 33 bool DestroyLoop(); 34 35 chrono::SystemClock::time_point now(); 36 37 void Post(Task& task); 38 void PostAfter(Task& task, chrono::SystemClock::duration delay); 39 void PostAt(Task& task, chrono::SystemClock::time_point time); 40 41 bool Cancel(Task& task); 42 43 bool RunUntilIdle(); 44 bool RunUntil(chrono::SystemClock::time_point end_time); 45 bool RunFor(chrono::SystemClock::duration duration); 46 47 private: 48 // FakeAsyncLoop is an adapted version of the Zircon async-loop (implemented 49 // in zircon/system/ulib/async-loop/loop.c) for testing. It contains adapted 50 // copies of a subset of the async-loop methods. 51 // 52 // In the method copies, 1) code interfacing with Zircon timers has been 53 // replaced with a simulated timer system and 2) code related to thread 54 // safety/synchronization has been elided. 55 class FakeAsyncLoop { 56 public: 57 explicit FakeAsyncLoop(); ~FakeAsyncLoop()58 ~FakeAsyncLoop() { Shutdown(); } 59 60 // Returns true iff any task was invoked. 61 bool Shutdown(); 62 chrono::SystemClock::time_point Now() const; 63 zx_status_t PostTask(async_task_t* task); 64 zx_status_t CancelTask(async_task_t* task); 65 // Returns true iff any task was invoked. 66 bool RunUntilIdle(); 67 // Returns true iff any task was invoked. 68 bool Run(zx_time_t deadline, bool once); Runnable()69 bool Runnable() const { return state_ == ASYNC_LOOP_RUNNABLE; } 70 71 private: TaskToNode(async_task_t * task)72 static inline list_node_t* TaskToNode(async_task_t* task) { 73 return reinterpret_cast<list_node_t*>(&task->state); 74 } NodeToTask(list_node_t * node)75 static inline async_task_t* NodeToTask(list_node_t* node) { 76 return reinterpret_cast<async_task_t*>(reinterpret_cast<char*>(node) - 77 offsetof(async_task_t, state)); 78 } 79 80 void InsertTask(async_task_t* task); 81 void RestartTimer(); 82 zx_time_t NextDeadline(); 83 // Sets task_invoked to true iff a task was invoked. 84 zx_status_t RunOnce(zx_time_t deadline, bool* task_invoked); 85 // Returns true iff a task was invoked. 86 bool DispatchTasks(); 87 // Returns true iff a task was invoked. 88 bool CancelAll(); 89 90 // Tracks the current time as viewed by the fake loop. 91 zx_time_t now_ = 0; 92 // Simulated timer. Stores ZX_TIME_INFINITE when no timer is set. 93 zx_time_t next_timer_expiration_ = ZX_TIME_INFINITE; 94 95 async_loop_state_t state_ = ASYNC_LOOP_RUNNABLE; 96 97 // True while the loop is busy dispatching tasks. 98 bool dispatching_tasks_ = false; 99 // Pending tasks, earliest deadline first. 100 list_node_t task_list_; 101 // Due tasks, earliest deadline first. 102 list_node_t due_list_; 103 // True if the simulated timer has been set and has not fired yet. 104 bool timer_armed_ = false; 105 }; 106 107 Dispatcher& dispatcher_; 108 FakeAsyncLoop fake_loop_; 109 bool stop_requested_ = false; 110 }; 111 112 } // namespace pw::async::test::backend 113