summaryrefslogtreecommitdiffstats
path: root/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp')
-rw-r--r--lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp189
1 files changed, 93 insertions, 96 deletions
diff --git a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
index e529867e083..5def42efe78 100644
--- a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
+++ b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
@@ -1069,7 +1069,6 @@ namespace
{
PTRACE(PTRACE_DETACH, m_tid, nullptr, 0, 0, m_error);
}
-
} // end of anonymous namespace
// Simple helper function to ensure flags are enabled on the given file
@@ -1105,7 +1104,8 @@ EnsureFDFlags(int fd, int flags)
// pipe, and the completion of the operation is signalled over the semaphore.
// - thread exit event: this is signaled from the Monitor destructor by closing the write end
// of the command pipe.
-class NativeProcessLinux::Monitor {
+class NativeProcessLinux::Monitor
+{
private:
// The initial monitor operation (launch or attach). It returns a inferior process id.
std::unique_ptr<InitialOperation> m_initial_operation_up;
@@ -1124,7 +1124,11 @@ private:
sem_t m_operation_sem;
Error m_operation_error;
- static constexpr char operation_command = 'o';
+ unsigned m_operation_nesting_level = 0;
+
+ static constexpr char operation_command = 'o';
+ static constexpr char begin_block_command = '{';
+ static constexpr char end_block_command = '}';
void
HandleSignals();
@@ -1143,7 +1147,22 @@ private:
RunMonitor(void *arg);
Error
- WaitForOperation();
+ WaitForAck();
+
+ void
+ BeginOperationBlock()
+ {
+ write(m_pipefd[WRITE], &begin_block_command, sizeof operation_command);
+ WaitForAck();
+ }
+
+ void
+ EndOperationBlock()
+ {
+ write(m_pipefd[WRITE], &end_block_command, sizeof operation_command);
+ WaitForAck();
+ }
+
public:
Monitor(const InitialOperation &initial_operation,
NativeProcessLinux *native_process)
@@ -1159,9 +1178,26 @@ public:
Initialize();
void
+ Terminate();
+
+ void
DoOperation(Operation *op);
+
+ class ScopedOperationLock {
+ Monitor &m_monitor;
+
+ public:
+ ScopedOperationLock(Monitor &monitor)
+ : m_monitor(monitor)
+ { m_monitor.BeginOperationBlock(); }
+
+ ~ScopedOperationLock()
+ { m_monitor.EndOperationBlock(); }
+ };
};
constexpr char NativeProcessLinux::Monitor::operation_command;
+constexpr char NativeProcessLinux::Monitor::begin_block_command;
+constexpr char NativeProcessLinux::Monitor::end_block_command;
Error
NativeProcessLinux::Monitor::Initialize()
@@ -1198,7 +1234,7 @@ NativeProcessLinux::Monitor::Initialize()
return Error("Failed to create monitor thread for NativeProcessLinux.");
// Wait for initial operation to complete.
- return WaitForOperation();
+ return WaitForAck();
}
void
@@ -1218,15 +1254,24 @@ NativeProcessLinux::Monitor::DoOperation(Operation *op)
// notify the thread that an operation is ready to be processed
write(m_pipefd[WRITE], &operation_command, sizeof operation_command);
- WaitForOperation();
+ WaitForAck();
}
-NativeProcessLinux::Monitor::~Monitor()
+void
+NativeProcessLinux::Monitor::Terminate()
{
if (m_pipefd[WRITE] >= 0)
+ {
close(m_pipefd[WRITE]);
+ m_pipefd[WRITE] = -1;
+ }
if (m_thread.IsJoinable())
m_thread.Join(nullptr);
+}
+
+NativeProcessLinux::Monitor::~Monitor()
+{
+ Terminate();
if (m_pipefd[READ] >= 0)
close(m_pipefd[READ]);
if (m_signal_fd >= 0)
@@ -1356,6 +1401,7 @@ NativeProcessLinux::Monitor::HandleCommands()
{
if (log)
log->Printf("NativeProcessLinux::Monitor::%s exit command received, exiting...", __FUNCTION__);
+ assert(m_operation_nesting_level == 0 && "Unbalanced begin/end block commands detected");
return true; // We are done.
}
@@ -1363,15 +1409,22 @@ NativeProcessLinux::Monitor::HandleCommands()
{
case operation_command:
m_operation->Execute(m_native_process);
-
- // notify calling thread that operation is complete
- sem_post(&m_operation_sem);
+ break;
+ case begin_block_command:
+ ++m_operation_nesting_level;
+ break;
+ case end_block_command:
+ assert(m_operation_nesting_level > 0);
+ --m_operation_nesting_level;
break;
default:
if (log)
log->Printf("NativeProcessLinux::Monitor::%s received unknown command '%c'",
__FUNCTION__, command);
}
+
+ // notify calling thread that the command has been processed
+ sem_post(&m_operation_sem);
}
}
@@ -1387,7 +1440,10 @@ NativeProcessLinux::Monitor::MainLoop()
{
fd_set fds;
FD_ZERO(&fds);
- FD_SET(m_signal_fd, &fds);
+ // Only process waitpid events if we are outside of an operation block. Any pending
+ // events will be processed after we leave the block.
+ if (m_operation_nesting_level == 0)
+ FD_SET(m_signal_fd, &fds);
FD_SET(m_pipefd[READ], &fds);
int max_fd = std::max(m_signal_fd, m_pipefd[READ]) + 1;
@@ -1416,7 +1472,7 @@ NativeProcessLinux::Monitor::MainLoop()
}
Error
-NativeProcessLinux::Monitor::WaitForOperation()
+NativeProcessLinux::Monitor::WaitForAck()
{
Error error;
while (sem_wait(&m_operation_sem) != 0)
@@ -1617,8 +1673,7 @@ NativeProcessLinux::NativeProcessLinux () :
m_supports_mem_region (eLazyBoolCalculate),
m_mem_region_cache (),
m_mem_region_cache_mutex (),
- m_coordinator_up (new ThreadStateCoordinator (GetThreadLoggerFunction ())),
- m_coordinator_thread ()
+ m_coordinator_up (new ThreadStateCoordinator (GetThreadLoggerFunction ()))
{
}
@@ -1652,10 +1707,6 @@ NativeProcessLinux::LaunchInferior (
StartMonitorThread ([&] (Error &e) { return Launch(args.get(), e); }, error);
if (!error.Success ())
return;
-
- error = StartCoordinatorThread ();
- if (!error.Success ())
- return;
}
void
@@ -1705,16 +1756,12 @@ NativeProcessLinux::AttachToInferior (lldb::pid_t pid, Error &error)
StartMonitorThread ([=] (Error &e) { return Attach(pid, e); }, error);
if (!error.Success ())
return;
-
- error = StartCoordinatorThread ();
- if (!error.Success ())
- return;
}
void
NativeProcessLinux::Terminate ()
{
- StopMonitor();
+ m_monitor_up->Terminate();
}
::pid_t
@@ -2997,6 +3044,7 @@ NativeProcessLinux::Resume (const ResumeActionList &resume_actions)
bool stepping = false;
bool software_single_step = !SupportHardwareSingleStepping();
+ Monitor::ScopedOperationLock monitor_lock(*m_monitor_up);
Mutex::Locker locker (m_threads_mutex);
if (software_single_step)
@@ -3144,7 +3192,7 @@ NativeProcessLinux::Detach ()
error = Detach (GetID ());
// Stop monitoring the inferior.
- StopMonitor ();
+ m_monitor_up->Terminate();
// No error.
return error;
@@ -3179,6 +3227,7 @@ NativeProcessLinux::Interrupt ()
if (log)
log->Printf ("NativeProcessLinux::%s selecting running thread for interrupt target", __FUNCTION__);
+ Monitor::ScopedOperationLock monitor_lock(*m_monitor_up);
Mutex::Locker locker (m_threads_mutex);
for (auto thread_sp : m_threads)
@@ -3233,6 +3282,7 @@ NativeProcessLinux::Interrupt ()
// Tell the process delegate that the process is in a stopped state.
SetState (StateType::eStateStopped, true);
});
+
return Error();
}
@@ -3834,7 +3884,25 @@ NativeProcessLinux::GetCrashReasonForSIGBUS(const siginfo_t *info)
#endif
Error
-NativeProcessLinux::ReadMemory(lldb::addr_t addr, void *buf, size_t size, size_t &bytes_read)
+NativeProcessLinux::SetWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags, bool hardware)
+{
+ // The base SetWatchpoint will end up executing monitor operations. Let's lock the monitor
+ // for it.
+ Monitor::ScopedOperationLock monitor_lock(*m_monitor_up);
+ return NativeProcessProtocol::SetWatchpoint(addr, size, watch_flags, hardware);
+}
+
+Error
+NativeProcessLinux::RemoveWatchpoint (lldb::addr_t addr)
+{
+ // The base RemoveWatchpoint will end up executing monitor operations. Let's lock the monitor
+ // for it.
+ Monitor::ScopedOperationLock monitor_lock(*m_monitor_up);
+ return NativeProcessProtocol::RemoveWatchpoint(addr);
+}
+
+Error
+NativeProcessLinux::ReadMemory (lldb::addr_t addr, void *buf, lldb::addr_t size, lldb::addr_t &bytes_read)
{
ReadOperation op(addr, buf, size, bytes_read);
m_monitor_up->DoOperation(&op);
@@ -3997,77 +4065,6 @@ NativeProcessLinux::StartMonitorThread(const InitialOperation &initial_operation
}
}
-void
-NativeProcessLinux::StopMonitor()
-{
- StopCoordinatorThread ();
- m_monitor_up.reset();
-}
-
-Error
-NativeProcessLinux::StartCoordinatorThread ()
-{
- Error error;
- static const char *g_thread_name = "lldb.process.linux.ts_coordinator";
- Log *const log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
-
- // Skip if thread is already running
- if (m_coordinator_thread.IsJoinable())
- {
- error.SetErrorString ("ThreadStateCoordinator's run loop is already running");
- if (log)
- log->Printf ("NativeProcessLinux::%s %s", __FUNCTION__, error.AsCString ());
- return error;
- }
-
- // Enable verbose logging if lldb thread logging is enabled.
- m_coordinator_up->LogEnableEventProcessing (log != nullptr);
-
- if (log)
- log->Printf ("NativeProcessLinux::%s launching ThreadStateCoordinator thread for pid %" PRIu64, __FUNCTION__, GetID ());
- m_coordinator_thread = ThreadLauncher::LaunchThread(g_thread_name, CoordinatorThread, this, &error);
- return error;
-}
-
-void *
-NativeProcessLinux::CoordinatorThread (void *arg)
-{
- Log *const log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
-
- NativeProcessLinux *const process = static_cast<NativeProcessLinux*> (arg);
- assert (process && "null process passed to CoordinatorThread");
- if (!process)
- {
- if (log)
- log->Printf ("NativeProcessLinux::%s null process, exiting ThreadStateCoordinator processing loop", __FUNCTION__);
- return nullptr;
- }
-
- // Run the thread state coordinator loop until it is done. This call uses
- // efficient waiting for an event to be ready.
- while (process->m_coordinator_up->ProcessNextEvent () == ThreadStateCoordinator::eventLoopResultContinue)
- {
- }
-
- if (log)
- log->Printf ("NativeProcessLinux::%s pid %" PRIu64 " exiting ThreadStateCoordinator processing loop due to coordinator indicating completion", __FUNCTION__, process->GetID ());
-
- return nullptr;
-}
-
-void
-NativeProcessLinux::StopCoordinatorThread()
-{
- Log *const log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
- if (log)
- log->Printf ("NativeProcessLinux::%s requesting ThreadStateCoordinator stop for pid %" PRIu64, __FUNCTION__, GetID ());
-
- // Tell the coordinator we're done. This will cause the coordinator
- // run loop thread to exit when the processing queue hits this message.
- m_coordinator_up->StopCoordinator ();
- m_coordinator_thread.Join (nullptr);
-}
-
bool
NativeProcessLinux::HasThreadNoLock (lldb::tid_t thread_id)
{
OpenPOWER on IntegriCloud