//===-- Thread.h ------------------------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#ifndef liblldb_Thread_h_
#define liblldb_Thread_h_

// C Includes
// C++ Includes
#include <memory>
#include <string>
#include <vector>

// Other libraries and framework includes
// Project includes
#include "lldb/lldb-private.h"
#include "lldb/Host/Mutex.h"
#include "lldb/Core/Broadcaster.h"
#include "lldb/Core/Event.h"
#include "lldb/Core/StructuredData.h"
#include "lldb/Core/UserID.h"
#include "lldb/Core/UserSettingsController.h"
#include "lldb/Target/ExecutionContextScope.h"
#include "lldb/Target/RegisterCheckpoint.h"
#include "lldb/Target/StackFrameList.h"

#define LLDB_THREAD_MAX_STOP_EXC_DATA 8

namespace lldb_private {

class ThreadProperties : public Properties
{
public:
    ThreadProperties(bool is_global);
    
    ~ThreadProperties() override;
    
    //------------------------------------------------------------------
    /// The regular expression returned determines symbols that this
    /// thread won't stop in during "step-in" operations.
    ///
    /// @return
    ///    A pointer to a regular expression to compare against symbols,
    ///    or nullptr if all symbols are allowed.
    ///
    //------------------------------------------------------------------
    const RegularExpression *
    GetSymbolsToAvoidRegexp();
    
    FileSpecList &
    GetLibrariesToAvoid() const;
    
    bool
    GetTraceEnabledState() const;
    
    bool
    GetStepInAvoidsNoDebug () const;
    
