Skip to content

Commit

Permalink
Move thread plan stacks into the Process, indexed by TID.
Browse files Browse the repository at this point in the history
Differential Revision: https://reviews.llvm.org/D75880
  • Loading branch information
jimingham committed Apr 3, 2020
1 parent 2c1c57a commit 61e8e68
Show file tree
Hide file tree
Showing 10 changed files with 668 additions and 340 deletions.
20 changes: 19 additions & 1 deletion lldb/include/lldb/Target/Process.h
Expand Up @@ -37,6 +37,7 @@
#include "lldb/Target/Memory.h"
#include "lldb/Target/QueueList.h"
#include "lldb/Target/ThreadList.h"
#include "lldb/Target/ThreadPlanStack.h"
#include "lldb/Utility/ArchSpec.h"
#include "lldb/Utility/Broadcaster.h"
#include "lldb/Utility/Event.h"
Expand Down Expand Up @@ -2197,6 +2198,19 @@ class Process : public std::enable_shared_from_this<Process>,
}

void SetDynamicCheckers(DynamicCheckerFunctions *dynamic_checkers);

/// Find the thread plan stack associated with thread with \a tid.
///
/// \param[in] tid
/// The tid whose Plan Stack we are seeking..
///
/// \return
/// Returns a ThreadPlan if the TID is found or nullptr if not.
ThreadPlanStack *FindThreadPlans(lldb::tid_t tid);

void AddThreadPlansForThread(Thread &thread);

void RemoveThreadPlansForTID(lldb::tid_t tid);

/// Call this to set the lldb in the mode where it breaks on new thread
/// creations, and then auto-restarts. This is useful when you are trying
Expand Down Expand Up @@ -2533,7 +2547,7 @@ class Process : public std::enable_shared_from_this<Process>,
virtual EventActionResult HandleBeingInterrupted() = 0;
virtual const char *GetExitString() = 0;
void RequestResume() { m_process->m_resume_requested = true; }

protected:
Process *m_process;
};
Expand Down Expand Up @@ -2667,6 +2681,10 @@ class Process : public std::enable_shared_from_this<Process>,
///see them. This is usually the same as
///< m_thread_list_real, but might be different if there is an OS plug-in
///creating memory threads
ThreadPlanStackMap m_thread_plans; ///< This is the list of thread plans for
/// threads in m_thread_list, as well as
/// threads we knew existed, but haven't
/// determined that they have died yet.
ThreadList m_extended_thread_list; ///< Owner for extended threads that may be
///generated, cleared on natural stops
uint32_t m_extended_thread_stop_id; ///< The natural stop id when
Expand Down
36 changes: 15 additions & 21 deletions lldb/include/lldb/Target/Thread.h
Expand Up @@ -28,6 +28,8 @@

