blob: e98d5eee01c1b297f22b692d2320244e6786ac6c [file] [log] [blame]
/*
* Copyright (C) 2018 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 SRC_PROFILING_MEMORY_PROCESS_MATCHER_H_
#define SRC_PROFILING_MEMORY_PROCESS_MATCHER_H_
#include <map>
#include <set>
#include <string>
#include <vector>
#include "src/profiling/memory/wire_protocol.h"
namespace perfetto {
namespace profiling {
struct Process {
pid_t pid;
std::string cmdline;
};
struct ProcessSetSpec {
std::set<pid_t> pids;
std::set<std::string> process_cmdline;
bool all = false;
ClientConfiguration client_configuration{};
};
// The Matcher allows DataSources to wait for ProcessSetSpecs, and the
// SocketListener to notify connection of a new Process. Both of these
// operations return an opaque handle that should be held on to by the caller.
//
// If the ProcessHandle gets destroyed, it signals to the Matcher that the
// process disconnected. If the ProcessSetSpecHandle goes away, it signals to
// the Matcher that the ProcessSetSpec has been torn down. When the last
// ProcessSetSpec referring to a Process gets torn down, the Process has to be
// shut down.
//
// In the constructor, a match_fn and a shutdown_fn are supplied.
// match_fn is called when the set of ProcessSetSpecs for a given process
// changes, so that the SocketListener can compute and send the appropriate
// ClientConfiguration.
// shutdown_fn is called when the last DataSource for a process gets torn
// down.
class ProcessMatcher {
private:
struct ProcessItem;
struct ProcessSetSpecItem;
public:
class Delegate {
public:
virtual void Match(
const Process& process,
const std::vector<const ProcessSetSpec*>& process_sets) = 0;
virtual void Disconnect(pid_t pid) = 0;
virtual ~Delegate();
};
class ProcessHandle {
public:
friend class ProcessMatcher;
friend void swap(ProcessHandle&, ProcessHandle&);
ProcessHandle() = default;
~ProcessHandle();
ProcessHandle(const ProcessHandle&) = delete;
ProcessHandle& operator=(const ProcessHandle&) = delete;
ProcessHandle(ProcessHandle&&) noexcept;
ProcessHandle& operator=(ProcessHandle&&) noexcept;
private:
ProcessHandle(ProcessMatcher* matcher, pid_t pid);
ProcessMatcher* matcher_ = nullptr;
pid_t pid_;
};
class ProcessSetSpecHandle {
public:
friend class ProcessMatcher;
friend void swap(ProcessSetSpecHandle&, ProcessSetSpecHandle&);
ProcessSetSpecHandle() = default;
~ProcessSetSpecHandle();
ProcessSetSpecHandle(const ProcessSetSpecHandle&) = delete;
ProcessSetSpecHandle& operator=(const ProcessSetSpecHandle&) = delete;
ProcessSetSpecHandle(ProcessSetSpecHandle&&) noexcept;
ProcessSetSpecHandle& operator=(ProcessSetSpecHandle&&) noexcept;
std::set<pid_t> GetPIDs() const;
private:
ProcessSetSpecHandle(ProcessMatcher* matcher,
std::multiset<ProcessSetSpecItem>::iterator iterator);
ProcessMatcher* matcher_ = nullptr;
std::multiset<ProcessSetSpecItem>::iterator iterator_;
};
ProcessMatcher(Delegate* delegate);
// Notify that a process has connected. This will determine which
// ProcessSetSpecs it matches, and call match_fn with that set.
// This is called by the SocketListener.
ProcessHandle ProcessConnected(Process process);
// Wait for connection of a set of processes as specified in ProcessSetSpec.
// When a process matching that specificaton connects, match_fn will be called
// with this and other ProcessSetSpecs that have called this function
// previously.
// This is called by HeapprofdProducer.
ProcessSetSpecHandle AwaitProcessSetSpec(ProcessSetSpec process_set);
private:
// ProcessItem and ProcessSetSpecItem are held internally in the Matcher for
// each Process and ProcessSetSpec. Matched Processes and ProcessSetSpecs have
// pointers to each other in their ProcessItem and ProcessSetSpecItem structs,
// which are automatically kept up to date in the destructors.
struct ProcessItem {
// No copy or move as we rely on pointer stability in ProcessSetSpecItem.
ProcessItem(const ProcessItem&) = delete;
ProcessItem& operator=(const ProcessItem&) = delete;
ProcessItem(ProcessItem&&) = delete;
ProcessItem& operator=(ProcessItem&&) = delete;
ProcessItem(Process p) : process(std::move(p)) {}
Process process;
std::set<ProcessSetSpecItem*> references;
~ProcessItem();
};
struct ProcessSetSpecItem {
// No copy or move as we rely on pointer stability in ProcessSetSpec.
ProcessSetSpecItem(const ProcessSetSpecItem&) = delete;
ProcessSetSpecItem& operator=(const ProcessSetSpecItem&) = delete;
ProcessSetSpecItem(ProcessSetSpecItem&&) = delete;
ProcessSetSpecItem& operator=(ProcessSetSpecItem&&) = delete;
ProcessSetSpecItem(ProcessMatcher* m, ProcessSetSpec ps)
: matcher(m), process_set(std::move(ps)) {}
~ProcessSetSpecItem();
bool operator<(const ProcessSetSpecItem& other) const;
ProcessMatcher* matcher;
const ProcessSetSpec process_set;
std::set<ProcessItem*> process_items;
};
void UnwaitProcessSetSpec(
std::multiset<ProcessSetSpecItem>::iterator iterator);
void RemoveProcess(pid_t pid);
void ShutdownProcess(pid_t pid);
void RunMatchFn(ProcessItem* process_item);
Delegate* delegate_;
std::map<pid_t, ProcessItem> pid_to_process_;
std::multimap<std::string, ProcessItem*> cmdline_to_process_;
std::multiset<ProcessSetSpecItem> process_sets_;
std::multimap<pid_t, ProcessSetSpecItem*> pid_to_process_set_;
std::multimap<std::string, ProcessSetSpecItem*> cmdline_to_process_set_;
std::set<ProcessSetSpecItem*> process_set_for_all_;
};
void swap(ProcessMatcher::ProcessHandle& a, ProcessMatcher::ProcessHandle& b);
void swap(ProcessMatcher::ProcessSetSpecHandle& a,
ProcessMatcher::ProcessSetSpecHandle& b);
} // namespace profiling
} // namespace perfetto
#endif // SRC_PROFILING_MEMORY_PROCESS_MATCHER_H_