Add gdb/nat common functions for listing threads
authorKamil Rytarowski <n54@gmx.com>
Wed, 2 Sep 2020 17:13:19 +0000 (19:13 +0200)
committerKamil Rytarowski <n54@gmx.com>
Thu, 10 Sep 2020 13:37:52 +0000 (15:37 +0200)
Add netbsd_nat::netbsd_thread_lister a generic thread lister, used
internally in netbsd-nat.c, copied from gdb/nbsd-nat.c.

Add public extern functions for listing threads:
 * netbsd_nat::thread_alive
 * netbsd_nat::thread_name
 * netbsd_nat::for_each_thread

gdb/ChangeLog:

* netbsd-nat.h: Include "gdbsupport/function-view.h".
* (netbsd_nat::thread_alive, netbsd_nat::thread_name)
(netbsd_nat::for_each_thread): Add.
* netbsd-nat.c: Include "gdbsupport/common-defs.h" and
"gdbsupport/common-debug.h".
* (netbsd_nat::netbsd_thread_lister)
(netbsd_nat::thread_alive, netbsd_nat::thread_name)
(netbsd_nat::for_each_thread): Add.

gdb/ChangeLog
gdb/nat/netbsd-nat.c
gdb/nat/netbsd-nat.h

index 2b8a0ac9e3a426419ae34790815162ed62a90a3d..21f30e4b297e8f83d7a5ff1193c5e7577eeb4568 100644 (file)
@@ -1,3 +1,14 @@
+2020-09-10  Kamil Rytarowski  <n54@gmx.com>
+
+       * netbsd-nat.h: Include "gdbsupport/function-view.h".
+       * (netbsd_nat::thread_alive, netbsd_nat::thread_name)
+       (netbsd_nat::for_each_thread): Add.
+       * netbsd-nat.c: Include "gdbsupport/common-defs.h" and
+       "gdbsupport/common-debug.h".
+       * (netbsd_nat::netbsd_thread_lister)
+       (netbsd_nat::thread_alive, netbsd_nat::thread_name)
+       (netbsd_nat::for_each_thread): Add.
+
 2020-09-10  Kamil Rytarowski  <n54@gmx.com>
 
        * netbsd-nat.h: Include <unistd.h>.
index a63ac04a39c2f883488909de75868f056eeeb266..3f8b8b8eeab3acfe5dc1b9ff76f8f4ea81ef3542 100644 (file)
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
+#include "gdbsupport/common-defs.h"
 #include "nat/netbsd-nat.h"
+#include "gdbsupport/common-debug.h"
 
 #include <sys/types.h>
 #include <sys/sysctl.h>
 
+#include <cstring>
+
+#include "gdbsupport/function-view.h"
+
 namespace netbsd_nat
 {
 
@@ -38,4 +44,123 @@ pid_to_exec_file (pid_t pid)
   return buf;
 }
 
+/* Generic thread (LWP) lister within a specified PID.  The CALLBACK
+   parameters is a C++ function that is called for each detected thread.
+   When the CALLBACK function returns true, the iteration is interrupted.
+
+   This function assumes internally that the queried process is stopped
+   and the number of threads does not change between two sysctl () calls.  */
+
+static bool
+netbsd_thread_lister (const pid_t pid,
+                     gdb::function_view<bool (const struct kinfo_lwp *)>
+                     callback)
+{
+  int mib[5] = {CTL_KERN, KERN_LWP, pid, sizeof (struct kinfo_lwp), 0};
+  size_t size;
+
+  if (sysctl (mib, ARRAY_SIZE (mib), NULL, &size, NULL, 0) == -1 || size == 0)
+    perror_with_name (("sysctl"));
+
+  mib[4] = size / sizeof (size_t);
+
+  gdb::unique_xmalloc_ptr<struct kinfo_lwp[]> kl
+    ((struct kinfo_lwp *) xcalloc (size, 1));
+
+  if (sysctl (mib, ARRAY_SIZE (mib), kl.get (), &size, NULL, 0) == -1
+      || size == 0)
+    perror_with_name (("sysctl"));
+
+  for (size_t i = 0; i < size / sizeof (struct kinfo_lwp); i++)
+    {
+      struct kinfo_lwp *l = &kl[i];
+
+      /* Return true if the specified thread is alive.  */
+      auto lwp_alive
+       = [] (struct kinfo_lwp *lwp)
+         {
+           switch (lwp->l_stat)
+             {
+             case LSSLEEP:
+             case LSRUN:
+             case LSONPROC:
+             case LSSTOP:
+             case LSSUSPENDED:
+               return true;
+             default:
+               return false;
+             }
+         };
+
+      /* Ignore embryonic or demised threads.  */
+      if (!lwp_alive (l))
+       continue;
+
+      if (callback (l))
+       return true;
+    }
+
+  return false;
+}
+
+/* See netbsd-nat.h.  */
+
+bool
+thread_alive (ptid_t ptid)
+{
+  pid_t pid = ptid.pid ();
+  lwpid_t lwp = ptid.lwp ();
+
+  auto fn
+    = [=] (const struct kinfo_lwp *kl)
+      {
+        return kl->l_lid == lwp;
+      };
+
+  return netbsd_thread_lister (pid, fn);
+}
+
+/* See netbsd-nat.h.  */
+
+const char *
+thread_name (ptid_t ptid)
+{
+  pid_t pid = ptid.pid ();
+  lwpid_t lwp = ptid.lwp ();
+
+  static char buf[KI_LNAMELEN] = {};
+
+  auto fn
+    = [=] (const struct kinfo_lwp *kl)
+      {
+       if (kl->l_lid == lwp)
+         {
+           xsnprintf (buf, sizeof buf, "%s", kl->l_name);
+           return true;
+         }
+       return false;
+      };
+
+  if (netbsd_thread_lister (pid, fn))
+    return buf;
+  else
+    return NULL;
+}
+
+/* See netbsd-nat.h.  */
+
+void
+for_each_thread (pid_t pid, gdb::function_view<void (ptid_t)> callback)
+{
+  auto fn
+    = [=, &callback] (const struct kinfo_lwp *kl)
+      {
+       ptid_t ptid = ptid_t (pid, kl->l_lid, 0);
+       callback (ptid);
+       return false;
+      };
+
+  netbsd_thread_lister (pid, fn);
+}
+
 }
index d11fadd247c1d09a3142ffcfe45fe179207769c8..3f2650f5cada24ace1e912d1425e2bcf48ba03c6 100644 (file)
@@ -20,6 +20,8 @@
 #ifndef NAT_NETBSD_NAT_H
 #define NAT_NETBSD_NAT_H
 
+#include "gdbsupport/function-view.h"
+
 #include <unistd.h>
 
 namespace netbsd_nat
@@ -30,6 +32,24 @@ namespace netbsd_nat
 
 extern const char *pid_to_exec_file (pid_t pid);
 
+/* Return true if PTID is still active in the inferior.  */
+
+extern bool thread_alive (ptid_t ptid);
+
+/* Return the name assigned to a thread by an application.  Returns
+   the string in a static buffer.
+
+   This function assumes internally that the queried process is stopped.  */
+
+extern const char *thread_name (ptid_t ptid);
+
+/* A generic thread lister within a specific PID.  The CALLBACK parameter
+   is a C++ function that is called for each detected thread.
+
+   This function assumes internally that the queried process is stopped.  */
+
+extern void for_each_thread (pid_t pid,
+                            gdb::function_view<void (ptid_t)> callback);
 }
 
 #endif