Based on the conversation at
http://lists.cs.uiuc.edu/pipermail/lldb-commits/Week-of-Mon-20140901/012760.html
this patch splits the current ThreadList class into a process-related thread
object called "ProcessThreadList" and a generic thread list now called just
ThreadList. The idea is to expose the ThreadList as SBThreadList and make
ASan-related API based on it.
http://reviews.llvm.org/D5200
Files:
include/lldb/Target/OperatingSystem.h
include/lldb/Target/Process.h
include/lldb/Target/ProcessThreadList.h
include/lldb/Target/Thread.h
include/lldb/Target/ThreadList.h
include/lldb/lldb-forward.h
lldb.xcodeproj/project.pbxproj
source/Commands/CommandObjectTarget.cpp
source/Core/Debugger.cpp
source/Core/IOHandler.cpp
source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp
source/Plugins/OperatingSystem/Python/OperatingSystemPython.h
source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp
source/Plugins/Process/MacOSX-Kernel/ProcessKDP.h
source/Plugins/Process/elf-core/ProcessElfCore.cpp
source/Plugins/Process/elf-core/ProcessElfCore.h
source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
source/Plugins/Process/mach-core/ProcessMachCore.cpp
source/Plugins/Process/mach-core/ProcessMachCore.h
source/Target/Process.cpp
source/Target/ProcessThreadList.cpp
source/Target/Target.cpp
source/Target/ThreadList.cpp
Index: include/lldb/Target/OperatingSystem.h
===================================================================
--- include/lldb/Target/OperatingSystem.h
+++ include/lldb/Target/OperatingSystem.h
@@ -65,9 +65,9 @@
// Plug-in Methods
//------------------------------------------------------------------
virtual bool
- UpdateThreadList (ThreadList &old_thread_list,
- ThreadList &real_thread_list,
- ThreadList &new_thread_list) = 0;
+ UpdateThreadList (ProcessThreadList &old_thread_list,
+ ProcessThreadList &real_thread_list,
+ ProcessThreadList &new_thread_list) = 0;
virtual void
ThreadWasSelected (Thread *thread) = 0;
Index: include/lldb/Target/Process.h
===================================================================
--- include/lldb/Target/Process.h
+++ include/lldb/Target/Process.h
@@ -48,7 +48,7 @@
#include "lldb/Target/ProcessInfo.h"
#include "lldb/Target/ProcessLaunchInfo.h"
#include "lldb/Target/QueueList.h"
-#include "lldb/Target/ThreadList.h"
+#include "lldb/Target/ProcessThreadList.h"
#include "lldb/Target/UnixSignals.h"
#include "lldb/Utility/PseudoTerminal.h"
@@ -701,7 +701,7 @@
friend class ProcessEventData;
friend class StopInfo;
friend class Target;
- friend class ThreadList;
+ friend class ProcessThreadList;
public:
@@ -2601,12 +2601,12 @@
// Thread Queries
//------------------------------------------------------------------
virtual bool
- UpdateThreadList (ThreadList &old_thread_list, ThreadList &new_thread_list) = 0;
+ UpdateThreadList (ProcessThreadList &old_thread_list, ProcessThreadList &new_thread_list) = 0;
void
UpdateThreadListIfNeeded ();
- ThreadList &
+ ProcessThreadList &
GetThreadList ()
{
return m_thread_list;
@@ -2617,13 +2617,13 @@
// threads in this list are not iterated over - driver programs need to
// request the extended backtrace calls starting from a root concrete
// thread one by one.
- ThreadList &
+ ProcessThreadList &
GetExtendedThreadList ()
{
return m_extended_thread_list;
}
- ThreadList::ThreadIterable
+ ProcessThreadList::ThreadIterable
Threads ()
{
return m_thread_list.Threads();
@@ -2914,6 +2914,9 @@
else
return m_public_run_lock;
}
+
+ lldb::ThreadListSP
+ GetHistoryThreads(lldb::addr_t addr);
public:
virtual Error
@@ -3047,10 +3050,10 @@
int m_exit_status; ///< The exit status of the process, or -1 if not set.
std::string m_exit_string; ///< A textual description of why a process exited.
Mutex m_thread_mutex;
- ThreadList m_thread_list_real; ///< The threads for this process as are known to the protocol we are debugging with
- ThreadList m_thread_list; ///< The threads for this process as the user will see them. This is usually the same as
+ ProcessThreadList m_thread_list_real; ///< The threads for this process as are known to the protocol we are debugging with
+ ProcessThreadList m_thread_list; ///< The threads for this process as the user will 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
- ThreadList m_extended_thread_list; ///< Owner for extended threads that may be generated, cleared on natural stops
+ ProcessThreadList 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 extended_thread_list was last updated
QueueList m_queue_list; ///< The list of libdispatch queues at a given stop point
uint32_t m_queue_list_stop_id; ///< The natural stop id when queue list was last fetched
Index: include/lldb/Target/ProcessThreadList.h
===================================================================
--- include/lldb/Target/ProcessThreadList.h
+++ include/lldb/Target/ProcessThreadList.h
@@ -0,0 +1,155 @@
+//===-- ProcessThreadList.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_ProcessThreadList_h_
+#define liblldb_ProcessThreadList_h_
+
+#include <vector>
+
+#include "lldb/lldb-private.h"
+#include "lldb/Core/UserID.h"
+#include "lldb/Utility/Iterable.h"
+#include "lldb/Target/ThreadList.h"
+
+namespace lldb_private {
+
+class ProcessThreadList : public ThreadList
+{
+ friend class Process;
+
+public:
+
+ ProcessThreadList (Process *process);
+
+ ProcessThreadList (const ProcessThreadList &rhs);
+
+ ~ProcessThreadList ();
+
+ const ProcessThreadList&
+ operator = (const ProcessThreadList& rhs);
+
+ uint32_t
+ GetSize(bool can_update = true);
+
+ // Return the selected thread if there is one. Otherwise, return the thread
+ // selected at index 0.
+ lldb::ThreadSP
+ GetSelectedThread ();
+
+ bool
+ SetSelectedThreadByID (lldb::tid_t tid, bool notify = false);
+
+ bool
+ SetSelectedThreadByIndexID (uint32_t index_id, bool notify = false);
+
+ void
+ Clear();
+
+ void
+ Flush();
+
+ void
+ Destroy();
+
+ // Note that "idx" is not the same as the "thread_index". It is a zero
+ // based index to accessing the current threads, whereas "thread_index"
+ // is a unique index assigned
+ lldb::ThreadSP
+ GetThreadAtIndex (uint32_t idx, bool can_update = true);
+
+ lldb::ThreadSP
+ FindThreadByID (lldb::tid_t tid, bool can_update = true);
+
+ lldb::ThreadSP
+ FindThreadByProtocolID (lldb::tid_t tid, bool can_update = true);
+
+ lldb::ThreadSP
+ RemoveThreadByID (lldb::tid_t tid, bool can_update = true);
+
+ lldb::ThreadSP
+ RemoveThreadByProtocolID (lldb::tid_t tid, bool can_update = true);
+
+ lldb::ThreadSP
+ FindThreadByIndexID (uint32_t index_id, bool can_update = true);
+
+ lldb::ThreadSP
+ GetThreadSPForThreadPtr (Thread *thread_ptr);
+
+ bool
+ ShouldStop (Event *event_ptr);
+
+ Vote
+ ShouldReportStop (Event *event_ptr);
+
+ Vote
+ ShouldReportRun (Event *event_ptr);
+
+ void
+ RefreshStateAfterStop ();
+
+ //------------------------------------------------------------------
+ /// The thread list asks tells all the threads it is about to resume.
+ /// If a thread can "resume" without having to resume the target, it
+ /// will return false for WillResume, and then the process will not be
+ /// restarted.
+ ///
+ /// @return
+ /// \b true instructs the process to resume normally,
+ /// \b false means start & stopped events will be generated, but
+ /// the process will not actually run. The thread must then return
+ /// the correct StopInfo when asked.
+ ///
+ //------------------------------------------------------------------
+ bool
+ WillResume ();
+
+ void
+ DidResume ();
+
+ void
+ DidStop ();
+
+ void
+ DiscardThreadPlans();
+
+ uint32_t
+ GetStopID () const;
+
+ void
+ SetStopID (uint32_t stop_id);
+
+ Mutex &
+ GetMutex ();
+
+ void
+ Update (ProcessThreadList &rhs);
+
+
+protected:
+
+ void
+ SetShouldReportStop (Vote vote);
+
+ void
+ NotifySelectedThreadChanged (lldb::tid_t tid);
+
+ //------------------------------------------------------------------
+ // Classes that inherit from Process can see and modify these
+ //------------------------------------------------------------------
+ Process *m_process; ///< The process that manages this thread list.
+ uint32_t m_stop_id; ///< The process stop ID that this thread list is valid for.
+ lldb::tid_t m_selected_tid; ///< For targets that need the notion of a current thread.
+
+private:
+ ProcessThreadList ();
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ProcessThreadList_h_
Index: include/lldb/Target/Thread.h
===================================================================
--- include/lldb/Target/Thread.h
+++ include/lldb/Target/Thread.h
@@ -1235,7 +1235,7 @@
protected:
friend class ThreadPlan;
- friend class ThreadList;
+ friend class ProcessThreadList;
friend class ThreadEventData;
friend class StackFrameList;
friend class StackFrame;
Index: include/lldb/Target/ThreadList.h
===================================================================
--- include/lldb/Target/ThreadList.h
+++ include/lldb/Target/ThreadList.h
@@ -17,156 +17,48 @@
#include "lldb/Utility/Iterable.h"
-// FIXME: Currently this is a thread list with lots of functionality for use only by
-// the process for which this is the thread list. If we ever want a container class
-// to hand out that is just a random subset of threads, with iterator functionality,
-// then we should make that part a base class, and make a ProcessThreadList for the
-// process.
namespace lldb_private {
class ThreadList
{
-friend class Process;
-
public:
-
- ThreadList (Process *process);
-
- ThreadList (const ThreadList &rhs);
-
- ~ThreadList ();
-
- const ThreadList&
- operator = (const ThreadList& rhs);
-
+ typedef std::vector<lldb::ThreadSP> collection;
+ typedef LockingAdaptedIterable<collection, lldb::ThreadSP, vector_adapter> ThreadIterable;
+
+ ThreadList();
+
+ ThreadList(collection threads);
+
uint32_t
- GetSize(bool can_update = true);
+ GetSize();
void
AddThread (const lldb::ThreadSP &thread_sp);
void
InsertThread (const lldb::ThreadSP &thread_sp, uint32_t idx);
- // Return the selected thread if there is one. Otherwise, return the thread
- // selected at index 0.
- lldb::ThreadSP
- GetSelectedThread ();
- bool
- SetSelectedThreadByID (lldb::tid_t tid, bool notify = false);
-
- bool
- SetSelectedThreadByIndexID (uint32_t index_id, bool notify = false);
-
- void
- Clear();
-
- void
- Flush();
-
- void
- Destroy();
-
// Note that "idx" is not the same as the "thread_index". It is a zero
// based index to accessing the current threads, whereas "thread_index"
// is a unique index assigned
lldb::ThreadSP
- GetThreadAtIndex (uint32_t idx, bool can_update = true);
+ GetThreadAtIndex (uint32_t idx);
- typedef std::vector<lldb::ThreadSP> collection;
- typedef LockingAdaptedIterable<collection, lldb::ThreadSP, vector_adapter> ThreadIterable;
-
ThreadIterable
Threads ()
{
return ThreadIterable(m_threads, GetMutex());
}
-
- lldb::ThreadSP
- FindThreadByID (lldb::tid_t tid, bool can_update = true);
- lldb::ThreadSP
- FindThreadByProtocolID (lldb::tid_t tid, bool can_update = true);
+ Mutex &
+ GetMutex()
+ {
+ return m_mutex;
+ }
- lldb::ThreadSP
- RemoveThreadByID (lldb::tid_t tid, bool can_update = true);
-
- lldb::ThreadSP
- RemoveThreadByProtocolID (lldb::tid_t tid, bool can_update = true);
-
- lldb::ThreadSP
- FindThreadByIndexID (uint32_t index_id, bool can_update = true);
-
- lldb::ThreadSP
- GetThreadSPForThreadPtr (Thread *thread_ptr);
-
- bool
- ShouldStop (Event *event_ptr);
-
- Vote
- ShouldReportStop (Event *event_ptr);
-
- Vote
- ShouldReportRun (Event *event_ptr);
-
- void
- RefreshStateAfterStop ();
-
- //------------------------------------------------------------------
- /// The thread list asks tells all the threads it is about to resume.
- /// If a thread can "resume" without having to resume the target, it
- /// will return false for WillResume, and then the process will not be
- /// restarted.
- ///
- /// @return
- /// \b true instructs the process to resume normally,
- /// \b false means start & stopped events will be generated, but
- /// the process will not actually run. The thread must then return
- /// the correct StopInfo when asked.
- ///
- //------------------------------------------------------------------
- bool
- WillResume ();
-
- void
- DidResume ();
-
- void
- DidStop ();
-
- void
- DiscardThreadPlans();
-
- uint32_t
- GetStopID () const;
-
- void
- SetStopID (uint32_t stop_id);
-
- Mutex &
- GetMutex ();
-
- void
- Update (ThreadList &rhs);
-
protected:
-
- void
- SetShouldReportStop (Vote vote);
-
- void
- NotifySelectedThreadChanged (lldb::tid_t tid);
-
- //------------------------------------------------------------------
- // Classes that inherit from Process can see and modify these
- //------------------------------------------------------------------
- Process *m_process; ///< The process that manages this thread list.
- uint32_t m_stop_id; ///< The process stop ID that this thread list is valid for.
collection m_threads; ///< The threads for this process.
- lldb::tid_t m_selected_tid; ///< For targets that need the notion of a current thread.
-
-private:
- ThreadList ();
+ Mutex m_mutex;
};
} // namespace lldb_private
Index: include/lldb/lldb-forward.h
===================================================================
--- include/lldb/lldb-forward.h
+++ include/lldb/lldb-forward.h
@@ -160,6 +160,7 @@
class ProcessInstanceInfoList;
class ProcessInstanceInfoMatch;
class ProcessLaunchInfo;
+class ProcessThreadList;
class Property;
struct PropertyDefinition;
class PythonArray;
@@ -381,6 +382,7 @@
typedef std::weak_ptr<lldb_private::Target> TargetWP;
typedef std::shared_ptr<lldb_private::Thread> ThreadSP;
typedef std::weak_ptr<lldb_private::Thread> ThreadWP;
+ typedef std::shared_ptr<lldb_private::ThreadList> ThreadListSP;
typedef std::shared_ptr<lldb_private::ThreadPlan> ThreadPlanSP;
typedef std::shared_ptr<lldb_private::ThreadPlanTracer> ThreadPlanTracerSP;
typedef std::shared_ptr<lldb_private::Type> TypeSP;
Index: lldb.xcodeproj/project.pbxproj
===================================================================
--- lldb.xcodeproj/project.pbxproj
+++ lldb.xcodeproj/project.pbxproj
@@ -620,6 +620,7 @@
4CF52AF8142829390051E832 /* SBFileSpecList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CF52AF7142829390051E832 /* SBFileSpecList.cpp */; };
8C2D6A53197A1EAF006989C9 /* MemoryHistory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C2D6A52197A1EAF006989C9 /* MemoryHistory.cpp */; };
8C2D6A5E197A250F006989C9 /* MemoryHistoryASan.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C2D6A5A197A1FDC006989C9 /* MemoryHistoryASan.cpp */; };
+ 8C395A2D19B91D37001C9B07 /* ProcessThreadList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C395A2B19B91C8F001C9B07 /* ProcessThreadList.cpp */; };
94094C6B163B6F840083A547 /* ValueObjectCast.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94094C69163B6CD90083A547 /* ValueObjectCast.cpp */; };
94145431175E63B500284436 /* lldb-versioning.h in Headers */ = {isa = PBXBuildFile; fileRef = 94145430175D7FDE00284436 /* lldb-versioning.h */; settings = {ATTRIBUTES = (Public, ); }; };
941BCC7F14E48C4000BB969C /* SBTypeFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 9461568614E355F2003A195C /* SBTypeFilter.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -1900,6 +1903,8 @@
8C2D6A54197A1EBE006989C9 /* MemoryHistory.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = MemoryHistory.h; path = include/lldb/Target/MemoryHistory.h; sourceTree = "<group>"; };
8C2D6A5A197A1FDC006989C9 /* MemoryHistoryASan.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MemoryHistoryASan.cpp; sourceTree = "<group>"; };
8C2D6A5B197A1FDC006989C9 /* MemoryHistoryASan.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MemoryHistoryASan.h; sourceTree = "<group>"; };
+ 8C395A2B19B91C8F001C9B07 /* ProcessThreadList.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ProcessThreadList.cpp; path = source/Target/ProcessThreadList.cpp; sourceTree = "<group>"; };
+ 8C395A2C19B91C8F001C9B07 /* ProcessThreadList.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ProcessThreadList.h; path = include/lldb/Target/ProcessThreadList.h; sourceTree = "<group>"; };
94005E0313F438DF001EF42D /* python-wrapper.swig */ = {isa = PBXFileReference; lastKnownFileType = text; path = "python-wrapper.swig"; sourceTree = "<group>"; };
94005E0513F45A1B001EF42D /* embedded_interpreter.py */ = {isa = PBXFileReference; lastKnownFileType = text.script.python; name = embedded_interpreter.py; path = source/Interpreter/embedded_interpreter.py; sourceTree = "<group>"; };
94031A9F13CF5B3D00DCFF3C /* PriorityPointerPair.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = PriorityPointerPair.h; path = include/lldb/Utility/PriorityPointerPair.h; sourceTree = "<group>"; };
@@ -3681,6 +3692,8 @@
233B007B1960C9E60090E598 /* ProcessInfo.cpp */,
233B007E1960CB280090E598 /* ProcessLaunchInfo.cpp */,
233B007919609DB40090E598 /* ProcessLaunchInfo.h */,
+ 8C395A2C19B91C8F001C9B07 /* ProcessThreadList.h */,
+ 8C395A2B19B91C8F001C9B07 /* ProcessThreadList.cpp */,
26BC7DF310F1B81A00F91463 /* Process.h */,
26BC7F3610F1B90C00F91463 /* Process.cpp */,
260A63111860FDB600FECF8E /* Queue.h */,
@@ -4867,6 +4882,7 @@
2689002713353DDE00698AC0 /* CommandObjectTarget.cpp in Sources */,
2689002813353DDE00698AC0 /* CommandObjectThread.cpp in Sources */,
2689002913353DDE00698AC0 /* CommandObjectVersion.cpp in Sources */,
+ 8C395A2D19B91D37001C9B07 /* ProcessThreadList.cpp in Sources */,
2689002A13353E0400698AC0 /* Address.cpp in Sources */,
2689002B13353E0400698AC0 /* AddressRange.cpp in Sources */,
236124A41986B4E2004EFC37 /* IOObject.cpp in Sources */,
Index: source/Commands/CommandObjectTarget.cpp
===================================================================
--- source/Commands/CommandObjectTarget.cpp
+++ source/Commands/CommandObjectTarget.cpp
@@ -3648,7 +3648,7 @@
return false;
}
- ThreadList threads(process->GetThreadList());
+ ProcessThreadList threads(process->GetThreadList());
if (threads.GetSize() == 0)
{
result.AppendError ("The process must be paused to use this command.");
Index: source/Core/Debugger.cpp
===================================================================
--- source/Core/Debugger.cpp
+++ source/Core/Debugger.cpp
@@ -3053,7 +3053,7 @@
{
// Lock the thread list so it doesn't change on us, this is the scope for the locker:
{
- ThreadList &thread_list = process_sp->GetThreadList();
+ ProcessThreadList &thread_list = process_sp->GetThreadList();
Mutex::Locker locker (thread_list.GetMutex());
ThreadSP curr_thread (thread_list.GetSelectedThread());
Index: source/Core/IOHandler.cpp
===================================================================
--- source/Core/IOHandler.cpp
+++ source/Core/IOHandler.cpp
@@ -3232,7 +3232,7 @@
ThreadSP thread_sp = GetThread (item);
if (thread_sp)
{
- ThreadList &thread_list = thread_sp->GetProcess()->GetThreadList();
+ ProcessThreadList &thread_list = thread_sp->GetProcess()->GetThreadList();
Mutex::Locker locker (thread_list.GetMutex());
ThreadSP selected_thread_sp = thread_list.GetSelectedThread();
if (selected_thread_sp->GetID() != thread_sp->GetID())
@@ -3315,7 +3315,7 @@
}
TreeItem t (&item, *m_thread_delegate_sp, false);
- ThreadList &threads = process_sp->GetThreadList();
+ ProcessThreadList &threads = process_sp->GetThreadList();
Mutex::Locker locker (threads.GetMutex());
size_t num_threads = threads.GetSize();
item.Resize (num_threads, t);
@@ -4333,7 +4333,7 @@
else if (submenus.size() > 8)
submenus.erase (submenus.begin() + 8, submenus.end());
- ThreadList &threads = process->GetThreadList();
+ ProcessThreadList &threads = process->GetThreadList();
Mutex::Locker locker (threads.GetMutex());
size_t num_threads = threads.GetSize();
for (size_t i=0; i<num_threads; ++i)
Index: source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
===================================================================
--- source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
+++ source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
@@ -5306,7 +5306,7 @@
mach_header.ncmds = segment_load_commands.size();
mach_header.flags = 0;
mach_header.reserved = 0;
- ThreadList &thread_list = process_sp->GetThreadList();
+ ProcessThreadList &thread_list = process_sp->GetThreadList();
const uint32_t num_threads = thread_list.GetSize();
// Make an array of LC_THREAD data items. Each one contains
Index: source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp
===================================================================
--- source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp
+++ source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp
@@ -167,9 +167,9 @@
}
bool
-OperatingSystemPython::UpdateThreadList (ThreadList &old_thread_list,
- ThreadList &core_thread_list,
- ThreadList &new_thread_list)
+OperatingSystemPython::UpdateThreadList (ProcessThreadList &old_thread_list,
+ ProcessThreadList &core_thread_list,
+ ProcessThreadList &new_thread_list)
{
if (!m_interpreter || !m_python_object_sp)
return false;
@@ -240,8 +240,8 @@
ThreadSP
OperatingSystemPython::CreateThreadFromThreadInfo (PythonDictionary &thread_dict,
- ThreadList &core_thread_list,
- ThreadList &old_thread_list,
+ ProcessThreadList &core_thread_list,
+ ProcessThreadList &old_thread_list,
std::vector<bool> &core_used_map,
bool *did_create_ptr)
{
@@ -421,8 +421,8 @@
std::vector<bool> core_used_map;
if (thread_info_dict)
{
- ThreadList core_threads(m_process);
- ThreadList &thread_list = m_process->GetThreadList();
+ ProcessThreadList core_threads(m_process);
+ ProcessThreadList &thread_list = m_process->GetThreadList();
bool did_create = false;
ThreadSP thread_sp (CreateThreadFromThreadInfo (thread_info_dict, core_threads, thread_list, core_used_map, &did_create));
if (did_create)
Index: source/Plugins/OperatingSystem/Python/OperatingSystemPython.h
===================================================================
--- source/Plugins/OperatingSystem/Python/OperatingSystemPython.h
+++ source/Plugins/OperatingSystem/Python/OperatingSystemPython.h
@@ -62,9 +62,9 @@
// lldb_private::OperatingSystem Methods
//------------------------------------------------------------------
virtual bool
- UpdateThreadList (lldb_private::ThreadList &old_thread_list,
- lldb_private::ThreadList &real_thread_list,
- lldb_private::ThreadList &new_thread_list);
+ UpdateThreadList (lldb_private::ProcessThreadList &old_thread_list,
+ lldb_private::ProcessThreadList &real_thread_list,
+ lldb_private::ProcessThreadList &new_thread_list);
virtual void
ThreadWasSelected (lldb_private::Thread *thread);
@@ -91,8 +91,8 @@
lldb::ThreadSP
CreateThreadFromThreadInfo (lldb_private::PythonDictionary &thread_dict,
- lldb_private::ThreadList &core_thread_list,
- lldb_private::ThreadList &old_thread_list,
+ lldb_private::ProcessThreadList &core_thread_list,
+ lldb_private::ProcessThreadList &old_thread_list,
std::vector<bool> &core_used_map,
bool *did_create_ptr);
Index: source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp
===================================================================
--- source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp
+++ source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp
@@ -575,7 +575,7 @@
bool
-ProcessKDP::UpdateThreadList (ThreadList &old_thread_list, ThreadList &new_thread_list)
+ProcessKDP::UpdateThreadList (ProcessThreadList &old_thread_list, ProcessThreadList &new_thread_list)
{
// locker will keep a mutex locked until it goes out of scope
Log *log (ProcessKDPLog::GetLogIfAllCategoriesSet (KDP_LOG_THREAD));
Index: source/Plugins/Process/MacOSX-Kernel/ProcessKDP.h
===================================================================
--- source/Plugins/Process/MacOSX-Kernel/ProcessKDP.h
+++ source/Plugins/Process/MacOSX-Kernel/ProcessKDP.h
@@ -229,8 +229,8 @@
Clear ( );
virtual bool
- UpdateThreadList (lldb_private::ThreadList &old_thread_list,
- lldb_private::ThreadList &new_thread_list);
+ UpdateThreadList (lldb_private::ProcessThreadList &old_thread_list,
+ lldb_private::ProcessThreadList &new_thread_list);
enum
{
Index: source/Plugins/Process/elf-core/ProcessElfCore.cpp
===================================================================
--- source/Plugins/Process/elf-core/ProcessElfCore.cpp
+++ source/Plugins/Process/elf-core/ProcessElfCore.cpp
@@ -264,7 +264,7 @@
}
bool
-ProcessElfCore::UpdateThreadList (ThreadList &old_thread_list, ThreadList &new_thread_list)
+ProcessElfCore::UpdateThreadList (ProcessThreadList &old_thread_list, ProcessThreadList &new_thread_list)
{
const uint32_t num_threads = GetNumThreadContexts ();
if (!m_thread_data_valid)
Index: source/Plugins/Process/elf-core/ProcessElfCore.h
===================================================================
--- source/Plugins/Process/elf-core/ProcessElfCore.h
+++ source/Plugins/Process/elf-core/ProcessElfCore.h
@@ -127,8 +127,8 @@
Clear ( );
virtual bool
- UpdateThreadList (lldb_private::ThreadList &old_thread_list,
- lldb_private::ThreadList &new_thread_list);
+ UpdateThreadList (lldb_private::ProcessThreadList &old_thread_list,
+ lldb_private::ProcessThreadList &new_thread_list);
private:
//------------------------------------------------------------------
Index: source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
===================================================================
--- source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -1482,7 +1482,7 @@
}
bool
-ProcessGDBRemote::UpdateThreadList (ThreadList &old_thread_list, ThreadList &new_thread_list)
+ProcessGDBRemote::UpdateThreadList (ProcessThreadList &old_thread_list, ProcessThreadList &new_thread_list)
{
// locker will keep a mutex locked until it goes out of scope
Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_THREAD));
@@ -1499,7 +1499,7 @@
num_thread_ids = m_thread_ids.size();
}
- ThreadList old_thread_list_copy(old_thread_list);
+ ProcessThreadList old_thread_list_copy(old_thread_list);
if (num_thread_ids > 0)
{
for (size_t i=0; i<num_thread_ids; ++i)
@@ -1991,7 +1991,7 @@
DisableAllBreakpointSites();
bool stop_looks_like_crash = false;
- ThreadList &threads = GetThreadList();
+ ProcessThreadList &threads = GetThreadList();
{
Mutex::Locker locker(threads.GetMutex());
Index: source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
===================================================================
--- source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
+++ source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
@@ -285,8 +285,8 @@
}
virtual bool
- UpdateThreadList (lldb_private::ThreadList &old_thread_list,
- lldb_private::ThreadList &new_thread_list);
+ UpdateThreadList (lldb_private::ProcessThreadList &old_thread_list,
+ lldb_private::ProcessThreadList &new_thread_list);
lldb_private::Error
LaunchAndConnectToDebugserver (const lldb_private::ProcessInfo &process_info);
Index: source/Plugins/Process/mach-core/ProcessMachCore.cpp
===================================================================
--- source/Plugins/Process/mach-core/ProcessMachCore.cpp
+++ source/Plugins/Process/mach-core/ProcessMachCore.cpp
@@ -375,7 +375,7 @@
}
bool
-ProcessMachCore::UpdateThreadList (ThreadList &old_thread_list, ThreadList &new_thread_list)
+ProcessMachCore::UpdateThreadList (ProcessThreadList &old_thread_list, ProcessThreadList &new_thread_list)
{
if (old_thread_list.GetSize(false) == 0)
{
Index: source/Plugins/Process/mach-core/ProcessMachCore.h
===================================================================
--- source/Plugins/Process/mach-core/ProcessMachCore.h
+++ source/Plugins/Process/mach-core/ProcessMachCore.h
@@ -118,8 +118,8 @@
Clear ( );
virtual bool
- UpdateThreadList (lldb_private::ThreadList &old_thread_list,
- lldb_private::ThreadList &new_thread_list);
+ UpdateThreadList (lldb_private::ProcessThreadList &old_thread_list,
+ lldb_private::ProcessThreadList &new_thread_list);
lldb_private::ObjectFile *
GetCoreObjectFile ();
Index: source/Target/Process.cpp
===================================================================
--- source/Target/Process.cpp
+++ source/Target/Process.cpp
@@ -1279,9 +1280,9 @@
// m_thread_list does have its own mutex, but we need to
// hold onto the mutex between the call to UpdateThreadList(...)
// and the os->UpdateThreadList(...) so it doesn't change on us
- ThreadList &old_thread_list = m_thread_list;
- ThreadList real_thread_list(this);
- ThreadList new_thread_list(this);
+ ProcessThreadList &old_thread_list = m_thread_list;
+ ProcessThreadList real_thread_list(this);
+ ProcessThreadList new_thread_list(this);
// Always update the thread list with the protocol specific
// thread list, but only update if "true" is returned
if (UpdateThreadList (m_thread_list_real, real_thread_list))
@@ -4244,7 +4245,7 @@
// If we're stopped and haven't restarted, then do the StopInfo actions here:
if (m_state == eStateStopped && ! m_restarted)
{
- ThreadList &curr_thread_list = m_process_sp->GetThreadList();
+ ProcessThreadList &curr_thread_list = m_process_sp->GetThreadList();
uint32_t num_threads = curr_thread_list.GetSize();
uint32_t idx;
@@ -5637,7 +5638,7 @@
break;
}
- ThreadList &thread_list = process->GetThreadList();
+ ProcessThreadList &thread_list = process->GetThreadList();
uint32_t num_threads = thread_list.GetSize();
uint32_t thread_index;
@@ -5861,7 +5862,7 @@
//Scope for thread list locker;
{
Mutex::Locker locker (GetThreadList().GetMutex());
- ThreadList &curr_thread_list = GetThreadList();
+ ProcessThreadList &curr_thread_list = GetThreadList();
num_threads = curr_thread_list.GetSize();
uint32_t idx;
thread_index_array.resize(num_threads);
Index: source/Target/ProcessThreadList.cpp
===================================================================
--- source/Target/ProcessThreadList.cpp
+++ source/Target/ProcessThreadList.cpp
@@ -0,0 +1,800 @@
+//===-- ProcessThreadList.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <stdlib.h>
+
+#include <algorithm>
+
+#include "lldb/Core/Log.h"
+#include "lldb/Core/State.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/ProcessThreadList.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlan.h"
+#include "lldb/Target/Process.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+ProcessThreadList::ProcessThreadList (Process *process) :
+ThreadList (),
+m_process (process),
+m_stop_id (0),
+m_selected_tid (LLDB_INVALID_THREAD_ID)
+{
+}
+
+ProcessThreadList::ProcessThreadList (const ProcessThreadList &rhs) :
+ThreadList (),
+m_process (rhs.m_process),
+m_stop_id (rhs.m_stop_id),
+m_selected_tid ()
+{
+ // Use the assignment operator since it uses the mutex
+ *this = rhs;
+}
+
+const ProcessThreadList&
+ProcessThreadList::operator = (const ProcessThreadList& rhs)
+{
+ if (this != &rhs)
+ {
+ // Lock both mutexes to make sure neither side changes anyone on us
+ // while the assignement occurs
+ Mutex::Locker locker(GetMutex());
+ m_process = rhs.m_process;
+ m_stop_id = rhs.m_stop_id;
+ m_threads = rhs.m_threads;
+ m_selected_tid = rhs.m_selected_tid;
+ }
+ return *this;
+}
+
+
+ProcessThreadList::~ProcessThreadList()
+{
+ // Clear the thread list. Clear will take the mutex lock
+ // which will ensure that if anyone is using the list
+ // they won't get it removed while using it.
+ Clear();
+}
+
+
+uint32_t
+ProcessThreadList::GetStopID () const
+{
+ return m_stop_id;
+}
+
+void
+ProcessThreadList::SetStopID (uint32_t stop_id)
+{
+ m_stop_id = stop_id;
+}
+
+uint32_t
+ProcessThreadList::GetSize (bool can_update)
+{
+ Mutex::Locker locker(GetMutex());
+ if (can_update)
+ m_process->UpdateThreadListIfNeeded();
+ return m_threads.size();
+}
+
+ThreadSP
+ProcessThreadList::GetThreadAtIndex (uint32_t idx, bool can_update)
+{
+ Mutex::Locker locker(GetMutex());
+ if (can_update)
+ m_process->UpdateThreadListIfNeeded();
+
+ ThreadSP thread_sp;
+ if (idx < m_threads.size())
+ thread_sp = m_threads[idx];
+ return thread_sp;
+}
+
+ThreadSP
+ProcessThreadList::FindThreadByID (lldb::tid_t tid, bool can_update)
+{
+ Mutex::Locker locker(GetMutex());
+
+ if (can_update)
+ m_process->UpdateThreadListIfNeeded();
+
+ ThreadSP thread_sp;
+ uint32_t idx = 0;
+ const uint32_t num_threads = m_threads.size();
+ for (idx = 0; idx < num_threads; ++idx)
+ {
+ if (m_threads[idx]->GetID() == tid)
+ {
+ thread_sp = m_threads[idx];
+ break;
+ }
+ }
+ return thread_sp;
+}
+
+ThreadSP
+ProcessThreadList::FindThreadByProtocolID (lldb::tid_t tid, bool can_update)
+{
+ Mutex::Locker locker(GetMutex());
+
+ if (can_update)
+ m_process->UpdateThreadListIfNeeded();
+
+ ThreadSP thread_sp;
+ uint32_t idx = 0;
+ const uint32_t num_threads = m_threads.size();
+ for (idx = 0; idx < num_threads; ++idx)
+ {
+ if (m_threads[idx]->GetProtocolID() == tid)
+ {
+ thread_sp = m_threads[idx];
+ break;
+ }
+ }
+ return thread_sp;
+}
+
+
+ThreadSP
+ProcessThreadList::RemoveThreadByID (lldb::tid_t tid, bool can_update)
+{
+ Mutex::Locker locker(GetMutex());
+
+ if (can_update)
+ m_process->UpdateThreadListIfNeeded();
+
+ ThreadSP thread_sp;
+ uint32_t idx = 0;
+ const uint32_t num_threads = m_threads.size();
+ for (idx = 0; idx < num_threads; ++idx)
+ {
+ if (m_threads[idx]->GetID() == tid)
+ {
+ thread_sp = m_threads[idx];
+ m_threads.erase(m_threads.begin()+idx);
+ break;
+ }
+ }
+ return thread_sp;
+}
+
+ThreadSP
+ProcessThreadList::RemoveThreadByProtocolID (lldb::tid_t tid, bool can_update)
+{
+ Mutex::Locker locker(GetMutex());
+
+ if (can_update)
+ m_process->UpdateThreadListIfNeeded();
+
+ ThreadSP thread_sp;
+ uint32_t idx = 0;
+ const uint32_t num_threads = m_threads.size();
+ for (idx = 0; idx < num_threads; ++idx)
+ {
+ if (m_threads[idx]->GetProtocolID() == tid)
+ {
+ thread_sp = m_threads[idx];
+ m_threads.erase(m_threads.begin()+idx);
+ break;
+ }
+ }
+ return thread_sp;
+}
+
+ThreadSP
+ProcessThreadList::GetThreadSPForThreadPtr (Thread *thread_ptr)
+{
+ ThreadSP thread_sp;
+ if (thread_ptr)
+ {
+ Mutex::Locker locker(GetMutex());
+
+ uint32_t idx = 0;
+ const uint32_t num_threads = m_threads.size();
+ for (idx = 0; idx < num_threads; ++idx)
+ {
+ if (m_threads[idx].get() == thread_ptr)
+ {
+ thread_sp = m_threads[idx];
+ break;
+ }
+ }
+ }
+ return thread_sp;
+}
+
+
+
+ThreadSP
+ProcessThreadList::FindThreadByIndexID (uint32_t index_id, bool can_update)
+{
+ Mutex::Locker locker(GetMutex());
+
+ if (can_update)
+ m_process->UpdateThreadListIfNeeded();
+
+ ThreadSP thread_sp;
+ const uint32_t num_threads = m_threads.size();
+ for (uint32_t idx = 0; idx < num_threads; ++idx)
+ {
+ if (m_threads[idx]->GetIndexID() == index_id)
+ {
+ thread_sp = m_threads[idx];
+ break;
+ }
+ }
+ return thread_sp;
+}
+
+bool
+ProcessThreadList::ShouldStop (Event *event_ptr)
+{
+ // Running events should never stop, obviously...
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+
+ // The ShouldStop method of the threads can do a whole lot of work,
+ // figuring out whether the thread plan conditions are met. So we don't want
+ // to keep the ThreadList locked the whole time we are doing this.
+ // FIXME: It is possible that running code could cause new threads
+ // to be created. If that happens we will miss asking them whether
+ // then should stop. This is not a big deal, since we haven't had
+ // a chance to hang any interesting operations on those threads yet.
+
+ collection threads_copy;
+ {
+ // Scope for locker
+ Mutex::Locker locker(GetMutex());
+
+ m_process->UpdateThreadListIfNeeded();
+ threads_copy = m_threads;
+ }
+
+ collection::iterator pos, end = threads_copy.end();
+
+ if (log)
+ {
+ log->PutCString("");
+ log->Printf ("ThreadList::%s: %" PRIu64 " threads", __FUNCTION__, (uint64_t)m_threads.size());
+ }
+
+ bool did_anybody_stop_for_a_reason = false;
+
+ // If the event is an Interrupt event, then we're going to stop no matter what. Otherwise, presume we won't stop.
+ bool should_stop = false;
+ if (Process::ProcessEventData::GetInterruptedFromEvent(event_ptr))
+ {
+ if (log)
+ log->Printf("ThreadList::%s handling interrupt event, should stop set to true", __FUNCTION__);
+
+ should_stop = true;
+ }
+
+ // Now we run through all the threads and get their stop info's. We want to make sure to do this first before
+ // we start running the ShouldStop, because one thread's ShouldStop could destroy information (like deleting a
+ // thread specific breakpoint another thread had stopped at) which could lead us to compute the StopInfo incorrectly.
+ // We don't need to use it here, we just want to make sure it gets computed.
+
+ for (pos = threads_copy.begin(); pos != end; ++pos)
+ {
+ ThreadSP thread_sp(*pos);
+ thread_sp->GetStopInfo();
+ }
+
+ for (pos = threads_copy.begin(); pos != end; ++pos)
+ {
+ ThreadSP thread_sp(*pos);
+
+ // We should never get a stop for which no thread had a stop reason, but sometimes we do see this -
+ // for instance when we first connect to a remote stub. In that case we should stop, since we can't figure out
+ // the right thing to do and stopping gives the user control over what to do in this instance.
+ //
+ // Note, this causes a problem when you have a thread specific breakpoint, and a bunch of threads hit the breakpoint,
+ // but not the thread which we are waiting for. All the threads that are not "supposed" to hit the breakpoint
+ // are marked as having no stop reason, which is right, they should not show a stop reason. But that triggers this
+ // code and causes us to stop seemingly for no reason.
+ //
+ // Since the only way we ever saw this error was on first attach, I'm only going to trigger set did_anybody_stop_for_a_reason
+ // to true unless this is the first stop.
+ //
+ // If this becomes a problem, we'll have to have another StopReason like "StopInfoHidden" which will look invalid
+ // everywhere but at this check.
+
+ if (thread_sp->GetProcess()->GetStopID() > 1)
+ did_anybody_stop_for_a_reason = true;
+ else
+ did_anybody_stop_for_a_reason |= thread_sp->ThreadStoppedForAReason();
+
+ const bool thread_should_stop = thread_sp->ShouldStop(event_ptr);
+ if (thread_should_stop)
+ should_stop |= true;
+ }
+
+ if (!should_stop && !did_anybody_stop_for_a_reason)
+ {
+ should_stop = true;
+ if (log)
+ log->Printf ("ThreadList::%s we stopped but no threads had a stop reason, overriding should_stop and stopping.", __FUNCTION__);
+ }
+
+ if (log)
+ log->Printf ("ThreadList::%s overall should_stop = %i", __FUNCTION__, should_stop);
+
+ if (should_stop)
+ {
+ for (pos = threads_copy.begin(); pos != end; ++pos)
+ {
+ ThreadSP thread_sp(*pos);
+ thread_sp->WillStop ();
+ }
+ }
+
+ return should_stop;
+}
+
+Vote
+ProcessThreadList::ShouldReportStop (Event *event_ptr)
+{
+ Mutex::Locker locker(GetMutex());
+
+ Vote result = eVoteNoOpinion;
+ m_process->UpdateThreadListIfNeeded();
+ collection::iterator pos, end = m_threads.end();
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+
+ if (log)
+ log->Printf ("ThreadList::%s %" PRIu64 " threads", __FUNCTION__, (uint64_t)m_threads.size());
+
+ // Run through the threads and ask whether we should report this event.
+ // For stopping, a YES vote wins over everything. A NO vote wins over NO opinion.
+ for (pos = m_threads.begin(); pos != end; ++pos)
+ {
+ ThreadSP thread_sp(*pos);
+ const Vote vote = thread_sp->ShouldReportStop (event_ptr);
+ switch (vote)
+ {
+ case eVoteNoOpinion:
+ continue;
+
+ case eVoteYes:
+ result = eVoteYes;
+ break;
+
+ case eVoteNo:
+ if (result == eVoteNoOpinion)
+ {
+ result = eVoteNo;
+ }
+ else
+ {
+ if (log)
+ log->Printf ("ThreadList::%s thread 0x%4.4" PRIx64 ": voted %s, but lost out because result was %s",
+ __FUNCTION__,
+ thread_sp->GetID (),
+ GetVoteAsCString (vote),
+ GetVoteAsCString (result));
+ }
+ break;
+ }
+ }
+ if (log)
+ log->Printf ("ThreadList::%s returning %s", __FUNCTION__, GetVoteAsCString (result));
+ return result;
+}
+
+void
+ProcessThreadList::SetShouldReportStop (Vote vote)
+{
+ Mutex::Locker locker(GetMutex());
+ m_process->UpdateThreadListIfNeeded();
+ collection::iterator pos, end = m_threads.end();
+ for (pos = m_threads.begin(); pos != end; ++pos)
+ {
+ ThreadSP thread_sp(*pos);
+ thread_sp->SetShouldReportStop (vote);
+ }
+}
+
+Vote
+ProcessThreadList::ShouldReportRun (Event *event_ptr)
+{
+
+ Mutex::Locker locker(GetMutex());
+
+ Vote result = eVoteNoOpinion;
+ m_process->UpdateThreadListIfNeeded();
+ collection::iterator pos, end = m_threads.end();
+
+ // Run through the threads and ask whether we should report this event.
+ // The rule is NO vote wins over everything, a YES vote wins over no opinion.
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+
+ for (pos = m_threads.begin(); pos != end; ++pos)
+ {
+ if ((*pos)->GetResumeState () != eStateSuspended)
+ {
+ switch ((*pos)->ShouldReportRun (event_ptr))
+ {
+ case eVoteNoOpinion:
+ continue;
+ case eVoteYes:
+ if (result == eVoteNoOpinion)
+ result = eVoteYes;
+ break;
+ case eVoteNo:
+ if (log)
+ log->Printf ("ThreadList::ShouldReportRun() thread %d (0x%4.4" PRIx64 ") says don't report.",
+ (*pos)->GetIndexID(),
+ (*pos)->GetID());
+ result = eVoteNo;
+ break;
+ }
+ }
+ }
+ return result;
+}
+
+void
+ProcessThreadList::Clear()
+{
+ Mutex::Locker locker(GetMutex());
+ m_stop_id = 0;
+ m_threads.clear();
+ m_selected_tid = LLDB_INVALID_THREAD_ID;
+}
+
+void
+ProcessThreadList::Destroy()
+{
+ Mutex::Locker locker(GetMutex());
+ const uint32_t num_threads = m_threads.size();
+ for (uint32_t idx = 0; idx < num_threads; ++idx)
+ {
+ m_threads[idx]->DestroyThread();
+ }
+}
+
+void
+ProcessThreadList::RefreshStateAfterStop ()
+{
+ Mutex::Locker locker(GetMutex());
+
+ m_process->UpdateThreadListIfNeeded();
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+ if (log && log->GetVerbose())
+ log->Printf ("Turning off notification of new threads while single stepping a thread.");
+
+ collection::iterator pos, end = m_threads.end();
+ for (pos = m_threads.begin(); pos != end; ++pos)
+ (*pos)->RefreshStateAfterStop ();
+}
+
+void
+ProcessThreadList::DiscardThreadPlans ()
+{
+ // You don't need to update the thread list here, because only threads
+ // that you currently know about have any thread plans.
+ Mutex::Locker locker(GetMutex());
+
+ collection::iterator pos, end = m_threads.end();
+ for (pos = m_threads.begin(); pos != end; ++pos)
+ (*pos)->DiscardThreadPlans (true);
+
+}
+
+bool
+ProcessThreadList::WillResume ()
+{
+ // Run through the threads and perform their momentary actions.
+ // But we only do this for threads that are running, user suspended
+ // threads stay where they are.
+
+ Mutex::Locker locker(GetMutex());
+ m_process->UpdateThreadListIfNeeded();
+
+ collection::iterator pos, end = m_threads.end();
+
+ // See if any thread wants to run stopping others. If it does, then we won't
+ // setup the other threads for resume, since they aren't going to get a chance
+ // to run. This is necessary because the SetupForResume might add "StopOthers"
+ // plans which would then get to be part of the who-gets-to-run negotiation, but
+ // they're coming in after the fact, and the threads that are already set up should
+ // take priority.
+
+ bool wants_solo_run = false;
+
+ for (pos = m_threads.begin(); pos != end; ++pos)
+ {
+ if ((*pos)->GetResumeState() != eStateSuspended &&
+ (*pos)->GetCurrentPlan()->StopOthers())
+ {
+ if ((*pos)->IsOperatingSystemPluginThread() && !(*pos)->GetBackingThread())
+ continue;
+ wants_solo_run = true;
+ break;
+ }
+ }
+
+ if (wants_solo_run)
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+ if (log && log->GetVerbose())
+ log->Printf ("Turning on notification of new threads while single stepping a thread.");
+ m_process->StartNoticingNewThreads();
+ }
+ else
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+ if (log && log->GetVerbose())
+ log->Printf ("Turning off notification of new threads while single stepping a thread.");
+ m_process->StopNoticingNewThreads();
+ }
+
+ // Give all the threads that are likely to run a last chance to set up their state before we
+ // negotiate who is actually going to get a chance to run...
+ // Don't set to resume suspended threads, and if any thread wanted to stop others, only
+ // call setup on the threads that request StopOthers...
+
+ for (pos = m_threads.begin(); pos != end; ++pos)
+ {
+ if ((*pos)->GetResumeState() != eStateSuspended
+ && (!wants_solo_run || (*pos)->GetCurrentPlan()->StopOthers()))
+ {
+ if ((*pos)->IsOperatingSystemPluginThread() && !(*pos)->GetBackingThread())
+ continue;
+ (*pos)->SetupForResume ();
+ }
+ }
+
+ // Now go through the threads and see if any thread wants to run just itself.
+ // if so then pick one and run it.
+
+ ProcessThreadList run_me_only_list (m_process);
+
+ run_me_only_list.SetStopID(m_process->GetStopID());
+
+ bool run_only_current_thread = false;
+
+ for (pos = m_threads.begin(); pos != end; ++pos)
+ {
+ ThreadSP thread_sp(*pos);
+ if (thread_sp->GetResumeState() != eStateSuspended &&
+ thread_sp->GetCurrentPlan()->StopOthers())
+ {
+ if ((*pos)->IsOperatingSystemPluginThread() && !(*pos)->GetBackingThread())
+ continue;
+
+ // You can't say "stop others" and also want yourself to be suspended.
+ assert (thread_sp->GetCurrentPlan()->RunState() != eStateSuspended);
+
+ if (thread_sp == GetSelectedThread())
+ {
+ run_only_current_thread = true;
+ run_me_only_list.Clear();
+ run_me_only_list.AddThread (thread_sp);
+ break;
+ }
+
+ run_me_only_list.AddThread (thread_sp);
+ }
+
+ }
+
+ bool need_to_resume = true;
+
+ if (run_me_only_list.GetSize (false) == 0)
+ {
+ // Everybody runs as they wish:
+ for (pos = m_threads.begin(); pos != end; ++pos)
+ {
+ ThreadSP thread_sp(*pos);
+ StateType run_state;
+ if (thread_sp->GetResumeState() != eStateSuspended)
+ run_state = thread_sp->GetCurrentPlan()->RunState();
+ else
+ run_state = eStateSuspended;
+ if (!thread_sp->ShouldResume(run_state))
+ need_to_resume = false;
+ }
+ }
+ else
+ {
+ ThreadSP thread_to_run;
+
+ if (run_only_current_thread)
+ {
+ thread_to_run = GetSelectedThread();
+ }
+ else if (run_me_only_list.GetSize (false) == 1)
+ {
+ thread_to_run = run_me_only_list.GetThreadAtIndex (0);
+ }
+ else
+ {
+ int random_thread = (int)
+ ((run_me_only_list.GetSize (false) * (double) rand ()) / (RAND_MAX + 1.0));
+ thread_to_run = run_me_only_list.GetThreadAtIndex (random_thread);
+ }
+
+ for (pos = m_threads.begin(); pos != end; ++pos)
+ {
+ ThreadSP thread_sp(*pos);
+ if (thread_sp == thread_to_run)
+ {
+ if (!thread_sp->ShouldResume(thread_sp->GetCurrentPlan()->RunState()))
+ need_to_resume = false;
+ }
+ else
+ thread_sp->ShouldResume (eStateSuspended);
+ }
+ }
+
+ return need_to_resume;
+}
+
+void
+ProcessThreadList::DidResume ()
+{
+ Mutex::Locker locker(GetMutex());
+ collection::iterator pos, end = m_threads.end();
+ for (pos = m_threads.begin(); pos != end; ++pos)
+ {
+ // Don't clear out threads that aren't going to get a chance to run, rather
+ // leave their state for the next time around.
+ ThreadSP thread_sp(*pos);
+ if (thread_sp->GetResumeState() != eStateSuspended)
+ thread_sp->DidResume ();
+ }
+}
+
+void
+ProcessThreadList::DidStop ()
+{
+ Mutex::Locker locker(GetMutex());
+ collection::iterator pos, end = m_threads.end();
+ for (pos = m_threads.begin(); pos != end; ++pos)
+ {
+ // Notify threads that the process just stopped.
+ // Note, this currently assumes that all threads in the list
+ // stop when the process stops. In the future we will want to support
+ // a debugging model where some threads continue to run while others
+ // are stopped. We either need to handle that somehow here or
+ // create a special thread list containing only threads which will
+ // stop in the code that calls this method (currently
+ // Process::SetPrivateState).
+ ThreadSP thread_sp(*pos);
+ if (StateIsRunningState(thread_sp->GetState()))
+ thread_sp->DidStop ();
+ }
+}
+
+ThreadSP
+ProcessThreadList::GetSelectedThread ()
+{
+ Mutex::Locker locker(GetMutex());
+ ThreadSP thread_sp = FindThreadByID(m_selected_tid);
+ if (!thread_sp.get())
+ {
+ if (m_threads.size() == 0)
+ return thread_sp;
+ m_selected_tid = m_threads[0]->GetID();
+ thread_sp = m_threads[0];
+ }
+ return thread_sp;
+}
+
+bool
+ProcessThreadList::SetSelectedThreadByID (lldb::tid_t tid, bool notify)
+{
+ Mutex::Locker locker(GetMutex());
+ ThreadSP selected_thread_sp(FindThreadByID(tid));
+ if (selected_thread_sp)
+ {
+ m_selected_tid = tid;
+ selected_thread_sp->SetDefaultFileAndLineToSelectedFrame();
+ }
+ else
+ m_selected_tid = LLDB_INVALID_THREAD_ID;
+
+ if (notify)
+ NotifySelectedThreadChanged(m_selected_tid);
+
+ return m_selected_tid != LLDB_INVALID_THREAD_ID;
+}
+
+bool
+ProcessThreadList::SetSelectedThreadByIndexID (uint32_t index_id, bool notify)
+{
+ Mutex::Locker locker(GetMutex());
+ ThreadSP selected_thread_sp (FindThreadByIndexID(index_id));
+ if (selected_thread_sp.get())
+ {
+ m_selected_tid = selected_thread_sp->GetID();
+ selected_thread_sp->SetDefaultFileAndLineToSelectedFrame();
+ }
+ else
+ m_selected_tid = LLDB_INVALID_THREAD_ID;
+
+ if (notify)
+ NotifySelectedThreadChanged(m_selected_tid);
+
+ return m_selected_tid != LLDB_INVALID_THREAD_ID;
+}
+
+void
+ProcessThreadList::NotifySelectedThreadChanged (lldb::tid_t tid)
+{
+ ThreadSP selected_thread_sp (FindThreadByID(tid));
+ if (selected_thread_sp->EventTypeHasListeners(Thread::eBroadcastBitThreadSelected))
+ selected_thread_sp->BroadcastEvent(Thread::eBroadcastBitThreadSelected,
+ new Thread::ThreadEventData(selected_thread_sp));
+}
+
+void
+ProcessThreadList::Update (ProcessThreadList &rhs)
+{
+ if (this != &rhs)
+ {
+ // Lock both mutexes to make sure neither side changes anyone on us
+ // while the assignement occurs
+ Mutex::Locker locker(GetMutex());
+ m_process = rhs.m_process;
+ m_stop_id = rhs.m_stop_id;
+ m_threads.swap(rhs.m_threads);
+ m_selected_tid = rhs.m_selected_tid;
+
+
+ // Now we look for threads that we are done with and
+ // make sure to clear them up as much as possible so
+ // anyone with a shared pointer will still have a reference,
+ // but the thread won't be of much use. Using std::weak_ptr
+ // for all backward references (such as a thread to a process)
+ // will eventually solve this issue for us, but for now, we
+ // need to work around the issue
+ collection::iterator rhs_pos, rhs_end = rhs.m_threads.end();
+ for (rhs_pos = rhs.m_threads.begin(); rhs_pos != rhs_end; ++rhs_pos)
+ {
+ const lldb::tid_t tid = (*rhs_pos)->GetID();
+ bool thread_is_alive = false;
+ const uint32_t num_threads = m_threads.size();
+ for (uint32_t idx = 0; idx < num_threads; ++idx)
+ {
+ if (m_threads[idx]->GetID() == tid)
+ {
+ thread_is_alive = true;
+ break;
+ }
+ }
+ if (!thread_is_alive)
+ (*rhs_pos)->DestroyThread();
+ }
+ }
+}
+
+void
+ProcessThreadList::Flush ()
+{
+ Mutex::Locker locker(GetMutex());
+ collection::iterator pos, end = m_threads.end();
+ for (pos = m_threads.begin(); pos != end; ++pos)
+ (*pos)->Flush ();
+}
+
+Mutex &
+ProcessThreadList::GetMutex ()
+{
+ return m_process->m_thread_mutex;
+}
+
Index: source/Target/Target.cpp
===================================================================
--- source/Target/Target.cpp
+++ source/Target/Target.cpp
@@ -2109,7 +2109,7 @@
std::vector<ExecutionContext> exc_ctx_with_reasons;
std::vector<SymbolContext> sym_ctx_with_reasons;
- ThreadList &cur_threadlist = m_process_sp->GetThreadList();
+ ProcessThreadList &cur_threadlist = m_process_sp->GetThreadList();
size_t num_threads = cur_threadlist.GetSize();
for (size_t i = 0; i < num_threads; i++)
{
Index: source/Target/ThreadList.cpp
===================================================================
--- source/Target/ThreadList.cpp
+++ source/Target/ThreadList.cpp
@@ -6,79 +6,27 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-#include <stdlib.h>
-#include <algorithm>
-
-#include "lldb/Core/Log.h"
-#include "lldb/Core/State.h"
-#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/ThreadList.h"
-#include "lldb/Target/Thread.h"
-#include "lldb/Target/ThreadPlan.h"
-#include "lldb/Target/Process.h"
using namespace lldb;
using namespace lldb_private;
-ThreadList::ThreadList (Process *process) :
- m_process (process),
- m_stop_id (0),
- m_threads(),
- m_selected_tid (LLDB_INVALID_THREAD_ID)
+ThreadList::ThreadList() :
+m_threads(),
+m_mutex()
{
+
}
-ThreadList::ThreadList (const ThreadList &rhs) :
- m_process (rhs.m_process),
- m_stop_id (rhs.m_stop_id),
- m_threads (),
- m_selected_tid ()
+ThreadList::ThreadList(collection threads) :
+m_threads(threads),
+m_mutex()
{
- // Use the assignment operator since it uses the mutex
- *this = rhs;
+
}
-const ThreadList&
-ThreadList::operator = (const ThreadList& rhs)
-{
- if (this != &rhs)
- {
- // Lock both mutexes to make sure neither side changes anyone on us
- // while the assignement occurs
- Mutex::Locker locker(GetMutex());
- m_process = rhs.m_process;
- m_stop_id = rhs.m_stop_id;
- m_threads = rhs.m_threads;
- m_selected_tid = rhs.m_selected_tid;
- }
- return *this;
-}
-
-
-ThreadList::~ThreadList()
-{
- // Clear the thread list. Clear will take the mutex lock
- // which will ensure that if anyone is using the list
- // they won't get it removed while using it.
- Clear();
-}
-
-
-uint32_t
-ThreadList::GetStopID () const
-{
- return m_stop_id;
-}
-
void
-ThreadList::SetStopID (uint32_t stop_id)
-{
- m_stop_id = stop_id;
-}
-
-
-void
ThreadList::AddThread (const ThreadSP &thread_sp)
{
Mutex::Locker locker(GetMutex());
@@ -95,725 +43,20 @@
m_threads.push_back (thread_sp);
}
-
uint32_t
-ThreadList::GetSize (bool can_update)
+ThreadList::GetSize ()
{
Mutex::Locker locker(GetMutex());
- if (can_update)
- m_process->UpdateThreadListIfNeeded();
return m_threads.size();
}
ThreadSP
-ThreadList::GetThreadAtIndex (uint32_t idx, bool can_update)
+ThreadList::GetThreadAtIndex (uint32_t idx)
{
Mutex::Locker locker(GetMutex());
- if (can_update)
- m_process->UpdateThreadListIfNeeded();
-
+
ThreadSP thread_sp;
if (idx < m_threads.size())
thread_sp = m_threads[idx];
return thread_sp;
}
-
-ThreadSP
-ThreadList::FindThreadByID (lldb::tid_t tid, bool can_update)
-{
- Mutex::Locker locker(GetMutex());
-
- if (can_update)
- m_process->UpdateThreadListIfNeeded();
-
- ThreadSP thread_sp;
- uint32_t idx = 0;
- const uint32_t num_threads = m_threads.size();
- for (idx = 0; idx < num_threads; ++idx)
- {
- if (m_threads[idx]->GetID() == tid)
- {
- thread_sp = m_threads[idx];
- break;
- }
- }
- return thread_sp;
-}
-
-ThreadSP
-ThreadList::FindThreadByProtocolID (lldb::tid_t tid, bool can_update)
-{
- Mutex::Locker locker(GetMutex());
-
- if (can_update)
- m_process->UpdateThreadListIfNeeded();
-
- ThreadSP thread_sp;
- uint32_t idx = 0;
- const uint32_t num_threads = m_threads.size();
- for (idx = 0; idx < num_threads; ++idx)
- {
- if (m_threads[idx]->GetProtocolID() == tid)
- {
- thread_sp = m_threads[idx];
- break;
- }
- }
- return thread_sp;
-}
-
-
-ThreadSP
-ThreadList::RemoveThreadByID (lldb::tid_t tid, bool can_update)
-{
- Mutex::Locker locker(GetMutex());
-
- if (can_update)
- m_process->UpdateThreadListIfNeeded();
-
- ThreadSP thread_sp;
- uint32_t idx = 0;
- const uint32_t num_threads = m_threads.size();
- for (idx = 0; idx < num_threads; ++idx)
- {
- if (m_threads[idx]->GetID() == tid)
- {
- thread_sp = m_threads[idx];
- m_threads.erase(m_threads.begin()+idx);
- break;
- }
- }
- return thread_sp;
-}
-
-ThreadSP
-ThreadList::RemoveThreadByProtocolID (lldb::tid_t tid, bool can_update)
-{
- Mutex::Locker locker(GetMutex());
-
- if (can_update)
- m_process->UpdateThreadListIfNeeded();
-
- ThreadSP thread_sp;
- uint32_t idx = 0;
- const uint32_t num_threads = m_threads.size();
- for (idx = 0; idx < num_threads; ++idx)
- {
- if (m_threads[idx]->GetProtocolID() == tid)
- {
- thread_sp = m_threads[idx];
- m_threads.erase(m_threads.begin()+idx);
- break;
- }
- }
- return thread_sp;
-}
-
-ThreadSP
-ThreadList::GetThreadSPForThreadPtr (Thread *thread_ptr)
-{
- ThreadSP thread_sp;
- if (thread_ptr)
- {
- Mutex::Locker locker(GetMutex());
-
- uint32_t idx = 0;
- const uint32_t num_threads = m_threads.size();
- for (idx = 0; idx < num_threads; ++idx)
- {
- if (m_threads[idx].get() == thread_ptr)
- {
- thread_sp = m_threads[idx];
- break;
- }
- }
- }
- return thread_sp;
-}
-
-
-
-ThreadSP
-ThreadList::FindThreadByIndexID (uint32_t index_id, bool can_update)
-{
- Mutex::Locker locker(GetMutex());
-
- if (can_update)
- m_process->UpdateThreadListIfNeeded();
-
- ThreadSP thread_sp;
- const uint32_t num_threads = m_threads.size();
- for (uint32_t idx = 0; idx < num_threads; ++idx)
- {
- if (m_threads[idx]->GetIndexID() == index_id)
- {
- thread_sp = m_threads[idx];
- break;
- }
- }
- return thread_sp;
-}
-
-bool
-ThreadList::ShouldStop (Event *event_ptr)
-{
- // Running events should never stop, obviously...
-
- Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
-
- // The ShouldStop method of the threads can do a whole lot of work,
- // figuring out whether the thread plan conditions are met. So we don't want
- // to keep the ThreadList locked the whole time we are doing this.
- // FIXME: It is possible that running code could cause new threads
- // to be created. If that happens we will miss asking them whether
- // then should stop. This is not a big deal, since we haven't had
- // a chance to hang any interesting operations on those threads yet.
-
- collection threads_copy;
- {
- // Scope for locker
- Mutex::Locker locker(GetMutex());
-
- m_process->UpdateThreadListIfNeeded();
- threads_copy = m_threads;
- }
-
- collection::iterator pos, end = threads_copy.end();
-
- if (log)
- {
- log->PutCString("");
- log->Printf ("ThreadList::%s: %" PRIu64 " threads", __FUNCTION__, (uint64_t)m_threads.size());
- }
-
- bool did_anybody_stop_for_a_reason = false;
-
- // If the event is an Interrupt event, then we're going to stop no matter what. Otherwise, presume we won't stop.
- bool should_stop = false;
- if (Process::ProcessEventData::GetInterruptedFromEvent(event_ptr))
- {
- if (log)
- log->Printf("ThreadList::%s handling interrupt event, should stop set to true", __FUNCTION__);
-
- should_stop = true;
- }
-
- // Now we run through all the threads and get their stop info's. We want to make sure to do this first before
- // we start running the ShouldStop, because one thread's ShouldStop could destroy information (like deleting a
- // thread specific breakpoint another thread had stopped at) which could lead us to compute the StopInfo incorrectly.
- // We don't need to use it here, we just want to make sure it gets computed.
-
- for (pos = threads_copy.begin(); pos != end; ++pos)
- {
- ThreadSP thread_sp(*pos);
- thread_sp->GetStopInfo();
- }
-
- for (pos = threads_copy.begin(); pos != end; ++pos)
- {
- ThreadSP thread_sp(*pos);
-
- // We should never get a stop for which no thread had a stop reason, but sometimes we do see this -
- // for instance when we first connect to a remote stub. In that case we should stop, since we can't figure out
- // the right thing to do and stopping gives the user control over what to do in this instance.
- //
- // Note, this causes a problem when you have a thread specific breakpoint, and a bunch of threads hit the breakpoint,
- // but not the thread which we are waiting for. All the threads that are not "supposed" to hit the breakpoint
- // are marked as having no stop reason, which is right, they should not show a stop reason. But that triggers this
- // code and causes us to stop seemingly for no reason.
- //
- // Since the only way we ever saw this error was on first attach, I'm only going to trigger set did_anybody_stop_for_a_reason
- // to true unless this is the first stop.
- //
- // If this becomes a problem, we'll have to have another StopReason like "StopInfoHidden" which will look invalid
- // everywhere but at this check.
-
- if (thread_sp->GetProcess()->GetStopID() > 1)
- did_anybody_stop_for_a_reason = true;
- else
- did_anybody_stop_for_a_reason |= thread_sp->ThreadStoppedForAReason();
-
- const bool thread_should_stop = thread_sp->ShouldStop(event_ptr);
- if (thread_should_stop)
- should_stop |= true;
- }
-
- if (!should_stop && !did_anybody_stop_for_a_reason)
- {
- should_stop = true;
- if (log)
- log->Printf ("ThreadList::%s we stopped but no threads had a stop reason, overriding should_stop and stopping.", __FUNCTION__);
- }
-
- if (log)
- log->Printf ("ThreadList::%s overall should_stop = %i", __FUNCTION__, should_stop);
-
- if (should_stop)
- {
- for (pos = threads_copy.begin(); pos != end; ++pos)
- {
- ThreadSP thread_sp(*pos);
- thread_sp->WillStop ();
- }
- }
-
- return should_stop;
-}
-
-Vote
-ThreadList::ShouldReportStop (Event *event_ptr)
-{
- Mutex::Locker locker(GetMutex());
-
- Vote result = eVoteNoOpinion;
- m_process->UpdateThreadListIfNeeded();
- collection::iterator pos, end = m_threads.end();
-
- Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
-
- if (log)
- log->Printf ("ThreadList::%s %" PRIu64 " threads", __FUNCTION__, (uint64_t)m_threads.size());
-
- // Run through the threads and ask whether we should report this event.
- // For stopping, a YES vote wins over everything. A NO vote wins over NO opinion.
- for (pos = m_threads.begin(); pos != end; ++pos)
- {
- ThreadSP thread_sp(*pos);
- const Vote vote = thread_sp->ShouldReportStop (event_ptr);
- switch (vote)
- {
- case eVoteNoOpinion:
- continue;
-
- case eVoteYes:
- result = eVoteYes;
- break;
-
- case eVoteNo:
- if (result == eVoteNoOpinion)
- {
- result = eVoteNo;
- }
- else
- {
- if (log)
- log->Printf ("ThreadList::%s thread 0x%4.4" PRIx64 ": voted %s, but lost out because result was %s",
- __FUNCTION__,
- thread_sp->GetID (),
- GetVoteAsCString (vote),
- GetVoteAsCString (result));
- }
- break;
- }
- }
- if (log)
- log->Printf ("ThreadList::%s returning %s", __FUNCTION__, GetVoteAsCString (result));
- return result;
-}
-
-void
-ThreadList::SetShouldReportStop (Vote vote)
-{
- Mutex::Locker locker(GetMutex());
- m_process->UpdateThreadListIfNeeded();
- collection::iterator pos, end = m_threads.end();
- for (pos = m_threads.begin(); pos != end; ++pos)
- {
- ThreadSP thread_sp(*pos);
- thread_sp->SetShouldReportStop (vote);
- }
-}
-
-Vote
-ThreadList::ShouldReportRun (Event *event_ptr)
-{
-
- Mutex::Locker locker(GetMutex());
-
- Vote result = eVoteNoOpinion;
- m_process->UpdateThreadListIfNeeded();
- collection::iterator pos, end = m_threads.end();
-
- // Run through the threads and ask whether we should report this event.
- // The rule is NO vote wins over everything, a YES vote wins over no opinion.
-
- Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
-
- for (pos = m_threads.begin(); pos != end; ++pos)
- {
- if ((*pos)->GetResumeState () != eStateSuspended)
- {
- switch ((*pos)->ShouldReportRun (event_ptr))
- {
- case eVoteNoOpinion:
- continue;
- case eVoteYes:
- if (result == eVoteNoOpinion)
- result = eVoteYes;
- break;
- case eVoteNo:
- if (log)
- log->Printf ("ThreadList::ShouldReportRun() thread %d (0x%4.4" PRIx64 ") says don't report.",
- (*pos)->GetIndexID(),
- (*pos)->GetID());
- result = eVoteNo;
- break;
- }
- }
- }
- return result;
-}
-
-void
-ThreadList::Clear()
-{
- Mutex::Locker locker(GetMutex());
- m_stop_id = 0;
- m_threads.clear();
- m_selected_tid = LLDB_INVALID_THREAD_ID;
-}
-
-void
-ThreadList::Destroy()
-{
- Mutex::Locker locker(GetMutex());
- const uint32_t num_threads = m_threads.size();
- for (uint32_t idx = 0; idx < num_threads; ++idx)
- {
- m_threads[idx]->DestroyThread();
- }
-}
-
-void
-ThreadList::RefreshStateAfterStop ()
-{
- Mutex::Locker locker(GetMutex());
-
- m_process->UpdateThreadListIfNeeded();
-
- Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
- if (log && log->GetVerbose())
- log->Printf ("Turning off notification of new threads while single stepping a thread.");
-
- collection::iterator pos, end = m_threads.end();
- for (pos = m_threads.begin(); pos != end; ++pos)
- (*pos)->RefreshStateAfterStop ();
-}
-
-void
-ThreadList::DiscardThreadPlans ()
-{
- // You don't need to update the thread list here, because only threads
- // that you currently know about have any thread plans.
- Mutex::Locker locker(GetMutex());
-
- collection::iterator pos, end = m_threads.end();
- for (pos = m_threads.begin(); pos != end; ++pos)
- (*pos)->DiscardThreadPlans (true);
-
-}
-
-bool
-ThreadList::WillResume ()
-{
- // Run through the threads and perform their momentary actions.
- // But we only do this for threads that are running, user suspended
- // threads stay where they are.
-
- Mutex::Locker locker(GetMutex());
- m_process->UpdateThreadListIfNeeded();
-
- collection::iterator pos, end = m_threads.end();
-
- // See if any thread wants to run stopping others. If it does, then we won't
- // setup the other threads for resume, since they aren't going to get a chance
- // to run. This is necessary because the SetupForResume might add "StopOthers"
- // plans which would then get to be part of the who-gets-to-run negotiation, but
- // they're coming in after the fact, and the threads that are already set up should
- // take priority.
-
- bool wants_solo_run = false;
-
- for (pos = m_threads.begin(); pos != end; ++pos)
- {
- if ((*pos)->GetResumeState() != eStateSuspended &&
- (*pos)->GetCurrentPlan()->StopOthers())
- {
- if ((*pos)->IsOperatingSystemPluginThread() && !(*pos)->GetBackingThread())
- continue;
- wants_solo_run = true;
- break;
- }
- }
-
- if (wants_solo_run)
- {
- Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
- if (log && log->GetVerbose())
- log->Printf ("Turning on notification of new threads while single stepping a thread.");
- m_process->StartNoticingNewThreads();
- }
- else
- {
- Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
- if (log && log->GetVerbose())
- log->Printf ("Turning off notification of new threads while single stepping a thread.");
- m_process->StopNoticingNewThreads();
- }
-
- // Give all the threads that are likely to run a last chance to set up their state before we
- // negotiate who is actually going to get a chance to run...
- // Don't set to resume suspended threads, and if any thread wanted to stop others, only
- // call setup on the threads that request StopOthers...
-
- for (pos = m_threads.begin(); pos != end; ++pos)
- {
- if ((*pos)->GetResumeState() != eStateSuspended
- && (!wants_solo_run || (*pos)->GetCurrentPlan()->StopOthers()))
- {
- if ((*pos)->IsOperatingSystemPluginThread() && !(*pos)->GetBackingThread())
- continue;
- (*pos)->SetupForResume ();
- }
- }
-
- // Now go through the threads and see if any thread wants to run just itself.
- // if so then pick one and run it.
-
- ThreadList run_me_only_list (m_process);
-
- run_me_only_list.SetStopID(m_process->GetStopID());
-
- bool run_only_current_thread = false;
-
- for (pos = m_threads.begin(); pos != end; ++pos)
- {
- ThreadSP thread_sp(*pos);
- if (thread_sp->GetResumeState() != eStateSuspended &&
- thread_sp->GetCurrentPlan()->StopOthers())
- {
- if ((*pos)->IsOperatingSystemPluginThread() && !(*pos)->GetBackingThread())
- continue;
-
- // You can't say "stop others" and also want yourself to be suspended.
- assert (thread_sp->GetCurrentPlan()->RunState() != eStateSuspended);
-
- if (thread_sp == GetSelectedThread())
- {
- run_only_current_thread = true;
- run_me_only_list.Clear();
- run_me_only_list.AddThread (thread_sp);
- break;
- }
-
- run_me_only_list.AddThread (thread_sp);
- }
-
- }
-
- bool need_to_resume = true;
-
- if (run_me_only_list.GetSize (false) == 0)
- {
- // Everybody runs as they wish:
- for (pos = m_threads.begin(); pos != end; ++pos)
- {
- ThreadSP thread_sp(*pos);
- StateType run_state;
- if (thread_sp->GetResumeState() != eStateSuspended)
- run_state = thread_sp->GetCurrentPlan()->RunState();
- else
- run_state = eStateSuspended;
- if (!thread_sp->ShouldResume(run_state))
- need_to_resume = false;
- }
- }
- else
- {
- ThreadSP thread_to_run;
-
- if (run_only_current_thread)
- {
- thread_to_run = GetSelectedThread();
- }
- else if (run_me_only_list.GetSize (false) == 1)
- {
- thread_to_run = run_me_only_list.GetThreadAtIndex (0);
- }
- else
- {
- int random_thread = (int)
- ((run_me_only_list.GetSize (false) * (double) rand ()) / (RAND_MAX + 1.0));
- thread_to_run = run_me_only_list.GetThreadAtIndex (random_thread);
- }
-
- for (pos = m_threads.begin(); pos != end; ++pos)
- {
- ThreadSP thread_sp(*pos);
- if (thread_sp == thread_to_run)
- {
- if (!thread_sp->ShouldResume(thread_sp->GetCurrentPlan()->RunState()))
- need_to_resume = false;
- }
- else
- thread_sp->ShouldResume (eStateSuspended);
- }
- }
-
- return need_to_resume;
-}
-
-void
-ThreadList::DidResume ()
-{
- Mutex::Locker locker(GetMutex());
- collection::iterator pos, end = m_threads.end();
- for (pos = m_threads.begin(); pos != end; ++pos)
- {
- // Don't clear out threads that aren't going to get a chance to run, rather
- // leave their state for the next time around.
- ThreadSP thread_sp(*pos);
- if (thread_sp->GetResumeState() != eStateSuspended)
- thread_sp->DidResume ();
- }
-}
-
-void
-ThreadList::DidStop ()
-{
- Mutex::Locker locker(GetMutex());
- collection::iterator pos, end = m_threads.end();
- for (pos = m_threads.begin(); pos != end; ++pos)
- {
- // Notify threads that the process just stopped.
- // Note, this currently assumes that all threads in the list
- // stop when the process stops. In the future we will want to support
- // a debugging model where some threads continue to run while others
- // are stopped. We either need to handle that somehow here or
- // create a special thread list containing only threads which will
- // stop in the code that calls this method (currently
- // Process::SetPrivateState).
- ThreadSP thread_sp(*pos);
- if (StateIsRunningState(thread_sp->GetState()))
- thread_sp->DidStop ();
- }
-}
-
-ThreadSP
-ThreadList::GetSelectedThread ()
-{
- Mutex::Locker locker(GetMutex());
- ThreadSP thread_sp = FindThreadByID(m_selected_tid);
- if (!thread_sp.get())
- {
- if (m_threads.size() == 0)
- return thread_sp;
- m_selected_tid = m_threads[0]->GetID();
- thread_sp = m_threads[0];
- }
- return thread_sp;
-}
-
-bool
-ThreadList::SetSelectedThreadByID (lldb::tid_t tid, bool notify)
-{
- Mutex::Locker locker(GetMutex());
- ThreadSP selected_thread_sp(FindThreadByID(tid));
- if (selected_thread_sp)
- {
- m_selected_tid = tid;
- selected_thread_sp->SetDefaultFileAndLineToSelectedFrame();
- }
- else
- m_selected_tid = LLDB_INVALID_THREAD_ID;
-
- if (notify)
- NotifySelectedThreadChanged(m_selected_tid);
-
- return m_selected_tid != LLDB_INVALID_THREAD_ID;
-}
-
-bool
-ThreadList::SetSelectedThreadByIndexID (uint32_t index_id, bool notify)
-{
- Mutex::Locker locker(GetMutex());
- ThreadSP selected_thread_sp (FindThreadByIndexID(index_id));
- if (selected_thread_sp.get())
- {
- m_selected_tid = selected_thread_sp->GetID();
- selected_thread_sp->SetDefaultFileAndLineToSelectedFrame();
- }
- else
- m_selected_tid = LLDB_INVALID_THREAD_ID;
-
- if (notify)
- NotifySelectedThreadChanged(m_selected_tid);
-
- return m_selected_tid != LLDB_INVALID_THREAD_ID;
-}
-
-void
-ThreadList::NotifySelectedThreadChanged (lldb::tid_t tid)
-{
- ThreadSP selected_thread_sp (FindThreadByID(tid));
- if (selected_thread_sp->EventTypeHasListeners(Thread::eBroadcastBitThreadSelected))
- selected_thread_sp->BroadcastEvent(Thread::eBroadcastBitThreadSelected,
- new Thread::ThreadEventData(selected_thread_sp));
-}
-
-void
-ThreadList::Update (ThreadList &rhs)
-{
- if (this != &rhs)
- {
- // Lock both mutexes to make sure neither side changes anyone on us
- // while the assignement occurs
- Mutex::Locker locker(GetMutex());
- m_process = rhs.m_process;
- m_stop_id = rhs.m_stop_id;
- m_threads.swap(rhs.m_threads);
- m_selected_tid = rhs.m_selected_tid;
-
-
- // Now we look for threads that we are done with and
- // make sure to clear them up as much as possible so
- // anyone with a shared pointer will still have a reference,
- // but the thread won't be of much use. Using std::weak_ptr
- // for all backward references (such as a thread to a process)
- // will eventually solve this issue for us, but for now, we
- // need to work around the issue
- collection::iterator rhs_pos, rhs_end = rhs.m_threads.end();
- for (rhs_pos = rhs.m_threads.begin(); rhs_pos != rhs_end; ++rhs_pos)
- {
- const lldb::tid_t tid = (*rhs_pos)->GetID();
- bool thread_is_alive = false;
- const uint32_t num_threads = m_threads.size();
- for (uint32_t idx = 0; idx < num_threads; ++idx)
- {
- if (m_threads[idx]->GetID() == tid)
- {
- thread_is_alive = true;
- break;
- }
- }
- if (!thread_is_alive)
- (*rhs_pos)->DestroyThread();
- }
- }
-}
-
-void
-ThreadList::Flush ()
-{
- Mutex::Locker locker(GetMutex());
- collection::iterator pos, end = m_threads.end();
- for (pos = m_threads.begin(); pos != end; ++pos)
- (*pos)->Flush ();
-}
-
-Mutex &
-ThreadList::GetMutex ()
-{
- return m_process->m_thread_mutex;
-}
-
_______________________________________________
lldb-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/lldb-commits