1 /*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "perfetto/tracing/core/startup_trace_writer_registry.h"
18
19 #include <functional>
20
21 #include "perfetto/base/logging.h"
22 #include "perfetto/base/task_runner.h"
23 #include "perfetto/tracing/core/startup_trace_writer.h"
24 #include "src/tracing/core/shared_memory_arbiter_impl.h"
25
26 using ChunkHeader = perfetto::SharedMemoryABI::ChunkHeader;
27
28 namespace perfetto {
29
StartupTraceWriterRegistryHandle(StartupTraceWriterRegistry * registry)30 StartupTraceWriterRegistryHandle::StartupTraceWriterRegistryHandle(
31 StartupTraceWriterRegistry* registry)
32 : registry_(registry) {}
33
OnWriterDestroyed(StartupTraceWriter * writer)34 void StartupTraceWriterRegistryHandle::OnWriterDestroyed(
35 StartupTraceWriter* writer) {
36 std::lock_guard<std::mutex> lock(lock_);
37 if (registry_)
38 registry_->OnStartupTraceWriterDestroyed(writer);
39 }
40
OnRegistryDestroyed()41 void StartupTraceWriterRegistryHandle::OnRegistryDestroyed() {
42 std::lock_guard<std::mutex> lock(lock_);
43 registry_ = nullptr;
44 }
45
StartupTraceWriterRegistry()46 StartupTraceWriterRegistry::StartupTraceWriterRegistry()
47 : handle_(std::make_shared<StartupTraceWriterRegistryHandle>(this)) {}
48
~StartupTraceWriterRegistry()49 StartupTraceWriterRegistry::~StartupTraceWriterRegistry() {
50 handle_->OnRegistryDestroyed();
51 }
52
53 std::unique_ptr<StartupTraceWriter>
CreateUnboundTraceWriter()54 StartupTraceWriterRegistry::CreateUnboundTraceWriter() {
55 std::lock_guard<std::mutex> lock(lock_);
56 PERFETTO_DCHECK(!arbiter_); // Should only be called while unbound.
57 std::unique_ptr<StartupTraceWriter> writer(new StartupTraceWriter(handle_));
58 unbound_writers_.insert(writer.get());
59 return writer;
60 }
61
ReturnUnboundTraceWriter(std::unique_ptr<StartupTraceWriter> trace_writer)62 void StartupTraceWriterRegistry::ReturnUnboundTraceWriter(
63 std::unique_ptr<StartupTraceWriter> trace_writer) {
64 std::lock_guard<std::mutex> lock(lock_);
65 PERFETTO_DCHECK(!arbiter_); // Should only be called while unbound.
66 PERFETTO_DCHECK(!trace_writer->write_in_progress_);
67 PERFETTO_DCHECK(unbound_writers_.count(trace_writer.get()));
68 unbound_writers_.erase(trace_writer.get());
69 unbound_owned_writers_.push_back(std::move(trace_writer));
70 }
71
BindToArbiter(SharedMemoryArbiterImpl * arbiter,BufferID target_buffer,base::TaskRunner * task_runner,std::function<void (StartupTraceWriterRegistry *)> on_bound_callback)72 void StartupTraceWriterRegistry::BindToArbiter(
73 SharedMemoryArbiterImpl* arbiter,
74 BufferID target_buffer,
75 base::TaskRunner* task_runner,
76 std::function<void(StartupTraceWriterRegistry*)> on_bound_callback) {
77 std::vector<std::unique_ptr<StartupTraceWriter>> unbound_owned_writers;
78 {
79 std::lock_guard<std::mutex> lock(lock_);
80 PERFETTO_DCHECK(!arbiter_);
81 arbiter_ = arbiter;
82 target_buffer_ = target_buffer;
83 task_runner_ = task_runner;
84 // Weakptrs should be valid on |task_runner|. For this, the factory needs to
85 // be created on |task_runner|, i.e. BindToArbiter must be called on
86 // |task_runner|.
87 PERFETTO_DCHECK(task_runner_->RunsTasksOnCurrentThread());
88 weak_ptr_factory_.reset(
89 new base::WeakPtrFactory<StartupTraceWriterRegistry>(this));
90 on_bound_callback_ = std::move(on_bound_callback);
91 // We can't destroy the writers while holding |lock_|, so we swap them out
92 // here instead. After we are bound, no more writers can be added to the
93 // list.
94 unbound_owned_writers.swap(unbound_owned_writers_);
95 }
96
97 // Bind and destroy the owned writers.
98 for (const auto& writer : unbound_owned_writers) {
99 // This should succeed since nobody can write to these writers concurrently.
100 bool success = writer->BindToArbiter(arbiter_, target_buffer_);
101 PERFETTO_DCHECK(success);
102 }
103 unbound_owned_writers.clear();
104
105 TryBindWriters();
106 }
107
TryBindWriters()108 void StartupTraceWriterRegistry::TryBindWriters() {
109 std::lock_guard<std::mutex> lock(lock_);
110 for (auto it = unbound_writers_.begin(); it != unbound_writers_.end();) {
111 if ((*it)->BindToArbiter(arbiter_, target_buffer_)) {
112 it = unbound_writers_.erase(it);
113 } else {
114 it++;
115 }
116 }
117 if (!unbound_writers_.empty()) {
118 auto weak_this = weak_ptr_factory_->GetWeakPtr();
119 task_runner_->PostTask([weak_this] {
120 if (weak_this)
121 weak_this->TryBindWriters();
122 });
123 }
124 OnUnboundWritersRemovedLocked();
125 }
126
OnStartupTraceWriterDestroyed(StartupTraceWriter * trace_writer)127 void StartupTraceWriterRegistry::OnStartupTraceWriterDestroyed(
128 StartupTraceWriter* trace_writer) {
129 std::lock_guard<std::mutex> lock(lock_);
130 if (unbound_writers_.erase(trace_writer) > 0)
131 OnUnboundWritersRemovedLocked();
132 }
133
OnUnboundWritersRemovedLocked()134 void StartupTraceWriterRegistry::OnUnboundWritersRemovedLocked() {
135 if (!unbound_writers_.empty() || !task_runner_ || !on_bound_callback_)
136 return;
137
138 PERFETTO_DCHECK(weak_ptr_factory_);
139 auto weak_this = weak_ptr_factory_->GetWeakPtr();
140 // Run callback in PostTask() since the callback may delete |this| and thus
141 // might otherwise cause a deadlock.
142 auto callback = on_bound_callback_;
143 on_bound_callback_ = nullptr;
144 task_runner_->PostTask([weak_this, callback]() {
145 if (!weak_this)
146 return;
147 // Note: callback may delete |this|.
148 callback(weak_this.get());
149 });
150 }
151
152 } // namespace perfetto
153