[Lldb-commits] [lldb] r124520 - in /lldb/trunk: include/lldb/Target/Process.h source/Commands/CommandObjectProcess.cpp source/Target/Process.cpp

Jim Ingham jingham at apple.com
Fri Jan 28 17:49:25 PST 2011


Author: jingham
Date: Fri Jan 28 19:49:25 2011
New Revision: 124520

URL: http://llvm.org/viewvc/llvm-project?rev=124520&view=rev
Log:
Added a completion action class to the Process events so that we can make things like Attach and later Launch start their job, and then return to the event loop while waiting for the work to be done.

Modified:
    lldb/trunk/include/lldb/Target/Process.h
    lldb/trunk/source/Commands/CommandObjectProcess.cpp
    lldb/trunk/source/Target/Process.cpp

Modified: lldb/trunk/include/lldb/Target/Process.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/Process.h?rev=124520&r1=124519&r2=124520&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/Process.h (original)
+++ lldb/trunk/include/lldb/Target/Process.h Fri Jan 28 19:49:25 2011
@@ -1795,6 +1795,59 @@
     GetSP ();
     
 protected:
+    //------------------------------------------------------------------
+    // lldb::ExecutionContextScope pure virtual functions
+    //------------------------------------------------------------------
+    class NextEventAction
+    {
+    public:
+        typedef enum EventActionResult
+        {
+            eEventActionSuccess,
+            eEventActionRetry,
+            eEventActionExit
+        } EventActionResult;
+        
+        NextEventAction (Process *process) : 
+            m_process(process)
+        {}
+        virtual ~NextEventAction() {}
+        
+        virtual EventActionResult PerformAction (lldb::EventSP &event_sp) = 0;
+        virtual void HandleBeingUnshipped () {};
+        virtual EventActionResult HandleBeingInterrupted () = 0;
+        virtual const char *GetExitString() = 0;
+    protected:
+        Process *m_process;
+    };
+    
+    void SetNextEventAction (Process::NextEventAction *next_event_action)
+    {
+        if (m_next_event_action)
+        {
+            m_next_event_action->HandleBeingUnshipped();
+            delete m_next_event_action;
+        }
+        m_next_event_action = next_event_action;
+    }
+    
+    // This is the completer for Attaching:
+    class AttachCompletionHandler : public NextEventAction
+    {
+    public:
+        AttachCompletionHandler (Process *process) :
+            NextEventAction(process)
+        {}
+        virtual ~AttachCompletionHandler() {}
+        
+        virtual EventActionResult PerformAction (lldb::EventSP &event_sp);
+        virtual EventActionResult HandleBeingInterrupted ();
+        virtual const char *GetExitString();
+    private:
+        std::string m_exit_string;
+    };
+
+    
     class MemoryCache
     {
     public:
@@ -1867,6 +1920,7 @@
 
     typedef std::map<lldb::LanguageType, lldb::LanguageRuntimeSP> LanguageRuntimeCollection; 
     LanguageRuntimeCollection m_language_runtimes;
+    NextEventAction          *m_next_event_action;
 
     size_t
     RemoveBreakpointOpcodesFromBuffer (lldb::addr_t addr, size_t size, uint8_t *buf) const;
@@ -1904,10 +1958,6 @@
     lldb::StateType
     WaitForProcessStopPrivate (const TimeValue *timeout, lldb::EventSP &event_sp);
 
-    Error
-    CompleteAttach ();
-
-
     // This waits for both the state change broadcaster, and the control broadcaster.
     // If control_only, it only waits for the control broadcaster.
 

Modified: lldb/trunk/source/Commands/CommandObjectProcess.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Commands/CommandObjectProcess.cpp?rev=124520&r1=124519&r2=124520&view=diff
==============================================================================
--- lldb/trunk/source/Commands/CommandObjectProcess.cpp (original)
+++ lldb/trunk/source/Commands/CommandObjectProcess.cpp Fri Jan 28 19:49:25 2011
@@ -536,7 +536,8 @@
              CommandReturnObject &result)
     {
         Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
-
+        bool synchronous_execution = m_interpreter.GetSynchronous ();
+        
         Process *process = m_interpreter.GetDebugger().GetExecutionContext().process;
         if (process)
         {
@@ -636,6 +637,24 @@
                         result.SetStatus (eReturnStatusFailed);
                         return false;                
                     }
+                    // If we're synchronous, wait for the stopped event and report that.
+                    // Otherwise just return.  
+                    // FIXME: in the async case it will now be possible to get to the command
+                    // interpreter with a state eStateAttaching.  Make sure we handle that correctly.
+                    if (synchronous_execution)
+                    {
+                        StateType state = process->WaitForProcessToStop (NULL);
+
+                        result.SetDidChangeProcessState (true);
+                        result.AppendMessageWithFormat ("Process %i %s\n", process->GetID(), StateAsCString (state));
+                        result.SetStatus (eReturnStatusSuccessFinishNoResult);
+                    }
+                    else
+                    {
+                        result.SetDidChangeProcessState (true);
+                        result.AppendMessageWithFormat ("Starting to attach to process.");
+                        result.SetStatus (eReturnStatusSuccessFinishNoResult);
+                    }
                 }
                 else
                 {
@@ -681,6 +700,21 @@
                                                          error.AsCString());
                             result.SetStatus (eReturnStatusFailed);
                         }