    bool
    GetStepOutAvoidsNoDebug () const;
};

typedef std::shared_ptr<ThreadProperties> ThreadPropertiesSP;

class Thread :
    public std::enable_shared_from_this<Thread>,
    public ThreadProperties,
    public UserID,
    public ExecutionContextScope,
    public Broadcaster
{
public:
    //------------------------------------------------------------------
    /// Broadcaster event bits definitions.
    //------------------------------------------------------------------
    enum
    {
        eBroadcastBitStackChanged           = (1 << 0),
        eBroadcastBitThreadSuspended        = (1 << 1),
        eBroadcastBitThreadResumed          = (1 << 2),
        eBroadcastBitSelectedFrameChanged   = (1 << 3),
        eBroadcastBitThreadSelected         = (1 << 4)
    };

    static ConstString &GetStaticBroadcasterClass ();
    
    ConstString &GetBroadcasterClass() const override
    {
        return GetStaticBroadcasterClass();
    }
    
    class ThreadEventData :
        public EventData
    {
    public:
        ThreadEventData (const lldb::ThreadSP thread_sp);
        
        ThreadEventData (const lldb::ThreadSP thread_sp, const StackID &stack_id);
        
        ThreadEventData();
        
        ~ThreadEventData() override;
        
        static const ConstString &
        GetFlavorString ();

        const ConstString &
        GetFlavor() const override
        {
            return ThreadEventData::GetFlavorString ();
        }
        
        void
        Dump(Stream *s) const override;
    
        static const ThreadEventData *
        GetEventDataFromEvent (const Event *event_ptr);
        
        static lldb::ThreadSP
        GetThreadFromEvent (const Event *event_ptr);
        
        static StackID
        GetStackIDFromEvent (const Event *event_ptr);
        
        static lldb::StackFrameSP
        GetStackFrameFromEvent (const Event *event_ptr);
        
        lldb::ThreadSP
        GetThread () const
        {
            return m_thread_sp;
        }
        
        StackID
        GetStackID () const
        {
            return m_stack_id;
        }
    
    private:
        lldb::ThreadSP m_thread_sp;
        StackID        m_stack_id;

        DISALLOW_COPY_AND_ASSIGN (ThreadEventData);
    };

    struct ThreadStateCheckpoint
    {
        uint32_t           orig_stop_id;  // Dunno if I need this yet but it is an interesting bit of data.
        lldb::StopInfoSP   stop_info_sp;  // You have to restore the stop info or you might continue with the wrong signals.
        lldb::RegisterCheckpointSP register_backup_sp;  // You need to restore the registers, of course...
        uint32_t           current_inlined_depth;
        lldb::addr_t       current_inlined_pc;
    };

    //------------------------------------------------------------------
    /// Constructor
    ///
    /// @param [in] process
    ///
    /// @param [in] tid
    ///
    /// @param [in] use_invalid_index_id
    ///     Optional parameter, defaults to false.  The only subclass that
    ///     is likely to set use_invalid_index_id == true is the HistoryThread
    ///     class.  In that case, the Thread we are constructing represents
    ///     a thread from earlier in the program execution.  We may have the 
    ///     tid of the original thread that they represent but we don't want 
    ///     to reuse the IndexID of that thread, or create a new one.  If a
    ///     client wants to know the original thread's IndexID, they should use
    ///     Thread::GetExtendedBacktraceOriginatingIndexID().
    //------------------------------------------------------------------
    Thread (Process &process, lldb::tid_t tid, bool use_invalid_index_id = false);

    ~Thread() override;

    static void
    SettingsInitialize ();

    static void
    SettingsTerminate ();

    static const ThreadPropertiesSP &
    GetGlobalProperties();

    lldb::ProcessSP
    GetProcess() const
    {
        return m_process_wp.lock(); 
    }

    int
    GetResumeSignal () const
    {
        return m_resume_signal;
    }

    void
    SetResumeSignal (int signal)
    {
        m_resume_signal = signal;
    }

    lldb::StateType
    GetState() const;

    void
    SetState (lldb::StateType state);

    //------------------------------------------------------------------
    /// Sets the USER resume state for this thread.  If you set a thread to suspended with
    /// this API, it won't take part in any of the arbitration for ShouldResume, and will stay
    /// suspended even when other threads do get to run.
    ///
    /// N.B. This is not the state that is used internally by thread plans to implement
    /// staying on one thread while stepping over a breakpoint, etc.  The is the
    /// TemporaryResume state, and if you are implementing some bit of strategy in the stepping
    /// machinery you should be using that state and not the user resume state.
    ///
    /// If you are just preparing all threads to run, you should not override the threads that are
    /// marked as suspended by the debugger.  In that case, pass override_suspend = false.  If you want
    /// to force the thread to run (e.g. the "thread continue" command, or are resetting the state
    /// (e.g. in SBThread::Resume()), then pass true to override_suspend.
    /// @return
    ///    The User resume state for this thread.
    //------------------------------------------------------------------
    void
    SetResumeState (lldb::StateType state, bool override_suspend = false)
    {
        if (m_resume_state == lldb::eStateSuspended && !override_suspend)
            return;
        m_resume_state = state;
    }

    //------------------------------------------------------------------
    /// Gets the USER resume state for this thread.  This is not the same as what
    /// this thread is going to do for any particular step, however if this thread
    /// returns eStateSuspended, then the process control logic will never allow this
    /// thread to run.
    ///
    /// @return
    ///    The User resume state for this thread.
    //------------------------------------------------------------------
    lldb::StateType
    GetResumeState () const
    {
        return m_resume_state;
    }
    
    // This function is called on all the threads before "ShouldResume" and
    // "WillResume" in case a thread needs to change its state before the
    // ThreadList polls all the threads to figure out which ones actually
    // will get to run and how.
    void
    SetupForResume ();
    
    // Do not override this function, it is for thread plan logic only
    bool
    ShouldResume (lldb::StateType resume_state);

    // Override this to do platform specific tasks before resume.
    virtual void
    WillResume (lldb::StateType resume_state)
    {
    }

    // This clears generic thread state after a resume.  If you subclass this,
    // be sure to call it.
    virtual void
    DidResume ();

    // This notifies the thread when a private stop occurs.
    virtual void
    DidStop ();

    virtual void
    RefreshStateAfterStop() = 0;

    void
    WillStop ();

    bool
    ShouldStop (Event *event_ptr);

    Vote
    ShouldReportStop (Event *event_ptr);
    
    Vote
    ShouldReportRun (Event *event_ptr);
    
    void
    Flush ();

    // Return whether this thread matches the specification in ThreadSpec.  This is a virtual
    // method because at some point we may extend the thread spec with a platform specific
    // dictionary of attributes, which then only the platform specific Thread implementation
    // would know how to match.  For now, this just calls through to the ThreadSpec's 
    // ThreadPassesBasicTests method.
    virtual bool
    MatchesSpec (const ThreadSpec *spec);

    lldb::StopInfoSP
    GetStopInfo ();

    lldb::StopReason
    GetStopReason();

    bool
    StopInfoIsUpToDate() const;

    // This sets the stop reason to a "blank" stop reason, so you can call functions on the thread
    // without having the called function run with whatever stop reason you stopped with.
    void
    SetStopInfoToNothing();
    
    bool
    ThreadStoppedForAReason ();

    static const char *
    RunModeAsCString (lldb::RunMode mode);

    static const char *
    StopReasonAsCString (lldb::StopReason reason);

    virtual const char *
    GetInfo ()
    {
        return nullptr;
    }

    //------------------------------------------------------------------
    /// Retrieve a dictionary of information about this thread 
    ///
    /// On Mac OS X systems there may be voucher information.
    /// The top level dictionary returned will have an "activity" key and the
    /// value of the activity is a dictionary.  Keys in that dictionary will 
    /// be "name" and "id", among others.
    /// There may also be "trace_messages" (an array) with each entry in that array
    /// being a dictionary (keys include "message" with the text of the trace
    /// message).
    //------------------------------------------------------------------
    StructuredData::ObjectSP
    GetExtendedInfo ()
    {
        if (m_extended_info_fetched == false)
        {
            m_extended_info = FetchThreadExtendedInfo ();
            m_extended_info_fetched = true;
        }
        return m_extended_info;
    }

    virtual const char *
    GetName ()
    {
        return nullptr;
    }

    virtual void
    SetName (const char *name)
    {
    }

    //------------------------------------------------------------------
    /// Whether this thread can be associated with a libdispatch queue
    /// 
    /// The Thread may know if it is associated with a libdispatch queue,
    /// it may know definitively that it is NOT associated with a libdispatch
    /// queue, or it may be unknown whether it is associated with a libdispatch
    /// queue.  
    ///
    /// @return
    ///     eLazyBoolNo if this thread is definitely not associated with a
    ///     libdispatch queue (e.g. on a non-Darwin system where GCD aka 
    ///     libdispatch is not available).
    ///
    ///     eLazyBoolYes this thread is associated with a libdispatch queue.
    ///
    ///     eLazyBoolCalculate this thread may be associated with a libdispatch 
    ///     queue but the thread doesn't know one way or the other.
    //------------------------------------------------------------------
    virtual lldb_private::LazyBool
    GetAssociatedWithLibdispatchQueue ()
    {
        return eLazyBoolNo;
    }

    virtual void
    SetAssociatedWithLibdispatchQueue (lldb_private::LazyBool associated_with_libdispatch_queue)
    {
    }

    //------------------------------------------------------------------
    /// Retrieve the Queue ID for the queue currently using this Thread
    ///
    /// If this Thread is doing work on behalf of a libdispatch/GCD queue,
    /// retrieve the QueueID.
    ///
    /// This is a unique identifier for the libdispatch/GCD queue in a 
    /// process.  Often starting at 1 for the initial system-created 
    /// queues and incrementing, a QueueID will not be reused for a
    /// different queue during the lifetime of a proces.
    ///
    /// @return
    ///     A QueueID if the Thread subclass implements this, else
    ///     LLDB_INVALID_QUEUE_ID.
    //------------------------------------------------------------------
    virtual lldb::queue_id_t
    GetQueueID ()
    {
        return LLDB_INVALID_QUEUE_ID;
    }

    virtual void
    SetQueueID (lldb::queue_id_t new_val)
    {
    }

    //------------------------------------------------------------------
    /// Retrieve the Queue name for the queue currently using this Thread
    ///
    /// If this Thread is doing work on behalf of a libdispatch/GCD queue,
    /// retrieve the Queue name.
    ///
    /// @return
    ///     The Queue name, if the Thread subclass implements this, else
    ///     nullptr.
    //------------------------------------------------------------------
    virtual const char *
    GetQueueName ()
    {
        return nullptr;
    }

    virtual void
    SetQueueName (const char *name)
    {
    }

    //------------------------------------------------------------------
    /// Retrieve the Queue kind for the queue currently using this Thread
    ///
    /// If this Thread is doing work on behalf of a libdispatch/GCD queue,
    /// retrieve the Queue kind - either eQueueKindSerial or 
    /// eQueueKindConcurrent, indicating that this queue processes work
    /// items serially or concurrently.
    ///
    /// @return
    ///     The Queue kind, if the Thread subclass implements this, else
    ///     eQueueKindUnknown.
    //------------------------------------------------------------------
    virtual lldb::QueueKind
    GetQueueKind ()
    {
        return lldb::eQueueKindUnknown;
    }

    virtual void
    SetQueueKind (lldb::QueueKind kind)
    {
    }

    //------------------------------------------------------------------
    /// Retrieve the Queue for this thread, if any.
    ///
    /// @return
    ///     A QueueSP for the queue that is currently associated with this 
    ///     thread.
    ///     An empty shared pointer indicates that this thread is not
    ///     associated with a queue, or libdispatch queues are not 
    ///     supported on this target.
    //------------------------------------------------------------------
    virtual lldb::QueueSP
    GetQueue ()
    {
        return lldb::QueueSP();
    }

    //------------------------------------------------------------------
    /// Retrieve the address of the libdispatch_queue_t struct for queue
    /// currently using this Thread
    ///
    /// If this Thread is doing work on behalf of a libdispatch/GCD queue,
    /// retrieve the address of the libdispatch_queue_t structure describing
    /// the queue.
    ///
    /// This address may be reused for different queues later in the Process
    /// lifetime and should not be used to identify a queue uniquely.  Use
    /// the GetQueueID() call for that.
    ///
    /// @return
    ///     The Queue's libdispatch_queue_t address if the Thread subclass
    ///     implements this, else LLDB_INVALID_ADDRESS.
    //------------------------------------------------------------------
    virtual lldb::addr_t
    GetQueueLibdispatchQueueAddress ()
    {
        return LLDB_INVALID_ADDRESS;
    }

    virtual void
    SetQueueLibdispatchQueueAddress (lldb::addr_t dispatch_queue_t)
    {
    }

    //------------------------------------------------------------------
    /// Whether this Thread already has all the Queue information cached or not
    ///
    /// A Thread may be associated with a libdispatch work Queue at a given
    /// public stop event.  If so, the thread can satisify requests like
    /// GetQueueLibdispatchQueueAddress, GetQueueKind, GetQueueName, and GetQueueID
    /// either from information from the remote debug stub when it is initially
    /// created, or it can query the SystemRuntime for that information.
    ///
    /// This method allows the SystemRuntime to discover if a thread has this
    /// information already, instead of calling the thread to get the information
    /// and having the thread call the SystemRuntime again.
    //------------------------------------------------------------------
    virtual bool
    ThreadHasQueueInformation () const
    {
        return false;
    }

    virtual uint32_t
    GetStackFrameCount()
    {
        return GetStackFrameList()->GetNumFrames();
    }

    virtual lldb::StackFrameSP
    GetStackFrameAtIndex (uint32_t idx)
    {
        return GetStackFrameList()->GetFrameAtIndex(idx);
    }
    
    virtual lldb::StackFrameSP
    GetFrameWithConcreteFrameIndex (uint32_t unwind_idx);
    
    bool
    DecrementCurrentInlinedDepth()
    {
        return GetStackFrameList()->DecrementCurrentInlinedDepth();
    }
    
    uint32_t
    GetCurrentInlinedDepth()
    {
        return GetStackFrameList()->GetCurrentInlinedDepth();
    }
    
    Error
    ReturnFromFrameWithIndex (uint32_t frame_idx, lldb::ValueObjectSP return_value_sp, bool broadcast = false);
    
    Error
    ReturnFromFrame (lldb::StackFrameSP frame_sp, lldb::ValueObjectSP return_value_sp, bool broadcast = false);

    Error
    JumpToLine(const FileSpec &file, uint32_t line, bool can_leave_function, std::string *warnings = nullptr);

    virtual lldb::StackFrameSP
    GetFrameWithStackID (const StackID &stack_id)
    {
        if (stack_id.IsValid())
            return GetStackFrameList()->GetFrameWithStackID (stack_id);
        return lldb::StackFrameSP();
    }

    uint32_t
    GetSelectedFrameIndex ()
    {
        return GetStackFrameList()->GetSelectedFrameIndex();
    }

    lldb::StackFrameSP
    GetSelectedFrame ();

    uint32_t
    SetSelectedFrame (lldb_private::StackFrame *frame, bool broadcast = false);

    bool
    SetSelectedFrameByIndex (uint32_t frame_idx, bool broadcast = false);

    bool
    SetSelectedFrameByIndexNoisily (uint32_t frame_idx, Stream &output_stream);

    void
    SetDefaultFileAndLineToSelectedFrame()
    {
        GetStackFrameList()->SetDefaultFileAndLineToSelectedFrame();
    }

    virtual lldb::RegisterContextSP
    GetRegisterContext () = 0;

    virtual lldb::RegisterContextSP
    CreateRegisterContextForFrame (StackFrame *frame) = 0;
    
    virtual void
    ClearStackFrames ();

    virtual bool
    SetBackingThread (const lldb::ThreadSP &thread_sp)
    {
        return false;
    }
    
    virtual lldb::ThreadSP
    GetBackingThread () const
    {
        return lldb::ThreadSP();
    }

    virtual void
    ClearBackingThread ()
    {
        // Subclasses can use this function if a thread is actually backed by
        // another thread. This is currently used for the OperatingSystem plug-ins
        // where they might have a thread that is in memory, yet its registers
        // are available through the lldb_private::Thread subclass for the current
        // lldb_private::Process class. Since each time the process stops the backing
        // threads for memory threads can change, we need a way to clear the backing
        // thread for all memory threads each time we stop.
    }

    void
    DumpUsingSettingsFormat (Stream &strm, uint32_t frame_idx);

    bool
    GetDescription (Stream &s, lldb::DescriptionLevel level, bool print_json_thread, bool print_json_stopinfo);

    //------------------------------------------------------------------
    /// Default implementation for stepping into.
    ///
    /// This function is designed to be used by commands where the
    /// process is publicly stopped.
    ///
    /// @param[in] source_step
    ///     If true and the frame has debug info, then do a source level
    ///     step in, else do a single instruction step in.
    ///
    /// @param[in] step_in_avoids_code_without_debug_info
    ///     If \a true, then avoid stepping into code that doesn't have
    ///     debug info, else step into any code regardless of whether it
    ///     has debug info.
    ///
    /// @param[in] step_out_avoids_code_without_debug_info
    ///     If \a true, then if you step out to code with no debug info, keep
    ///     stepping out till you get to code with debug info.
    ///
    /// @return
    ///     An error that describes anything that went wrong
    //------------------------------------------------------------------
    virtual Error
    StepIn (bool source_step,
            LazyBool step_in_avoids_code_without_debug_info = eLazyBoolCalculate,
            LazyBool step_out_avoids_code_without_debug_info = eLazyBoolCalculate);

    //------------------------------------------------------------------
    /// Default implementation for stepping over.
    ///
    /// This function is designed to be used by commands where the
    /// process is publicly stopped.
    ///
    /// @param[in] source_step
    ///     If true and the frame has debug info, then do a source level
    ///     step over, else do a single instruction step over.
    ///
    /// @return
    ///     An error that describes anything that went wrong
    //------------------------------------------------------------------
    virtual Error
    StepOver (bool source_step,
              LazyBool step_out_avoids_code_without_debug_info = eLazyBoolCalculate);

    //------------------------------------------------------------------
    /// Default implementation for stepping out.
    ///
    /// This function is designed to be used by commands where the
    /// process is publicly stopped.
    ///
    /// @return
    ///     An error that describes anything that went wrong
    //------------------------------------------------------------------
    virtual Error
    StepOut ();

    //------------------------------------------------------------------
    /// Retrieves the per-thread data area.
    /// Most OSs maintain a per-thread pointer (e.g. the FS register on
    /// x64), which we return the value of here.
    ///
    /// @return
    ///     LLDB_INVALID_ADDRESS if not supported, otherwise the thread
    ///     pointer value.
    //------------------------------------------------------------------
    virtual lldb::addr_t
    GetThreadPointer ();

    //------------------------------------------------------------------
    /// Retrieves the per-module TLS block for a thread.
    ///
    /// @param[in] module
    ///     The module to query TLS data for.
    ///
    /// @return
    ///     If the thread has TLS data allocated for the
    ///     module, the address of the TLS block. Otherwise
    ///     LLDB_INVALID_ADDRESS is returned.
    //------------------------------------------------------------------
    virtual lldb::addr_t
    GetThreadLocalData (const lldb::ModuleSP module);

    //------------------------------------------------------------------
    /// Check whether this thread is safe to run functions
    ///
    /// The SystemRuntime may know of certain thread states (functions in 
    /// process of execution, for instance) which can make it unsafe for 
    /// functions to be called.
    ///
    /// @return
    ///     True if it is safe to call functions on this thread.
    ///     False if function calls should be avoided on this thread.
    //------------------------------------------------------------------
    virtual bool
    SafeToCallFunctions ();

    //------------------------------------------------------------------
    // Thread Plan Providers:
    // This section provides the basic thread plans that the Process control
    // machinery uses to run the target.  ThreadPlan.h provides more details on
    // how this mechanism works.
    // The thread provides accessors to a set of plans that perform basic operations.
    // The idea is that particular Platform plugins can override these methods to
    // provide the implementation of these basic operations appropriate to their
    // environment.
    //
    // NB: All the QueueThreadPlanXXX providers return Shared Pointers to
    // Thread plans.  This is useful so that you can modify the plans after
    // creation in ways specific to that plan type.  Also, it is often necessary for
    // ThreadPlans that utilize other ThreadPlans to implement their task to keep a shared
    // pointer to the sub-plan.
    // But besides that, the shared pointers should only be held onto by entities who live no longer
    // than the thread containing the ThreadPlan.
    // FIXME: If this becomes a problem, we can make a version that just returns a pointer,
    // which it is clearly unsafe to hold onto, and a shared pointer version, and only allow
    // ThreadPlan and Co. to use the latter.  That is made more annoying to do because there's
    // no elegant way to friend a method to all sub-classes of a given class.
    //
    //------------------------------------------------------------------

    //------------------------------------------------------------------
    /// Queues the base plan for a thread.
    /// The version returned by Process does some things that are useful,
    /// like handle breakpoints and signals, so if you return a plugin specific
    /// one you probably want to call through to the Process one for anything
    /// your plugin doesn't explicitly handle.
    ///
    /// @param[in] abort_other_plans
    ///    \b true if we discard the currently queued plans and replace them with this one.
    ///    Otherwise this plan will go on the end of the plan stack.
    ///
    /// @return
    ///     A shared pointer to the newly queued thread plan, or nullptr if the plan could not be queued.
    //------------------------------------------------------------------
    virtual lldb::ThreadPlanSP
    QueueFundamentalPlan (bool abort_other_plans);

    //------------------------------------------------------------------
    /// Queues the plan used to step one instruction from the current PC of \a thread.
    ///
    /// @param[in] step_over
    ///    \b true if we step over calls to functions, false if we step in.
    ///
    /// @param[in] abort_other_plans
    ///    \b true if we discard the currently queued plans and replace them with this one.
    ///    Otherwise this plan will go on the end of the plan stack.
    ///
    /// @param[in] stop_other_threads
    ///    \b true if we will stop other threads while we single step this one.
    ///
    /// @return
    ///     A shared pointer to the newly queued thread plan, or nullptr if the plan could not be queued.
    //------------------------------------------------------------------
    virtual lldb::ThreadPlanSP
    QueueThreadPlanForStepSingleInstruction (bool step_over,
                                             bool abort_other_plans,
                                             bool stop_other_threads);

    //------------------------------------------------------------------
    /// Queues the plan used to step through an address range, stepping  over
    /// function calls.
    ///
    /// @param[in] abort_other_plans
    ///    \b true if we discard the currently queued plans and replace them with this one.
    ///    Otherwise this plan will go on the end of the plan stack.
    ///
    /// @param[in] type
    ///    Type of step to do, only eStepTypeInto and eStepTypeOver are supported by this plan.
    ///
    /// @param[in] range
    ///    The address range to step through.
    ///
    /// @param[in] addr_context
    ///    When dealing with stepping through inlined functions the current PC is not enough information to know
    ///    what "step" means.  For instance a series of nested inline functions might start at the same address.
    //     The \a addr_context provides the current symbol context the step
    ///    is supposed to be out of.
    //   FIXME: Currently unused.
    ///
    /// @param[in] stop_other_threads
    ///    \b true if we will stop other threads while we single step this one.
    ///
    /// @param[in] step_out_avoids_code_without_debug_info
    ///    If eLazyBoolYes, if the step over steps out it will continue to step out till it comes to a frame with debug info.
    ///    If eLazyBoolCalculate, we will consult the default set in the thread.
    ///
    /// @return
    ///     A shared pointer to the newly queued thread plan, or nullptr if the plan could not be queued.
    //------------------------------------------------------------------
    virtual lldb::ThreadPlanSP
    QueueThreadPlanForStepOverRange (bool abort_other_plans,
                                     const AddressRange &range,
                                     const SymbolContext &addr_context,
                                     lldb::RunMode stop_other_threads,
                                     LazyBool step_out_avoids_code_without_debug_info = eLazyBoolCalculate);

    // Helper function that takes a LineEntry to step, insted of an AddressRange.  This may combine multiple
    // LineEntries of the same source line number to step over a longer address range in a single operation.
    virtual lldb::ThreadPlanSP
    QueueThreadPlanForStepOverRange (bool abort_other_plans,
                                     const LineEntry &line_entry,
                                     const SymbolContext &addr_context,
                                     lldb::RunMode stop_other_threads,
                                     LazyBool step_out_avoids_code_without_debug_info = eLazyBoolCalculate);

    //------------------------------------------------------------------
    /// Queues the plan used to step through an address range, stepping into functions.
    ///
    /// @param[in] abort_other_plans
    ///    \b true if we discard the currently queued plans and replace them with this one.
    ///    Otherwise this plan will go on the end of the plan stack.
    ///
    /// @param[in] type
    ///    Type of step to do, only eStepTypeInto and eStepTypeOver are supported by this plan.
    ///
    /// @param[in] range
    ///    The address range to step through.
    ///
    /// @param[in] addr_context
    ///    When dealing with stepping through inlined functions the current PC is not enough information to know
    ///    what "step" means.  For instance a series of nested inline functions might start at the same address.
    //     The \a addr_context provides the current symbol context the step
    ///    is supposed to be out of.
    //   FIXME: Currently unused.
    ///
    /// @param[in] step_in_target
    ///    Name if function we are trying to step into.  We will step out if we don't land in that function.
    ///
    /// @param[in] stop_other_threads
    ///    \b true if we will stop other threads while we single step this one.
    ///
    /// @param[in] step_in_avoids_code_without_debug_info
    ///    If eLazyBoolYes we will step out if we step into code with no debug info.
    ///    If eLazyBoolCalculate we will consult the default set in the thread.
    ///
    /// @param[in] step_out_avoids_code_without_debug_info
    ///    If eLazyBoolYes, if the step over steps out it will continue to step out till it comes to a frame with debug info.
    ///    If eLazyBoolCalculate, it will consult the default set in the thread.
    ///
    /// @return
    ///     A shared pointer to the newly queued thread plan, or nullptr if the plan could not be queued.
    //------------------------------------------------------------------
    virtual lldb::ThreadPlanSP
    QueueThreadPlanForStepInRange (bool abort_other_plans,
                                   const AddressRange &range,
                                   const SymbolContext &addr_context,
                                   const char *step_in_target,
                                   lldb::RunMode stop_other_threads,
                                   LazyBool step_in_avoids_code_without_debug_info = eLazyBoolCalculate,
                                   LazyBool step_out_avoids_code_without_debug_info = eLazyBoolCalculate);

    // Helper function that takes a LineEntry to step, insted of an AddressRange.  This may combine multiple
    // LineEntries of the same source line number to step over a longer address range in a single operation.
    virtual lldb::ThreadPlanSP
    QueueThreadPlanForStepInRange (bool abort_other_plans,
                                   const LineEntry &line_entry,
                                   const SymbolContext &addr_context,
                                   const char *step_in_target,
                                   lldb::RunMode stop_other_threads,
                                   LazyBool step_in_avoids_code_without_debug_info = eLazyBoolCalculate,
                                   LazyBool step_out_avoids_code_without_debug_info = eLazyBoolCalculate);

    //------------------------------------------------------------------
    /// Queue the plan used to step out of the function at the current PC of
    /// \a thread.
    ///
    /// @param[in] abort_other_plans
    ///    \b true if we discard the currently queued plans and replace them with this one.
    ///    Otherwise this plan will go on the end of the plan stack.
    ///
    /// @param[in] addr_context
    ///    When dealing with stepping through inlined functions the current PC is not enough information to know
    ///    what "step" means.  For instance a series of nested inline functions might start at the same address.
    //     The \a addr_context provides the current symbol context the step
    ///    is supposed to be out of.
    //   FIXME: Currently unused.
    ///
    /// @param[in] first_insn
    ///     \b true if this is the first instruction of a function.
    ///
    /// @param[in] stop_other_threads
    ///    \b true if we will stop other threads while we single step this one.
    ///
    /// @param[in] stop_vote
    /// @param[in] run_vote
    ///    See standard meanings for the stop & run votes in ThreadPlan.h.
    ///
    /// @param[in] step_out_avoids_code_without_debug_info
    ///    If eLazyBoolYes, if the step over steps out it will continue to step out till it comes to a frame with debug info.
    ///    If eLazyBoolCalculate, it will consult the default set in the thread.
    ///
    /// @return
    ///     A shared pointer to the newly queued thread plan, or nullptr if the plan could not be queued.
    //------------------------------------------------------------------
    virtual lldb::ThreadPlanSP
    QueueThreadPlanForStepOut (bool abort_other_plans,
                               SymbolContext *addr_context,
                               bool first_insn,
                               bool stop_other_threads,
                               Vote stop_vote, // = eVoteYes,
                               Vote run_vote, // = eVoteNoOpinion);
                               uint32_t frame_idx,
                               LazyBool step_out_avoids_code_without_debug_info = eLazyBoolCalculate);

    //------------------------------------------------------------------
    /// Queue the plan used to step out of the function at the current PC of
    /// a thread.  This version does not consult the should stop here callback, and should only
    /// be used by other thread plans when they need to retain control of the step out.
    ///
    /// @param[in] abort_other_plans
    ///    \b true if we discard the currently queued plans and replace them with this one.
    ///    Otherwise this plan will go on the end of the plan stack.
    ///
    /// @param[in] addr_context
    ///    When dealing with stepping through inlined functions the current PC is not enough information to know
    ///    what "step" means.  For instance a series of nested inline functions might start at the same address.
    //     The \a addr_context provides the current symbol context the step
    ///    is supposed to be out of.
    //   FIXME: Currently unused.
    ///
    /// @param[in] first_insn
    ///     \b true if this is the first instruction of a function.
    ///
    /// @param[in] stop_other_threads
    ///    \b true if we will stop other threads while we single step this one.
    ///
    /// @param[in] stop_vote
    /// @param[in] run_vote
    ///    See standard meanings for the stop & run votes in ThreadPlan.h.
    ///
    /// @param[in] continue_to_next_branch
    ///    Normally this will enqueue a plan that will put a breakpoint on the return address and continue
    ///    to there.  If continue_to_next_branch is true, this is an operation not involving the user -- 
    ///    e.g. stepping "next" in a source line and we instruction stepped into another function -- 
    ///    so instead of putting a breakpoint on the return address, advance the breakpoint to the 
    ///    end of the source line that is doing the call, or until the next flow control instruction.
    ///    If the return value from the function call is to be retrieved / displayed to the user, you must stop
    ///    on the return address.  The return value may be stored in volatile registers which are overwritten
    ///    before the next branch instruction.
    ///
    /// @return
    ///     A shared pointer to the newly queued thread plan, or nullptr if the plan could not be queued.
    //------------------------------------------------------------------
    virtual lldb::ThreadPlanSP
    QueueThreadPlanForStepOutNoShouldStop (bool abort_other_plans,
                                           SymbolContext *addr_context,
                                           bool first_insn,
                                           bool stop_other_threads,
                                           Vote stop_vote, // = eVoteYes,
                                           Vote run_vote, // = eVoteNoOpinion);
                                           uint32_t frame_idx,
                                           bool continue_to_next_branch = false);

    //------------------------------------------------------------------
    /// Gets the plan used to step through the code that steps from a function
    /// call site at the current PC into the actual function call.
    ///
    ///
    /// @param[in] return_stack_id
    ///    The stack id that we will return to (by setting backstop breakpoints on the return
    ///    address to that frame) if we fail to step through.
    ///
    /// @param[in] abort_other_plans
    ///    \b true if we discard the currently queued plans and replace them with this one.
    ///    Otherwise this plan will go on the end of the plan stack.
    ///
    /// @param[in] stop_other_threads
    ///    \b true if we will stop other threads while we single step this one.
    ///
    /// @return
    ///     A shared pointer to the newly queued thread plan, or nullptr if the plan could not be queued.
    //------------------------------------------------------------------
    virtual lldb::ThreadPlanSP
    QueueThreadPlanForStepThrough (StackID &return_stack_id,
                                   bool abort_other_plans,
                                   bool stop_other_threads);

    //------------------------------------------------------------------
    /// Gets the plan used to continue from the current PC.
    /// This is a simple plan, mostly useful as a backstop when you are continuing
    /// for some particular purpose.
    ///
    /// @param[in] abort_other_plans
    ///    \b true if we discard the currently queued plans and replace them with this one.
    ///    Otherwise this plan will go on the end of the plan stack.
    ///
    /// @param[in] target_addr
    ///    The address to which we're running.
    ///
    /// @param[in] stop_other_threads
    ///    \b true if we will stop other threads while we single step this one.
    ///
    /// @return
    ///     A shared pointer to the newly queued thread plan, or nullptr if the plan could not be queued.
    //------------------------------------------------------------------
    virtual lldb::ThreadPlanSP
    QueueThreadPlanForRunToAddress (bool abort_other_plans,
                                    Address &target_addr,
                                    bool stop_other_threads);

    virtual lldb::ThreadPlanSP
    QueueThreadPlanForStepUntil (bool abort_other_plans,
                                 lldb::addr_t *address_list,
                                 size_t num_addresses,
                                 bool stop_others,
                                 uint32_t frame_idx);

    virtual lldb::ThreadPlanSP
    QueueThreadPlanForStepScripted (bool abort_other_plans,
                                    const char *class_name,
                                    bool stop_other_threads);

    //------------------------------------------------------------------
    // Thread Plan accessors:
    //------------------------------------------------------------------

    //------------------------------------------------------------------
    /// Gets the plan which will execute next on the plan stack.
    ///
    /// @return
    ///     A pointer to the next executed plan.
    //------------------------------------------------------------------
    ThreadPlan *
    GetCurrentPlan ();
    
    //------------------------------------------------------------------
    /// Unwinds the thread stack for the innermost expression plan currently
    /// on the thread plan stack.
    ///
    /// @return
    ///     An error if the thread plan could not be unwound.
    //------------------------------------------------------------------

    Error
    UnwindInnermostExpression();

    //------------------------------------------------------------------
    /// Gets the outer-most plan that was popped off the plan stack in the
    /// most recent stop.  Useful for printing the stop reason accurately.
    ///
    /// @return
    ///     A pointer to the last completed plan.
    //------------------------------------------------------------------
    lldb::ThreadPlanSP
    GetCompletedPlan ();

    //------------------------------------------------------------------
    /// 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 ();

    //------------------------------------------------------------------
    /// 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 ();

    //------------------------------------------------------------------
    ///  Checks whether the given plan is in the completed plans for this
    ///  stop.
    ///
    /// @param[in] plan
    ///     Pointer to the plan you're checking.
    ///
    /// @return
    ///     Returns true if the input plan is in the completed plan stack,
    ///     false otherwise.
    //------------------------------------------------------------------
    bool
    IsThreadPlanDone (ThreadPlan *plan);

    //------------------------------------------------------------------
    ///  Checks whether the given plan is in the discarded plans for this
    ///  stop.
    ///
    /// @param[in] plan
    ///     Pointer to the plan you're checking.
    ///
    /// @return
    ///     Returns true if the input plan is in the discarded plan stack,
    ///     false otherwise.
    //------------------------------------------------------------------
    bool
    WasThreadPlanDiscarded (ThreadPlan *plan);

    //------------------------------------------------------------------
    /// Queues a generic thread plan.
    ///
    /// @param[in] plan_sp
    ///    The plan to queue.
    ///
    /// @param[in] abort_other_plans
    ///    \b true if we discard the currently queued plans and replace them with this one.
    ///    Otherwise this plan will go on the end of the plan stack.
    ///
    /// @return
    ///     A pointer to the last completed plan.
    //------------------------------------------------------------------
    void
    QueueThreadPlan (lldb::ThreadPlanSP &plan_sp, bool abort_other_plans);

    //------------------------------------------------------------------
    /// Discards the plans queued on the plan stack of the current thread.  This is
    /// arbitrated by the "Master" ThreadPlans, using the "OkayToDiscard" call.
    //  But if \a force is true, all thread plans are discarded.
    //------------------------------------------------------------------
    void
    DiscardThreadPlans (bool force);

    //------------------------------------------------------------------
    /// Discards the plans queued on the plan stack of the current thread up to and
    /// including up_to_plan_sp.
    //
    // @param[in] up_to_plan_sp
    //   Discard all plans up to and including this one.
    //------------------------------------------------------------------
    void
    DiscardThreadPlansUpToPlan (lldb::ThreadPlanSP &up_to_plan_sp);

    void
    DiscardThreadPlansUpToPlan (ThreadPlan *up_to_plan_ptr);

    //------------------------------------------------------------------
    /// Discards the plans queued on the plan stack of the current thread up to and
    /// including the plan in that matches \a thread_index counting only
    /// the non-Private plans.
    ///
    /// @param[in] up_to_plan_sp
    ///   Discard all plans up to and including this user plan given by this index.
    ///
    /// @return
    ///    \b true if there was a thread plan with that user index, \b false otherwise.
    //------------------------------------------------------------------
    bool
    DiscardUserThreadPlansUpToIndex (uint32_t thread_index);
    
    //------------------------------------------------------------------
    /// Prints the current plan stack.
    ///
    /// @param[in] s
    ///    The stream to which to dump the plan stack info.
    ///
    //------------------------------------------------------------------
    void
    DumpThreadPlans (Stream *s,
                     lldb::DescriptionLevel desc_level = lldb::eDescriptionLevelVerbose,
                     bool include_internal = true,
                     bool ignore_boring = false) const;
    
    virtual bool
    CheckpointThreadState (ThreadStateCheckpoint &saved_state);
    
    virtual bool
    RestoreRegisterStateFromCheckpoint (ThreadStateCheckpoint &saved_state);
    
    virtual bool
    RestoreThreadStateFromCheckpoint (ThreadStateCheckpoint &saved_state);
    
    void
    EnableTracer (bool value, bool single_step);
    
    void
    SetTracer (lldb::ThreadPlanTracerSP &tracer_sp);

    //------------------------------------------------------------------
    // Get the thread index ID. The index ID that is guaranteed to not
    // be re-used by a process. They start at 1 and increase with each
    // new thread. This allows easy command line access by a unique ID
    // that is easier to type than the actual system thread ID.
    //------------------------------------------------------------------
    uint32_t
    GetIndexID () const;

    //------------------------------------------------------------------
    // Get the originating thread's index ID. 
    // In the case of an "extended" thread -- a thread which represents
    // the stack that enqueued/spawned work that is currently executing --
    // we need to provide the IndexID of the thread that actually did
    // this work.  We don't want to just masquerade as that thread's IndexID
    // by using it in our own IndexID because that way leads to madness -
    // but the driver program which is iterating over extended threads 
    // may ask for the OriginatingThreadID to display that information
    // to the user. 
    // Normal threads will return the same thing as GetIndexID();
    //------------------------------------------------------------------
    virtual uint32_t
    GetExtendedBacktraceOriginatingIndexID ()
    {
        return GetIndexID ();
    }

    //------------------------------------------------------------------
    // The API ID is often the same as the Thread::GetID(), but not in
    // all cases. Thread::GetID() is the user visible thread ID that
    // clients would want to see. The API thread ID is the thread ID
    // that is used when sending data to/from the debugging protocol.
    //------------------------------------------------------------------
    virtual lldb::user_id_t
    GetProtocolID () const
    {
        return GetID();
    }

    //------------------------------------------------------------------
    // lldb::ExecutionContextScope pure virtual functions
    //------------------------------------------------------------------
    lldb::TargetSP
    CalculateTarget() override;
    
    lldb::ProcessSP
    CalculateProcess() override;
    
    lldb::ThreadSP
    CalculateThread() override;
    
    lldb::StackFrameSP
    CalculateStackFrame() override;

    void
    CalculateExecutionContext(ExecutionContext &exe_ctx) override;
    
    lldb::StackFrameSP
    GetStackFrameSPForStackFramePtr (StackFrame *stack_frame_ptr);
    
    size_t
    GetStatus (Stream &strm, 
               uint32_t start_frame, 
               uint32_t num_frames,
               uint32_t num_frames_with_source);

    size_t
    GetStackFrameStatus (Stream& strm,
                         uint32_t first_frame,
                         uint32_t num_frames,
                         bool show_frame_info,
                         uint32_t num_frames_with_source);

    // We need a way to verify that even though we have a thread in a shared
    // pointer that the object itself is still valid. Currently this won't be
    // the case if DestroyThread() was called. DestroyThread is called when
    // a thread has been removed from the Process' thread list.
    bool
    IsValid () const
    {
        return !m_destroy_called;
    }

    // Sets and returns a valid stop info based on the process stop ID and the
    // current thread plan. If the thread stop ID does not match the process'
    // stop ID, the private stop reason is not set and an invalid StopInfoSP may
    // be returned.
    //
    // NOTE: This function must be called before the current thread plan is
    // moved to the completed plan stack (in Thread::ShouldStop()).
    //
    // NOTE: If subclasses override this function, ensure they do not overwrite
    // the m_actual_stop_info if it is valid.  The stop info may be a
    // "checkpointed and restored" stop info, so if it is still around it is
    // right even if you have not calculated this yourself, or if it disagrees
    // with what you might have calculated.
    virtual lldb::StopInfoSP
    GetPrivateStopInfo ();

    //----------------------------------------------------------------------
    // Ask the thread subclass to set its stop info.
    //
    // Thread subclasses should call Thread::SetStopInfo(...) with the
    // reason the thread stopped.
    //
    // @return
    //      True if Thread::SetStopInfo(...) was called, false otherwise.
    //----------------------------------------------------------------------
    virtual bool
    CalculateStopInfo () = 0;

    //----------------------------------------------------------------------
    // Gets the temporary resume state for a thread.
    //
    // This value gets set in each thread by complex debugger logic in
    // Thread::ShouldResume() and an appropriate thread resume state will get
    // set in each thread every time the process is resumed prior to calling
    // Process::DoResume(). The lldb_private::Process subclass should adhere
    // to the thread resume state request which will be one of:
    //
    //  eStateRunning   - thread will resume when process is resumed
    //  eStateStepping  - thread should step 1 instruction and stop when process
    //                    is resumed
    //  eStateSuspended - thread should not execute any instructions when
    //                    process is resumed
    //----------------------------------------------------------------------
    lldb::StateType
    GetTemporaryResumeState() const
    {
        return m_temporary_resume_state;
    }

    void
    SetStopInfo (const lldb::StopInfoSP &stop_info_sp);

    void
    SetShouldReportStop (Vote vote);

    //----------------------------------------------------------------------
    /// Sets the extended backtrace token for this thread
    ///
    /// Some Thread subclasses may maintain a token to help with providing
    /// an extended backtrace.  The SystemRuntime plugin will set/request this.
    ///
    /// @param [in] token
    //----------------------------------------------------------------------
    virtual void
    SetExtendedBacktraceToken (uint64_t token) { }

    //----------------------------------------------------------------------
    /// Gets the extended backtrace token for this thread
    ///
    /// Some Thread subclasses may maintain a token to help with providing
    /// an extended backtrace.  The SystemRuntime plugin will set/request this.
    ///
    /// @return
    ///     The token needed by the SystemRuntime to create an extended backtrace.
    ///     LLDB_INVALID_ADDRESS is returned if no token is available.
    //----------------------------------------------------------------------
    virtual uint64_t
    GetExtendedBacktraceToken ()
    {
        return LLDB_INVALID_ADDRESS;
    }

protected:
    friend class ThreadPlan;
    friend class ThreadList;
    friend class ThreadEventData;
    friend class StackFrameList;
    friend class StackFrame;
    friend class OperatingSystem;
    
    // This is necessary to make sure thread assets get destroyed while the 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 ();

    void
    PushPlan (lldb::ThreadPlanSP &plan_sp);

    void
    PopPlan ();

    void
    DiscardPlan ();

    ThreadPlan *GetPreviousPlan (ThreadPlan *plan);

    typedef std::vector<lldb::ThreadPlanSP> plan_stack;

    virtual lldb_private::Unwind *
    GetUnwinder ();

    // Check to see whether the thread is still at the last breakpoint hit that stopped it.
    virtual bool
    IsStillAtLastBreakpointHit();

    // Some threads are threads that are made up by OperatingSystem plugins that
    // are threads that exist and are context switched out into memory. The
    // OperatingSystem plug-in need a ways to know if a thread is "real" or made
    // up.
    virtual bool
    IsOperatingSystemPluginThread () const
    {
        return false;
    }
    
    // Subclasses that have a way to get an extended info dictionary for this thread should
    // fill 
    virtual lldb_private::StructuredData::ObjectSP
    FetchThreadExtendedInfo ()
    {
        return StructuredData::ObjectSP();
    }

    lldb::StackFrameListSP
    GetStackFrameList ();

    void
    SetTemporaryResumeState(lldb::StateType new_state)
    {
        m_temporary_resume_state = new_state;
    }

    void
    FunctionOptimizationWarning (lldb_private::StackFrame *frame);

    //------------------------------------------------------------------
    // Classes that inherit from Process can see and modify these
    //------------------------------------------------------------------
    lldb::ProcessWP     m_process_wp;           ///< The process that owns this thread.
    lldb::StopInfoSP    m_stop_info_sp;         ///< The private stop reason for this thread
    uint32_t            m_stop_info_stop_id;    // This is the stop id for which the StopInfo is valid.  Can use this so you know that
    // the thread's m_stop_info_sp is current and you don't have to fetch it again
    uint32_t            m_stop_info_override_stop_id;    // The stop ID containing the last time the stop info was checked against the stop info override
    const uint32_t      m_index_id;             ///< A unique 1 based index assigned to each thread for easy UI/command line access.
    lldb::RegisterContextSP m_reg_context_sp;   ///< The register context for this thread's current register state.
    lldb::StateType     m_state;                ///< The state of our process.
    mutable 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 Mutex       m_frame_mutex;          ///< Multithreaded protection for m_state.
    lldb::StackFrameListSP m_curr_frames_sp;    ///< The stack frames that get lazily populated after a thread stops.
    lldb::StackFrameListSP m_prev_frames_sp;    ///< The previous stack frames from the last time this thread stopped.
    int                 m_resume_signal;        ///< The signal that should be used when continuing this thread.
    lldb::StateType     m_resume_state;         ///< This state is used to force a thread to be suspended from outside the ThreadPlan logic.
    lldb::StateType     m_temporary_resume_state; ///< This state records what the thread was told to do by the thread plan logic for the current resume.
                                                  /// It gets set in Thread::ShouldResume.
    std::unique_ptr<lldb_private::Unwind> m_unwinder_ap;
    bool                m_destroy_called;       // This is used internally to make sure derived Thread classes call DestroyThread.
    LazyBool            m_override_should_notify;
private:
    bool                m_extended_info_fetched;  // Have we tried to retrieve the m_extended_info for 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);
};

} // namespace lldb_private

#endif // liblldb_Thread_h_
