Coverage Report

Created: 2025-06-13 06:31

/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