+                        // See comment for synchronous_execution above.
+                        if (synchronous_execution)
+                        {
+                            StateType state = process->WaitForProcessToStop (NULL);
+
+                            result.SetDidChangeProcessState (true);
+                            result.AppendMessageWithFormat ("Process %i %s\n", process->GetID(), StateAsCString (state));
+                            result.SetStatus (eReturnStatusSuccessFinishNoResult);
+                        }
+                        else
+                        {
+                            result.SetDidChangeProcessState (true);
+                            result.AppendMessageWithFormat ("Starting to attach to process.");
+                            result.SetStatus (eReturnStatusSuccessFinishNoResult);
+                        }
                     }
                     else
                     {

Modified: lldb/trunk/source/Target/Process.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Process.cpp?rev=124520&r1=124519&r2=124520&view=diff
==============================================================================
--- lldb/trunk/source/Target/Process.cpp (original)
+++ lldb/trunk/source/Target/Process.cpp Fri Jan 28 19:49:25 2011
@@ -237,7 +237,8 @@
     m_stdio_communication ("process.stdio"),
     m_stdio_communication_mutex (Mutex::eMutexTypeRecursive),
     m_stdout_data (),
-    m_memory_cache ()
+    m_memory_cache (),
+    m_next_event_action(NULL)
 {
     UpdateInstanceName();
 
@@ -273,6 +274,8 @@
     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
     if (log)
         log->Printf ("%p Process::~Process()", this);
+    if (m_next_event_action)
+        SetNextEventAction(NULL);
     StopPrivateStateThread();
 }
 
@@ -1583,23 +1586,18 @@
     return error;
 }
 
