C/C++ API Reference
Loading...
Searching...
No Matches
dispatcher_base.h
1// Copyright 2025 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 "pw_async2/context.h"
17#include "pw_async2/internal/config.h"
18#include "pw_async2/lock.h"
19#include "pw_async2/task.h"
20#include "pw_async2/waker.h"
21#include "pw_containers/intrusive_list.h"
22#include "pw_metric/metric.h"
23#include "pw_sync/lock_annotations.h"
24#include "pw_sync/mutex.h"
25
26namespace pw::async2 {
27
29
30// Forward-declare ``Dispatcher``.
31// This concrete type must be provided by a backend.
32class Dispatcher;
33
34template <typename T>
35using PendOutputOf = typename decltype(std::declval<T>().Pend(
36 std::declval<Context&>()))::value_type;
37
38// Windows GCC doesn't realize the nonvirtual destructor is protected.
40PW_MODIFY_DIAGNOSTIC_GCC(ignored, "-Wnon-virtual-dtor");
41
50 public:
51 NativeDispatcherBase() = default;
54 NativeDispatcherBase& operator=(NativeDispatcherBase&) = delete;
55 NativeDispatcherBase& operator=(NativeDispatcherBase&&) = delete;
56
57 protected:
58 ~NativeDispatcherBase() = default;
59
61 bool HasPostedTask(Task& task)
63 return task.dispatcher_ == this;
64 }
65
73 void Deregister() PW_LOCKS_EXCLUDED(impl::dispatcher_lock());
74
75 void Post(Task& task) PW_LOCKS_EXCLUDED(impl::dispatcher_lock());
76
81 class [[nodiscard]] SleepInfo {
82 friend class NativeDispatcherBase;
83
84 public:
85 bool should_sleep() const { return should_sleep_; }
86
87 private:
88 SleepInfo(bool should_sleep) : should_sleep_(should_sleep) {}
89
90 static SleepInfo DontSleep() { return SleepInfo(false); }
91
92 static SleepInfo Indefinitely() { return SleepInfo(true); }
93
94 bool should_sleep_;
95 };
96
112
116 class [[nodiscard]] RunOneTaskResult {
117 public:
118 RunOneTaskResult(bool completed_all_tasks,
119 bool completed_main_task,
120 bool ran_a_task)
121 : completed_all_tasks_(completed_all_tasks),
122 completed_main_task_(completed_main_task),
123 ran_a_task_(ran_a_task) {}
124 bool completed_all_tasks() const { return completed_all_tasks_; }
125 bool completed_main_task() const { return completed_main_task_; }
126 bool ran_a_task() const { return ran_a_task_; }
127
128 private:
129 bool completed_all_tasks_;
130 bool completed_main_task_;
131 bool ran_a_task_;
132 };
133
136 [[nodiscard]] RunOneTaskResult RunOneTask(Dispatcher& dispatcher,
137 Task* task_to_look_for);
138
139 uint32_t tasks_polled() const { return tasks_polled_.value(); }
140 uint32_t tasks_completed() const { return tasks_completed_.value(); }
141 uint32_t sleep_count() const { return sleep_count_.value(); }
142 uint32_t wake_count() const { return wake_count_.value(); }
143
144 private:
145 friend class Dispatcher;
146 friend class Task;
147 friend class Waker;
148
149 void Wake() {
150 wake_count_.Increment();
151 DoWake();
152 }
153
162 virtual void DoWake() = 0;
163
164 static void UnpostTaskList(IntrusiveList<Task>& list)
166 void RemoveWokenTaskLocked(Task&)
168 void RemoveSleepingTaskLocked(Task&)
170
171 // For use by ``Waker``.
173
174 // For use by ``RunOneTask``.
175 Task* PopWokenTask() PW_EXCLUSIVE_LOCKS_REQUIRED(impl::dispatcher_lock());
176
177 void LogRegisteredTasks();
178
179#if PW_ASYNC2_DEBUG_WAIT_REASON
180 void LogTaskWakers(const Task& task)
182#endif // PW_ASYNC2_DEBUG_WAIT_REASON
183
184 // A lock guarding ``Task`` execution.
185 //
186 // This will be acquired prior to pulling any tasks off of the ``Task``
187 // queue, and only released after they have been run and possibly
188 // destroyed.
189 //
190 // If acquiring this lock and ``impl::dispatcher_lock()``, this lock must
191 // be acquired first in order to avoid deadlocks.
192 //
193 // Acquiring this lock may be a slow process, as it must wait until
194 // the running task has finished executing ``Task::Pend``.
195 pw::sync::Mutex task_execution_lock_;
196
199 bool wants_wake_ PW_GUARDED_BY(impl::dispatcher_lock()) = false;
200
201 PW_METRIC_GROUP(metrics_, "pw::async2::NativeDispatcherBase");
202 PW_METRIC(metrics_, tasks_polled_, "tasks_polled", 0u);
203 PW_METRIC(metrics_, tasks_completed_, "tasks_completed", 0u);
204 PW_METRIC(metrics_, sleep_count_, "sleep_count", 0u);
205 PW_METRIC(metrics_, wake_count_, "wake_count", 0u);
206};
207
209
211
212} // namespace pw::async2
A single-threaded cooperatively scheduled runtime for async tasks.
Definition: dispatcher.h:48
Definition: dispatcher_base.h:81
Definition: dispatcher_base.h:49
RunOneTaskResult RunOneTask(Dispatcher &dispatcher, Task *task_to_look_for)
bool HasPostedTask(Task &task)
Check that a task is posted on this Dispatcher.
Definition: dispatcher_base.h:61
SleepInfo AttemptRequestWake(bool allow_empty)
Definition: task.h:63
Definition: intrusive_list.h:88
Definition: mutex.h:40
pw::sync::InterruptSpinLock & dispatcher_lock()
Definition: lock.h:33
#define PW_MODIFY_DIAGNOSTICS_POP()
Definition: compiler.h:194
#define PW_MODIFY_DIAGNOSTIC_GCC(kind, option)
Definition: compiler.h:211
#define PW_MODIFY_DIAGNOSTICS_PUSH()
Definition: compiler.h:189
#define PW_GUARDED_BY(x)
Definition: lock_annotations.h:60
#define PW_EXCLUSIVE_LOCKS_REQUIRED(...)
Definition: lock_annotations.h:146
#define PW_LOCKS_EXCLUDED(...)
Definition: lock_annotations.h:176