Add the ability to set timeout & "run all threads" options both from the "expr" comma...
authorJim Ingham <jingham@apple.com>
Tue, 16 Oct 2012 21:41:58 +0000 (21:41 +0000)
committerJim Ingham <jingham@apple.com>
Tue, 16 Oct 2012 21:41:58 +0000 (21:41 +0000)
the SB API's that evaluate expressions.

<rdar://problem/12457211>

llvm-svn: 166062

32 files changed:
lldb/include/lldb/API/SBDefines.h
lldb/include/lldb/API/SBExpressionOptions.h [new file with mode: 0644]
lldb/include/lldb/API/SBFrame.h
lldb/include/lldb/API/SBValue.h
lldb/include/lldb/Expression/ClangFunction.h
lldb/include/lldb/Expression/ClangUserExpression.h
lldb/include/lldb/Target/Process.h
lldb/include/lldb/Target/Target.h
lldb/include/lldb/lldb-forward.h
lldb/lldb.xcodeproj/project.pbxproj
lldb/scripts/Python/build-swig-Python.sh
lldb/scripts/Python/interface/SBExpressionOptions.i [new file with mode: 0644]
lldb/scripts/Python/interface/SBFrame.i
lldb/scripts/Python/interface/SBValue.i
lldb/scripts/lldb.swig
lldb/source/API/SBExpressionOptions.cpp [new file with mode: 0644]
lldb/source/API/SBFrame.cpp
lldb/source/API/SBValue.cpp
lldb/source/Commands/CommandObjectExpression.cpp
lldb/source/Commands/CommandObjectExpression.h
lldb/source/Commands/CommandObjectThread.cpp
lldb/source/Commands/CommandObjectWatchpoint.cpp
lldb/source/Core/CXXFormatterFunctions.cpp
lldb/source/Expression/ClangFunction.cpp
lldb/source/Expression/ClangUserExpression.cpp
lldb/source/Interpreter/CommandInterpreter.cpp
lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
lldb/source/Target/Process.cpp
lldb/source/Target/Target.cpp
lldb/test/expression_command/timeout/Makefile [new file with mode: 0644]
lldb/test/expression_command/timeout/TestCallWithTimeout.py [new file with mode: 0644]
lldb/test/expression_command/timeout/wait-a-while.c [new file with mode: 0644]

index 28b71b1..e8740a8 100644 (file)
@@ -41,6 +41,7 @@ class SBDeclaration;
 class SBError;
 class SBEvent;
 class SBEventList;
+class SBExpressionOptions;
 class SBFileSpec;
 class SBFileSpecList;
 class SBFrame;
diff --git a/lldb/include/lldb/API/SBExpressionOptions.h b/lldb/include/lldb/API/SBExpressionOptions.h
new file mode 100644 (file)
index 0000000..509ec05
--- /dev/null
@@ -0,0 +1,96 @@
+//===-- SBEvent.h -----------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SBExpressionOptions_h_
+#define LLDB_SBExpressionOptions_h_
+
+#include "lldb/API/SBDefines.h"
+
+#include <memory>
+#include <vector>
+
+namespace lldb {
+
+
+class SBExpressionOptions
+{
+friend class SBFrame;
+friend class SBValue;
+
+public:
+    SBExpressionOptions();
+
+    SBExpressionOptions (const lldb::SBExpressionOptions &rhs);
+    
+    SBExpressionOptions (bool coerce_to_id,
+                         bool unwind_on_error,
+                         bool keep_in_memory,
+                         bool run_others,
+                         DynamicValueType use_dynamic,
+                         uint32_t timeout_usec);
+
+    ~SBExpressionOptions();
+
+    const SBExpressionOptions &
+    operator = (const lldb::SBExpressionOptions &rhs);
+
+    bool
+    DoesCoerceToId () const;
+    
+    void
+    SetCoerceToId (bool coerce = true);
+    
+    bool
+    DoesUnwindOnError () const;
+    
+    void
+    SetUnwindOnError (bool unwind = false);
+    
+    bool
+    DoesKeepInMemory () const;
+    
+    void
+    SetKeepInMemory (bool keep = true);
+
+    lldb::DynamicValueType
+    GetUseDynamic () const;
+    
+    void
+    SetUseDynamic (lldb::DynamicValueType dynamic = lldb::eDynamicCanRunTarget);
+    
+    uint32_t
+    GetTimeoutUsec () const;
+    
+    void
+    SetTimeoutUsec (uint32_t timeout = 0);
+    
+    bool
+    GetRunOthers () const;
+    
+    void
+    SetRunOthers (bool run_others = true);
+
+protected:
+
+    SBExpressionOptions (lldb_private::EvaluateExpressionOptions &expression_options);
+
+    lldb_private::EvaluateExpressionOptions *
+    get () const;
+
+    lldb_private::EvaluateExpressionOptions &
+    ref () const;
+
+private:
+    // This auto_pointer is made in the constructor and is always valid.
+    mutable std::auto_ptr<lldb_private::EvaluateExpressionOptions> m_opaque_ap;
+};
+
+} // namespace lldb
+
+#endif  // LLDB_SBExpressionOptions_h_
index 7d3d208..8af708b 100644 (file)
@@ -105,6 +105,9 @@ public:
 
     lldb::SBValue
     EvaluateExpression (const char *expr, lldb::DynamicValueType use_dynamic, bool unwind_on_error);
+    
+    lldb::SBValue
+    EvaluateExpression (const char *expr, const SBExpressionOptions &options);
 
     /// Gets the lexical block that defines the stack frame. Another way to think
     /// of this is it will return the block that contains all of the variables
index 802a6e2..0502074 100644 (file)
@@ -137,6 +137,9 @@ public:
     CreateValueFromExpression (const char *name, const char* expression);
     
     lldb::SBValue
+    CreateValueFromExpression (const char *name, const char* expression, SBExpressionOptions &options);
+    
+    lldb::SBValue
     CreateValueFromAddress (const char* name, 
                             lldb::addr_t address, 
                             lldb::SBType type);
index 47784d3..68093eb 100644 (file)
@@ -251,9 +251,10 @@ public:
     ///     function call, and return the program state to what it was before the
     ///     execution.  If false, we leave the program in the stopped state.
     /// 
-    /// @param[in] single_thread_timeout_usec
-    ///     If stop_others is true, the length of time to wait before
-    ///     concluding that the system is deadlocked.
+    /// @param[in] timeout_usec
+    ///     Timeout value (0 for no timeout). If try_all_threads is true, then we
+    ///     will try on one thread for the lesser of .25 sec and half the total timeout.
+    ///     then switch to running all threads, otherwise this will be the total timeout.
     ///
     /// @param[in] errors
     ///     The stream to write errors to.
@@ -272,7 +273,7 @@ public:
                      bool stop_others, 
                      bool try_all_threads,
                      bool discard_on_error,
-                     uint32_t single_thread_timeout_usec, 
+                     uint32_t timeout_usec,
                      Stream &errors,
                      lldb::addr_t* this_arg = 0);
     
@@ -329,7 +330,7 @@ public:
     //------------------------------------------------------------------
     /// Run the function this ClangFunction was created with.
     ///
-    /// This simple version will run the function on one thread.  If \a single_thread_timeout_usec
+    /// This simple version will run the function on one thread.  If \a timeout_usec
     /// is not zero, we time out after that timeout.  If \a try_all_threads is true, then we will
     /// resume with all threads on, otherwise we halt the process, and eExecutionInterrupted will be returned.
     ///
@@ -339,8 +340,10 @@ public:
     /// @param[in] errors
     ///     Errors will be written here if there are any.
     ///
-    /// @param[in] single_thread_timeout_usec
-    ///     If \b true, run only this thread, if \b false let all threads run.
+    /// @param[in] timeout_usec
+    ///     Timeout value (0 for no timeout). If try_all_threads is true, then we
+    ///     will try on one thread for the lesser of .25 sec and half the total timeout.
+    ///     then switch to running all threads, otherwise this will be the total timeout.
     ///
     /// @param[in] try_all_threads
     ///     If \b true, run only this thread, if \b false let all threads run.
@@ -379,8 +382,11 @@ public:
     /// @param[in] stop_others
     ///     If \b true, run only this thread, if \b false let all threads run.
     ///