-Error
-Process::CompleteAttach ()
+Process::NextEventAction::EventActionResult
+Process::AttachCompletionHandler::PerformAction (lldb::EventSP &event_sp)
 {
-    Error error;
-
-    if (GetID() == LLDB_INVALID_PROCESS_ID)
-    {
-        error.SetErrorString("no process");
-    }
-
-    EventSP event_sp;
-    StateType state = WaitForProcessStopPrivate(NULL, event_sp);
-    if (state == eStateStopped || state == eStateCrashed)
+    StateType state = ProcessEventData::GetStateFromEvent (event_sp.get());
+    switch (state) 
     {
-        DidAttach ();
+      case eStateStopped:
+      case eStateCrashed:
+      {
+        m_process->DidAttach ();
         // Figure out which one is the executable, and set that in our target:
-        ModuleList &modules = GetTarget().GetImages();
+        ModuleList &modules = m_process->GetTarget().GetImages();
     
         size_t num_modules = modules.GetSize();
         for (int i = 0; i < num_modules; i++)
@@ -1607,31 +1605,37 @@
             ModuleSP module_sp = modules.GetModuleAtIndex(i);
             if (module_sp->IsExecutable())
             {
-                ModuleSP exec_module = GetTarget().GetExecutableModule();
+                ModuleSP exec_module = m_process->GetTarget().GetExecutableModule();
                 if (!exec_module || exec_module != module_sp)
                 {
                     
-                    GetTarget().SetExecutableModule (module_sp, false);
+                    m_process->GetTarget().SetExecutableModule (module_sp, false);
                 }
                 break;
             }
         }
-
-        // This delays passing the stopped event to listeners till DidLaunch gets
-        // a chance to complete...
-        HandlePrivateEvent(event_sp);
-        StartPrivateStateThread();
-    }
-    else
-    {
-        // We exited while trying to launch somehow.  Don't call DidLaunch as that's
-        // not likely to work, and return an invalid pid.
-        if (state == eStateExited)
-            HandlePrivateEvent (event_sp);
-        error.SetErrorStringWithFormat("invalid state after attach: %s", 
-                                        lldb_private::StateAsCString(state));
+        return eEventActionSuccess;
+      }
+      break;
+      default:
+      case eStateExited:   
+      case eStateInvalid:
+        m_exit_string.assign ("No valid Process");
+        return eEventActionExit;
+        break;
     }
-    return error;
+}
+
+Process::NextEventAction::EventActionResult
+Process::AttachCompletionHandler::HandleBeingInterrupted()
+{
+    return eEventActionSuccess;
+}
+
+const char *
+Process::AttachCompletionHandler::GetExitString ()
+{
+    return m_exit_string.c_str();
 }
 
 Error
@@ -1660,7 +1664,8 @@
         error = DoAttachToProcessWithID (attach_pid);
         if (error.Success())
         {
-            error = CompleteAttach();
+            SetNextEventAction(new Process::AttachCompletionHandler(this));
+            StartPrivateStateThread();
         }
         else
         {
@@ -1717,7 +1722,8 @@
         }
         else
         {
-            error = CompleteAttach();
+            SetNextEventAction(new Process::AttachCompletionHandler(this));
+            StartPrivateStateThread();
         }
     }
     return error;
