blob: 603e457778887e4ba39fc7a6851f53b16f5bbf37 [file]
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "lldb/Target/TargetGroup.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/TargetGroupList.h"
#include <algorithm>
#include <cassert>
using namespace lldb;
using namespace lldb_private;
char TargetGroup::ID;
char TargetGroupCPUAndAccelerators::ID;
TargetGroup::TargetGroup(TargetGroupList &group_list,
llvm::StringRef description)
: m_debugger_wp(group_list.m_debugger.shared_from_this()),
m_description(description), m_mutex(group_list.m_mutex) {}
TargetGroup::~TargetGroup() {
assert(m_entries.empty() &&
"target group destroyed while it still contains targets");
}
llvm::Error TargetGroup::ValidateTargetAddition(const TargetSP &, Role) const {
return llvm::Error::success();
}
TargetGroupCPUAndAccelerators::TargetGroupCPUAndAccelerators(
TargetGroupList &group_list, llvm::StringRef description)
: Base(group_list, description) {}
llvm::Error
TargetGroupCPUAndAccelerators::ValidateTargetAddition(const TargetSP &,
Role role) const {
switch (role) {
case Role::CPU:
if (!GetTargets().empty())
return llvm::createStringError(
"the CPU target must be the first target in the group");
break;
case Role::Accelerator:
if (GetTargets(Role::CPU).size() != 1)
return llvm::createStringError(
"the group must contain one CPU target before adding accelerators");
break;
}
return llvm::Error::success();
}
TargetSP TargetGroupCPUAndAccelerators::GetCPUTarget() const {
std::vector<TargetSP> cpu_targets = GetTargets(Role::CPU);
assert(cpu_targets.size() <= 1 &&
"CPU and accelerator group contains multiple CPU targets");
return cpu_targets.empty() ? nullptr : cpu_targets.front();
}
llvm::Error TargetGroup::AddTarget(const TargetSP &target_sp, Role role) {
if (!target_sp)
return llvm::createStringError(
"cannot add a null target to a target group");
if (!target_sp->IsValid())
return llvm::createStringError(
"cannot add an invalid target to a target group");
DebuggerSP debugger_sp = m_debugger_wp.lock();
if (!debugger_sp)
return llvm::createStringError("target group's debugger no longer exists");
if (&target_sp->GetDebugger() != debugger_sp.get())
return llvm::createStringError("target belongs to a different debugger");
std::lock_guard<std::recursive_mutex> guard(*m_mutex);
for (const Entry &entry : m_entries) {
TargetSP member_sp = entry.target_wp.lock();
assert(member_sp && "target did not remove itself from its target group");
if (!member_sp)
continue;
if (member_sp != target_sp)
continue;
if (entry.role == role)
return llvm::Error::success();
return llvm::createStringError(
"target is already in the group with a different role");
}
if (llvm::Error error = ValidateTargetAddition(target_sp, role))
return error;
m_entries.push_back({target_sp, role});
target_sp->AddTargetGroup(shared_from_this());
return llvm::Error::success();
}
bool TargetGroup::RemoveTarget(const TargetSP &target_sp) {
if (!target_sp)
return false;
std::lock_guard<std::recursive_mutex> guard(*m_mutex);
bool removed = false;
auto it = std::remove_if(
m_entries.begin(), m_entries.end(), [&](const Entry &entry) {
TargetSP member_sp = entry.target_wp.lock();
assert(member_sp && "target did not remove itself from its "
"target group");
if (member_sp == target_sp) {
removed = true;
return true;
}
return false;
});
m_entries.erase(it, m_entries.end());
if (removed)
target_sp->RemoveTargetGroup(this);
return removed;
}
std::optional<TargetGroup::Role>
TargetGroup::GetRole(const TargetSP &target_sp) const {
if (!target_sp)
return std::nullopt;
std::lock_guard<std::recursive_mutex> guard(*m_mutex);
for (const Entry &entry : m_entries) {
TargetSP member_sp = entry.target_wp.lock();
assert(member_sp && "target did not remove itself from its target group");
if (member_sp == target_sp)
return entry.role;
}
return std::nullopt;
}
std::vector<TargetSP> TargetGroup::GetTargets() const {
std::vector<TargetSP> targets;
std::lock_guard<std::recursive_mutex> guard(*m_mutex);
for (const Entry &entry : m_entries) {
TargetSP target_sp = entry.target_wp.lock();
assert(target_sp && "target did not remove itself from its target group");
if (target_sp)
targets.push_back(std::move(target_sp));
}
return targets;
}
std::vector<TargetSP> TargetGroup::GetTargets(Role role) const {
std::vector<TargetSP> targets;
std::lock_guard<std::recursive_mutex> guard(*m_mutex);
for (const Entry &entry : m_entries) {
if (entry.role != role)
continue;
TargetSP target_sp = entry.target_wp.lock();
assert(target_sp && "target did not remove itself from its target group");
if (target_sp)
targets.push_back(std::move(target_sp));
}
return targets;
}