-    /// @param[in] single_thread_timeout_usec
-    ///     If \b true, run only this thread, if \b false let all threads run.
+    /// @param[in] timeout_usec
+    ///     Timeout value (0 for no timeout). If try_all_threads is true, then we
+    ///     will try on one thread for the lesser of .25 sec and half the total timeout.
+    ///     then switch to running all threads, otherwise this will be the total timeout.
+    ///
     ///
     /// @param[in] try_all_threads
     ///     If \b true, run only this thread, if \b false let all threads run.
@@ -396,7 +402,7 @@ public:
                     lldb::addr_t *args_addr_ptr, 
                     Stream &errors, 
                     bool stop_others, 
-                    uint32_t single_thread_timeout_usec,
+                    uint32_t timeout_usec,
                     bool try_all_threads,
                     bool discard_on_error, 
                     Value &results);
index 772f7f6..dc46ebe 100644 (file)
@@ -132,9 +132,16 @@ public:
     ///     A pointer to direct at the persistent variable in which the
     ///     expression's result is stored.
     ///
-    /// @param[in] single_thread_timeout_usec
-    ///     The amount of time (in usec) that we are willing to wait for this
-    ///     expression to complete, before assuming that we are blocked and giving up
+    /// @param[in] try_all_threads
+    ///     If true, then we will try to run all threads if the function doesn't complete on
+    ///     one thread.  See timeout_usec for the interaction of this variable and
+    ///     the timeout.
+    ///
+    /// @param[in] timeout_usec
+    ///     Timeout value (0 for no timeout). If try_all_threads is true, then we
+    ///     will try on one thread for the lesser of .25 sec and half the total timeout.
+    ///     then switch to running all threads, otherwise this will be the total timeout.
+    ///
     ///
     /// @return
     ///     A Process::Execution results value.
@@ -145,7 +152,8 @@ public:
              bool discard_on_error,
              ClangUserExpressionSP &shared_ptr_to_me,
              lldb::ClangExpressionVariableSP &result,
-             uint32_t single_thread_timeout_usec = 500000);
+             bool try_all_threads = true,
+             uint32_t timeout_usec = 500000);
              
     ThreadPlan *
     GetThreadPlanToExecuteJITExpression (Stream &error_stream,
@@ -314,9 +322,15 @@ public:
     /// @param[in/out] result_valobj_sp
     ///      If execution is successful, the result valobj is placed here.
     ///
-    /// @param[in] single_thread_timeout_usec
-    ///     The amount of time (in usec) that we are willing to wait for this
-    ///     expression to complete, before assuming that we are blocked and giving up
+    /// @param[in] try_all_threads
+    ///     If true, then we will try to run all threads if the function doesn't complete on
+    ///     one thread.  See timeout_usec for the interaction of this variable and
+    ///     the timeout.
+    ///
+    /// @param[in] timeout_usec
+    ///     Timeout value (0 for no timeout). If try_all_threads is true, then we
+    ///     will try on one thread for the lesser of .25 sec and half the total timeout.
+    ///     then switch to running all threads, otherwise this will be the total timeout.
     ///
     /// @result
     ///      A Process::ExecutionResults value.  eExecutionCompleted for success.
@@ -330,7 +344,8 @@ public:
               const char *expr_cstr,
               const char *expr_prefix,
               lldb::ValueObjectSP &result_valobj_sp,
-              uint32_t single_thread_timeout_usec = 500000);
+              bool try_all_threads = true,
+              uint32_t timeout_usec = 500000);
               
     static ExecutionResults
     EvaluateWithError (ExecutionContext &exe_ctx,
@@ -342,7 +357,8 @@ public:
                        const char *expr_prefix,
                        lldb::ValueObjectSP &result_valobj_sp,
                        Error &error,
-                       uint32_t single_thread_timeout_usec = 500000);
+                       bool try_all_threads = true,
+                       uint32_t timeout_usec = 500000);
     
     static const Error::ValueType kNoResult = 0x1001; ///< ValueObject::GetError() returns this if there is no result from the expression.
 private:
index e043190..1278a44 100644 (file)
@@ -2363,9 +2363,9 @@ public:
     RunThreadPlan (ExecutionContext &exe_ctx,    
                     lldb::ThreadPlanSP &thread_plan_sp,
                     bool stop_others,
-                    bool try_all_threads,
+                    bool run_others,
                     bool discard_on_error,
-                    uint32_t single_thread_timeout_usec,
+                    uint32_t timeout_usec,
                     Stream &errors);
 
     static const char *
index 15b87d7..8d68a49 100644 (file)
@@ -137,6 +137,121 @@ public:
 
 typedef STD_SHARED_PTR(TargetProperties) TargetPropertiesSP;
 
+class EvaluateExpressionOptions
+{
+public:
+    static const uint32_t default_timeout = 500000;
+    EvaluateExpressionOptions() :
+        m_execution_policy(eExecutionPolicyOnlyWhenNeeded),
+        m_coerce_to_id(false),
+        m_unwind_on_error(true),
+        m_keep_in_memory(false),
+        m_run_others(true),
+        m_use_dynamic(lldb::eNoDynamicValues),
+        m_timeout_usec(default_timeout)
+    {}
+    
+    ExecutionPolicy
+    GetExecutionPolicy () const
+    {
+        return m_execution_policy;
+    }
+    
+    EvaluateExpressionOptions&
+    SetExecutionPolicy (ExecutionPolicy policy = eExecutionPolicyAlways)
+    {
+        m_execution_policy = policy;
+        return *this;
+    }
+    
+    bool
+    DoesCoerceToId () const
+    {
+        return m_coerce_to_id;
+    }
+    
+    EvaluateExpressionOptions&
+    SetCoerceToId (bool coerce = true)
+    {
+        m_coerce_to_id = coerce;
+        return *this;
+    }
+    
+    bool
+    DoesUnwindOnError () const
+    {
+        return m_unwind_on_error;
+    }
+    
+    EvaluateExpressionOptions&
+    SetUnwindOnError (bool unwind = false)
+    {
+        m_unwind_on_error = unwind;
+        return *this;
+    }
+    
+    bool
+    DoesKeepInMemory () const
+    {
+        return m_keep_in_memory;
+    }
+    
+    EvaluateExpressionOptions&
+    SetKeepInMemory (bool keep = true)
+    {
+        m_keep_in_memory = keep;
+        return *this;
+    }
+    
+    lldb::DynamicValueType
+    GetUseDynamic () const
+    {
+        return m_use_dynamic;
+    }
+    
+    EvaluateExpressionOptions&
+    SetUseDynamic (lldb::DynamicValueType dynamic = lldb::eDynamicCanRunTarget)
+    {
+        m_use_dynamic = dynamic;
+        return *this;
+    }
+    
+    uint32_t
+    GetTimeoutUsec () const
+    {
+        return m_timeout_usec;
+    }
+    
+    EvaluateExpressionOptions&
+    SetTimeoutUsec (uint32_t timeout = 0)
+    {
+        m_timeout_usec = timeout;
+        return *this;
+    }
+    
+    bool
+    GetRunOthers () const
+    {
+        return m_run_others;
+    }
+    
+    EvaluateExpressionOptions&
+    SetRunOthers (bool run_others = true)
+    {
+        m_run_others = run_others;
+        return *this;
+    }
+    
+private:
+    ExecutionPolicy m_execution_policy;
+    bool m_coerce_to_id;
+    bool m_unwind_on_error;
+    bool m_keep_in_memory;
+    bool m_run_others;
+    lldb::DynamicValueType m_use_dynamic;
+    uint32_t m_timeout_usec;
+};
+
 //----------------------------------------------------------------------
 // Target
 //----------------------------------------------------------------------
@@ -760,104 +875,6 @@ public:
     ClangASTImporter *
     GetClangASTImporter();
     