@@ -1769,73 +1775,82 @@
 Error
 Process::Halt ()
 {
-    Error error (WillHalt());
+    // Pause our private state thread so we can ensure no one else eats
+    // the stop event out from under us.
+    PausePrivateStateThread();
+
+    EventSP event_sp;
+    Error error;
     
-    if (error.Success())
+    if (m_public_state.GetValue() == eStateAttaching)
     {
+        SetExitStatus(SIGKILL, "Cancelled async attach.");
+    }
+    else
+    {
+        error = WillHalt();
         
-        bool caused_stop = false;
-        EventSP event_sp;
-        
-        // Pause our private state thread so we can ensure no one else eats
-        // the stop event out from under us.
-        PausePrivateStateThread();
-
-        // Ask the process subclass to actually halt our process
-        error = DoHalt(caused_stop);
         if (error.Success())
         {
-            // If "caused_stop" is true, then DoHalt stopped the process. If
-            // "caused_stop" is false, the process was already stopped.
-            // If the DoHalt caused the process to stop, then we want to catch
-            // this event and set the interrupted bool to true before we pass
-            // this along so clients know that the process was interrupted by
-            // a halt command.
-            if (caused_stop)
-            {
-                // Wait for 2 seconds for the process to stop.
-                TimeValue timeout_time;
-                timeout_time = TimeValue::Now();
-                timeout_time.OffsetWithSeconds(1);
-                StateType state = WaitForStateChangedEventsPrivate (&timeout_time, event_sp);
-                
-                if (state == eStateInvalid)
-                {
-                    // We timeout out and didn't get a stop event...
-                    error.SetErrorString ("Halt timed out.");
-                }
-                else
-                {
-                    if (StateIsStoppedState (state))
+            
+            bool caused_stop = false;
+            
+            // Ask the process subclass to actually halt our process
+            error = DoHalt(caused_stop);
+            if (error.Success())
+            {
+                // If "caused_stop" is true, then DoHalt stopped the process. If
+                // "caused_stop" is false, the process was already stopped.
+                // If the DoHalt caused the process to stop, then we want to catch
+                // this event and set the interrupted bool to true before we pass
+                // this along so clients know that the process was interrupted by
+                // a halt command.
+                if (caused_stop)
+                {
+                    // Wait for 2 seconds for the process to stop.
+                    TimeValue timeout_time;
+                    timeout_time = TimeValue::Now();
+                    timeout_time.OffsetWithSeconds(1);
+                    StateType state = WaitForStateChangedEventsPrivate (&timeout_time, event_sp);
+                    
+                    if (state == eStateInvalid)
                     {
-                        // We caused the process to interrupt itself, so mark this
-                        // as such in the stop event so clients can tell an interrupted
-                        // process from a natural stop
-                        ProcessEventData::SetInterruptedInEvent (event_sp.get(), true);
+                        // We timeout out and didn't get a stop event...
+                        error.SetErrorString ("Halt timed out.");
                     }
                     else
                     {
-                        LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
-                        if (log)
-                            log->Printf("Process::Halt() failed to stop, state is: %s", StateAsCString(state));
-                        error.SetErrorString ("Did not get stopped event after halt.");
+                        if (StateIsStoppedState (state))
+                        {
+                            // We caused the process to interrupt itself, so mark this
+                            // as such in the stop event so clients can tell an interrupted
+                            // process from a natural stop
+                            ProcessEventData::SetInterruptedInEvent (event_sp.get(), true);
+                        }
+                        else
+                        {
+                            LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+                            if (log)
+                                log->Printf("Process::Halt() failed to stop, state is: %s", StateAsCString(state));
+                            error.SetErrorString ("Did not get stopped event after halt.");
+                        }
                     }
                 }
-            }
-            DidHalt();
+                DidHalt();
 
+            }
         }
-        // Resume our private state thread before we post the event (if any)
-        ResumePrivateStateThread();
+    }
+    // Resume our private state thread before we post the event (if any)
+    ResumePrivateStateThread();
 
-        // Post any event we might have consumed. If all goes well, we will have
-        // stopped the process, intercepted the event and set the interrupted
-        // bool in the event.  Post it to the private event queue and that will end up
-        // correctly setting the state.
-        if (event_sp)
-            m_private_state_broadcaster.BroadcastEvent(event_sp);
+    // Post any event we might have consumed. If all goes well, we will have
+    // stopped the process, intercepted the event and set the interrupted
+    // bool in the event.  Post it to the private event queue and that will end up
+    // correctly setting the state.
+    if (event_sp)
+        m_private_state_broadcaster.BroadcastEvent(event_sp);
 
-    }
     return error;
 }
 
@@ -2123,7 +2138,27 @@
 Process::HandlePrivateEvent (EventSP &event_sp)
 {
     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+    
     const StateType new_state = Process::ProcessEventData::GetStateFromEvent(event_sp.get());
+    
+    // First check to see if anybody wants a shot at this event:
+    if (m_next_event_action != NULL)
+    {
+        NextEventAction::EventActionResult action_result = m_next_event_action->PerformAction(event_sp);
+        switch (action_result)
+        {
+            case NextEventAction::eEventActionSuccess:
+                SetNextEventAction(NULL);
+                break;
+            case NextEventAction::eEventActionRetry:
+                break;
+            case NextEventAction::eEventActionExit:
+                // Handle Exiting Here...
+                
+                break;
+        }
+    }
+    
     // See if we should broadcast this state to external clients?
     const bool should_broadcast = ShouldBroadcastEvent (event_sp.get());
 





More information about the lldb-commits mailing list