blob: a9e43bc3a438eed69cb5c154db8aff6a703b3738 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/profiling/memlog_connection_manager.h"
#include "base/bind.h"
#include "base/memory/ptr_util.h"
#include "base/strings/stringprintf.h"
#include "base/threading/thread.h"
#include "chrome/profiling/allocation_tracker.h"
#include "chrome/profiling/memlog_stream_parser.h"
#include "chrome/profiling/profiling_globals.h"
namespace profiling {
struct MemlogConnectionManager::Connection {
Connection(AllocationTracker::CompleteCallback complete_cb,
int process_id,
scoped_refptr<MemlogReceiverPipe> p)
: thread(base::StringPrintf("Proc %d thread", process_id)),
pipe(p),
tracker(std::move(complete_cb)) {}
~Connection() {}
base::Thread thread;
scoped_refptr<MemlogReceiverPipe> pipe;
scoped_refptr<MemlogStreamParser> parser;
AllocationTracker tracker;
};
MemlogConnectionManager::MemlogConnectionManager() {}
MemlogConnectionManager::~MemlogConnectionManager() {
// Clear the callback since the server is refcounted and may outlive us.
server_->set_on_new_connection(
base::RepeatingCallback<void(scoped_refptr<MemlogReceiverPipe>)>());
}
void MemlogConnectionManager::StartConnections(const std::string& pipe_id) {
server_ = new MemlogReceiverPipeServer(
ProfilingGlobals::Get()->GetIORunner(), pipe_id,
base::BindRepeating(&MemlogConnectionManager::OnNewConnection,
base::Unretained(this)));
server_->Start();
}
void MemlogConnectionManager::OnNewConnection(
scoped_refptr<MemlogReceiverPipe> new_pipe) {
int remote_process = new_pipe->GetRemoteProcessID();
// Task to post to clean up the connection. Don't need to retain |this| since
// it wil be called by objects owned by the MemlogConnectionManager.
AllocationTracker::CompleteCallback complete_cb = base::BindOnce(
&MemlogConnectionManager::OnConnectionCompleteThunk,
base::Unretained(this), base::MessageLoop::current()->task_runner(),
remote_process);
std::unique_ptr<Connection> connection = base::MakeUnique<Connection>(
std::move(complete_cb), remote_process, new_pipe);
connection->thread.Start();
connection->parser = new MemlogStreamParser(&connection->tracker);
new_pipe->SetReceiver(connection->thread.task_runner(), connection->parser);
connections_[remote_process] = std::move(connection);
}
void MemlogConnectionManager::OnConnectionComplete(int process_id) {
auto found = connections_.find(process_id);
CHECK(found != connections_.end());
connections_.erase(found);
// When all connections are closed, exit.
if (connections_.empty())
ProfilingGlobals::Get()->QuitWhenIdle();
}
// Posts back to the given thread the connection complete message.
void MemlogConnectionManager::OnConnectionCompleteThunk(
scoped_refptr<base::SingleThreadTaskRunner> main_loop,
int process_id) {
// This code is called by the allocation tracker which is owned by the
// connection manager. When we tell the connection manager a connection is
// done, we know the conncetion manager will still be in scope.
main_loop->PostTask(FROM_HERE,
base::Bind(&MemlogConnectionManager::OnConnectionComplete,
base::Unretained(this), process_id));
}
} // namespace profiling