-    class EvaluateExpressionOptions
-    {
-    public:
-        EvaluateExpressionOptions() :
-            m_execution_policy(eExecutionPolicyOnlyWhenNeeded),
-            m_coerce_to_id(false),
-            m_unwind_on_error(true),
-            m_keep_in_memory(false),
-            m_use_dynamic(lldb::eNoDynamicValues),
-            m_single_thread_timeout_usec(500000)
-        {}
-        
-        ExecutionPolicy
-        GetExecutionPolicy () const
-        {
-            return m_execution_policy;
-        }
-        
-        EvaluateExpressionOptions&
-        SetExecutionPolicy (ExecutionPolicy policy = eExecutionPolicyAlways)
-        {
-            m_execution_policy = policy;
-            return *this;
-        }
-        
-        bool
-        DoesCoerceToId () const
-        {
-            return m_coerce_to_id;
-        }
-        
-        EvaluateExpressionOptions&
-        SetCoerceToId (bool coerce = true)
-        {
-            m_coerce_to_id = coerce;
-            return *this;
-        }
-        
-        bool
-        DoesUnwindOnError () const
-        {
-            return m_unwind_on_error;
-        }
-        
-        EvaluateExpressionOptions&
-        SetUnwindOnError (bool unwind = false)
-        {
-            m_unwind_on_error = unwind;
-            return *this;
-        }
-        
-        bool
-        DoesKeepInMemory () const
-        {
-            return m_keep_in_memory;
-        }
-        
-        EvaluateExpressionOptions&
-        SetKeepInMemory (bool keep = true)
-        {
-            m_keep_in_memory = keep;
-            return *this;
-        }
-        
-        lldb::DynamicValueType
-        GetUseDynamic () const
-        {
-            return m_use_dynamic;
-        }
-        
-        EvaluateExpressionOptions&
-        SetUseDynamic (lldb::DynamicValueType dynamic = lldb::eDynamicCanRunTarget)
-        {
-            m_use_dynamic = dynamic;
-            return *this;
-        }
-        
-        uint32_t
-        GetSingleThreadTimeoutUsec () const
-        {
-            return m_single_thread_timeout_usec;
-        }
-        
-        EvaluateExpressionOptions&
-        SetSingleThreadTimeoutUsec (uint32_t timeout = 0)
-        {
-            m_single_thread_timeout_usec = timeout;
-            return *this;
-        }
-        
-    private:
-        ExecutionPolicy m_execution_policy;
-        bool m_coerce_to_id;
-        bool m_unwind_on_error;
-        bool m_keep_in_memory;
-        lldb::DynamicValueType m_use_dynamic;
-        uint32_t m_single_thread_timeout_usec;
-    };
     
     // Since expressions results can persist beyond the lifetime of a process,
     // and the const expression results are available after a process is gone,
index 84cecd1..c128de1 100644 (file)
@@ -98,6 +98,7 @@ class   DynamicLibrary;
 class   DynamicLoader;
 class   EmulateInstruction;
 class   Error;
+class   EvaluateExpressionOptions;
 class   Event;
 class   EventData;
 class   ExecutionContext;
index 9139e5c..8046972 100644 (file)
                4CCA645613B40B82003BDF98 /* AppleObjCTrampolineHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CCA644813B40B82003BDF98 /* AppleObjCTrampolineHandler.cpp */; };
                4CCA645813B40B82003BDF98 /* AppleThreadPlanStepThroughObjCTrampoline.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CCA644A13B40B82003BDF98 /* AppleThreadPlanStepThroughObjCTrampoline.cpp */; };
                4CD0BD0F134BFADF00CB44D4 /* ValueObjectDynamicValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CD0BD0E134BFADF00CB44D4 /* ValueObjectDynamicValue.cpp */; };
+               4CE4F673162C971A00F75CB3 /* SBExpressionOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 4CE4F672162C971A00F75CB3 /* SBExpressionOptions.h */; settings = {ATTRIBUTES = (Public, ); }; };
+               4CE4F675162C973F00F75CB3 /* SBExpressionOptions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CE4F674162C973F00F75CB3 /* SBExpressionOptions.cpp */; };
                4CF3D80C15AF4DC800845BF3 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EDB919B414F6F10D008FF64B /* Security.framework */; };
                4CF52AF51428291E0051E832 /* SBFileSpecList.h in Headers */ = {isa = PBXBuildFile; fileRef = 4CF52AF41428291E0051E832 /* SBFileSpecList.h */; settings = {ATTRIBUTES = (Public, ); }; };
                4CF52AF8142829390051E832 /* SBFileSpecList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CF52AF7142829390051E832 /* SBFileSpecList.cpp */; };
                4CCA644B13B40B82003BDF98 /* AppleThreadPlanStepThroughObjCTrampoline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppleThreadPlanStepThroughObjCTrampoline.h; sourceTree = "<group>"; };
                4CD0BD0C134BFAB600CB44D4 /* ValueObjectDynamicValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ValueObjectDynamicValue.h; path = include/lldb/Core/ValueObjectDynamicValue.h; sourceTree = "<group>"; };
                4CD0BD0E134BFADF00CB44D4 /* ValueObjectDynamicValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ValueObjectDynamicValue.cpp; path = source/Core/ValueObjectDynamicValue.cpp; sourceTree = "<group>"; };
+               4CE4F672162C971A00F75CB3 /* SBExpressionOptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBExpressionOptions.h; path = include/lldb/API/SBExpressionOptions.h; sourceTree = "<group>"; };
+               4CE4F674162C973F00F75CB3 /* SBExpressionOptions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBExpressionOptions.cpp; path = source/API/SBExpressionOptions.cpp; sourceTree = "<group>"; };
+               4CE4F676162CE1E100F75CB3 /* SBExpressionOptions.i */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c.preprocessed; path = SBExpressionOptions.i; sourceTree = "<group>"; };
                4CEDAED311754F5E00E875A6 /* ThreadPlanStepUntil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadPlanStepUntil.h; path = include/lldb/Target/ThreadPlanStepUntil.h; sourceTree = "<group>"; };
                4CF52AF41428291E0051E832 /* SBFileSpecList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBFileSpecList.h; path = include/lldb/API/SBFileSpecList.h; sourceTree = "<group>"; };
                4CF52AF7142829390051E832 /* SBFileSpecList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBFileSpecList.cpp; path = source/API/SBFileSpecList.cpp; sourceTree = "<group>"; };
                                2611FEFC142D83060017FEA3 /* SBFileSpec.i */,
                                2611FEFD142D83060017FEA3 /* SBFileSpecList.i */,
                                2611FEFE142D83060017FEA3 /* SBFrame.i */,
+                               4CE4F676162CE1E100F75CB3 /* SBExpressionOptions.i */,
                                2611FEFF142D83060017FEA3 /* SBFunction.i */,
                                2611FF00142D83060017FEA3 /* SBHostOS.i */,
                                2611FF01142D83060017FEA3 /* SBInputReader.i */,
                                2682F284115EF3A700CCFF99 /* SBError.cpp */,
                                9A9830FE1125FC5800A56CB0 /* SBEvent.h */,
                                9A9830FD1125FC5800A56CB0 /* SBEvent.cpp */,
+                               4CE4F672162C971A00F75CB3 /* SBExpressionOptions.h */,
+                               4CE4F674162C973F00F75CB3 /* SBExpressionOptions.cpp */,
                                26022531115F27FA00A601A2 /* SBFileSpec.h */,
                                26022532115F281400A601A2 /* SBFileSpec.cpp */,
                                4CF52AF41428291E0051E832 /* SBFileSpecList.h */,
                                B2A58722143119810092BFBA /* SBWatchpoint.h in Headers */,
                                26D265A2136B40EE002EEE45 /* SharingPtr.h in Headers */,
                                26D265BC136B4269002EEE45 /* lldb-public.h in Headers */,
+                               4CE4F673162C971A00F75CB3 /* SBExpressionOptions.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                9475C18814E5E9FA001BFC6D /* SBTypeCategory.cpp in Sources */,
                                9475C18E14E5F834001BFC6D /* SBTypeNameSpecifier.cpp in Sources */,
                                9452573A16262D0200325455 /* SBDeclaration.cpp in Sources */,
