Rework how the API mutex is acquired when filling out an ExecutionContext from an ExecutionContextRef,
particularly in the SBThread & SBFrame interfaces. Instead of filling the whole context & then getting
the API mutex, we now get only the target, acquire the API mutex from it, then fill out the rest of the
context. This removes a race condition where you get a ThreadSP, then wait on the API mutex while another
command Destroy's the Thread you've just gotten.
Also fixed the ExecutionContextRef::Get*SP calls so they don't return invalid objects.
Also fixed the ExecutionContext::Has*Scope calls so they don't claim to have a scope if the object representing
that scope has been destroyed.
Also fixed a think-o in Thread::IsValid which was causing it to return the opposite of the desired value.
<rdar://problem/11995490>
git-svn-id: https://llvm.org/svn/llvm-project/lldb/trunk@162401 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/source/Target/ExecutionContext.cpp b/source/Target/ExecutionContext.cpp
index 300e879..ae3fc20 100644
--- a/source/Target/ExecutionContext.cpp
+++ b/source/Target/ExecutionContext.cpp
@@ -169,6 +169,40 @@
}
}
+ExecutionContext::ExecutionContext (const ExecutionContextRef *exe_ctx_ref_ptr, Mutex::Locker &locker) :
+ m_target_sp (),
+ m_process_sp (),
+ m_thread_sp (),
+ m_frame_sp ()
+{
+ if (exe_ctx_ref_ptr)
+ {
+ m_target_sp = exe_ctx_ref_ptr->GetTargetSP();
+ if (m_target_sp)
+ {
+ locker.Lock(m_target_sp->GetAPIMutex());
+ m_process_sp = exe_ctx_ref_ptr->GetProcessSP();
+ m_thread_sp = exe_ctx_ref_ptr->GetThreadSP();
+ m_frame_sp = exe_ctx_ref_ptr->GetFrameSP();
+ }
+ }
+}
+
+ExecutionContext::ExecutionContext (const ExecutionContextRef &exe_ctx_ref, Mutex::Locker &locker) :
+ m_target_sp (exe_ctx_ref.GetTargetSP()),
+ m_process_sp (),
+ m_thread_sp (),
+ m_frame_sp ()
+{
+ if (m_target_sp)
+ {
+ locker.Lock(m_target_sp->GetAPIMutex());
+ m_process_sp = exe_ctx_ref.GetProcessSP();
+ m_thread_sp = exe_ctx_ref.GetThreadSP();
+ m_frame_sp = exe_ctx_ref.GetFrameSP();
+ }
+}
+
ExecutionContext::ExecutionContext (ExecutionContextScope *exe_scope_ptr) :
m_target_sp (),
m_process_sp (),
@@ -459,6 +493,32 @@
return !(*this == rhs);
}
+bool
+ExecutionContext::HasTargetScope () const
+{
+ return ((bool) m_target_sp
+ && m_target_sp->IsValid());
+}
+
+bool
+ExecutionContext::HasProcessScope () const
+{
+ return (HasTargetScope()
+ && ((bool) m_process_sp && m_process_sp->IsValid()));
+}
+
+bool
+ExecutionContext::HasThreadScope () const
+{
+ return (HasProcessScope()
+ && ((bool) m_thread_sp && m_thread_sp->IsValid()));
+}
+
+bool
+ExecutionContext::HasFrameScope () const
+{
+ return HasThreadScope() && m_frame_sp;
+}
ExecutionContextRef::ExecutionContextRef() :
m_target_wp (),
@@ -703,11 +763,29 @@
Clear();
}
+lldb::TargetSP
+ExecutionContextRef::GetTargetSP () const
+{
+ lldb::TargetSP target_sp(m_target_wp.lock());
+ if (target_sp && !target_sp->IsValid())
+ target_sp.reset();
+ return target_sp;
+}
+
+lldb::ProcessSP
+ExecutionContextRef::GetProcessSP () const
+{
+ lldb::ProcessSP process_sp(m_process_wp.lock());
+ if (process_sp && !process_sp->IsValid())
+ process_sp.reset();
+ return process_sp;
+}
lldb::ThreadSP
ExecutionContextRef::GetThreadSP () const
{
lldb::ThreadSP thread_sp (m_thread_wp.lock());
+
if (m_tid != LLDB_INVALID_THREAD_ID)
{
// We check if the thread has been destroyed in cases where clients
@@ -716,13 +794,20 @@
if (!thread_sp || !thread_sp->IsValid())
{
lldb::ProcessSP process_sp(GetProcessSP());
- if (process_sp)
+ if (process_sp && process_sp->IsValid())
{
thread_sp = process_sp->GetThreadList().FindThreadByID(m_tid);
m_thread_wp = thread_sp;
}
}
}
+
+ // Check that we aren't about to return an invalid thread sp. We might return a NULL thread_sp,
+ // but don't return an invalid one.
+
+ if (thread_sp && !thread_sp->IsValid())
+ thread_sp.reset();
+
return thread_sp;
}
@@ -738,6 +823,12 @@
frame_sp = thread_sp->GetFrameWithStackID (m_stack_id);
m_frame_wp = frame_sp;
}
+ else
+ {
+ // If the thread that this frame was supposed to belong to is not valid, then
+ // return a NULL frame_sp.
+ frame_sp.reset();
+ }
}
return frame_sp;
}