Skip to content
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
5 changes: 5 additions & 0 deletions lldb/include/lldb/Host/ProcessRunLock.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,14 @@ class ProcessRunLock {
class ProcessRunLocker {
public:
ProcessRunLocker() = default;
ProcessRunLocker(ProcessRunLocker &&other) : m_lock(other.m_lock) {
other.m_lock = nullptr;
}

~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
22 changes: 17 additions & 5 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,25 @@ 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.
/// These two variants take in an API lock and a process run lock.
/// If the ExecutionContextRef has a Target, the API lock will be acquired.
/// If the ExecutionContextRef also has a Process, an attempt to acquire
/// ProcessRunLock is made. If successful (i.e. the Process is stopped), frame
/// and thread information might be available.
/// As a corollary, if the ProcessRunLocker has been locked, this
/// ExecutionContext contains non-null Process and Target pointers.
/// If a Status object is provided, it will be updated if the
/// ExecutionContextRef/Process/Target are null, or if the process is running.
ExecutionContext(const ExecutionContextRef &exe_ctx_ref,
std::unique_lock<std::recursive_mutex> &locker)
: ExecutionContext(&exe_ctx_ref, locker) {}
std::unique_lock<std::recursive_mutex> &api_lock,
ProcessRunLock::ProcessRunLocker &stop_locker,
Status *status = nullptr)
: ExecutionContext(&exe_ctx_ref, api_lock, stop_locker, status) {}

ExecutionContext(const ExecutionContextRef *exe_ctx_ref,
std::unique_lock<std::recursive_mutex> &locker);
std::unique_lock<std::recursive_mutex> &api_lock,
ProcessRunLock::ProcessRunLocker &stop_locker,
Status *status = nullptr);
// Create execution contexts from execution context scopes
ExecutionContext(ExecutionContextScope *exe_scope);
ExecutionContext(ExecutionContextScope &exe_scope);
Expand Down
Loading
Loading