https://github.com/feg208 updated 
https://github.com/llvm/llvm-project/pull/91544

>From 18b0d55d1c4e04842e531c7f7e304998f2b2ad4e Mon Sep 17 00:00:00 2001
From: Fred Grim <fg...@apple.com>
Date: Wed, 8 May 2024 15:36:16 -0700
Subject: [PATCH] [lldb] Adds additional fields to ProcessInfo

To implement SaveCore for elf binaries we need to populate some
additional fields in the prpsinfo struct. Those fields are the nice
value of the process whose core is to be taken as well as a boolean
flag indicating whether or not that process is a zombie. This commit
adds those as well as tests to ensure that the values are consistent
with expectations
---
 lldb/include/lldb/Utility/ProcessInfo.h | 28 +++++++++++++++
 lldb/source/Host/linux/Host.cpp         | 45 ++++++++++++++-----------
 lldb/source/Utility/ProcessInfo.cpp     |  4 +++
 lldb/unittests/Host/linux/HostTest.cpp  | 20 +++++++++++
 4 files changed, 77 insertions(+), 20 deletions(-)

diff --git a/lldb/include/lldb/Utility/ProcessInfo.h 
b/lldb/include/lldb/Utility/ProcessInfo.h
index 54ac000dc7fc..240f78d1c4e4 100644
--- a/lldb/include/lldb/Utility/ProcessInfo.h
+++ b/lldb/include/lldb/Utility/ProcessInfo.h
@@ -15,6 +15,7 @@
 #include "lldb/Utility/FileSpec.h"
 #include "lldb/Utility/NameMatches.h"
 #include "lldb/Utility/StructuredData.h"