namespace lldb_private {

class ThreadPlanStack;

class ThreadProperties : public Properties {
public:
ThreadProperties(bool is_global);
Expand Down Expand Up @@ -119,7 +121,7 @@ class Thread : public std::enable_shared_from_this<Thread>,
// bit of data.
lldb::StopInfoSP stop_info_sp; // You have to restore the stop info or you
// might continue with the wrong signals.
std::vector<lldb::ThreadPlanSP> m_completed_plan_stack;
size_t m_completed_plan_checkpoint;
lldb::RegisterCheckpointSP
register_backup_sp; // You need to restore the registers, of course...
uint32_t current_inlined_depth;
Expand Down Expand Up @@ -912,7 +914,7 @@ class Thread : public std::enable_shared_from_this<Thread>,
///
/// \return
/// A pointer to the next executed plan.
ThreadPlan *GetCurrentPlan();
ThreadPlan *GetCurrentPlan() const;

/// Unwinds the thread stack for the innermost expression plan currently
/// on the thread plan stack.
Expand All @@ -927,22 +929,22 @@ class Thread : public std::enable_shared_from_this<Thread>,
///
/// \return
/// A pointer to the last completed plan.
lldb::ThreadPlanSP GetCompletedPlan();
lldb::ThreadPlanSP GetCompletedPlan() const;

/// Gets the outer-most return value from the completed plans
///
/// \return
/// A ValueObjectSP, either empty if there is no return value,
/// or containing the return value.
lldb::ValueObjectSP GetReturnValueObject();
lldb::ValueObjectSP GetReturnValueObject() const;

/// Gets the outer-most expression variable from the completed plans
///
/// \return
/// A ExpressionVariableSP, either empty if there is no
/// plan completed an expression during the current stop
/// or the expression variable that was made for the completed expression.
lldb::ExpressionVariableSP GetExpressionVariable();
lldb::ExpressionVariableSP GetExpressionVariable() const;

/// Checks whether the given plan is in the completed plans for this
/// stop.
Expand All @@ -953,7 +955,7 @@ class Thread : public std::enable_shared_from_this<Thread>,
/// \return
/// Returns true if the input plan is in the completed plan stack,
/// false otherwise.
bool IsThreadPlanDone(ThreadPlan *plan);
bool IsThreadPlanDone(ThreadPlan *plan) const;

/// Checks whether the given plan is in the discarded plans for this
/// stop.
Expand All @@ -964,14 +966,14 @@ class Thread : public std::enable_shared_from_this<Thread>,
/// \return
/// Returns true if the input plan is in the discarded plan stack,
/// false otherwise.
bool WasThreadPlanDiscarded(ThreadPlan *plan);
bool WasThreadPlanDiscarded(ThreadPlan *plan) const;

/// Check if we have completed plan to override breakpoint stop reason
///
/// \return
/// Returns true if completed plan stack is not empty
/// false otherwise.
bool CompletedPlanOverridesBreakpoint();
bool CompletedPlanOverridesBreakpoint() const;

/// Queues a generic thread plan.
///
Expand Down Expand Up @@ -1184,16 +1186,16 @@ class Thread : public std::enable_shared_from_this<Thread>,
// thread is still in good shape to call virtual thread methods. This must
// be called by classes that derive from Thread in their destructor.
virtual void DestroyThread();

ThreadPlanStack &GetPlans() const;

void PushPlan(lldb::ThreadPlanSP &plan_sp);
void PushPlan(lldb::ThreadPlanSP plan_sp);

void PopPlan();

void DiscardPlan();

ThreadPlan *GetPreviousPlan(ThreadPlan *plan);

typedef std::vector<lldb::ThreadPlanSP> plan_stack;
ThreadPlan *GetPreviousPlan(ThreadPlan *plan) const;

virtual Unwind &GetUnwinder();

Expand Down Expand Up @@ -1238,13 +1240,6 @@ class Thread : public std::enable_shared_from_this<Thread>,
lldb::StateType m_state; ///< The state of our process.
mutable std::recursive_mutex
m_state_mutex; ///< Multithreaded protection for m_state.
plan_stack m_plan_stack; ///< The stack of plans this thread is executing.
plan_stack m_completed_plan_stack; ///< Plans that have been completed by this
///stop. They get deleted when the thread
///resumes.
plan_stack m_discarded_plan_stack; ///< Plans that have been discarded by this
///stop. They get deleted when the thread
///resumes.
mutable std::recursive_mutex
m_frame_mutex; ///< Multithreaded protection for m_state.
lldb::StackFrameListSP m_curr_frames_sp; ///< The stack frames that get lazily
Expand Down Expand Up @@ -1272,8 +1267,7 @@ class Thread : public std::enable_shared_from_this<Thread>,
StructuredData::ObjectSP m_extended_info; // The extended info for this thread

private:
bool PlanIsBasePlan(ThreadPlan *plan_ptr);


void BroadcastSelectedFrameChange(StackID &new_frame_id);

DISALLOW_COPY_AND_ASSIGN(Thread);
Expand Down
4 changes: 2 additions & 2 deletions lldb/include/lldb/Target/ThreadPlan.h
Expand Up @@ -371,9 +371,9 @@ class ThreadPlan : public std::enable_shared_from_this<ThreadPlan>,
/// A pointer to the thread plan's owning thread.
Thread &GetThread();

Target &GetTarget() { return m_process.GetTarget(); }
Target &GetTarget();

const Target &GetTarget() const { return m_process.GetTarget(); }
const Target &GetTarget() const;

/// Print a description of this thread to the stream \a s.
/// \a thread.
Expand Down
153 changes: 153 additions & 0 deletions lldb/include/lldb/Target/ThreadPlanStack.h
@@ -0,0 +1,153 @@
//===-- ThreadPlanStack.h ---------------------------------------*- C++ -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//

#ifndef LLDB_TARGET_THREADPLANSTACK_H
#define LLDB_TARGET_THREADPLANSTACK_H

#include <mutex>
#include <string>
#include <unordered_map>
#include <vector>

#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#include "lldb/lldb-private-forward.h"
#include "lldb/lldb-private.h"

namespace lldb_private {

// The ThreadPlans have a thread for use when they are asked all the ThreadPlan
// state machine questions, but they should never cache any pointers from their
// owning lldb_private::Thread. That's because we want to be able to detach
// them from an owning thread, then reattach them by TID.
// The ThreadPlanStack holds the ThreadPlans for a given TID. All its methods
// are private, and it should only be accessed through the owning thread. When
// it is detached from a thread, all you can do is reattach it or delete it.
class ThreadPlanStack {
friend class lldb_private::Thread;

public:
ThreadPlanStack(Thread &thread) {}
~ThreadPlanStack() {}

enum StackKind { ePlans, eCompletedPlans, eDiscardedPlans };

using PlanStack = std::vector<lldb::ThreadPlanSP>;

void DumpThreadPlans(Stream *s, lldb::DescriptionLevel desc_level,
bool include_internal) const;

size_t CheckpointCompletedPlans();

void RestoreCompletedPlanCheckpoint(size_t checkpoint);

void DiscardCompletedPlanCheckpoint(size_t checkpoint);

void ThreadDestroyed(Thread *thread);

void EnableTracer(bool value, bool single_stepping);

void SetTracer(lldb::ThreadPlanTracerSP &tracer_sp);

void PushPlan(lldb::ThreadPlanSP new_plan_sp);

lldb::ThreadPlanSP PopPlan();

lldb::ThreadPlanSP DiscardPlan();

// If the input plan is nullptr, discard all plans. Otherwise make sure this
// plan is in the stack, and if so discard up to and including it.
void DiscardPlansUpToPlan(ThreadPlan *up_to_plan_ptr);

void DiscardAllPlans();

void DiscardConsultingMasterPlans();

lldb::ThreadPlanSP GetCurrentPlan() const;

lldb::ThreadPlanSP GetCompletedPlan(bool skip_private = true) const;

lldb::ThreadPlanSP GetPlanByIndex(uint32_t plan_idx,
bool skip_private = true) const;

lldb::ValueObjectSP GetReturnValueObject() const;

lldb::ExpressionVariableSP GetExpressionVariable() const;

bool AnyPlans() const;

bool AnyCompletedPlans() const;

bool AnyDiscardedPlans() const;

bool IsPlanDone(ThreadPlan *plan) const;

bool WasPlanDiscarded(ThreadPlan *plan) const;

ThreadPlan *GetPreviousPlan(ThreadPlan *current_plan) const;

ThreadPlan *GetInnermostExpression() const;

void WillResume();

private:
const PlanStack &GetStackOfKind(ThreadPlanStack::StackKind kind) const;

PlanStack m_plans; ///< The stack of plans this thread is executing.
PlanStack m_completed_plans; ///< Plans that have been completed by this
/// stop. They get deleted when the thread
/// resumes.
PlanStack m_discarded_plans; ///< Plans that have been discarded by this
/// stop. They get deleted when the thread
/// resumes.
size_t m_completed_plan_checkpoint = 0; // Monotonically increasing token for
// completed plan checkpoints.
std::unordered_map<size_t, PlanStack> m_completed_plan_store;
};

class ThreadPlanStackMap {
public:
ThreadPlanStackMap() {}
~ThreadPlanStackMap() {}

void AddThread(Thread &thread) {
lldb::tid_t tid = thread.GetID();
auto result = m_plans_list.emplace(tid, thread);
}

bool RemoveTID(lldb::tid_t tid) {
auto result = m_plans_list.find(tid);
if (result == m_plans_list.end())
return false;
result->second.ThreadDestroyed(nullptr);
m_plans_list.erase(result);
return true;
}

ThreadPlanStack *Find(lldb::tid_t tid) {
auto result = m_plans_list.find(tid);
if (result == m_plans_list.end())
return nullptr;
else
return &result->second;
}

void Clear() {
for (auto plan : m_plans_list)
plan.second.ThreadDestroyed(nullptr);
m_plans_list.clear();
}

private:
using PlansList = std::unordered_map<lldb::tid_t, ThreadPlanStack>;
PlansList m_plans_list;
};

} // namespace lldb_private

#endif // LLDB_TARGET_THREADPLANSTACK_H
1 change: 1 addition & 0 deletions lldb/source/Target/CMakeLists.txt
Expand Up @@ -63,6 +63,7 @@ add_lldb_library(lldbTarget
ThreadPlanStepThrough.cpp
ThreadPlanStepUntil.cpp
ThreadPlanTracer.cpp
ThreadPlanStack.cpp
ThreadSpec.cpp
UnixSignals.cpp
UnwindAssembly.cpp
Expand Down
20 changes: 20 additions & 0 deletions lldb/source/Target/Process.cpp
Expand Up @@ -60,6 +60,7 @@
#include "lldb/Target/ThreadPlan.h"
#include "lldb/Target/ThreadPlanBase.h"
#include "lldb/Target/ThreadPlanCallFunction.h"
#include "lldb/Target/ThreadPlanStack.h"
#include "lldb/Target/UnixSignals.h"
#include "lldb/Utility/Event.h"
#include "lldb/Utility/Log.h"
Expand Down Expand Up @@ -600,6 +601,7 @@ void Process::Finalize() {
m_system_runtime_up.reset();
m_dyld_up.reset();
m_jit_loaders_up.reset();
m_thread_plans.Clear();
m_thread_list_real.Destroy();
m_thread_list.Destroy();
m_extended_thread_list.Destroy();
Expand Down Expand Up @@ -1252,6 +1254,20 @@ void Process::UpdateThreadListIfNeeded() {
}
}

ThreadPlanStack *Process::FindThreadPlans(lldb::tid_t tid) {
return m_thread_plans.Find(tid);
}

void Process::AddThreadPlansForThread(Thread &thread) {
if (m_thread_plans.Find(thread.GetID()))
return;
m_thread_plans.AddThread(thread);
}

void Process::RemoveThreadPlansForTID(lldb::tid_t tid) {
m_thread_plans.RemoveTID(tid);
}

void Process::UpdateQueueListIfNeeded() {
if (m_system_runtime_up) {
if (m_queue_list.GetSize() == 0 ||
Expand Down Expand Up @@ -3231,6 +3247,10 @@ Status Process::Detach(bool keep_stopped) {
}

Status Process::Destroy(bool force_kill) {
// If we've already called Process::Finalize then there's nothing useful to
// be done here. Finalize has actually called Destroy already.
if (m_finalize_called)
return {};

// Tell ourselves we are in the process of destroying the process, so that we
// don't do any unnecessary work that might hinder the destruction. Remember
Expand Down

0 comments on commit 61e8e68

Please sign in to comment.