Fix signal handling for POSIX (only tested on Linux) processes in multi-threaded programs.
Also fix a related issue where if a thread exits after a thread continue, lldb would hang.
git-svn-id: https://llvm.org/svn/llvm-project/lldb/trunk@185944 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/source/Plugins/Process/Linux/ProcessMonitor.cpp b/source/Plugins/Process/Linux/ProcessMonitor.cpp
index 512639c..fe61798 100644
--- a/source/Plugins/Process/Linux/ProcessMonitor.cpp
+++ b/source/Plugins/Process/Linux/ProcessMonitor.cpp
@@ -1236,6 +1236,8 @@
log->Printf ("ProcessMonitor::%s() adding pid = %" PRIu64, __FUNCTION__, pid);
process.GetThreadList().AddThread(inferior);
+ process.AddThreadForInitialStopIfNeeded(pid);
+
// Let our process instance know the thread has stopped.
process.SendMessage(ProcessMessage::Trace(pid));
@@ -1294,7 +1296,6 @@
// Use a map to keep track of the threads which we have attached/need to attach.
Host::TidMap tids_to_attach;
-
if (pid <= 1)
{
args->m_error.SetErrorToGenericError();
@@ -1360,6 +1361,7 @@
log->Printf ("ProcessMonitor::%s() adding tid = %" PRIu64, __FUNCTION__, tid);
process.GetThreadList().AddThread(inferior);
it->second = true;
+ process.AddThreadForInitialStopIfNeeded(tid);
}
}
}
@@ -1513,7 +1515,7 @@
if (!monitor->GetEventMessage(pid, &data))
data = -1;
if (log)
- log->Printf ("ProcessMonitor::%s() received exit event, data = %lx, pid = %" PRIu64, __FUNCTION__, data, pid);
+ log->Printf ("ProcessMonitor::%s() received limbo event, data = %lx, pid = %" PRIu64, __FUNCTION__, data, pid);
message = ProcessMessage::Limbo(pid, (data >> 8));
break;
}
@@ -1711,6 +1713,27 @@
return true;
break;
+ case ProcessMessage::eSignalMessage:
+ if (log)
+ log->Printf ("ProcessMonitor::%s(bp) handling message", __FUNCTION__);
+ if (WSTOPSIG(status) == SIGSTOP)
+ {
+ m_process->AddThreadForInitialStopIfNeeded(tid);
+ thread->SetState(lldb::eStateStopped);
+ }
+ else
+ {
+ m_process->SendMessage(message);
+ // This isn't the stop we were expecting, but the thread is
+ // stopped. SendMessage will handle processing of this event,
+ // but we need to resume here to get the stop we are waiting
+ // for (otherwise the thread will stop again immediately when
+ // we try to resume).
+ if (wait_pid == tid)
+ Resume(wait_pid, eResumeSignalNone);
+ }
+ break;
+
case ProcessMessage::eSignalDeliveredMessage:
// This is the stop we're expecting.
if (wait_pid == tid && WIFSTOPPED(status) && WSTOPSIG(status) == SIGSTOP && info.si_code == SI_TKILL)
@@ -1721,7 +1744,6 @@
return true;
}
// else fall-through
- case ProcessMessage::eSignalMessage:
case ProcessMessage::eBreakpointMessage:
case ProcessMessage::eTraceMessage:
case ProcessMessage::eWatchpointMessage:
diff --git a/source/Plugins/Process/POSIX/ProcessPOSIX.cpp b/source/Plugins/Process/POSIX/ProcessPOSIX.cpp
index 6f25585..e09bfca 100644
--- a/source/Plugins/Process/POSIX/ProcessPOSIX.cpp
+++ b/source/Plugins/Process/POSIX/ProcessPOSIX.cpp
@@ -76,7 +76,8 @@
m_monitor(NULL),
m_module(NULL),
m_message_mutex (Mutex::eMutexTypeRecursive),
- m_exit_now(false)
+ m_exit_now(false),
+ m_seen_initial_stop()
{
// FIXME: Putting this code in the ctor and saving the byte order in a
// member variable is a hack to avoid const qual issues in GetByteOrder.
@@ -412,8 +413,23 @@
m_exit_status = message.GetExitStatus();
SetExitStatus(m_exit_status, NULL);
}
+ else if (!IsAThreadRunning())
+ SetPrivateState(eStateStopped);
break;
+ assert(thread);
+ thread->SetState(eStateStopped);
+ StopAllThreads(message.GetTID());
+ SetPrivateState(eStateStopped);
+ break;
+
+ case ProcessMessage::eSignalMessage:
+ case ProcessMessage::eSignalDeliveredMessage:
+ if (message.GetSignal() == SIGSTOP &&
+ AddThreadForInitialStopIfNeeded(message.GetTID()))
+ return;
+ // Intentional fall-through
+
case ProcessMessage::eBreakpointMessage:
case ProcessMessage::eTraceMessage:
case ProcessMessage::eWatchpointMessage:
@@ -424,24 +440,6 @@
StopAllThreads(message.GetTID());
SetPrivateState(eStateStopped);
break;
-
- case ProcessMessage::eSignalMessage:
- case ProcessMessage::eSignalDeliveredMessage:
- {
- lldb::tid_t tid = message.GetTID();
- lldb::tid_t pid = GetID();
- if (tid == pid) {
- assert(thread);
- thread->SetState(eStateStopped);
- StopAllThreads(message.GetTID());
- SetPrivateState(eStateStopped);
- break;
- } else {
- // FIXME: Ignore any signals generated by children.
- return;
- }
- }
-
}
m_message_queue.push(message);
@@ -453,6 +451,19 @@
// FIXME: Will this work the same way on FreeBSD and Linux?
}
+bool
+ProcessPOSIX::AddThreadForInitialStopIfNeeded(lldb::tid_t stop_tid)
+{
+ bool added_to_set = false;
+ ThreadStopSet::iterator it = m_seen_initial_stop.find(stop_tid);
+ if (it == m_seen_initial_stop.end())
+ {
+ m_seen_initial_stop.insert(stop_tid);
+ added_to_set = true;
+ }
+ return added_to_set;
+}
+
void
ProcessPOSIX::RefreshStateAfterStop()
{
@@ -497,6 +508,7 @@
log->Printf ("ProcessPOSIX::%s() removing thread, tid = %" PRIi64, __FUNCTION__, tid);
ThreadSP thread_sp = m_thread_list.RemoveThreadByID(tid, false);
thread_sp.reset();
+ m_seen_initial_stop.erase(tid);
}
m_message_queue.pop();
@@ -851,3 +863,22 @@
return false;
}
+
+bool
+ProcessPOSIX::IsAThreadRunning()
+{
+ bool is_running = false;
+ uint32_t thread_count = m_thread_list.GetSize(false);
+ for (uint32_t i = 0; i < thread_count; ++i)
+ {
+ POSIXThread *thread = static_cast<POSIXThread*>(
+ m_thread_list.GetThreadAtIndex(i, false).get());
+ StateType thread_state = thread->GetState();
+ if (thread_state == eStateRunning || thread_state == eStateStepping)
+ {
+ is_running = true;
+ break;
+ }
+ }
+ return is_running;
+}
diff --git a/source/Plugins/Process/POSIX/ProcessPOSIX.h b/source/Plugins/Process/POSIX/ProcessPOSIX.h
index 8402aad..a865fe2 100644
--- a/source/Plugins/Process/POSIX/ProcessPOSIX.h
+++ b/source/Plugins/Process/POSIX/ProcessPOSIX.h
@@ -14,6 +14,7 @@
// C++ Includes
#include <queue>
+#include <set>
// Other libraries and framework includes
#include "lldb/Target/Process.h"
@@ -157,6 +158,11 @@
virtual void
StopAllThreads(lldb::tid_t stop_tid);
+ /// Adds the thread to the list of threads for which we have received the initial stopping signal.
+ /// The \p stop_tid paramter indicates the thread which the stop happened for.
+ bool
+ AddThreadForInitialStopIfNeeded(lldb::tid_t stop_tid);
+
protected:
/// Target byte order.
lldb::ByteOrder m_byte_order;
@@ -183,8 +189,16 @@
/// Returns true if the process is stopped.
bool IsStopped();
+ /// Returns true if at least one running is currently running
+ bool IsAThreadRunning();
+
typedef std::map<lldb::addr_t, lldb::addr_t> MMapMap;
MMapMap m_addr_to_mmap_size;
+
+ typedef std::set<lldb::tid_t> ThreadStopSet;
+ /// Every thread begins with a stop signal. This keeps track
+ /// of the threads for which we have received the stop signal.
+ ThreadStopSet m_seen_initial_stop;
};
#endif // liblldb_MacOSXProcess_H_