[gimp] libgimpbase: improve multi-threaded stack traces.



commit ae6a7bf98f409d184e13ddfd18581777339c45eb
Author: Jehan <jehan girinstud io>
Date:   Tue Apr 10 14:36:51 2018 +0200

    libgimpbase: improve multi-threaded stack traces.
    
    Since commit bb52431cdd, we get multi-thread traces in functions
    gimp_stack_trace_*(). Adding now the LLDB equivalent improvement.
    
    Also adding the process and thread id information, from which the trace
    order was made, atop the listing, as well as the thread list. This would
    allow to easily find and associate the threads.
    The problem is that sometimes the thread where we got a trace from may
    not matter (for instance signals, even such as SIGABRT or SIGSEGV, seem
    to sent a bit randomly to either the thread which provoked them or the
    main thread; there is a bit of contradictory info on this when reading
    on the topic, in my case I experienced this), in such case, getting all
    thread stack is important to find the origin of the signal.
    Other times it will highly matter, in particular when getting a trace
    for a WARNING or CRITICAL. This information will help to discriminate
    between thread traces.

 libgimpbase/gimputils.c |   70 +++++++++++++++++++++++++++++++++--------------
 1 files changed, 49 insertions(+), 21 deletions(-)
---
diff --git a/libgimpbase/gimputils.c b/libgimpbase/gimputils.c
index c2fbbe9..eb2c5ad 100644
--- a/libgimpbase/gimputils.c
+++ b/libgimpbase/gimputils.c
@@ -38,6 +38,7 @@
 #include <glib/gprintf.h>
 
 #if defined(G_OS_WIN32)
+
 /* This is a hack for Windows known directory support.
  * DATADIR (autotools-generated constant) is a type defined in objidl.h
  * so we must #undef it before including shlobj.h in order to avoid a
@@ -45,15 +46,22 @@
 #undef DATADIR
 #include <windows.h>
 #include <shlobj.h>
+
 #else /* G_OS_WIN32 */
+
 /* For waitpid() */
 #include <sys/wait.h>
 #include <unistd.h>
 #include <errno.h>
 
+/* For thread IDs. */
+#include <sys/types.h>
+#include <sys/syscall.h>
+
 #ifdef HAVE_SYS_PRCTL_H
 #include <sys/prctl.h>
 #endif
+
 #endif /* G_OS_WIN32 */
 
 #include "gimpbasetypes.h"
@@ -1152,9 +1160,9 @@ gimp_stack_trace_available (gboolean optimal)
  * Since: 2.10
  **/
 gboolean
-gimp_stack_trace_print (const gchar *prog_name,
-                        gpointer     stream,
-                        gchar      **trace)
+gimp_stack_trace_print (const gchar   *prog_name,
+                        gpointer      stream,
+                        gchar       **trace)
 {
   gboolean stack_printed = FALSE;
 
@@ -1162,13 +1170,19 @@ gimp_stack_trace_print (const gchar *prog_name,
 #ifndef G_OS_WIN32
   GString *gtrace = NULL;
   gchar    gimp_pid[16];
-  pid_t    pid;
   gchar    buffer[256];
   ssize_t  read_n;
   int      sync_fd[2];
   int      out_fd[2];
+  pid_t    fork_pid;
+  pid_t    pid = getpid();
+#if defined(G_OS_WIN32)
+  DWORD    tid = GetCurrentThreadId ();
+#else
+  long     tid = syscall (SYS_gettid);
+#endif
 
-  g_snprintf (gimp_pid, 16, "%u", (guint) getpid ());
+  g_snprintf (gimp_pid, 16, "%u", (guint) pid);
 
   if (pipe (sync_fd) == -1)
     {
@@ -1183,17 +1197,19 @@ gimp_stack_trace_print (const gchar *prog_name,
       return FALSE;
     }
 
-  pid = fork ();
-  if (pid == 0)
+  fork_pid = fork ();
+  if (fork_pid == 0)
     {
       /* Child process. */
-      gchar *args[7] = { "gdb", "-batch", "-ex", "thread apply all backtrace full",
+      gchar *args[9] = { "gdb", "-batch",
+                         "-ex", "info threads",
+                         "-ex", "thread apply all backtrace full",
                          (gchar *) prog_name, NULL, NULL };
 
       if (prog_name == NULL)
-        args[4] = "-p";
+        args[6] = "-p";
 
-      args[5] = gimp_pid;
+      args[7] = gimp_pid;
 
       /* Wait until the parent enabled us to ptrace it. */
       {
@@ -1220,8 +1236,10 @@ gimp_stack_trace_print (const gchar *prog_name,
         {
           /* LLDB as alternative if the GDB call failed or if it was in
            * a too-old version. */
-          gchar *args_lldb[11] = { "lldb", "--attach-pid", NULL, "--batch",
-                                   "--one-line", "bt",
+          gchar *args_lldb[15] = { "lldb", "--attach-pid", NULL, "--batch",
+                                   "--one-line", "thread list",
+                                   "--one-line", "thread backtrace all",
+                                   "--one-line", "bt all",
                                    "--one-line-on-crash", "bt",
                                    "--one-line-on-crash", "quit", NULL };
 
@@ -1232,7 +1250,7 @@ gimp_stack_trace_print (const gchar *prog_name,
 
       _exit (0);
     }
-  else if (pid > 0)
+  else if (fork_pid > 0)
     {
       /* Main process */
       int status;
@@ -1240,7 +1258,7 @@ gimp_stack_trace_print (const gchar *prog_name,
       /* Allow the child to ptrace us, and signal it to start. */
       close (sync_fd[0]);
 #ifdef PR_SET_PTRACER
-      prctl (PR_SET_PTRACER, pid, 0, 0, 0);
+      prctl (PR_SET_PTRACER, fork_pid, 0, 0, 0);
 #endif
       close (sync_fd[1]);
 
@@ -1252,6 +1270,20 @@ gimp_stack_trace_print (const gchar *prog_name,
 
       while ((read_n = read (out_fd[0], buffer, 256)) > 0)
         {
+          if (! stack_printed)
+            {
+              if (stream)
+                g_fprintf (stream,
+                           "\n# Stack traces obtained from PID %d - Thread %lu #\n\n",
+                           pid, tid);
+              if (trace)
+                {
+                  gtrace = g_string_new (NULL);
+                  g_string_printf (gtrace,
+                                   "\n# Stack traces obtained from PID %d - Thread %lu #\n\n",
+                                   pid, tid);
+                }
+            }
           /* It's hard to know if the debugger was found since it
            * happened in the child. Let's just assume that any output
            * means it succeeded.
@@ -1262,11 +1294,7 @@ gimp_stack_trace_print (const gchar *prog_name,
           if (stream)
             g_fprintf (stream, "%s", buffer);
           if (trace)
-            {
-              if (! gtrace)
-                gtrace = g_string_new (NULL);
-              g_string_append (gtrace, (const gchar *) buffer);
-            }
+            g_string_append (gtrace, (const gchar *) buffer);
         }
       close (out_fd[0]);
 
@@ -1275,9 +1303,9 @@ gimp_stack_trace_print (const gchar *prog_name,
       prctl (PR_SET_PTRACER, 0, 0, 0, 0);
 #endif
 
-      waitpid (pid, &status, 0);
+      waitpid (fork_pid, &status, 0);
     }
-  /* else if (pid == (pid_t) -1)
+  /* else if (fork_pid == (pid_t) -1)
    * Fork failed!
    * Just continue, maybe the backtrace() API will succeed.
    */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]