[Lldb-commits] [lldb] r235304 - NativeProcessLinux: Merge operation and monitor threads
Pavel Labath
labath at google.com
Mon Apr 20 06:53:49 PDT 2015
Author: labath
Date: Mon Apr 20 08:53:49 2015
New Revision: 235304
URL: http://llvm.org/viewvc/llvm-project?rev=235304&view=rev
Log:
NativeProcessLinux: Merge operation and monitor threads
Summary:
This commit moves the functionality of the operation thread into the new monitor thread. This is
required to avoid a kernel race between the two threads and I believe it actually makes the code
cleaner.
Test Plan: Ran the test suite a couple of times, no regressions.
Reviewers: ovyalov, tberghammer, vharron
Subscribers: tberghammer, lldb-commits
Differential Revision: http://reviews.llvm.org/D9080
Modified:
lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp
lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.h
lldb/trunk/test/functionalities/thread/concurrent_events/TestConcurrentEvents.py
Modified: lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp?rev=235304&r1=235303&r2=235304&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp Mon Apr 20 08:53:49 2015
@@ -146,8 +146,6 @@ using namespace llvm;
// Private bits we only need internally.
namespace
{
- static void * const EXIT_OPERATION = nullptr;
-
const UnixSignals&
GetUnixSignals ()
{
@@ -1074,16 +1072,60 @@ namespace
} // end of anonymous namespace
+// Simple helper function to ensure flags are enabled on the given file
+// descriptor.
+static Error
+EnsureFDFlags(int fd, int flags)
+{
+ Error error;
+
+ int status = fcntl(fd, F_GETFL);
+ if (status == -1)
+ {
+ error.SetErrorToErrno();
+ return error;
+ }
+
+ if (fcntl(fd, F_SETFL, status | flags) == -1)
+ {
+ error.SetErrorToErrno();
+ return error;
+ }
+
+ return error;
+}
+
+// This class encapsulates the privileged thread which performs all ptrace and wait operations on
+// the inferior. The thread consists of a main loop which waits for events and processes them
+// - SIGCHLD (delivered over a signalfd file descriptor): These signals notify us of events in
+// the inferior process. Upon receiving this signal we do a waitpid to get more information
+// and dispatch to NativeProcessLinux::MonitorCallback.
+// - requests for ptrace operations: These initiated via the DoOperation method, which funnels
+// them to the Monitor thread via m_operation member. The Monitor thread is signaled over a
+// 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 {
private:
- ::pid_t m_child_pid;
- NativeProcessLinux *m_native_process;
+ // The initial monitor operation (launch or attach). It returns a inferior process id.
+ std::unique_ptr<InitialOperation> m_initial_operation_up;
+
+ ::pid_t m_child_pid = -1;
+ NativeProcessLinux * m_native_process;
enum { READ, WRITE };
int m_pipefd[2] = {-1, -1};
int m_signal_fd = -1;
HostThread m_thread;
+ // current operation which must be executed on the priviliged thread
+ Mutex m_operation_mutex;
+ Operation *m_operation = nullptr;
+ sem_t m_operation_sem;
+ Error m_operation_error;
+
+ static constexpr char operation_command = 'o';
+
void
HandleSignals();
@@ -1100,17 +1142,26 @@ private:
static void *
RunMonitor(void *arg);
+ Error
+ WaitForOperation();
public:
- // Takes ownership of command_fd.
- Monitor(::pid_t child_pid, NativeProcessLinux *native_process)
- : m_child_pid(-getpgid(child_pid)), m_native_process(native_process)
- {}
+ Monitor(const InitialOperation &initial_operation,
+ NativeProcessLinux *native_process)
+ : m_initial_operation_up(new InitialOperation(initial_operation)),
+ m_native_process(native_process)
+ {
+ sem_init(&m_operation_sem, 0, 0);
+ }
~Monitor();
Error
Initialize();
+
+ void
+ DoOperation(Operation *op);
};
+constexpr char NativeProcessLinux::Monitor::operation_command;
Error
NativeProcessLinux::Monitor::Initialize()
@@ -1137,11 +1188,37 @@ NativeProcessLinux::Monitor::Initialize(
return error;
}
- m_thread = ThreadLauncher::LaunchThread("monitor", Monitor::RunMonitor, this, nullptr);
+ if ((error = EnsureFDFlags(m_pipefd[READ], O_NONBLOCK)).Fail()) {
+ return error;
+ }
+
+ static const char g_thread_name[] = "lldb.process.nativelinux.monitor";
+ m_thread = ThreadLauncher::LaunchThread(g_thread_name, Monitor::RunMonitor, this, nullptr);
if (!m_thread.IsJoinable())
return Error("Failed to create monitor thread for NativeProcessLinux.");
- return error;
+ // Wait for initial operation to complete.
+ return WaitForOperation();
+}
+
+void
+NativeProcessLinux::Monitor::DoOperation(Operation *op)
+{
+ if (m_thread.EqualsThread(pthread_self())) {
+ // If we're on the Monitor thread, we can simply execute the operation.
+ op->Execute(m_native_process);
+ return;
+ }
+
+ // Otherwise we need to pass the operation to the Monitor thread so it can handle it.
+ Mutex::Locker lock(m_operation_mutex);
+
+ m_operation = op;
+
+ // notify the thread that an operation is ready to be processed
+ write(m_pipefd[WRITE], &operation_command, sizeof operation_command);
+
+ WaitForOperation();
}
NativeProcessLinux::Monitor::~Monitor()
@@ -1154,6 +1231,7 @@ NativeProcessLinux::Monitor::~Monitor()
close(m_pipefd[READ]);
if (m_signal_fd >= 0)
close(m_signal_fd);
+ sem_destroy(&m_operation_sem);
}
void
@@ -1280,15 +1358,31 @@ NativeProcessLinux::Monitor::HandleComma
log->Printf("NativeProcessLinux::Monitor::%s exit command received, exiting...", __FUNCTION__);
return true; // We are done.
}
- if (log)
- log->Printf("NativeProcessLinux::Monitor::%s received unknown command '%c'",
- __FUNCTION__, command);
+
+ switch (command)
+ {
+ case operation_command:
+ m_operation->Execute(m_native_process);
+
+ // notify calling thread that operation is complete
+ sem_post(&m_operation_sem);
+ break;
+ default:
+ if (log)
+ log->Printf("NativeProcessLinux::Monitor::%s received unknown command '%c'",
+ __FUNCTION__, command);
+ }
}
}
void
NativeProcessLinux::Monitor::MainLoop()
{
+ ::pid_t child_pid = (*m_initial_operation_up)(m_operation_error);
+ m_initial_operation_up.reset();
+ m_child_pid = -getpgid(child_pid),
+ sem_post(&m_operation_sem);
+
while (true)
{
fd_set fds;
@@ -1321,49 +1415,31 @@ NativeProcessLinux::Monitor::MainLoop()
}
}
-void *
-NativeProcessLinux::Monitor::RunMonitor(void *arg)
-{
- static_cast<Monitor *>(arg)->MainLoop();
- return nullptr;
-}
-
-
-// Simple helper function to ensure flags are enabled on the given file
-// descriptor.
-static bool
-EnsureFDFlags(int fd, int flags, Error &error)
+Error
+NativeProcessLinux::Monitor::WaitForOperation()
{
- int status;
-
- if ((status = fcntl(fd, F_GETFL)) == -1)
+ Error error;
+ while (sem_wait(&m_operation_sem) != 0)
{
- error.SetErrorToErrno();
- return false;
- }
+ if (errno == EINTR)
+ continue;
- if (fcntl(fd, F_SETFL, status | flags) == -1)
- {
error.SetErrorToErrno();
- return false;
+ return error;
}
- return true;
+ return m_operation_error;
}
-NativeProcessLinux::OperationArgs::OperationArgs(NativeProcessLinux *monitor)
- : m_monitor(monitor)
+void *
+NativeProcessLinux::Monitor::RunMonitor(void *arg)
{
- sem_init(&m_semaphore, 0, 0);
+ static_cast<Monitor *>(arg)->MainLoop();
+ return nullptr;
}
-NativeProcessLinux::OperationArgs::~OperationArgs()
-{
- sem_destroy(&m_semaphore);
-}
-NativeProcessLinux::LaunchArgs::LaunchArgs(NativeProcessLinux *monitor,
- Module *module,
+NativeProcessLinux::LaunchArgs::LaunchArgs(Module *module,
char const **argv,
char const **envp,
const std::string &stdin_path,
@@ -1371,8 +1447,7 @@ NativeProcessLinux::LaunchArgs::LaunchAr
const std::string &stderr_path,
const char *working_dir,
const ProcessLaunchInfo &launch_info)
- : OperationArgs(monitor),
- m_module(module),
+ : m_module(module),
m_argv(argv),
m_envp(envp),
m_stdin_path(stdin_path),
@@ -1386,13 +1461,6 @@ NativeProcessLinux::LaunchArgs::LaunchAr
NativeProcessLinux::LaunchArgs::~LaunchArgs()
{ }
-NativeProcessLinux::AttachArgs::AttachArgs(NativeProcessLinux *monitor,
- lldb::pid_t pid)
- : OperationArgs(monitor), m_pid(pid) { }
-
-NativeProcessLinux::AttachArgs::~AttachArgs()
-{ }
-
// -----------------------------------------------------------------------------
// Public Static Methods
// -----------------------------------------------------------------------------
@@ -1546,11 +1614,6 @@ NativeProcessLinux::AttachToProcess (
NativeProcessLinux::NativeProcessLinux () :
NativeProcessProtocol (LLDB_INVALID_PROCESS_ID),
m_arch (),
- m_operation_thread (),
- m_operation (nullptr),
- m_operation_mutex (),
- m_operation_pending (),
- m_operation_done (),
m_supports_mem_region (eLazyBoolCalculate),
m_mem_region_cache (),
m_mem_region_cache_mutex (),
@@ -1560,17 +1623,9 @@ NativeProcessLinux::NativeProcessLinux (
}
//------------------------------------------------------------------------------
-/// The basic design of the NativeProcessLinux is built around two threads.
-///
-/// One thread (@see SignalThread) simply blocks on a call to waitpid() looking
-/// for changes in the debugee state. When a change is detected a
-/// ProcessMessage is sent to the associated ProcessLinux instance. This thread
-/// "drives" state changes in the debugger.
-///
-/// The second thread (@see OperationThread) is responsible for two things 1)
-/// launching or attaching to the inferior process, and then 2) servicing
-/// operations such as register reads/writes, stepping, etc. See the comments
-/// on the Operation class for more info as to why this is needed.
+// NativeProcessLinux spawns a new thread which performs all operations on the inferior process.
+// Refer to Monitor and Operation classes to see why this is necessary.
+//------------------------------------------------------------------------------
void
NativeProcessLinux::LaunchInferior (
Module *module,
@@ -1590,45 +1645,17 @@ NativeProcessLinux::LaunchInferior (
std::unique_ptr<LaunchArgs> args(
new LaunchArgs(
- this, module, argv, envp,
+ module, argv, envp,
stdin_path, stdout_path, stderr_path,
working_dir, launch_info));
- sem_init (&m_operation_pending, 0, 0);
- sem_init (&m_operation_done, 0, 0);
-
- StartLaunchOpThread (args.get(), error);
+ StartMonitorThread ([&] (Error &e) { return Launch(args.get(), e); }, error);
if (!error.Success ())
return;
error = StartCoordinatorThread ();
if (!error.Success ())
return;
-
-WAIT_AGAIN:
- // Wait for the operation thread to initialize.
- if (sem_wait(&args->m_semaphore))
- {
- if (errno == EINTR)
- goto WAIT_AGAIN;
- else
- {
- error.SetErrorToErrno();
- return;
- }
- }
-
- // Check that the launch was a success.
- if (!args->m_error.Success())
- {
- StopOpThread();
- StopCoordinatorThread ();
- error = args->m_error;
- return;
- }
-
- // Finally, start monitoring the child process for change in state.
- StartMonitorThread(error);
}
void
@@ -1675,43 +1702,13 @@ NativeProcessLinux::AttachToInferior (ll
m_pid = pid;
SetState(eStateAttaching);
- sem_init (&m_operation_pending, 0, 0);
- sem_init (&m_operation_done, 0, 0);
-
- std::unique_ptr<AttachArgs> args (new AttachArgs (this, pid));
-
- StartAttachOpThread(args.get (), error);
+ StartMonitorThread ([=] (Error &e) { return Attach(pid, e); }, error);
if (!error.Success ())
return;
error = StartCoordinatorThread ();
if (!error.Success ())
return;
-
-WAIT_AGAIN:
- // Wait for the operation thread to initialize.
- if (sem_wait (&args->m_semaphore))
- {
- if (errno == EINTR)
- goto WAIT_AGAIN;
- else
- {
- error.SetErrorToErrno ();
- return;
- }
- }
-
- // Check that the attach was a success.
- if (!args->m_error.Success ())
- {
- StopOpThread ();
- StopCoordinatorThread ();
- error = args->m_error;
- return;
- }
-
- // Finally, start monitoring the child process for change in state.
- StartMonitorThread(error);
}
void
@@ -1720,43 +1717,10 @@ NativeProcessLinux::Terminate ()
StopMonitor();
}
-//------------------------------------------------------------------------------
-// Thread setup and tear down.
-
-void
-NativeProcessLinux::StartLaunchOpThread(LaunchArgs *args, Error &error)
-{
- static const char *g_thread_name = "lldb.process.nativelinux.operation";
-
- if (m_operation_thread.IsJoinable())
- return;
-
- m_operation_thread = ThreadLauncher::LaunchThread(g_thread_name, LaunchOpThread, args, &error);
-}
-
-void *
-NativeProcessLinux::LaunchOpThread(void *arg)
-{
- LaunchArgs *args = static_cast<LaunchArgs*>(arg);
-
- if (!Launch(args)) {
- sem_post(&args->m_semaphore);
- return NULL;
- }
-
- ServeOperation(args);
- return NULL;
-}
-
-bool
-NativeProcessLinux::Launch(LaunchArgs *args)
+::pid_t
+NativeProcessLinux::Launch(LaunchArgs *args, Error &error)
{
assert (args && "null args");
- if (!args)
- return false;
-
- NativeProcessLinux *monitor = args->m_monitor;
- assert (monitor && "monitor is NULL");
const char **argv = args->m_argv;
const char **envp = args->m_envp;
@@ -1776,9 +1740,9 @@ NativeProcessLinux::Launch(LaunchArgs *a
if ((pid = terminal.Fork(err_str, err_len)) == static_cast<lldb::pid_t> (-1))
{
- args->m_error.SetErrorToGenericError();
- args->m_error.SetErrorString("Process fork failed.");
- return false;
+ error.SetErrorToGenericError();
+ error.SetErrorStringWithFormat("Process fork failed: %s", err_str);
+ return -1;
}
// Recognized child exit status codes.
@@ -1799,8 +1763,8 @@ NativeProcessLinux::Launch(LaunchArgs *a
// send log info to parent re: launch status, in place of the log lines removed here.
// Start tracing this child that is about to exec.
- PTRACE(PTRACE_TRACEME, 0, nullptr, nullptr, 0, args->m_error);
- if (args->m_error.Fail())
+ PTRACE(PTRACE_TRACEME, 0, nullptr, nullptr, 0, error);
+ if (error.Fail())
exit(ePtraceFailed);
// terminal has already dupped the tty descriptors to stdin/out/err.
@@ -1878,46 +1842,46 @@ NativeProcessLinux::Launch(LaunchArgs *a
int status;
if ((wpid = waitpid(pid, &status, 0)) < 0)
{
- args->m_error.SetErrorToErrno();
-
+ error.SetErrorToErrno();
if (log)
- log->Printf ("NativeProcessLinux::%s waitpid for inferior failed with %s", __FUNCTION__, args->m_error.AsCString ());
+ log->Printf ("NativeProcessLinux::%s waitpid for inferior failed with %s",
+ __FUNCTION__, error.AsCString ());
// Mark the inferior as invalid.
// FIXME this could really use a new state - eStateLaunchFailure. For now, using eStateInvalid.
- monitor->SetState (StateType::eStateInvalid);
+ SetState (StateType::eStateInvalid);
- return false;
+ return -1;
}
else if (WIFEXITED(status))
{
// open, dup or execve likely failed for some reason.
- args->m_error.SetErrorToGenericError();
+ error.SetErrorToGenericError();
switch (WEXITSTATUS(status))
{
case ePtraceFailed:
- args->m_error.SetErrorString("Child ptrace failed.");
+ error.SetErrorString("Child ptrace failed.");
break;
case eDupStdinFailed:
- args->m_error.SetErrorString("Child open stdin failed.");
+ error.SetErrorString("Child open stdin failed.");
break;
case eDupStdoutFailed:
- args->m_error.SetErrorString("Child open stdout failed.");
+ error.SetErrorString("Child open stdout failed.");
break;
case eDupStderrFailed:
- args->m_error.SetErrorString("Child open stderr failed.");
+ error.SetErrorString("Child open stderr failed.");
break;
case eChdirFailed:
- args->m_error.SetErrorString("Child failed to set working directory.");
+ error.SetErrorString("Child failed to set working directory.");
break;
case eExecFailed:
- args->m_error.SetErrorString("Child exec failed.");
+ error.SetErrorString("Child exec failed.");
break;
case eSetGidFailed:
- args->m_error.SetErrorString("Child setgid failed.");
+ error.SetErrorString("Child setgid failed.");
break;
default:
- args->m_error.SetErrorString("Child returned unknown exit status.");
+ error.SetErrorString("Child returned unknown exit status.");
break;
}
@@ -1930,9 +1894,9 @@ NativeProcessLinux::Launch(LaunchArgs *a
// Mark the inferior as invalid.
// FIXME this could really use a new state - eStateLaunchFailure. For now, using eStateInvalid.
- monitor->SetState (StateType::eStateInvalid);
+ SetState (StateType::eStateInvalid);
- return false;
+ return -1;
}
assert(WIFSTOPPED(status) && (wpid == static_cast< ::pid_t> (pid)) &&
"Could not sync with inferior process.");
@@ -1940,102 +1904,73 @@ NativeProcessLinux::Launch(LaunchArgs *a
if (log)
log->Printf ("NativeProcessLinux::%s inferior started, now in stopped state", __FUNCTION__);
- args->m_error = SetDefaultPtraceOpts(pid);
- if (args->m_error.Fail())
+ error = SetDefaultPtraceOpts(pid);
+ if (error.Fail())
{
if (log)
log->Printf ("NativeProcessLinux::%s inferior failed to set default ptrace options: %s",
- __FUNCTION__,
- args->m_error.AsCString ());
+ __FUNCTION__, error.AsCString ());
// Mark the inferior as invalid.
// FIXME this could really use a new state - eStateLaunchFailure. For now, using eStateInvalid.
- monitor->SetState (StateType::eStateInvalid);
+ SetState (StateType::eStateInvalid);
- return false;
+ return -1;
}
// Release the master terminal descriptor and pass it off to the
// NativeProcessLinux instance. Similarly stash the inferior pid.
- monitor->m_terminal_fd = terminal.ReleaseMasterFileDescriptor();
- monitor->m_pid = pid;
+ m_terminal_fd = terminal.ReleaseMasterFileDescriptor();
+ m_pid = pid;
// Set the terminal fd to be in non blocking mode (it simplifies the
// implementation of ProcessLinux::GetSTDOUT to have a non-blocking
// descriptor to read from).
- if (!EnsureFDFlags(monitor->m_terminal_fd, O_NONBLOCK, args->m_error))
+ error = EnsureFDFlags(m_terminal_fd, O_NONBLOCK);
+ if (error.Fail())
{
if (log)
log->Printf ("NativeProcessLinux::%s inferior EnsureFDFlags failed for ensuring terminal O_NONBLOCK setting: %s",
- __FUNCTION__,
- args->m_error.AsCString ());
+ __FUNCTION__, error.AsCString ());
// Mark the inferior as invalid.
// FIXME this could really use a new state - eStateLaunchFailure. For now, using eStateInvalid.
- monitor->SetState (StateType::eStateInvalid);
+ SetState (StateType::eStateInvalid);
- return false;
+ return -1;
}
if (log)
log->Printf ("NativeProcessLinux::%s() adding pid = %" PRIu64, __FUNCTION__, pid);
- thread_sp = monitor->AddThread (pid);
+ thread_sp = AddThread (pid);
assert (thread_sp && "AddThread() returned a nullptr thread");
- monitor->NotifyThreadCreateStopped (pid);
+ NotifyThreadCreateStopped (pid);
std::static_pointer_cast<NativeThreadLinux> (thread_sp)->SetStoppedBySignal (SIGSTOP);
// Let our process instance know the thread has stopped.
- monitor->SetCurrentThreadID (thread_sp->GetID ());
- monitor->SetState (StateType::eStateStopped);
+ SetCurrentThreadID (thread_sp->GetID ());
+ SetState (StateType::eStateStopped);
if (log)
{
- if (args->m_error.Success ())
+ if (error.Success ())
{
log->Printf ("NativeProcessLinux::%s inferior launching succeeded", __FUNCTION__);
}
else
{
log->Printf ("NativeProcessLinux::%s inferior launching failed: %s",
- __FUNCTION__,
- args->m_error.AsCString ());
+ __FUNCTION__, error.AsCString ());
+ return -1;
}
}
- return args->m_error.Success();
+ return pid;
}
-void
-NativeProcessLinux::StartAttachOpThread(AttachArgs *args, Error &error)
+::pid_t
+NativeProcessLinux::Attach(lldb::pid_t pid, Error &error)
{
- static const char *g_thread_name = "lldb.process.linux.operation";
-
- if (m_operation_thread.IsJoinable())
- return;
-
- m_operation_thread = ThreadLauncher::LaunchThread(g_thread_name, AttachOpThread, args, &error);
-}
-
-void *
-NativeProcessLinux::AttachOpThread(void *arg)
-{
- AttachArgs *args = static_cast<AttachArgs*>(arg);
-
- if (!Attach(args)) {
- sem_post(&args->m_semaphore);
- return nullptr;
- }
-
- ServeOperation(args);
- return nullptr;
-}
-
-bool
-NativeProcessLinux::Attach(AttachArgs *args)
-{
- lldb::pid_t pid = args->m_pid;
-
- NativeProcessLinux *monitor = args->m_monitor;
lldb::ThreadSP inferior;
Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
@@ -2043,9 +1978,9 @@ NativeProcessLinux::Attach(AttachArgs *a
Host::TidMap tids_to_attach;
if (pid <= 1)
{
- args->m_error.SetErrorToGenericError();
- args->m_error.SetErrorString("Attaching to process 1 is not allowed.");
- goto FINISH;
+ error.SetErrorToGenericError();
+ error.SetErrorString("Attaching to process 1 is not allowed.");
+ return -1;
}
while (Host::FindProcessThreads(pid, tids_to_attach))
@@ -2059,18 +1994,18 @@ NativeProcessLinux::Attach(AttachArgs *a
// Attach to the requested process.
// An attach will cause the thread to stop with a SIGSTOP.
- PTRACE(PTRACE_ATTACH, tid, nullptr, nullptr, 0, args->m_error);
- if (args->m_error.Fail())
+ PTRACE(PTRACE_ATTACH, tid, nullptr, nullptr, 0, error);
+ if (error.Fail())
{
// No such thread. The thread may have exited.
// More error handling may be needed.
- if (args->m_error.GetError() == ESRCH)
+ if (error.GetError() == ESRCH)
{
it = tids_to_attach.erase(it);
continue;
}
else
- goto FINISH;
+ return -1;
}
int status;
@@ -2087,15 +2022,14 @@ NativeProcessLinux::Attach(AttachArgs *a
}
else
{
- args->m_error.SetErrorToErrno();
- goto FINISH;
+ error.SetErrorToErrno();
+ return -1;
}
}
- args->m_error = SetDefaultPtraceOpts(tid);
- if (args->m_error.Fail())
- goto FINISH;
-
+ error = SetDefaultPtraceOpts(tid);
+ if (error.Fail())
+ return -1;
if (log)
log->Printf ("NativeProcessLinux::%s() adding tid = %" PRIu64, __FUNCTION__, tid);
@@ -2103,13 +2037,13 @@ NativeProcessLinux::Attach(AttachArgs *a
it->second = true;
// Create the thread, mark it as stopped.
- NativeThreadProtocolSP thread_sp (monitor->AddThread (static_cast<lldb::tid_t> (tid)));
+ NativeThreadProtocolSP thread_sp (AddThread (static_cast<lldb::tid_t> (tid)));
assert (thread_sp && "AddThread() returned a nullptr");
// This will notify this is a new thread and tell the system it is stopped.
- monitor->NotifyThreadCreateStopped (tid);
+ NotifyThreadCreateStopped (tid);
std::static_pointer_cast<NativeThreadLinux> (thread_sp)->SetStoppedBySignal (SIGSTOP);
- monitor->SetCurrentThreadID (thread_sp->GetID ());
+ SetCurrentThreadID (thread_sp->GetID ());
}
// move the loop forward
@@ -2119,18 +2053,18 @@ NativeProcessLinux::Attach(AttachArgs *a
if (tids_to_attach.size() > 0)
{
- monitor->m_pid = pid;
+ m_pid = pid;
// Let our process instance know the thread has stopped.
- monitor->SetState (StateType::eStateStopped);
+ SetState (StateType::eStateStopped);
}
else
{
- args->m_error.SetErrorToGenericError();
- args->m_error.SetErrorString("No such process.");
+ error.SetErrorToGenericError();
+ error.SetErrorString("No such process.");
+ return -1;
}
- FINISH:
- return args->m_error.Success();
+ return pid;
}
Error
@@ -3669,67 +3603,11 @@ NativeProcessLinux::GetCrashReasonForSIG
}
#endif
-void
-NativeProcessLinux::ServeOperation(OperationArgs *args)
-{
- NativeProcessLinux *monitor = args->m_monitor;
-
- // We are finised with the arguments and are ready to go. Sync with the
- // parent thread and start serving operations on the inferior.
- sem_post(&args->m_semaphore);
-
- for(;;)
- {
- // wait for next pending operation
- if (sem_wait(&monitor->m_operation_pending))
- {
- if (errno == EINTR)
- continue;
- assert(false && "Unexpected errno from sem_wait");
- }
-
- // EXIT_OPERATION used to stop the operation thread because Cancel() isn't supported on
- // android. We don't have to send a post to the m_operation_done semaphore because in this
- // case the synchronization is achieved by a Join() call
- if (monitor->m_operation == EXIT_OPERATION)
- break;
-
- static_cast<Operation*>(monitor->m_operation)->Execute(monitor);
-
- // notify calling thread that operation is complete
- sem_post(&monitor->m_operation_done);
- }
-}
-
-void
-NativeProcessLinux::DoOperation(void *op)
-{
- Mutex::Locker lock(m_operation_mutex);
-
- m_operation = op;
-
- // notify operation thread that an operation is ready to be processed
- sem_post(&m_operation_pending);
-
- // Don't wait for the operation to complete in case of an exit operation. The operation thread
- // will exit without posting to the semaphore
- if (m_operation == EXIT_OPERATION)
- return;
-
- // wait for operation to complete
- while (sem_wait(&m_operation_done))
- {
- if (errno == EINTR)
- continue;
- assert(false && "Unexpected errno from sem_wait");
- }
-}
-
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);
- DoOperation(&op);
+ m_monitor_up->DoOperation(&op);
return op.GetError ();
}
@@ -3737,7 +3615,7 @@ Error
NativeProcessLinux::WriteMemory (lldb::addr_t addr, const void *buf, lldb::addr_t size, lldb::addr_t &bytes_written)
{
WriteOperation op(addr, buf, size, bytes_written);
- DoOperation(&op);
+ m_monitor_up->DoOperation(&op);
return op.GetError ();
}
@@ -3746,7 +3624,7 @@ NativeProcessLinux::ReadRegisterValue(ll
uint32_t size, RegisterValue &value)
{
ReadRegOperation op(tid, offset, reg_name, value);
- DoOperation(&op);
+ m_monitor_up->DoOperation(&op);
return op.GetError();
}
@@ -3755,7 +3633,7 @@ NativeProcessLinux::WriteRegisterValue(l
const char* reg_name, const RegisterValue &value)
{
WriteRegOperation op(tid, offset, reg_name, value);
- DoOperation(&op);
+ m_monitor_up->DoOperation(&op);
return op.GetError();
}
@@ -3763,7 +3641,7 @@ Error
NativeProcessLinux::ReadGPR(lldb::tid_t tid, void *buf, size_t buf_size)
{
ReadGPROperation op(tid, buf, buf_size);
- DoOperation(&op);
+ m_monitor_up->DoOperation(&op);
return op.GetError();
}
@@ -3771,7 +3649,7 @@ Error
NativeProcessLinux::ReadFPR(lldb::tid_t tid, void *buf, size_t buf_size)
{
ReadFPROperation op(tid, buf, buf_size);
- DoOperation(&op);
+ m_monitor_up->DoOperation(&op);
return op.GetError();
}
@@ -3779,7 +3657,7 @@ Error
NativeProcessLinux::ReadRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset)
{
ReadRegisterSetOperation op(tid, buf, buf_size, regset);
- DoOperation(&op);
+ m_monitor_up->DoOperation(&op);
return op.GetError();
}
@@ -3787,7 +3665,7 @@ Error
NativeProcessLinux::WriteGPR(lldb::tid_t tid, void *buf, size_t buf_size)
{
WriteGPROperation op(tid, buf, buf_size);
- DoOperation(&op);
+ m_monitor_up->DoOperation(&op);
return op.GetError();
}
@@ -3795,7 +3673,7 @@ Error
NativeProcessLinux::WriteFPR(lldb::tid_t tid, void *buf, size_t buf_size)
{
WriteFPROperation op(tid, buf, buf_size);
- DoOperation(&op);
+ m_monitor_up->DoOperation(&op);
return op.GetError();
}
@@ -3803,7 +3681,7 @@ Error
NativeProcessLinux::WriteRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset)
{
WriteRegisterSetOperation op(tid, buf, buf_size, regset);
- DoOperation(&op);
+ m_monitor_up->DoOperation(&op);
return op.GetError();
}
@@ -3816,7 +3694,7 @@ NativeProcessLinux::Resume (lldb::tid_t
log->Printf ("NativeProcessLinux::%s() resuming thread = %" PRIu64 " with signal %s", __FUNCTION__, tid,
GetUnixSignals().GetSignalAsCString (signo));
ResumeOperation op (tid, signo);
- DoOperation (&op);
+ m_monitor_up->DoOperation (&op);
if (log)
log->Printf ("NativeProcessLinux::%s() resuming thread = %" PRIu64 " result = %s", __FUNCTION__, tid, op.GetError().Success() ? "true" : "false");
return op.GetError();
@@ -3991,7 +3869,7 @@ Error
NativeProcessLinux::SingleStep(lldb::tid_t tid, uint32_t signo)
{
SingleStepOperation op(tid, signo);
- DoOperation(&op);
+ m_monitor_up->DoOperation(&op);
return op.GetError();
}
@@ -4001,7 +3879,7 @@ Error
NativeProcessLinux::GetSignalInfo(lldb::tid_t tid, void *siginfo)
{
SiginfoOperation op(tid, siginfo);
- DoOperation(&op);
+ m_monitor_up->DoOperation(&op);
return op.GetError();
}
@@ -4009,7 +3887,7 @@ Error
NativeProcessLinux::GetEventMessage(lldb::tid_t tid, unsigned long *message)
{
EventMessageOperation op(tid, message);
- DoOperation(&op);
+ m_monitor_up->DoOperation(&op);
return op.GetError();
}
@@ -4020,7 +3898,7 @@ NativeProcessLinux::Detach(lldb::tid_t t
return Error();
DetachOperation op(tid);
- DoOperation(&op);
+ m_monitor_up->DoOperation(&op);
return op.GetError();
}
@@ -4039,9 +3917,9 @@ NativeProcessLinux::DupDescriptor(const
}
void
-NativeProcessLinux::StartMonitorThread(Error &error)
+NativeProcessLinux::StartMonitorThread(const InitialOperation &initial_operation, Error &error)
{
- m_monitor_up.reset(new Monitor(GetID(), this));
+ m_monitor_up.reset(new Monitor(initial_operation, this));
error = m_monitor_up->Initialize();
if (error.Fail()) {
m_monitor_up.reset();
@@ -4051,27 +3929,8 @@ NativeProcessLinux::StartMonitorThread(E
void
NativeProcessLinux::StopMonitor()
{
- m_monitor_up.reset();
StopCoordinatorThread ();
- StopOpThread();
- sem_destroy(&m_operation_pending);
- sem_destroy(&m_operation_done);
-
- // TODO: validate whether this still holds, fix up comment.
- // Note: ProcessPOSIX passes the m_terminal_fd file descriptor to
- // Process::SetSTDIOFileDescriptor, which in turn transfers ownership of
- // the descriptor to a ConnectionFileDescriptor object. Consequently
- // even though still has the file descriptor, we shouldn't close it here.
-}
-
-void
-NativeProcessLinux::StopOpThread()
-{
- if (!m_operation_thread.IsJoinable())
- return;
-
- DoOperation(EXIT_OPERATION);
- m_operation_thread.Join(nullptr);
+ m_monitor_up.reset();
}
Error
Modified: lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.h?rev=235304&r1=235303&r2=235304&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.h (original)
+++ lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.h Mon Apr 20 08:53:49 2015
@@ -176,16 +176,6 @@ namespace process_linux {
ArchSpec m_arch;
std::unique_ptr<Monitor> m_monitor_up;
- HostThread m_operation_thread;
-
- // current operation which must be executed on the priviliged thread
- void *m_operation;
- Mutex m_operation_mutex;
-
- // semaphores notified when Operation is ready to be processed and when
- // the operation is complete.
- sem_t m_operation_pending;
- sem_t m_operation_done;
LazyBool m_supports_mem_region;
std::vector<MemoryRegionInfo> m_mem_region_cache;
@@ -198,25 +188,13 @@ namespace process_linux {
// the relevan breakpoint
std::map<lldb::tid_t, lldb::addr_t> m_threads_stepping_with_breakpoint;
- struct OperationArgs
- {
- OperationArgs(NativeProcessLinux *monitor);
-
- ~OperationArgs();
-
- NativeProcessLinux *m_monitor; // The monitor performing the attach.
- sem_t m_semaphore; // Posted to once operation complete.
- Error m_error; // Set if process operation failed.
- };
-
/// @class LauchArgs
///
/// @brief Simple structure to pass data to the thread responsible for
/// launching a child process.
- struct LaunchArgs : OperationArgs
+ struct LaunchArgs
{
- LaunchArgs(NativeProcessLinux *monitor,
- Module *module,
+ LaunchArgs(Module *module,
char const **argv,
char const **envp,
const std::string &stdin_path,
@@ -237,15 +215,7 @@ namespace process_linux {
const ProcessLaunchInfo &m_launch_info;
};
- struct AttachArgs : OperationArgs
- {
- AttachArgs(NativeProcessLinux *monitor,
- lldb::pid_t pid);
-
- ~AttachArgs();
-
- lldb::pid_t m_pid; // pid of the process to be attached.
- };
+ typedef std::function<::pid_t(Error &)> InitialOperation;
// ---------------------------------------------------------------------
// Private Instance Methods
@@ -272,32 +242,17 @@ namespace process_linux {
AttachToInferior (lldb::pid_t pid, Error &error);
void
- StartMonitorThread(Error &error);
+ StartMonitorThread(const InitialOperation &operation, Error &error);
- void
- StartLaunchOpThread(LaunchArgs *args, Error &error);
+ ::pid_t
+ Launch(LaunchArgs *args, Error &error);
- static void *
- LaunchOpThread(void *arg);
-
- static bool
- Launch(LaunchArgs *args);
-
- void
- StartAttachOpThread(AttachArgs *args, Error &error);
-
- static void *
- AttachOpThread(void *args);
-
- static bool
- Attach(AttachArgs *args);
+ ::pid_t
+ Attach(lldb::pid_t pid, Error &error);
static Error
SetDefaultPtraceOpts(const lldb::pid_t);
- static void
- ServeOperation(OperationArgs *args);
-
static bool
DupDescriptor(const char *path, int fd, int flags);
@@ -336,13 +291,6 @@ namespace process_linux {
GetCrashReasonForSIGBUS(const siginfo_t *info);
#endif
- void
- DoOperation(void *op);
-
- /// Stops the operation thread used to attach/launch a process.
- void
- StopOpThread();
-
Error
StartCoordinatorThread ();
Modified: lldb/trunk/test/functionalities/thread/concurrent_events/TestConcurrentEvents.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/thread/concurrent_events/TestConcurrentEvents.py?rev=235304&r1=235303&r2=235304&view=diff
==============================================================================
--- lldb/trunk/test/functionalities/thread/concurrent_events/TestConcurrentEvents.py (original)
+++ lldb/trunk/test/functionalities/thread/concurrent_events/TestConcurrentEvents.py Mon Apr 20 08:53:49 2015
@@ -70,7 +70,6 @@ class ConcurrentEventsTestCase(TestBase)
self.do_thread_actions(num_breakpoint_threads=1, num_signal_threads=1)
@dwarf_test
- @expectedFailureLinux # this test fails 2/100 dosep runs
def test_delay_signal_break_dwarf(self):
"""Test (1-second delay) signal and a breakpoint in multiple threads."""
self.buildDwarf(dictionary=self.getBuildFlags())
More information about the lldb-commits
mailing list