https://github.com/medismailben updated 
https://github.com/llvm/llvm-project/pull/195762

>From 53a4804a64912627bb46f9d0cbdce5362100ff11 Mon Sep 17 00:00:00 2001
From: Med Ismail Bennani <[email protected]>
Date: Tue, 5 May 2026 13:01:03 -0700
Subject: [PATCH] [lldb] Add Policy infrastructure

Add a generic thread-local policy stack and a Policy
struct that describes what view of the process a thread should see
(private reality vs public illusion) and what operations it is allowed
to perform.

This is the infrastructure for replacing ad-hoc host thread identity
checks (CurrentThreadIsPrivateStateThread, IsOnThread, etc.) with a
unified, composable mechanism. No behavioral changes yet -- adoption
will follow in subsequent patches.

rdar://176223894

Signed-off-by: Med Ismail Bennani <[email protected]>
---
 lldb/include/lldb/Target/Policy.h    | 114 +++++++++++++++++++++++++
 lldb/unittests/Target/CMakeLists.txt |   1 +
 lldb/unittests/Target/PolicyTest.cpp | 122 +++++++++++++++++++++++++++
 3 files changed, 237 insertions(+)
 create mode 100644 lldb/include/lldb/Target/Policy.h
 create mode 100644 lldb/unittests/Target/PolicyTest.cpp

