xref: /aosp_15_r20/external/pigweed/pw_async/public/pw_async/dispatcher.h (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2022 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_chrono/system_clock.h"
17 
18 namespace pw::async {
19 
20 class Task;
21 
22 /// Abstract base class for an asynchronous dispatcher loop.
23 ///
24 /// `Dispatcher`s run many short, non-blocking units of work on a single thread.
25 /// This approach has a number of advantages compared with executing concurrent
26 /// tasks on separate threads:
27 ///
28 /// - `Dispatcher`s can make more efficient use of system resources, since they
29 ///   don't need to maintain separate thread stacks.
30 /// - `Dispatcher`s can run on systems without thread support, such as no-RTOS
31 ///   embedded environments.
32 /// - `Dispatcher`s allow tasks to communicate with one another without the
33 ///   synchronization overhead of locks, atomics, fences, or `volatile`.
34 ///
35 /// Thread support: `Dispatcher` methods may be safely invoked from any thread,
36 /// but the resulting tasks will always execute on a single thread. Whether
37 /// or not methods may be invoked from interrupt context is
38 /// implementation-defined.
39 ///
40 /// `VirtualSystemClock`: `Dispatcher` implements `VirtualSystemClock` in order
41 /// to provide a consistent source of (possibly mocked) time information to
42 /// tasks.
43 ///
44 /// A simple default dispatcher implementation is provided by `pw_async_basic`.
45 class Dispatcher : public chrono::VirtualSystemClock {
46  public:
47   ~Dispatcher() override = default;
48 
49   /// Post caller-owned |task| to be run on the dispatch loop.
50   ///
51   /// Posted tasks execute in the order they are posted. This ensures that
52   /// tasks can re-post themselves and yield in order to allow other tasks the
53   /// opportunity to execute.
54   ///
55   /// A given |task| must only be posted to a single `Dispatcher`.
Post(Task & task)56   virtual void Post(Task& task) { PostAt(task, now()); }
57 
58   /// Post caller owned |task| to be run after |delay|.
59   ///
60   /// If |task| was already posted to run at an earlier time (before |delay|
61   /// would expire), |task| must be run at the earlier time, and |task|
62   /// *may* also be run at the later time.
PostAfter(Task & task,chrono::SystemClock::duration delay)63   virtual void PostAfter(Task& task, chrono::SystemClock::duration delay) {
64     PostAt(task, now() + delay);
65   }
66 
67   /// Post caller owned |task| to be run at |time|.
68   ///
69   /// If |task| was already posted to run before |time|,
70   /// |task| must be run at the earlier time, and |task| *may* also be run at
71   /// the later time.
72   virtual void PostAt(Task& task, chrono::SystemClock::time_point time) = 0;
73 
74   /// Prevent a `Post`ed task from starting.
75   ///
76   /// Returns:
77   ///   true: the task was successfully canceled and will not be run by the
78   ///     dispatcher until `Post`ed again.
79   ///   false: the task could not be cancelled because it either was not
80   ///     posted, already ran, or is currently running on the `Dispatcher`
81   ///     thread.
82   virtual bool Cancel(Task& task) = 0;
83 };
84 
85 }  // namespace pw::async
86