Don't hold the ThreadList lock over calls to the GetStatus (Process or Thread) calls
or the lower levels of the Process won't be able to restart. <rdar://problem/16244835> llvm-svn: 203233
This commit is contained in:
parent
a04ef756d4
commit
4a65fb1f25
|
@ -2864,66 +2864,71 @@ Debugger::HandleProcessEvent (const EventSP &event_sp)
|
|||
}
|
||||
else
|
||||
{
|
||||
// Lock the thread list so it doesn't change on us
|
||||
ThreadList &thread_list = process_sp->GetThreadList();
|
||||
Mutex::Locker locker (thread_list.GetMutex());
|
||||
|
||||
ThreadSP curr_thread (thread_list.GetSelectedThread());
|
||||
ThreadSP thread;
|
||||
StopReason curr_thread_stop_reason = eStopReasonInvalid;
|
||||
if (curr_thread)
|
||||
curr_thread_stop_reason = curr_thread->GetStopReason();
|
||||
if (!curr_thread ||
|
||||
!curr_thread->IsValid() ||
|
||||
curr_thread_stop_reason == eStopReasonInvalid ||
|
||||
curr_thread_stop_reason == eStopReasonNone)
|
||||
// Lock the thread list so it doesn't change on us, this is the scope for the locker:
|
||||
{
|
||||
// Prefer a thread that has just completed its plan over another thread as current thread.
|
||||
ThreadSP plan_thread;
|
||||
ThreadSP other_thread;
|
||||
const size_t num_threads = thread_list.GetSize();
|
||||
size_t i;
|
||||
for (i = 0; i < num_threads; ++i)
|
||||
ThreadList &thread_list = process_sp->GetThreadList();
|
||||
Mutex::Locker locker (thread_list.GetMutex());
|
||||
|
||||
ThreadSP curr_thread (thread_list.GetSelectedThread());
|
||||
ThreadSP thread;
|
||||
StopReason curr_thread_stop_reason = eStopReasonInvalid;
|
||||
if (curr_thread)
|
||||
curr_thread_stop_reason = curr_thread->GetStopReason();
|
||||
if (!curr_thread ||
|
||||
!curr_thread->IsValid() ||
|
||||
curr_thread_stop_reason == eStopReasonInvalid ||
|
||||
curr_thread_stop_reason == eStopReasonNone)
|
||||
{
|
||||
thread = thread_list.GetThreadAtIndex(i);
|
||||
StopReason thread_stop_reason = thread->GetStopReason();
|
||||
switch (thread_stop_reason)
|
||||
// Prefer a thread that has just completed its plan over another thread as current thread.
|
||||
ThreadSP plan_thread;
|
||||
ThreadSP other_thread;
|
||||
const size_t num_threads = thread_list.GetSize();
|
||||
size_t i;
|
||||
for (i = 0; i < num_threads; ++i)
|
||||
{
|
||||
case eStopReasonInvalid:
|
||||
case eStopReasonNone:
|
||||
break;
|
||||
|
||||
case eStopReasonTrace:
|
||||
case eStopReasonBreakpoint:
|
||||
case eStopReasonWatchpoint:
|
||||
case eStopReasonSignal:
|
||||
case eStopReasonException:
|
||||
case eStopReasonExec:
|
||||
case eStopReasonThreadExiting:
|
||||
if (!other_thread)
|
||||
other_thread = thread;
|
||||
break;
|
||||
case eStopReasonPlanComplete:
|
||||
if (!plan_thread)
|
||||
plan_thread = thread;
|
||||
break;
|
||||
thread = thread_list.GetThreadAtIndex(i);
|
||||
StopReason thread_stop_reason = thread->GetStopReason();
|
||||
switch (thread_stop_reason)
|
||||
{
|
||||
case eStopReasonInvalid:
|
||||
case eStopReasonNone:
|
||||
break;
|
||||
|
||||
case eStopReasonTrace:
|
||||
case eStopReasonBreakpoint:
|
||||
case eStopReasonWatchpoint:
|
||||
case eStopReasonSignal:
|
||||
case eStopReasonException:
|
||||
case eStopReasonExec:
|
||||
case eStopReasonThreadExiting:
|
||||
if (!other_thread)
|
||||
other_thread = thread;
|
||||
break;
|
||||
case eStopReasonPlanComplete:
|
||||
if (!plan_thread)
|
||||
plan_thread = thread;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (plan_thread)
|
||||
thread_list.SetSelectedThreadByID (plan_thread->GetID());
|
||||
else if (other_thread)
|
||||
thread_list.SetSelectedThreadByID (other_thread->GetID());
|
||||
else
|
||||
{
|
||||
if (curr_thread && curr_thread->IsValid())
|
||||
thread = curr_thread;
|
||||
else
|
||||
thread = thread_list.GetThreadAtIndex(0);
|
||||
|
||||
if (thread)
|
||||
thread_list.SetSelectedThreadByID (thread->GetID());
|
||||
}
|
||||
}
|
||||
if (plan_thread)
|
||||
thread_list.SetSelectedThreadByID (plan_thread->GetID());
|
||||
else if (other_thread)
|
||||
thread_list.SetSelectedThreadByID (other_thread->GetID());
|
||||
else
|
||||
{
|
||||
if (curr_thread && curr_thread->IsValid())
|
||||
thread = curr_thread;
|
||||
else
|
||||
thread = thread_list.GetThreadAtIndex(0);
|
||||
|
||||
if (thread)
|
||||
thread_list.SetSelectedThreadByID (thread->GetID());
|
||||
}
|
||||
}
|
||||
// Drop the ThreadList mutex by here, since GetThreadStatus below might have to run code,
|
||||
// e.g. for Data formatters, and if we hold the ThreadList mutex, then the process is going to
|
||||
// have a hard time restarting the process.
|
||||
|
||||
if (GetTargetList().GetSelectedTarget().get() == &process_sp->GetTarget())
|
||||
{
|
||||
|
|
|
@ -5897,25 +5897,47 @@ Process::GetThreadStatus (Stream &strm,
|
|||
{
|
||||
size_t num_thread_infos_dumped = 0;
|
||||
|
||||
Mutex::Locker locker (GetThreadList().GetMutex());
|
||||
const size_t num_threads = GetThreadList().GetSize();
|
||||
// You can't hold the thread list lock while calling Thread::GetStatus. That very well might run code (e.g. if we need it
|
||||
// to get return values or arguments.) For that to work the process has to be able to acquire it. So instead copy the thread
|
||||
// ID's, and look them up one by one:
|
||||
|
||||
uint32_t num_threads;
|
||||
std::vector<uint32_t> thread_index_array;
|
||||
//Scope for thread list locker;
|
||||
{
|
||||
Mutex::Locker locker (GetThreadList().GetMutex());
|
||||
ThreadList &curr_thread_list = GetThreadList();
|
||||
num_threads = curr_thread_list.GetSize();
|
||||
uint32_t idx;
|
||||
thread_index_array.resize(num_threads);
|
||||
for (idx = 0; idx < num_threads; ++idx)
|
||||
thread_index_array[idx] = curr_thread_list.GetThreadAtIndex(idx)->GetID();
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < num_threads; i++)
|
||||
{
|
||||
Thread *thread = GetThreadList().GetThreadAtIndex(i).get();
|
||||
if (thread)
|
||||
ThreadSP thread_sp(GetThreadList().FindThreadByID(thread_index_array[i]));
|
||||
if (thread_sp)
|
||||
{
|
||||
if (only_threads_with_stop_reason)
|
||||
{
|
||||
StopInfoSP stop_info_sp = thread->GetStopInfo();
|
||||
StopInfoSP stop_info_sp = thread_sp->GetStopInfo();
|
||||
if (stop_info_sp.get() == NULL || !stop_info_sp->IsValid())
|
||||
continue;
|
||||
}
|
||||
thread->GetStatus (strm,
|
||||
thread_sp->GetStatus (strm,
|
||||
start_frame,
|
||||
num_frames,
|
||||
num_frames_with_source);
|
||||
++num_thread_infos_dumped;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS));
|
||||
if (log)
|
||||
log->Printf("Process::GetThreadStatus - thread 0x" PRIu64 " vanished while running Thread::GetStatus.");
|
||||
|
||||
}
|
||||
}
|
||||
return num_thread_infos_dumped;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue