[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