Home | History | Annotate | Download | only in core
      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