Skip to content
1 change: 1 addition & 0 deletions lldb/include/lldb/API/SBError.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ class LLDB_API SBError {
friend class SBDebugger;
friend class SBFile;
friend class SBFormat;
friend class SBFrame;
friend class SBHostOS;
friend class SBPlatform;
friend class SBProcess;
Expand Down
4 changes: 4 additions & 0 deletions lldb/include/lldb/API/SBFrame.h
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,10 @@ class LLDB_API SBFrame {

void SetFrameSP(const lldb::StackFrameSP &lldb_object_sp);

/// Return an SBValue containing an error message that warns the process is
/// not currently stopped.
static SBValue CreateProcessIsRunningExprEvalError();

lldb::ExecutionContextRefSP m_opaque_sp;
};

Expand Down
13 changes: 13 additions & 0 deletions lldb/include/lldb/Host/ProcessRunLock.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,22 @@ class ProcessRunLock {
class ProcessRunLocker {
public:
ProcessRunLocker() = default;
ProcessRunLocker(ProcessRunLocker &&other) : m_lock(other.m_lock) {
other.m_lock = nullptr;
}
ProcessRunLocker &operator=(ProcessRunLocker &&other) {
if (this != &other) {
Unlock();
m_lock = other.m_lock;
other.m_lock = nullptr;
}
return *this;
}

~ProcessRunLocker() { Unlock(); }

bool IsLocked() const { return m_lock; }

// Try to lock the read lock, but only do so if there are no writers.
bool TryLock(ProcessRunLock *lock) {
if (m_lock) {
Expand Down
56 changes: 48 additions & 8 deletions lldb/include/lldb/Target/ExecutionContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

#include <mutex>

#include "lldb/Host/ProcessRunLock.h"
#include "lldb/Target/StackID.h"
#include "lldb/lldb-private.h"

Expand Down Expand Up @@ -315,14 +316,6 @@ class ExecutionContext {
ExecutionContext(const ExecutionContextRef *exe_ctx_ref,
bool thread_and_frame_only_if_stopped = false);

// These two variants take in a locker, and grab the target, lock the API
// mutex into locker, then fill in the rest of the shared pointers.
ExecutionContext(const ExecutionContextRef &exe_ctx_ref,
std::unique_lock<std::recursive_mutex> &locker)
: ExecutionContext(&exe_ctx_ref, locker) {}

ExecutionContext(const ExecutionContextRef *exe_ctx_ref,
std::unique_lock<std::recursive_mutex> &locker);
// Create execution contexts from execution context scopes
ExecutionContext(ExecutionContextScope *exe_scope);
ExecutionContext(ExecutionContextScope &exe_scope);
Expand Down Expand Up @@ -566,6 +559,53 @@ class ExecutionContext {
lldb::StackFrameSP m_frame_sp; ///< The stack frame in thread.
};

/// A wrapper class representing an execution context with non-null Target
/// and Process pointers, a locked API mutex and a locked ProcessRunLock.
/// The locks are private by design: to unlock them, destroy the
/// StoppedExecutionContext.
struct StoppedExecutionContext : ExecutionContext {
StoppedExecutionContext(lldb::TargetSP &target_sp,
lldb::ProcessSP &process_sp,
lldb::ThreadSP &thread_sp,
lldb::StackFrameSP &frame_sp,
std::unique_lock<std::recursive_mutex> api_lock,
ProcessRunLock::ProcessRunLocker stop_locker)
: m_api_lock(std::move(api_lock)), m_stop_locker(std::move(stop_locker)) {
assert(target_sp);
assert(process_sp);
assert(m_api_lock.owns_lock());
assert(m_stop_locker.IsLocked());
SetTargetSP(target_sp);
SetProcessSP(process_sp);
SetThreadSP(thread_sp);
SetFrameSP(frame_sp);
}

/// Transfers ownership of the locks from `other` to `this`, making `other`
/// unusable.
StoppedExecutionContext(StoppedExecutionContext &&other)
: StoppedExecutionContext(other.m_target_sp, other.m_process_sp,
other.m_thread_sp, other.m_frame_sp,
std::move(other.m_api_lock),
std::move(other.m_stop_locker)) {
other.Clear();
}

/// Clears this context, unlocking the ProcessRunLock and returning the
/// locked API lock. Like after a move operation, this object is no longer
/// usable.
[[nodiscard]] std::unique_lock<std::recursive_mutex> Destroy();

private:
std::unique_lock<std::recursive_mutex> m_api_lock;
ProcessRunLock::ProcessRunLocker m_stop_locker;
};

llvm::Expected<StoppedExecutionContext>
GetStoppedExecutionContext(const ExecutionContextRef *exe_ctx_ref_ptr);
llvm::Expected<StoppedExecutionContext>
GetStoppedExecutionContext(const lldb::ExecutionContextRefSP &exe_ctx_ref_ptr);

} // namespace lldb_private

#endif // LLDB_TARGET_EXECUTIONCONTEXT_H
Loading
Loading