+#include <optional>
 #include <vector>
 
 namespace lldb_private {
@@ -144,6 +145,19 @@ class ProcessInstanceInfo : public ProcessInfo {
     long int tv_usec = 0;
   };
 
+  enum class ProcessState {
+    Unknown,
+    Dead,
+    DiskSleep,
+    Idle,
+    Paging,
+    Parked,
+    Running,
+    Sleeping,
+    TracedOrStopped,
+    Zombie,
+  };
+
   ProcessInstanceInfo() = default;
 
   ProcessInstanceInfo(const char *name, const ArchSpec &arch, lldb::pid_t pid)
@@ -237,6 +251,18 @@ class ProcessInstanceInfo : public ProcessInfo {
            m_cumulative_system_time.tv_usec > 0;
   }
 
+  int8_t GetPriorityValue() const { return m_priority_value.value(); }
+
+  void SetPriorityValue(int8_t priority_value) {
+    m_priority_value = priority_value;
+  }
+
+  bool PriorityValueIsValid() const;
+
+  void SetIsZombie(bool is_zombie = true) { m_zombie = is_zombie; }
+
+  bool IsZombie() const { return m_zombie; }
+
   void Dump(Stream &s, UserIDResolver &resolver) const;
 
   static void DumpTableHeader(Stream &s, bool show_args, bool verbose);
@@ -254,6 +280,8 @@ class ProcessInstanceInfo : public ProcessInfo {
   struct timespec m_system_time {};
   struct timespec m_cumulative_user_time {};
   struct timespec m_cumulative_system_time {};
+  std::optional<int8_t> m_priority_value = std::nullopt;
+  bool m_zombie = false;
 };
 
 typedef std::vector<ProcessInstanceInfo> ProcessInstanceInfoList;
diff --git a/lldb/source/Host/linux/Host.cpp b/lldb/source/Host/linux/Host.cpp
index c6490f2fc9e2..186323393c14 100644
--- a/lldb/source/Host/linux/Host.cpp
+++ b/lldb/source/Host/linux/Host.cpp
@@ -37,18 +37,8 @@ using namespace lldb;
 using namespace lldb_private;
 
 namespace {
-enum class ProcessState {
-  Unknown,
-  Dead,
-  DiskSleep,
-  Idle,
-  Paging,
-  Parked,
-  Running,
-  Sleeping,
-  TracedOrStopped,
-  Zombie,
-};
+
+using ProcessState = typename ProcessInstanceInfo::ProcessState;
 
 constexpr int task_comm_len = 16;
 
@@ -70,6 +60,12 @@ struct StatFields {
   long unsigned stime;
   long cutime;
   long cstime;
+  // in proc_pid_stat(5) this field is specified as priority
+  // but documented as realtime priority. To keep with the adopted
+  // nomenclature in ProcessInstanceInfo we adopt the documented
+  // naming here
+  long realtime_priority;
+  long priority;
   // .... other things. We don't need them below
 };
 }
@@ -91,14 +87,16 @@ static bool GetStatusInfo(::pid_t Pid, ProcessInstanceInfo 
&ProcessInfo,
   if (Rest.empty())
     return false;
   StatFields stat_fields;
-  if (sscanf(Rest.data(),
-             "%d %s %c %d %d %d %d %d %u %lu %lu %lu %lu %lu %lu %ld %ld",
-             &stat_fields.pid, stat_fields.comm, &stat_fields.state,
-             &stat_fields.ppid, &stat_fields.pgrp, &stat_fields.session,
-             &stat_fields.tty_nr, &stat_fields.tpgid, &stat_fields.flags,
-             &stat_fields.minflt, &stat_fields.cminflt, &stat_fields.majflt,
-             &stat_fields.cmajflt, &stat_fields.utime, &stat_fields.stime,
-             &stat_fields.cutime, &stat_fields.cstime) < 0) {
+  if (sscanf(
+          Rest.data(),
+          "%d %s %c %d %d %d %d %d %u %lu %lu %lu %lu %lu %lu %ld %ld %ld %ld",
+          &stat_fields.pid, stat_fields.comm, &stat_fields.state,
+          &stat_fields.ppid, &stat_fields.pgrp, &stat_fields.session,
+          &stat_fields.tty_nr, &stat_fields.tpgid, &stat_fields.flags,
+          &stat_fields.minflt, &stat_fields.cminflt, &stat_fields.majflt,
+          &stat_fields.cmajflt, &stat_fields.utime, &stat_fields.stime,
+          &stat_fields.cutime, &stat_fields.cstime,
+          &stat_fields.realtime_priority, &stat_fields.priority) < 0) {
     return false;
   }
 
@@ -115,6 +113,11 @@ static bool GetStatusInfo(::pid_t Pid, ProcessInstanceInfo 
&ProcessInfo,
     return ts;
   };
 
+  // priority (nice) values run from 19 to -20 inclusive (in linux). In the
+  // prpsinfo struct pr_nice is a char
+  auto priority_value = static_cast<int8_t>(
+      (stat_fields.priority < 0 ? 0x80 : 0x00) | (stat_fields.priority & 
0x7f));
+
   ProcessInfo.SetParentProcessID(stat_fields.ppid);
   ProcessInfo.SetProcessGroupID(stat_fields.pgrp);
   ProcessInfo.SetProcessSessionID(stat_fields.session);
@@ -122,6 +125,7 @@ static bool GetStatusInfo(::pid_t Pid, ProcessInstanceInfo 
&ProcessInfo,
   ProcessInfo.SetSystemTime(convert(stat_fields.stime));
   ProcessInfo.SetCumulativeUserTime(convert(stat_fields.cutime));
   ProcessInfo.SetCumulativeSystemTime(convert(stat_fields.cstime));
+  ProcessInfo.SetPriorityValue(priority_value);
   switch (stat_fields.state) {
   case 'R':
     State = ProcessState::Running;
@@ -134,6 +138,7 @@ static bool GetStatusInfo(::pid_t Pid, ProcessInstanceInfo 
&ProcessInfo,
     break;
   case 'Z':
     State = ProcessState::Zombie;
+    ProcessInfo.SetIsZombie();
     break;
   case 'X':
     State = ProcessState::Dead;
diff --git a/lldb/source/Utility/ProcessInfo.cpp 
b/lldb/source/Utility/ProcessInfo.cpp
index 6b2a7114dfb4..2e46b92b1054 100644
--- a/lldb/source/Utility/ProcessInfo.cpp
+++ b/lldb/source/Utility/ProcessInfo.cpp
@@ -117,6 +117,10 @@ bool ProcessInfo::IsScriptedProcess() const {
   return m_scripted_metadata_sp && *m_scripted_metadata_sp;
 }
 
+bool ProcessInstanceInfo::PriorityValueIsValid() const {
+  return m_priority_value.has_value();
+}
+
 void ProcessInstanceInfo::Dump(Stream &s, UserIDResolver &resolver) const {
   if (m_pid != LLDB_INVALID_PROCESS_ID)
     s.Printf("    pid = %" PRIu64 "\n", m_pid);
diff --git a/lldb/unittests/Host/linux/HostTest.cpp 
b/lldb/unittests/Host/linux/HostTest.cpp
index 8ecaf3ec0dec..b6318f4bb568 100644
--- a/lldb/unittests/Host/linux/HostTest.cpp
+++ b/lldb/unittests/Host/linux/HostTest.cpp
@@ -12,6 +12,9 @@
 #include "lldb/Utility/ProcessInfo.h"
 #include "gtest/gtest.h"
 
+#include <cerrno>
+#include <sys/resource.h>
+
 using namespace lldb_private;
 
 namespace {
@@ -86,4 +89,21 @@ TEST_F(HostTest, GetProcessInfo) {
   ProcessInstanceInfo::timespec next_user_time = Info.GetUserTime();
   ASSERT_TRUE(user_time.tv_sec <= next_user_time.tv_sec ||
               user_time.tv_usec <= next_user_time.tv_usec);
+
+  struct rlimit rlim;
+  EXPECT_EQ(getrlimit(RLIMIT_NICE, &rlim), 0);
+  // getpriority can return -1 so we zero errno first
+  errno = 0;
+  int prio = getpriority(PRIO_PROCESS, PRIO_PROCESS);
+  ASSERT_TRUE((prio < 0 && errno == 0) || prio >= 0);
+  ASSERT_EQ(Info.GetPriorityValue(), prio);
+  // If we can't raise our nice level then this test can't be performed
+  int max_incr = PRIO_MAX - rlim.rlim_cur;
+  if (max_incr < prio) {
+    EXPECT_EQ(setpriority(PRIO_PROCESS, PRIO_PROCESS, prio - 1), 0);
+    ASSERT_TRUE(Host::GetProcessInfo(getpid(), Info));
+    ASSERT_EQ(Info.GetPriorityValue(), prio - 1);
+    EXPECT_EQ(setpriority(PRIO_PROCESS, PRIO_PROCESS, prio), 0);
+  }
+  ASSERT_FALSE(Info.IsZombie());
 }

_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to