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 30 StartupTraceWriterRegistryHandle::StartupTraceWriterRegistryHandle( 31 StartupTraceWriterRegistry* registry) 32 : registry_(registry) {} 33 34 void StartupTraceWriterRegistryHandle::OnWriterDestroyed( 35 StartupTraceWriter* writer) { 36 std::lock_guard<std::mutex> lock(lock_); 37 if (registry_) 38 registry_->OnStartupTraceWriterDestroyed(writer); 39 } 40 41 void StartupTraceWriterRegistryHandle::OnRegistryDestroyed() { 42 std::lock_guard<std::mutex> lock(lock_); 43 registry_ = nullptr; 44 } 45 46 StartupTraceWriterRegistry::StartupTraceWriterRegistry() 47 : handle_(std::make_shared<StartupTraceWriterRegistryHandle>(this)) {} 48 49 StartupTraceWriterRegistry::~StartupTraceWriterRegistry() { 50 handle_->OnRegistryDestroyed(); 51 } 52 53 std::unique_ptr<StartupTraceWriter> 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 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 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 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 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 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