diff --git a/lldb/include/lldb/Target/Policy.h 
b/lldb/include/lldb/Target/Policy.h
new file mode 100644
index 0000000000000..36084a1fc2cb7
--- /dev/null
+++ b/lldb/include/lldb/Target/Policy.h
@@ -0,0 +1,114 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_TARGET_POLICY_H
+#define LLDB_TARGET_POLICY_H
+
+#include "llvm/ADT/SmallVector.h"
+
+#include <cassert>
+
+namespace lldb_private {
+
+/// Describes what view of the process a thread should see and what
+/// operations it is allowed to perform.
+///
+/// Frame providers are a public illusion layered on top of the private
+/// reality (the unwinder stack). The private state thread manages the
+/// stop of that private reality, so the correct view for its logic IS the
+/// private reality. The public illusion is only applied once the process
+/// has settled and clients query the stopped state.
+///
+/// This struct is a pure data store -- no business logic. It is pushed
+/// onto a per-thread stack (PolicyStack) so that code
+/// can consult the current policy instead of comparing host thread
+/// identities.
+struct Policy {
+  /// What view of the process this thread sees.
+  enum class View {
+    Public,  ///< Provider-augmented frames, public state, public run lock.
+    Private, ///< Parent (unwinder) frames, private state, private run lock.
+  };
+
+  /// What operations this thread is allowed to perform.
+  /// Enforced at specific callsites, not by the policy itself.
+  struct Capabilities {
+    bool can_evaluate_expressions = true;
+    /// Whether expression evaluation may resume all threads to avoid
+    /// deadlocks (e.g. when a lock is held by another thread).
+    bool can_run_all_threads = true;
+    /// Whether the expression runner may fall back to running all threads
+    /// after a single-thread attempt times out.
+    bool can_try_all_threads = true;
+    bool can_run_breakpoint_actions = true;
+    bool can_load_frame_providers = true;
+    bool can_run_frame_recognizers = true;
+  };
+
+  View view = View::Public;
+  Capabilities capabilities;
+
+  static Policy PublicState() { return {}; }
+
+  static Policy PrivateState() {
+    Policy p;
+    p.view = View::Private;
+    p.capabilities.can_load_frame_providers = false;
+    p.capabilities.can_run_frame_recognizers = false;
+    return p;
+  }
+
+  static Policy PublicStateRunningExpression() {
+    Policy p;
+    p.capabilities.can_run_breakpoint_actions = false;
+    return p;
+  }
+};
+
+/// Per-thread policy stack.
+///
+/// The stack lives in thread_local storage. Each thread has its own stack,
+/// initialized with a default-constructed base entry that is never popped.
+/// RAII guards (Guard) push and pop policies.
+///
+/// For thread pool workers that don't inherit thread_local storage, the
+/// policy must be passed into the lambda and pushed onto the worker
+/// thread's stack when the task starts.
+class PolicyStack {
+public:
+  static PolicyStack &GetForCurrentThread() {
+    static thread_local PolicyStack s_stack;
+    return s_stack;
+  }
+
+  Policy Current() const { return m_stack.back(); }
+
+  void Push(Policy policy) { m_stack.push_back(std::move(policy)); }
+
+  void Pop() {
+    assert(!m_stack.empty() && "can't pop the last policy");
+    m_stack.pop_back();
+  }
+
+  /// RAII guard that pushes a policy on construction and pops on destruction.
+  class Guard {
+  public:
+    explicit Guard(Policy policy) { GetForCurrentThread().Push(policy); }
+    ~Guard() { GetForCurrentThread().Pop(); }
+
+    Guard(const Guard &) = delete;
+    Guard &operator=(const Guard &) = delete;
+  };
+
+private:
+  llvm::SmallVector<Policy> m_stack = {Policy{}};
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_TARGET_POLICY_H
diff --git a/lldb/unittests/Target/CMakeLists.txt 
b/lldb/unittests/Target/CMakeLists.txt
index bf08a8f015ba0..c4578e2fbfc77 100644
--- a/lldb/unittests/Target/CMakeLists.txt
+++ b/lldb/unittests/Target/CMakeLists.txt
@@ -9,6 +9,7 @@ add_lldb_unittest(TargetTests
   MemoryTagMapTest.cpp
   ModuleCacheTest.cpp
   PathMappingListTest.cpp
+  PolicyTest.cpp
   RegisterFlagsTest.cpp
   RemoteAwarePlatformTest.cpp
   ScratchTypeSystemTest.cpp
diff --git a/lldb/unittests/Target/PolicyTest.cpp 
b/lldb/unittests/Target/PolicyTest.cpp
new file mode 100644
index 0000000000000..e1291d185eb21
--- /dev/null
+++ b/lldb/unittests/Target/PolicyTest.cpp
@@ -0,0 +1,122 @@
+//===-- PolicyTest.cpp 
----------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Target/Policy.h"
+#include "gtest/gtest.h"
+
+#include <thread>
+
+using namespace lldb_private;
+
+TEST(PolicyTest, DefaultIsPublicWithAllCapabilities) {
+  Policy p;
+  EXPECT_EQ(p.view, Policy::View::Public);
+  EXPECT_TRUE(p.capabilities.can_evaluate_expressions);
+  EXPECT_TRUE(p.capabilities.can_run_all_threads);
+  EXPECT_TRUE(p.capabilities.can_try_all_threads);
+  EXPECT_TRUE(p.capabilities.can_run_breakpoint_actions);
+  EXPECT_TRUE(p.capabilities.can_load_frame_providers);
+  EXPECT_TRUE(p.capabilities.can_run_frame_recognizers);
+}
+
+TEST(PolicyTest, PublicState) {
+  Policy p = Policy::PublicState();
+  EXPECT_EQ(p.view, Policy::View::Public);
+  EXPECT_TRUE(p.capabilities.can_evaluate_expressions);
+  EXPECT_TRUE(p.capabilities.can_run_all_threads);
+  EXPECT_TRUE(p.capabilities.can_try_all_threads);
+  EXPECT_TRUE(p.capabilities.can_run_breakpoint_actions);
+  EXPECT_TRUE(p.capabilities.can_load_frame_providers);
+  EXPECT_TRUE(p.capabilities.can_run_frame_recognizers);
+}
+
+TEST(PolicyTest, PrivateState) {
+  Policy p = Policy::PrivateState();
+  EXPECT_EQ(p.view, Policy::View::Private);
+  EXPECT_TRUE(p.capabilities.can_evaluate_expressions);
+  EXPECT_TRUE(p.capabilities.can_run_all_threads);
+  EXPECT_TRUE(p.capabilities.can_try_all_threads);
+  EXPECT_TRUE(p.capabilities.can_run_breakpoint_actions);
+  EXPECT_FALSE(p.capabilities.can_load_frame_providers);
+  EXPECT_FALSE(p.capabilities.can_run_frame_recognizers);
+}
+
+TEST(PolicyTest, PublicStateRunningExpression) {
+  Policy p = Policy::PublicStateRunningExpression();
+  EXPECT_EQ(p.view, Policy::View::Public);
+  EXPECT_TRUE(p.capabilities.can_evaluate_expressions);
+  EXPECT_TRUE(p.capabilities.can_run_all_threads);
+  EXPECT_TRUE(p.capabilities.can_try_all_threads);
+  EXPECT_FALSE(p.capabilities.can_run_breakpoint_actions);
+  EXPECT_TRUE(p.capabilities.can_load_frame_providers);
+  EXPECT_TRUE(p.capabilities.can_run_frame_recognizers);
+}
+
+TEST(PolicyTest, StackDefaultIsPublicState) {
+  PolicyStack &stack = PolicyStack::GetForCurrentThread();
+  Policy current = stack.Current();
+  EXPECT_EQ(current.view, Policy::View::Public);
+  EXPECT_TRUE(current.capabilities.can_evaluate_expressions);
+  EXPECT_TRUE(current.capabilities.can_load_frame_providers);
+}
+
+TEST(PolicyTest, StackPushPop) {
+  PolicyStack &stack = PolicyStack::GetForCurrentThread();
+
+  stack.Push(Policy::PrivateState());
+  EXPECT_EQ(stack.Current().view, Policy::View::Private);
+  EXPECT_FALSE(stack.Current().capabilities.can_load_frame_providers);
+
+  stack.Push(Policy::PublicStateRunningExpression());
+  EXPECT_EQ(stack.Current().view, Policy::View::Public);
+  EXPECT_FALSE(stack.Current().capabilities.can_run_breakpoint_actions);
+
+  stack.Pop();
+  EXPECT_EQ(stack.Current().view, Policy::View::Private);
+
+  stack.Pop();
+  EXPECT_EQ(stack.Current().view, Policy::View::Public);
+}
+
+TEST(PolicyTest, GuardRAII) {
+  PolicyStack &stack = PolicyStack::GetForCurrentThread();
+  EXPECT_EQ(stack.Current().view, Policy::View::Public);
+
+  {
+    PolicyStack::Guard guard(Policy::PrivateState());
+    EXPECT_EQ(stack.Current().view, Policy::View::Private);
+    EXPECT_FALSE(stack.Current().capabilities.can_load_frame_providers);
+
+    {
+      PolicyStack::Guard inner(Policy::PublicStateRunningExpression());
+      EXPECT_EQ(stack.Current().view, Policy::View::Public);
+      EXPECT_FALSE(stack.Current().capabilities.can_run_breakpoint_actions);
+    }
+
+    EXPECT_EQ(stack.Current().view, Policy::View::Private);
+  }
+
+  EXPECT_EQ(stack.Current().view, Policy::View::Public);
+}
+
+TEST(PolicyTest, StackIsPerThread) {
+  PolicyStack &main_stack = PolicyStack::GetForCurrentThread();
+  main_stack.Push(Policy::PrivateState());
+
+  Policy::View other_thread_view;
+  std::thread t([&other_thread_view]() {
+    PolicyStack &stack = PolicyStack::GetForCurrentThread();
+    other_thread_view = stack.Current().view;
+  });
+  t.join();
+
+  EXPECT_EQ(main_stack.Current().view, Policy::View::Private);
+  EXPECT_EQ(other_thread_view, Policy::View::Public);
+
+  main_stack.Pop();
+}

_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to