/proc/self/cwd/pw_async/heap_dispatcher.cc
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright 2023 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 "pw_async/heap_dispatcher.h" |
16 | | |
17 | | #include "pw_async/task.h" |
18 | | #include "pw_result/result.h" |
19 | | |
20 | | namespace pw::async { |
21 | | |
22 | | namespace { |
23 | | |
24 | | // TODO: b/277793223 - Optimize to avoid double virtual indirection and double |
25 | | // allocation. In situations in which pw::Function is large enough and the |
26 | | // captures are small enough, we could eliminate this by reshaping the task as |
27 | | // just a pw::Function. |
28 | | struct TaskAndFunction { |
29 | 543k | static Result<TaskAndFunction*> New(TaskFunction&& task) { |
30 | | // std::nothrow causes new to return a nullptr on failure instead of |
31 | | // throwing. |
32 | 543k | TaskAndFunction* t = new (std::nothrow) TaskAndFunction(); |
33 | 543k | if (!t) { |
34 | 0 | return Status::ResourceExhausted(); |
35 | 0 | } |
36 | 543k | t->func = std::move(task); |
37 | | |
38 | | // Closure captures must not include references, as that would be UB due to |
39 | | // the `delete` at the end of the function. See |
40 | | // https://reviews.llvm.org/D48239. |
41 | 543k | t->task.set_function([t](Context& ctx, Status status) { |
42 | 543k | t->func(ctx, status); |
43 | | |
44 | | // Delete must appear at the very end of this closure to avoid |
45 | | // use-after-free of captures or Context.task. |
46 | 543k | delete t; |
47 | 543k | }); |
48 | | |
49 | 543k | return t; |
50 | 543k | } |
51 | | Task task; |
52 | | TaskFunction func; |
53 | | }; |
54 | | } // namespace |
55 | | |
56 | | Status HeapDispatcher::PostAt(TaskFunction&& task_func, |
57 | 543k | chrono::SystemClock::time_point time) { |
58 | 543k | Result<TaskAndFunction*> result = TaskAndFunction::New(std::move(task_func)); |
59 | 543k | if (!result.ok()) { |
60 | 0 | return result.status(); |
61 | 0 | } |
62 | 543k | dispatcher_.PostAt((*result)->task, time); |
63 | 543k | return Status(); |
64 | 543k | } |
65 | | |
66 | | } // namespace pw::async |