blob: 0896f32fc74b3807d7911a090d959884d282e0ac [file] [log] [blame]
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef INCLUDE_PERFETTO_EXT_TRACING_CORE_STARTUP_TRACE_WRITER_REGISTRY_H_
#define INCLUDE_PERFETTO_EXT_TRACING_CORE_STARTUP_TRACE_WRITER_REGISTRY_H_
#include <functional>
#include <memory>
#include <mutex>
#include <vector>
#include "perfetto/base/export.h"
#include "perfetto/ext/base/weak_ptr.h"
#include "perfetto/ext/tracing/core/basic_types.h"
#include "perfetto/ext/tracing/core/shared_memory_arbiter.h"
#include "perfetto/tracing/buffer_exhausted_policy.h"
namespace perfetto {
class SharedMemoryArbiterImpl;
class StartupTraceWriter;
class StartupTraceWriterRegistry;
namespace base {
class TaskRunner;
} // namespace base
// Used to return a StartupTraceWriter back to its registry when the writer's
// thread is destroyed, provided the registry itself wasn't deleted yet. The
// indirection via the handle is necessary to avoid potential deadlocks caused
// by lock order inversion. These issues are avoided by locking on the handle's
// common lock.
class StartupTraceWriterRegistryHandle {
public:
explicit StartupTraceWriterRegistryHandle(StartupTraceWriterRegistry*);
// Called by StartupTraceWriterRegistry destructor.
void OnRegistryDestroyed();
// Called by StartupTraceWriter::ReturnToRegistry.
void ReturnWriterToRegistry(std::unique_ptr<StartupTraceWriter> writer);
private:
StartupTraceWriterRegistryHandle(const StartupTraceWriterRegistryHandle&) =
delete;
StartupTraceWriterRegistryHandle& operator=(
const StartupTraceWriterRegistryHandle&) = delete;
std::mutex lock_;
StartupTraceWriterRegistry* registry_;
};
// Embedders can use this registry to create unbound StartupTraceWriters during
// startup, and later bind them all safely to an arbiter and target buffer.
class PERFETTO_EXPORT StartupTraceWriterRegistry {
public:
StartupTraceWriterRegistry();
~StartupTraceWriterRegistry();
// Buffer size defaults to 1 mB per writer.
static constexpr size_t kDefaultMaxBufferSizeBytes = 1024 * 1024;
// Returns a new unbound StartupTraceWriter. Should only be called while
// unbound. Usually called on a writer thread. The writer should never be
// destroyed by the caller directly, but instead returned to the registry by
// calling StartupTraceWriter::ReturnToRegistry.
std::unique_ptr<StartupTraceWriter> CreateUnboundTraceWriter(
BufferExhaustedPolicy = BufferExhaustedPolicy::kDefault,
size_t max_buffer_size_bytes = kDefaultMaxBufferSizeBytes);
// Binds all StartupTraceWriters created by this registry to the given arbiter
// and target buffer. Should only be called once and on the passed
// TaskRunner's sequence. See
// SharedMemoryArbiter::BindStartupTraceWriterRegistry() for details.
//
// Note that the writers may not be bound synchronously if they are
// concurrently being written to. The registry will retry on the passed
// TaskRunner until all writers were bound successfully.
//
// Calls |on_bound_callback| asynchronously on the passed TaskRunner once all
// writers were bound.
//
// The commit of the StartupTraceWriters' locally buffered data to the SMB is
// rate limited to avoid exhausting the SMB, and may continue asynchronously
// even after |on_bound_callback| was called.
void BindToArbiter(
SharedMemoryArbiterImpl*,
BufferID target_buffer,
base::TaskRunner*,
std::function<void(StartupTraceWriterRegistry*)> on_bound_callback);
private:
friend class StartupTraceWriterRegistryHandle;
friend class StartupTraceWriterTest;
StartupTraceWriterRegistry(const StartupTraceWriterRegistry&) = delete;
StartupTraceWriterRegistry& operator=(const StartupTraceWriterRegistry&) =
delete;
// Try to bind the remaining unbound writers and post a continuation to
// |task_runner_| if any writers could not be bound.
void TryBindWriters();
// Notifies the arbiter when we have bound all writers. May delete |this|.
void OnUnboundWritersRemovedLocked();
// Return a StartupTraceWriter back to the registry, see
// StartupTraceWriter::ReturnToRegistry.
void ReturnTraceWriter(std::unique_ptr<StartupTraceWriter>);
std::shared_ptr<StartupTraceWriterRegistryHandle> handle_;
// Begin lock-protected members.
std::mutex lock_;
// Unbound writers that we handed out to writer threads. These writers may be
// concurrently written to by the writer threads.
std::vector<StartupTraceWriter*> unbound_writers_;
// Unbound writers that writer threads returned to the registry by calling
// ReturnUnboundTraceWriter(). Writers are removed from |unbound_writers_|
// when they are added to |unbound_owned_writers_|. No new data can be written
// to these writers.
std::vector<std::unique_ptr<StartupTraceWriter>> unbound_owned_writers_;
SharedMemoryArbiterImpl* arbiter_ = nullptr; // |nullptr| while unbound.
BufferID target_buffer_ = 0;
base::TaskRunner* task_runner_;
size_t chunks_per_batch_ = 0;
std::function<void(StartupTraceWriterRegistry*)> on_bound_callback_ = nullptr;
// Keep at the end. Initialized during |BindToArbiter()|, like |task_runner_|.
// Weak pointers are only valid on |task_runner_|'s thread/sequence.
std::unique_ptr<base::WeakPtrFactory<StartupTraceWriterRegistry>>
weak_ptr_factory_;
// End lock-protected members.
};
} // namespace perfetto
#endif // INCLUDE_PERFETTO_EXT_TRACING_CORE_STARTUP_TRACE_WRITER_REGISTRY_H_