• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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