+                               4CE4F675162C973F00F75CB3 /* SBExpressionOptions.cpp in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
index a38d2ff..59394f9 100755 (executable)
@@ -76,6 +76,7 @@ HEADER_FILES="${SRC_ROOT}/include/lldb/lldb.h"\
 " ${SRC_ROOT}/include/lldb/API/SBDebugger.h"\
 " ${SRC_ROOT}/include/lldb/API/SBError.h"\
 " ${SRC_ROOT}/include/lldb/API/SBEvent.h"\
+" ${SRC_ROOT}/include/lldb/API/SBExpressionOptions.h"\
 " ${SRC_ROOT}/include/lldb/API/SBFileSpec.h"\
 " ${SRC_ROOT}/include/lldb/API/SBFrame.h"\
 " ${SRC_ROOT}/include/lldb/API/SBFunction.h"\
@@ -120,6 +121,7 @@ INTERFACE_FILES="${SRC_ROOT}/scripts/Python/interface/SBAddress.i"\
 " ${SRC_ROOT}/scripts/Python/interface/SBDeclaration.i"\
 " ${SRC_ROOT}/scripts/Python/interface/SBError.i"\
 " ${SRC_ROOT}/scripts/Python/interface/SBEvent.i"\
+" ${SRC_ROOT}/scripts/Python/interface/SBExpressionOptions.i"\
 " ${SRC_ROOT}/scripts/Python/interface/SBFileSpec.i"\
 " ${SRC_ROOT}/scripts/Python/interface/SBFrame.i"\
 " ${SRC_ROOT}/scripts/Python/interface/SBFunction.i"\
diff --git a/lldb/scripts/Python/interface/SBExpressionOptions.i b/lldb/scripts/Python/interface/SBExpressionOptions.i
new file mode 100644 (file)
index 0000000..fa58fe3
--- /dev/null
@@ -0,0 +1,104 @@
+//===-- SWIG interface for SBExpressionOptions -----------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+namespace lldb {
+
+%feature("docstring",
+"A container for options to use when evaluating expressions."
+) SBExpressionOptions;
+
+class SBExpressionOptions
+{
+friend class SBFrame;
+friend class SBValue;
+
+public:
+    SBExpressionOptions();
+
+    SBExpressionOptions (const lldb::SBExpressionOptions &rhs);
+    
+    SBExpressionOptions (bool coerce_to_id,
+                         bool unwind_on_error,
+                         bool keep_in_memory,
+                         bool run_others,
+                         DynamicValueType use_dynamic,
+                         uint32_t timeout_usec);
+
+    ~SBExpressionOptions();
+
+    bool
+    DoesCoerceToId () const;
+    
+    %feature("docstring",
+    "Sets whether to coerce the expression result to ObjC id type after evaluation."
+    ) SetCoerceToId;
+    void
+    SetCoerceToId (bool coerce = true);
+    
+    bool
+    DoesUnwindOnError () const;
+    
+    %feature("docstring",
+    "Sets whether to unwind the expression stack on error."
+    ) SetUnwindOnError;
+    void
+    SetUnwindOnError (bool unwind = false);
+    
+    bool
+    DoesKeepInMemory () const;
+    
+    %feature("docstring",
+    "Sets whether to keep the expression result in the target program's memory - forced to true when creating SBValues."
+    ) SetKeepInMemory;
+    void
+    SetKeepInMemory (bool keep = true);
+
+    lldb::DynamicValueType
+    GetUseDynamic () const;
+    
+    %feature("docstring",
+    "Sets whether to cast the expression result to its dynamic type."
+    ) SetUseDynamic;
+    void
+    SetUseDynamic (lldb::DynamicValueType dynamic = lldb::eDynamicCanRunTarget);
+    
+    uint32_t
+    GetTimeoutUsec () const;
+    
+    %feature("docstring",
+    "Sets the duration we will wait before cancelling expression evaluation.  0 means wait forever."
+    ) SetTimeoutUsec;
+    void
+    SetTimeoutUsec (uint32_t timeout = 0);
+    
+    bool
+    GetRunOthers () const;
+    
+    %feature("docstring",
+    "Sets whether to run all threads if the expression does not complete on one thread."
+    ) SetRunOthers;
+    void
+    SetRunOthers (bool run_others = true);
+
+protected:
+
+    SBExpressionOptions (lldb_private::EvaluateExpressionOptions &expression_options);
+
+    lldb_private::EvaluateExpressionOptions *
+    get () const;
+
+    lldb_private::EvaluateExpressionOptions &
+    ref () const;
+
+private:
+    // This auto_pointer is made in the constructor and is always valid.
+    mutable std::auto_ptr<lldb_private::EvaluateExpressionOptions> m_opaque_ap;
+};
+
+} // namespace lldb
index 7d02564..1735dd9 100644 (file)
@@ -139,6 +139,9 @@ public:
 
     lldb::SBValue
     EvaluateExpression (const char *expr, lldb::DynamicValueType use_dynamic, bool unwind_on_error);
+    
+    lldb::SBValue
+    EvaluateExpression (const char *expr, SBExpressionOptions &options);
 
     %feature("docstring", "
     /// Gets the lexical block that defines the stack frame. Another way to think
index e316637..70c3d80 100644 (file)
@@ -222,6 +222,9 @@ public:
 
     lldb::SBValue
     CreateValueFromExpression (const char *name, const char* expression);
+    
+    lldb::SBValue
+    CreateValueFromExpression (const char *name, const char* expression, SBExpressionOptions &options);
 
     lldb::SBValue
     CreateValueFromAddress(const char* name, lldb::addr_t address, lldb::SBType type);
index 12dc859..a89b675 100644 (file)
@@ -66,6 +66,7 @@ import os
 #include "lldb/API/SBDeclaration.h"
 #include "lldb/API/SBError.h"
 #include "lldb/API/SBEvent.h"
+#include "lldb/API/SBExpressionOptions.h"
 #include "lldb/API/SBFileSpec.h"
 #include "lldb/API/SBFileSpecList.h"
 #include "lldb/API/SBFrame.h"
@@ -125,6 +126,7 @@ import os
 %include "./Python/interface/SBDeclaration.i"
 %include "./Python/interface/SBError.i"
 %include "./Python/interface/SBEvent.i"
+%include "./Python/interface/SBExpressionOptions.i"
 %include "./Python/interface/SBFileSpec.i"
 %include "./Python/interface/SBFileSpecList.i"
 %include "./Python/interface/SBFrame.i"
diff --git a/lldb/source/API/SBExpressionOptions.cpp b/lldb/source/API/SBExpressionOptions.cpp
new file mode 100644 (file)
index 0000000..2a4b9f5
--- /dev/null
@@ -0,0 +1,142 @@
+//===-- SBExpressionOptions.cpp ---------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/API/SBExpressionOptions.h"
+#include "lldb/API/SBStream.h"
+
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+SBExpressionOptions::SBExpressionOptions ()
+{
+    m_opaque_ap.reset(new EvaluateExpressionOptions());
+}
+
+SBExpressionOptions::SBExpressionOptions (bool coerce_to_id,
+                         bool unwind_on_error,
+                         bool keep_in_memory,
+                         bool run_others,
+                         DynamicValueType use_dynamic,
+                         uint32_t timeout_usec)
+{
+    m_opaque_ap.reset(new EvaluateExpressionOptions());
+    m_opaque_ap->SetCoerceToId(coerce_to_id);
+    m_opaque_ap->SetUnwindOnError(unwind_on_error);
+    m_opaque_ap->SetKeepInMemory(keep_in_memory);
+    m_opaque_ap->SetRunOthers(run_others);
+    m_opaque_ap->SetUseDynamic (use_dynamic);
+    m_opaque_ap->SetTimeoutUsec (timeout_usec);
+}
+
+SBExpressionOptions::SBExpressionOptions (const SBExpressionOptions &rhs)
+{
+    m_opaque_ap.reset(new EvaluateExpressionOptions());
+    *(m_opaque_ap.get()) = rhs.ref();
+}
+
+const SBExpressionOptions &
+SBExpressionOptions::operator = (const SBExpressionOptions &rhs)
+{
+    if (this != &rhs)
+    {
+        this->ref() = rhs.ref();
+    }
+    return *this;
+}
+
+SBExpressionOptions::~SBExpressionOptions()
+{
+}
+
+bool
+SBExpressionOptions::DoesCoerceToId () const
+{
+    return m_opaque_ap->DoesCoerceToId ();
+}
+
+void
+SBExpressionOptions::SetCoerceToId (bool coerce)
+{
+    m_opaque_ap->SetCoerceToId (coerce);
+}
+
+bool
+SBExpressionOptions::DoesUnwindOnError () const
+{
+    return m_opaque_ap->DoesUnwindOnError ();
+}
+
+void
+SBExpressionOptions::SetUnwindOnError (bool unwind)
+{
+    m_opaque_ap->SetUnwindOnError (unwind);
+}
+
+bool
+SBExpressionOptions::DoesKeepInMemory () const
+{
+    return m_opaque_ap->DoesKeepInMemory ();
+}
+
+void
+SBExpressionOptions::SetKeepInMemory (bool keep)
+{
+    m_opaque_ap->SetKeepInMemory (keep);
+}
+
+lldb::DynamicValueType
+SBExpressionOptions::GetUseDynamic () const
+{
+    return m_opaque_ap->GetUseDynamic ();
+}
+
+void
+SBExpressionOptions::SetUseDynamic (lldb::DynamicValueType dynamic)
+{
+    m_opaque_ap->SetUseDynamic (dynamic);
+}
+
+uint32_t
+SBExpressionOptions::GetTimeoutUsec () const
+{
+    return m_opaque_ap->GetTimeoutUsec ();
+}
+
+void
+SBExpressionOptions::SetTimeoutUsec (uint32_t timeout)
+{
+    m_opaque_ap->SetTimeoutUsec (timeout);
+}
+
+bool
+SBExpressionOptions::GetRunOthers () const
+{
+    return m_opaque_ap->GetRunOthers ();
+}
+
+void
+SBExpressionOptions::SetRunOthers (bool run_others)
+{
+    m_opaque_ap->SetRunOthers (run_others);
+}
+
+EvaluateExpressionOptions *
+SBExpressionOptions::get() const
+{
+    return m_opaque_ap.get();
+}
+
+EvaluateExpressionOptions &
+SBExpressionOptions::ref () const
+{
+    return *(m_opaque_ap.get());
+}
index b94a0ce..f89c25b 100644 (file)
@@ -40,6 +40,7 @@
 #include "lldb/API/SBDebugger.h"
 #include "lldb/API/SBValue.h"
 #include "lldb/API/SBAddress.h"
+#include "lldb/API/SBExpressionOptions.h"
 #include "lldb/API/SBStream.h"
 #include "lldb/API/SBSymbolContext.h"
 #include "lldb/API/SBThread.h"
@@ -1040,8 +1041,11 @@ SBFrame::EvaluateExpression (const char *expr)
     Target *target = exe_ctx.GetTargetPtr();
     if (frame && target)
     {
-        lldb::DynamicValueType use_dynamic = frame->CalculateTarget()->GetPreferDynamicValue();
-        result = EvaluateExpression (expr, use_dynamic);
+        SBExpressionOptions options;
+        lldb::DynamicValueType fetch_dynamic_value = frame->CalculateTarget()->GetPreferDynamicValue();
+        options.SetUseDynamic (fetch_dynamic_value);
+        options.SetUnwindOnError (true);
+        return EvaluateExpression (expr, options);
     }
     return result;
 }
@@ -1049,12 +1053,24 @@ SBFrame::EvaluateExpression (const char *expr)
 SBValue
 SBFrame::EvaluateExpression (const char *expr, lldb::DynamicValueType fetch_dynamic_value)
 {
-    return EvaluateExpression (expr, fetch_dynamic_value, true);
+    SBExpressionOptions options;
+    options.SetUseDynamic (fetch_dynamic_value);
+    options.SetUnwindOnError (true);
+    return EvaluateExpression (expr, options);
 }
 
 SBValue
 SBFrame::EvaluateExpression (const char *expr, lldb::DynamicValueType fetch_dynamic_value, bool unwind_on_error)
 {
+    SBExpressionOptions options;
+    options.SetUseDynamic (fetch_dynamic_value);
+    options.SetUnwindOnError (unwind_on_error);
+    return EvaluateExpression (expr, options);
+}
+
+lldb::SBValue
+SBFrame::EvaluateExpression (const char *expr, const SBExpressionOptions &options)
+{
     LogSP log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
     
     LogSP expr_log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
@@ -1080,16 +1096,12 @@ SBFrame::EvaluateExpression (const char *expr, lldb::DynamicValueType fetch_dyna
             StreamString frame_description;
             frame->DumpUsingSettingsFormat (&frame_description);
             Host::SetCrashDescriptionWithFormat ("SBFrame::EvaluateExpression (expr = \"%s\", fetch_dynamic_value = %u) %s",
-                                                 expr, fetch_dynamic_value, frame_description.GetString().c_str());
+                                                 expr, options.GetUseDynamic(), frame_description.GetString().c_str());
 #endif
-            Target::EvaluateExpressionOptions options;
-            options.SetUnwindOnError(unwind_on_error)
-            .SetUseDynamic(fetch_dynamic_value);
-            
             exe_results = target->EvaluateExpression (expr, 
                                                       frame,
                                                       expr_value_sp,
-                                                      options);
+                                                      options.ref());
             expr_result.SetSP(expr_value_sp);
 #ifdef LLDB_CONFIGURATION_DEBUG
             Host::SetCrashDescription (NULL);
index 913a447..0aa01a6 100644 (file)
 #include "lldb/Target/Target.h"
 #include "lldb/Target/Thread.h"
 
+#include "lldb/API/SBDebugger.h"
+#include "lldb/API/SBExpressionOptions.h"
+#include "lldb/API/SBFrame.h"
 #include "lldb/API/SBProcess.h"
 #include "lldb/API/SBTarget.h"
 #include "lldb/API/SBThread.h"
-#include "lldb/API/SBFrame.h"
-#include "lldb/API/SBDebugger.h"
 
 using namespace lldb;
 using namespace lldb_private;
@@ -694,9 +695,12 @@ SBValue::CreateChildAtOffset (const char *name, uint32_t offset, SBType type)
     if (log)
     {
         if (new_value_sp)
-            log->Printf ("SBValue(%p)::CreateChildAtOffset => \"%s\"", value_sp.get(), new_value_sp->GetName().AsCString());
+            log->Printf ("SBValue(%p)::CreateChildAtOffset => \"%s\"",
+                         value_sp.get(),
+                         new_value_sp->GetName().AsCString());
         else
-            log->Printf ("SBValue(%p)::CreateChildAtOffset => NULL", value_sp.get());
+            log->Printf ("SBValue(%p)::CreateChildAtOffset => NULL",
+                         value_sp.get());
     }
     return sb_value;
 }
@@ -715,6 +719,14 @@ SBValue::Cast (SBType type)
 lldb::SBValue
 SBValue::CreateValueFromExpression (const char *name, const char* expression)
 {
+    SBExpressionOptions options;
+    options.SetKeepInMemory(true);
+    return CreateValueFromExpression (name, expression, options);
+}
+
+lldb::SBValue
+SBValue::CreateValueFromExpression (const char *name, const char *expression, SBExpressionOptions &options)
+{
     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
     lldb::SBValue sb_value;
     lldb::ValueObjectSP value_sp(GetSP());
@@ -734,12 +746,11 @@ SBValue::CreateValueFromExpression (const char *name, const char* expression)
             Target* target = exe_ctx.GetTargetPtr();
             if (target)
             {
-                Target::EvaluateExpressionOptions options;
                 options.SetKeepInMemory(true);
                 target->EvaluateExpression (expression,
                                             exe_ctx.GetFramePtr(),
                                             new_value_sp,
-                                            options);
+                                            options.ref());
                 if (new_value_sp)
                 {
                     new_value_sp->SetName(ConstString(name));
@@ -1617,7 +1628,9 @@ SBValue::GetAddress()
     }
     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
     if (log)
-        log->Printf ("SBValue(%p)::GetAddress () => (%s,%llu)", value_sp.get(), (addr.GetSection() ? addr.GetSection()->GetName().GetCString() : "NULL"), addr.GetOffset());
+        log->Printf ("SBValue(%p)::GetAddress () => (%s,%llu)", value_sp.get(),
+                     (addr.GetSection() ? addr.GetSection()->GetName().GetCString() : "NULL"),
+                     addr.GetOffset());
     return SBAddress(new Address(addr));
 }
 
index 23c9dc1..ee05360 100644 (file)
@@ -50,7 +50,9 @@ CommandObjectExpression::CommandOptions::~CommandOptions ()
 OptionDefinition
 CommandObjectExpression::CommandOptions::g_option_table[] =
 {
+    { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "all-threads",        'a', required_argument, NULL, 0, eArgTypeBoolean,    "Should we run all threads if the execution doesn't complete on one thread."},
     { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "dynamic-value",      'd', required_argument, NULL, 0, eArgTypeBoolean,    "Upcast the value resulting from the expression to its dynamic type if available."},
+    { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "timeout",            't', required_argument, NULL, 0, eArgTypeUnsignedInteger,  "Timeout value for running the expression."},
     { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "unwind-on-error",    'u', required_argument, NULL, 0, eArgTypeBoolean,    "Clean up program state if the expression causes a crash, breakpoint hit or signal."},
     { LLDB_OPT_SET_2                 , false, "object-description", 'o', no_argument,       NULL, 0, eArgTypeNone,       "Print the object description of the value resulting from the expression."},
 };
@@ -80,8 +82,16 @@ CommandObjectExpression::CommandOptions::SetOptionValue (CommandInterpreter &int
       //}
       //break;
 
-    case 'o':
-        print_object = true;
+    case 'a':
+        {
+            bool success;
+            bool result;
+            result = Args::StringToBoolean(option_arg, true, &success);
+            if (!success)
+                error.SetErrorStringWithFormat("invalid all-threads value setting: \"%s\"", option_arg);
+            else
+                try_all_threads = result;
+        }
         break;
         
     case 'd':
@@ -101,6 +111,22 @@ CommandObjectExpression::CommandOptions::SetOptionValue (CommandInterpreter &int
         }
         break;
         
+    case 'o':
+        print_object = true;
+        break;
+        
+    case 't':
+        {
+            bool success;
+            uint32_t result;
+            result = Args::StringToUInt32(option_arg, 0, 0, &success);
+            if (success)
+                timeout = result;
+            else
+                error.SetErrorStringWithFormat ("invalid timeout setting \"%s\"", option_arg);
+        }
+        break;
+        
     case 'u':
         {
             bool success;
@@ -125,6 +151,8 @@ CommandObjectExpression::CommandOptions::OptionParsingStarting (CommandInterpret
     unwind_on_error = true;
     show_types = true;
     show_summary = true;
+    try_all_threads = true;
+    timeout = 0;
 }
 
 const OptionDefinition*
@@ -146,7 +174,13 @@ CommandObjectExpression::CommandObjectExpression (CommandInterpreter &interprete
     m_expr_lines ()
 {
   SetHelpLong(
-"Examples: \n\
+"Timeouts:\n\
+    If the expression can be evaluated statically (without runnning code) then it will be.\n\
+    Otherwise, by default the expression will run on the current thread with a short timeout:\n\
+    currently .25 seconds.  If it doesn't return in that time, the evaluation will be interrupted\n\
+    and resumed with all threads running.  You can use the -a option to disable retrying on all\n\
+    threads.  You can use the -t option to set a shorter timeout.\n\
+Examples: \n\
 \n\
    expr my_struct->a = my_array[3] \n\
    expr -f bin -- (index * 8) + 5 \n\
@@ -298,12 +332,13 @@ CommandObjectExpression::EvaluateExpression
             break;
         }
         
-        Target::EvaluateExpressionOptions options;
+        EvaluateExpressionOptions options;
         options.SetCoerceToId(m_command_options.print_object)
         .SetUnwindOnError(m_command_options.unwind_on_error)
         .SetKeepInMemory(keep_in_memory)
         .SetUseDynamic(use_dynamic)
-        .SetSingleThreadTimeoutUsec(0);
+        .SetRunOthers(m_command_options.try_all_threads)
+        .SetTimeoutUsec(m_command_options.timeout);
         
         exe_results = target->EvaluateExpression (expr, 
                                                   m_interpreter.GetExecutionContext().GetFramePtr(),
index 7c15aa1..4ccadfc 100644 (file)
@@ -55,6 +55,8 @@ public:
         bool        unwind_on_error;
         bool        show_types;
         bool        show_summary;
+        uint32_t    timeout;
+        bool        try_all_threads;
     };
 
     CommandObjectExpression (CommandInterpreter &interpreter);
index 8c2be37..0547d38 100644 (file)
@@ -1314,7 +1314,7 @@ protected:
         if (command && command[0] != '\0')
         {
             Target *target = exe_ctx.GetTargetPtr();
-            Target::EvaluateExpressionOptions options;
+            EvaluateExpressionOptions options;
 
             options.SetUnwindOnError(true);
             options.SetUseDynamic(eNoDynamicValues);
index 8a74471..63275f9 100644 (file)
@@ -1234,11 +1234,12 @@ protected:
         }
 
         // Use expression evaluation to arrive at the address to watch.
-        Target::EvaluateExpressionOptions options;
+        EvaluateExpressionOptions options;
         options.SetCoerceToId(false)
         .SetUnwindOnError(true)
         .SetKeepInMemory(false)
-        .SetSingleThreadTimeoutUsec(0);
+        .SetRunOthers(true)
+        .SetTimeoutUsec(0);
         
         ExecutionResults expr_result = target->EvaluateExpression (expr_str.c_str(), 
                                                                    frame, 
index d8b929e..67f7698 100644 (file)
@@ -47,7 +47,7 @@ lldb_private::formatters::ExtractValueFromObjCExpression (ValueObject &valobj,
     if (!target || !stack_frame)
         return false;
     
-    Target::EvaluateExpressionOptions options;
+    EvaluateExpressionOptions options;
     options.SetCoerceToId(false)
     .SetUnwindOnError(true)
     .SetKeepInMemory(true)
@@ -85,7 +85,7 @@ lldb_private::formatters::CallSelectorOnObject (ValueObject &valobj,
     if (!target || !stack_frame)
         return valobj_sp;
     
-    Target::EvaluateExpressionOptions options;
+    EvaluateExpressionOptions options;
     options.SetCoerceToId(false)
     .SetUnwindOnError(true)
     .SetKeepInMemory(true)
@@ -122,7 +122,7 @@ lldb_private::formatters::CallSelectorOnObject (ValueObject &valobj,
     if (!target || !stack_frame)
         return valobj_sp;
     
-    Target::EvaluateExpressionOptions options;
+    EvaluateExpressionOptions options;
     options.SetCoerceToId(false)
     .SetUnwindOnError(true)
     .SetKeepInMemory(true)
@@ -459,7 +459,7 @@ lldb_private::formatters::NSNumberSummaryProvider (ValueObject& valobj, Stream&
         if (!target || !stack_frame)
             return false;
         
-        Target::EvaluateExpressionOptions options;
+        EvaluateExpressionOptions options;
         options.SetCoerceToId(false)
         .SetUnwindOnError(true)
         .SetKeepInMemory(true)
@@ -1055,7 +1055,7 @@ lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::GetChildAtIn
     object_fetcher_expr.Printf("struct __lldb_autogen_nspair { id key; id value; } _lldb_valgen_item; _lldb_valgen_item.key = %s; _lldb_valgen_item.value = %s; _lldb_valgen_item;",key_fetcher_expr.GetData(),value_fetcher_expr.GetData());
     lldb::ValueObjectSP child_sp;
     m_backend.GetTargetSP()->EvaluateExpression(object_fetcher_expr.GetData(), m_backend.GetFrameSP().get(), child_sp,
-                                                Target::EvaluateExpressionOptions().SetKeepInMemory(true));
+                                                EvaluateExpressionOptions().SetKeepInMemory(true));
     if (child_sp)
         child_sp->SetName(ConstString(idx_name.GetData()));
     return child_sp;
index 62e4e8a..1909dc2 100644 (file)
@@ -485,13 +485,13 @@ ExecutionResults
 ClangFunction::ExecuteFunction(
         ExecutionContext &exe_ctx, 
         Stream &errors, 
-        uint32_t single_thread_timeout_usec, 
+        uint32_t timeout_usec, 
         bool try_all_threads, 
         Value &results)
 {
     const bool stop_others = true;
     const bool discard_on_error = true;
-    return ExecuteFunction (exe_ctx, NULL, errors, stop_others, single_thread_timeout_usec, 
+    return ExecuteFunction (exe_ctx, NULL, errors, stop_others, timeout_usec,
                             try_all_threads, discard_on_error, results);
 }
 
@@ -504,7 +504,7 @@ ClangFunction::ExecuteFunction (
         bool stop_others,
         bool try_all_threads,
         bool discard_on_error,
-        uint32_t single_thread_timeout_usec,
+        uint32_t timeout_usec,
         Stream &errors,
         lldb::addr_t *this_arg)
 {
@@ -529,7 +529,7 @@ ClangFunction::ExecuteFunction (
                                                                       stop_others, 
                                                                       try_all_threads, 
                                                                       discard_on_error,
-                                                                      single_thread_timeout_usec, 
+                                                                      timeout_usec,
                                                                       errors);
     
     if (exe_ctx.GetProcessPtr())
@@ -544,7 +544,7 @@ ClangFunction::ExecuteFunction(
         lldb::addr_t *args_addr_ptr, 
         Stream &errors, 
         bool stop_others, 
-        uint32_t single_thread_timeout_usec, 
+        uint32_t timeout_usec, 
         bool try_all_threads,
         bool discard_on_error, 
         Value &results)
@@ -574,7 +574,7 @@ ClangFunction::ExecuteFunction(
                                                    stop_others, 
                                                    try_all_threads, 
                                                    discard_on_error, 
-                                                   single_thread_timeout_usec, 
+                                                   timeout_usec, 
                                                    errors);
 
     if (args_addr_ptr != NULL)
index c037d02..4507282 100644 (file)
@@ -544,7 +544,8 @@ ClangUserExpression::Execute (Stream &error_stream,
                               bool discard_on_error,
                               ClangUserExpression::ClangUserExpressionSP &shared_ptr_to_me,
                               lldb::ClangExpressionVariableSP &result,
-                              uint32_t single_thread_timeout_usec)
+                              bool run_others,
+                              uint32_t timeout_usec)
 {
     // The expression log is quite verbose, and if you're just tracking the execution of the
     // expression, it's quite convenient to have these logs come out with the STEP log as well.
@@ -594,7 +595,7 @@ ClangUserExpression::Execute (Stream &error_stream,
                                                                                    stop_others, 
                                                                                    try_all_threads, 
                                                                                    discard_on_error,
-                                                                                   single_thread_timeout_usec, 
+                                                                                   timeout_usec, 
                                                                                    error_stream);
         
         if (exe_ctx.GetProcessPtr())
@@ -655,10 +656,21 @@ ClangUserExpression::Evaluate (ExecutionContext &exe_ctx,
                                const char *expr_cstr,
                                const char *expr_prefix,
                                lldb::ValueObjectSP &result_valobj_sp,
-                               uint32_t single_thread_timeout_usec)
+                               bool run_others,
+                               uint32_t timeout_usec)
 {
     Error error;
-    return EvaluateWithError (exe_ctx, execution_policy, language, desired_type, discard_on_error, expr_cstr, expr_prefix, result_valobj_sp, error, single_thread_timeout_usec);
+    return EvaluateWithError (exe_ctx,
+                              execution_policy,
+                              language,
+                              desired_type,
+                              discard_on_error,
+                              expr_cstr,
+                              expr_prefix,
+                              result_valobj_sp,
+                              error,
+                              run_others,
+                              timeout_usec);
 }
 
 ExecutionResults
@@ -671,7 +683,8 @@ ClangUserExpression::EvaluateWithError (ExecutionContext &exe_ctx,
                                         const char *expr_prefix,
                                         lldb::ValueObjectSP &result_valobj_sp,
                                         Error &error,
-                                        uint32_t single_thread_timeout_usec)
+                                        bool run_others,
+                                        uint32_t timeout_usec)
 {
     lldb::LogSP log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EXPRESSIONS | LIBLLDB_LOG_STEP));
 
@@ -747,7 +760,8 @@ ClangUserExpression::EvaluateWithError (ExecutionContext &exe_ctx,
                                                              discard_on_error,
                                                              user_expression_sp, 
                                                              expr_result,
-                                                             single_thread_timeout_usec);
+                                                             run_others,
+                                                             timeout_usec);
             
             if (execution_results != eExecutionCompleted)
             {
index 453004d..461f821 100644 (file)
@@ -1308,11 +1308,12 @@ CommandInterpreter::PreprocessCommand (std::string &command)
                 {
                     ValueObjectSP expr_result_valobj_sp;
                     
-                    Target::EvaluateExpressionOptions options;
+                    EvaluateExpressionOptions options;
                     options.SetCoerceToId(false)
                     .SetUnwindOnError(true)
                     .SetKeepInMemory(false)
-                    .SetSingleThreadTimeoutUsec(0);
+                    .SetRunOthers(true)
+                    .SetTimeoutUsec(0);
                     
                     ExecutionResults expr_result = target->EvaluateExpression (expr_str.c_str(), 
                                                                                exe_ctx.GetFramePtr(),
index 4d634f4..040058b 100644 (file)
@@ -50,7 +50,7 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr,
             const bool stop_other_threads = true;
             const bool discard_on_error = true;
             const bool try_all_threads = true;
-            const uint32_t single_thread_timeout_usec = 500000;
+            const uint32_t timeout_usec = 500000;
 
             addr_t prot_arg, flags_arg = 0;
             if (prot == eMmapProtNone)
@@ -105,7 +105,7 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr,
                                                                           stop_other_threads,
                                                                           try_all_threads,
                                                                           discard_on_error,
-                                                                          single_thread_timeout_usec,
+                                                                          timeout_usec,
                                                                           error_strm);
                         if (result == eExecutionCompleted)
                         {
@@ -154,7 +154,7 @@ bool lldb_private::InferiorCallMunmap(Process *process, addr_t addr,
            const bool stop_other_threads = true;
            const bool discard_on_error = true;
            const bool try_all_threads = true;
-           const uint32_t single_thread_timeout_usec = 500000;
+           const uint32_t timeout_usec = 500000;
            
            AddressRange munmap_range;
            if (sc.GetAddressRange(range_scope, 0, use_inline_block_range, munmap_range))
@@ -183,7 +183,7 @@ bool lldb_private::InferiorCallMunmap(Process *process, addr_t addr,
                                                                          stop_other_threads,
                                                                          try_all_threads,
                                                                          discard_on_error,
-                                                                         single_thread_timeout_usec,
+                                                                         timeout_usec,
                                                                          error_strm);
                        if (result == eExecutionCompleted)
                        {
index 3b37796..e77a898 100644 (file)
@@ -4133,9 +4133,9 @@ ExecutionResults
 Process::RunThreadPlan (ExecutionContext &exe_ctx,
                         lldb::ThreadPlanSP &thread_plan_sp,
                         bool stop_others,
-                        bool try_all_threads,
+                        bool run_others,
                         bool discard_on_error,
-                        uint32_t single_thread_timeout_usec,
+                        uint32_t timeout_usec,
                         Stream &errors)
 {
     ExecutionResults return_value = eExecutionSetupError;
@@ -4260,6 +4260,8 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
         
         bool first_timeout = true;
         bool do_resume = true;
+        const uint64_t default_one_thread_timeout_usec = 250000;
+        uint64_t computed_timeout = 0;
         
         while (1)
         {
@@ -4298,9 +4300,12 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
                 if (stop_state != eStateRunning)
                 {
                     if (log)
-                        log->Printf("Process::RunThreadPlan(): didn't get running event after initial resume, got %s instead.", StateAsCString(stop_state));
+                        log->Printf("Process::RunThreadPlan(): didn't get running event after "
+                                    "initial resume, got %s instead.",
+                                    StateAsCString(stop_state));
 
-                    errors.Printf("Didn't get running event after initial resume, got %s instead.", StateAsCString(stop_state));
+                    errors.Printf("Didn't get running event after initial resume, got %s instead.",
+                                  StateAsCString(stop_state));
                     return_value = eExecutionSetupError;
                     break;
                 }
@@ -4313,28 +4318,45 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
                 // We set the timeout AFTER the resume, since the resume takes some time and we
                 // don't want to charge that to the timeout.
                 
-                if (single_thread_timeout_usec != 0)
+                if (first_timeout)
                 {
-                    // we have a > 0 timeout, let us set it so that we stop after the deadline
-                    real_timeout = TimeValue::Now();
-                    real_timeout.OffsetWithMicroSeconds(single_thread_timeout_usec);
-                        
-                    timeout_ptr = &real_timeout;
+                    if (run_others)
+                    {
+                        // If we are running all threads then we take half the time to run all threads, bounded by
+                        // .25 sec.
+                        if (timeout_usec == 0)
+                            computed_timeout = default_one_thread_timeout_usec;
+                        else
+                        {
+                            computed_timeout = timeout_usec / 2;
+                            if (computed_timeout > default_one_thread_timeout_usec)
+                            {
+                                computed_timeout = default_one_thread_timeout_usec;
+                            }
+                            timeout_usec -= computed_timeout;
+                        }
+                    }
+                    else
+                    {
+                        computed_timeout = timeout_usec;
+                    }
+                }
+                else
+                {
+                    computed_timeout = timeout_usec;
                 }
-                else if (first_timeout)
+                
+                if (computed_timeout != 0)
                 {
-                    // if we are willing to wait "forever" we still need to have an initial timeout
-                    // this timeout is going to induce all threads to run when hit. we do this so that
-                    // we can avoid ending locked up because of multithreaded contention issues
+                    // we have a > 0 timeout, let us set it so that we stop after the deadline
                     real_timeout = TimeValue::Now();
-                    real_timeout.OffsetWithNanoSeconds(500000000UL);
+                    real_timeout.OffsetWithMicroSeconds(computed_timeout);
+                        
                     timeout_ptr = &real_timeout;
                 }
                 else
                 {
-                    timeout_ptr = NULL; // if we are in a no-timeout scenario, then we only need a fake timeout the first time through
-                    // at this point in the code, all threads will be running so we are willing to wait forever, and do not
-                    // need a timeout
+                    timeout_ptr = NULL;
                 }
             }
             else
@@ -4471,21 +4493,21 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
                 // Not really sure what to do if Halt fails here...
                 
                 if (log) {
-                    if (try_all_threads)
+                    if (run_others)
                     {
                         if (first_timeout)
-                            log->Printf ("Process::RunThreadPlan(): Running function with timeout: %d timed out, "
-                                         "trying with all threads enabled.",
-                                         single_thread_timeout_usec);
+                            log->Printf ("Process::RunThreadPlan(): Running function with timeout: %lld timed out, "
+                                         "trying  for %d usec with all threads enabled.",
+                                         computed_timeout, timeout_usec);
                         else
                             log->Printf ("Process::RunThreadPlan(): Restarting function with all threads enabled "
-                                         "and timeout: %d timed out.",
-                                         single_thread_timeout_usec);
+                                         "and timeout: %d timed out, abandoning execution.",
+                                         timeout_usec);
                     }
                     else
                         log->Printf ("Process::RunThreadPlan(): Running function with timeout: %d timed out, "
-                                     "halt and abandoning execution.", 
-                                     single_thread_timeout_usec);
+                                     "abandoning execution.", 
+                                     timeout_usec);
                 }
                 
                 Error halt_error = Halt();
@@ -4526,7 +4548,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
                                 break;
                             }
 
-                            if (!try_all_threads)
+                            if (!run_others)
                             {
                                 if (log)
                                     log->PutCString ("Process::RunThreadPlan(): try_all_threads was false, we stopped so now we're quitting.");
index 8a89687..0dd3463 100644 (file)
@@ -1747,7 +1747,8 @@ Target::EvaluateExpression
                                                                expr_cstr, 
                                                                prefix, 
                                                                result_valobj_sp,
-                                                               options.GetSingleThreadTimeoutUsec());
+                                                               options.GetRunOthers(),
+                                                               options.GetTimeoutUsec());
         }
     }
     
diff --git a/lldb/test/expression_command/timeout/Makefile b/lldb/test/expression_command/timeout/Makefile
new file mode 100644 (file)
index 0000000..1cd6782
--- /dev/null
@@ -0,0 +1,5 @@
+LEVEL = ../../make
+
+C_SOURCES := wait-a-while.c
+
+include $(LEVEL)/Makefile.rules
diff --git a/lldb/test/expression_command/timeout/TestCallWithTimeout.py b/lldb/test/expression_command/timeout/TestCallWithTimeout.py
new file mode 100644 (file)
index 0000000..fb9b7d0
--- /dev/null
@@ -0,0 +1,94 @@
+"""
+Test calling a function that waits a while, and make sure the timeout option to expr works.
+"""
+
+import unittest2
+import lldb
+import lldbutil
+from lldbtest import *
+
+class ExprCommandWithTimeoutsTestCase(TestBase):
+
+    mydir = os.path.join("expression_command", "timeout")
+
+    def setUp(self):
+        # Call super's setUp().
+        TestBase.setUp(self)
+
+        self.main_source = "wait-a-while.c"
+        self.main_source_spec = lldb.SBFileSpec (self.main_source)
+
+
+    @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
+    @dsym_test
+    def test_with_dsym(self):
+        """Test calling std::String member function."""
+        self.buildDsym()
+        self.call_function()
+
+    @dwarf_test
+    def test_with_dwarf(self):
+        """Test calling std::String member function."""
+        self.buildDsym()
+        self.call_function()
+
+    def call_function(self):
+        """Test calling function with timeout."""
+        exe_name = "a.out"
+        exe = os.path.join(os.getcwd(), exe_name)
+
+        target = self.dbg.CreateTarget(exe)
+        self.assertTrue(target, VALID_TARGET)
+
+        breakpoint = target.BreakpointCreateBySourceRegex('stop here in main.',self.main_source_spec)
+        self.assertTrue(breakpoint, VALID_BREAKPOINT)
+        self.runCmd("breakpoint list")
+
+        # Launch the process, and do not stop at the entry point.
+        process = target.LaunchSimple(None, None, os.getcwd())
+
+        self.assertTrue(process, PROCESS_IS_VALID)
+
+        # Frame #0 should be on self.step_out_of_malloc.
+        threads = lldbutil.get_threads_stopped_at_breakpoint (process, breakpoint)
+        
+        self.assertTrue(len(threads) == 1)
+        thread = threads[0]
+        
+        # First set the timeout too short, and make sure we fail.
+        options = lldb.SBExpressionOptions()
+        options.SetTimeoutUsec(100)
+        options.SetUnwindOnError(True)
+
+        frame = thread.GetFrameAtIndex(0)
+        
+        value = frame.EvaluateExpression ("wait_a_while (10000)", options)
+        self.assertTrue (value.IsValid())
+        self.assertTrue (value.GetError().Success() == False)
+
+        # Now do the same thing with the command line command, and make sure it works too.
+        interp = self.dbg.GetCommandInterpreter()
+
+        result = lldb.SBCommandReturnObject()
+        return_value = interp.HandleCommand ("expr -t 100 -u true -- wait_a_while(10000)", result)
+        self.assertTrue (return_value == lldb.eReturnStatusFailed)
+
+        # Okay, now do it again with long enough time outs:
+
+        options.SetTimeoutUsec(1000000)
+        value = frame.EvaluateExpression ("wait_a_while (1000)", options)
+        self.assertTrue(value.IsValid())
+        self.assertTrue (value.GetError().Success() == True)
+        
+        # Now do the same thingwith the command line command, and make sure it works too.
+        interp = self.dbg.GetCommandInterpreter()
+
+        result = lldb.SBCommandReturnObject()
+        return_value = interp.HandleCommand ("expr -t 1000000 -u true -- wait_a_while(1000)", result)
+        self.assertTrue(return_value == lldb.eReturnStatusSuccessFinishResult)
+
+if __name__ == '__main__':
+    import atexit
+    lldb.SBDebugger.Initialize()
+    atexit.register(lambda: lldb.SBDebugger.Terminate())
+    unittest2.main()
diff --git a/lldb/test/expression_command/timeout/wait-a-while.c b/lldb/test/expression_command/timeout/wait-a-while.c
new file mode 100644 (file)
index 0000000..f3475fc
--- /dev/null
@@ -0,0 +1,41 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <stdint.h>
+
+int 
+wait_a_while (useconds_t interval)
+{
+  int num_times = 0;
+  int return_value = 1;
+
+  struct timeval start_time;
+  gettimeofday(&start_time, NULL);
+  uint64_t target = start_time.tv_sec * 1000000 + start_time.tv_usec + interval;
+
+  while (1)
+    {
+      num_times++;
+      return_value = usleep (interval);
+      if (return_value != 0)
+        {
+          struct timeval now;
+          gettimeofday(&now, NULL);
+          interval = target - now.tv_sec * 1000000 + now.tv_usec;
+        }
+      else
+        break;
+    }
+  return num_times;
+}
+
+int
+main (int argc, char **argv)
+{
+  printf ("stop here in main.\n");
+  int num_times = wait_a_while (argc * 1000);
+  printf ("Done, took %d times.\n", num_times);
+
+  return 0;
+
+}