[gimp] app: make backtrace processed in the thread where error happens.



commit b0cd4412e03e80c33b2b2649c0881573eeac10d7
Author: Jehan <jehan girinstud io>
Date:   Mon Feb 12 05:13:22 2018 +0100

    app: make backtrace processed in the thread where error happens.
    
    Slight back step from commit 34fe992f44. I don't keep track anymore of
    the number of errors inside GimpCriticalDialog. The problem is that GTK+
    calls must happen in the main thread, and errors in another thread will
    be delayed into the main thread through gdk_threads_add_idle_full().
    This makes any backtrace generated as a consequence of a threaded error
    useless (in particular any error happening in GEGL since we always
    process these as multi-threaded, whether they are or not).
    Instead I now keep track of the number of errors in gui-message.c, which
    still allows to reset the counters when the unique debug dialog is
    closed. Therefore I can now generate backtraces conditionally to the
    error counters inside the problematic thread (and right when the error
    happened), without any GTK+ call.
    This finally makes GEGL backtraces useful in the debug dialog! :-)

 app/gui/gui-message.c            |  184 ++++++++++++++++++++++++++------------
 app/widgets/gimpcriticaldialog.c |   25 -----
 app/widgets/gimpcriticaldialog.h |    5 -
 3 files changed, 127 insertions(+), 87 deletions(-)
---
diff --git a/app/gui/gui-message.c b/app/gui/gui-message.c
index bbaa3ca..1c2512a 100644
--- a/app/gui/gui-message.c
+++ b/app/gui/gui-message.c
@@ -50,33 +50,47 @@
 
 #include "gimp-intl.h"
 
+#define MAX_TRACES 3
+#define MAX_ERRORS 10
+
+static GMutex mutex;
+static gint   n_traces = 0;
+static gint   n_errors = 0;
 
 typedef struct
 {
   Gimp                *gimp;
   gchar               *domain;
   gchar               *message;
+  gchar               *trace;
   GObject             *handler;
   GimpMessageSeverity  severity;
 } GimpLogMessageData;
 
 
-static gboolean  gui_message_idle          (gpointer             user_data);
-static gboolean  gui_message_error_console (Gimp                *gimp,
-                                            GimpMessageSeverity  severity,
-                                            const gchar         *domain,
-                                            const gchar         *message);
-static gboolean  gui_message_error_dialog  (Gimp                *gimp,
-                                            GObject             *handler,
-                                            GimpMessageSeverity  severity,
-                                            const gchar         *domain,
-                                            const gchar         *message);
-static void      gui_message_console       (GimpMessageSeverity  severity,
-                                            const gchar         *domain,
-                                            const gchar         *message);
-static gchar *   gui_message_format        (GimpMessageSeverity  severity,
-                                            const gchar         *domain,
-                                            const gchar         *message);
+static gboolean  gui_message_idle           (gpointer             user_data);
+static gboolean  gui_message_error_console  (Gimp                *gimp,
+                                             GimpMessageSeverity  severity,
+                                             const gchar         *domain,
+                                             const gchar         *message);
+static gboolean  gui_message_error_dialog   (Gimp                *gimp,
+                                             GObject             *handler,
+                                             GimpMessageSeverity  severity,
+                                             const gchar         *domain,
+                                             const gchar         *message,
+                                             const gchar         *trace);
+static void      gui_message_console        (GimpMessageSeverity  severity,
+                                             const gchar         *domain,
+                                             const gchar         *message);
+static gchar *   gui_message_format         (GimpMessageSeverity  severity,
+                                             const gchar         *domain,
+                                             const gchar         *message);
+
+static GtkWidget * global_error_dialog      (void);
+static GtkWidget * global_critical_dialog   (void);
+
+static void        gui_message_reset_errors (GtkObject           *object,
+                                             gpointer             user_data);
 
 
 void
@@ -86,6 +100,9 @@ gui_message (Gimp                *gimp,
              const gchar         *domain,
              const gchar         *message)
 {
+  gchar    *trace     = NULL;
+  gboolean  gen_trace = FALSE;
+
   switch (gimp->message_handler)
     {
     case GIMP_ERROR_CONSOLE:
@@ -96,6 +113,30 @@ gui_message (Gimp                *gimp,
       /*  fallthru  */
 
     case GIMP_MESSAGE_BOX:
+      if (severity == GIMP_MESSAGE_ERROR)
+        {
+          g_mutex_lock (&mutex);
+          /* Trace creation can be time consuming so don't block the
+           * mutex for too long and only increment and set a boolean
+           * here.
+           */
+          if (n_traces < MAX_TRACES)
+            {
+              gen_trace = TRUE;
+              n_traces++;
+            }
+          g_mutex_unlock (&mutex);
+        }
+      if (gen_trace)
+        {
+          /* We need to create the trace here because for multi-thread
+           * errors (i.e. non-GIMP ones), the backtrace after a idle
+           * function will simply be useless. It needs to happen in the
+           * buggy thread to be meaningful.
+           */
+          gimp_print_stack_trace (NULL, NULL, &trace);
+        }
+
       if (g_strcmp0 (GIMP_ACRONYM, domain) != 0)
         {
           /* Handle non-GIMP messages in a multi-thread safe way,
@@ -108,6 +149,7 @@ gui_message (Gimp                *gimp,
           data->gimp     = gimp;
           data->domain   = g_strdup (domain);
           data->message  = g_strdup (message);
+          data->trace    = trace;
           data->handler  = handler? g_object_ref (handler) : NULL;
           data->severity = severity;
 
@@ -117,8 +159,8 @@ gui_message (Gimp                *gimp,
           return;
         }
       if (gui_message_error_dialog (gimp, handler, severity,
-                                    domain, message))
-        return;
+                                    domain, message, trace))
+        break;
 
       gimp->message_handler = GIMP_CONSOLE;
       /*  fallthru  */
@@ -127,6 +169,8 @@ gui_message (Gimp                *gimp,
       gui_message_console (severity, domain, message);
       break;
     }
+  if (trace)
+    g_free (trace);
 }
 
 static gboolean
@@ -138,7 +182,8 @@ gui_message_idle (gpointer user_data)
                                   data->handler,
                                   data->severity,
                                   data->domain,
-                                  data->message))
+                                  data->message,
+                                  data->trace))
     {
       gui_message_console (data->severity,
                            data->domain,
@@ -146,6 +191,8 @@ gui_message_idle (gpointer user_data)
     }
   g_free (data->domain);
   g_free (data->message);
+  if (data->trace)
+    g_free (data->trace);
   if (data->handler)
     g_object_unref (data->handler);
 
@@ -245,42 +292,13 @@ progress_error_dialog (GimpProgress *progress)
   return dialog;
 }
 
-static GtkWidget *
-global_error_dialog (void)
-{
-  GdkScreen *screen;
-  gint       monitor;
-
-  monitor = gimp_get_monitor_at_pointer (&screen);
-
-  return gimp_dialog_factory_dialog_new (gimp_dialog_factory_get_singleton (),
-                                         screen, monitor,
-                                         NULL /*ui_manager*/,
-                                         "gimp-error-dialog", -1,
-                                         FALSE);
-}
-
-static GtkWidget *
-global_critical_dialog (void)
-{
-  GdkScreen *screen;
-  gint       monitor;
-
-  monitor = gimp_get_monitor_at_pointer (&screen);
-
-  return gimp_dialog_factory_dialog_new (gimp_dialog_factory_get_singleton (),
-                                         screen, monitor,
-                                         NULL /*ui_manager*/,
-                                         "gimp-critical-dialog", -1,
-                                         FALSE);
-}
-
 static gboolean
 gui_message_error_dialog (Gimp                *gimp,
                           GObject             *handler,
                           GimpMessageSeverity  severity,
                           const gchar         *domain,
-                          const gchar         *message)
+                          const gchar         *message,
+                          const gchar         *trace)
 {
   GtkWidget      *dialog;
   GtkMessageType  type   = GTK_MESSAGE_ERROR;
@@ -300,15 +318,21 @@ gui_message_error_dialog (Gimp                *gimp,
        * will require its own dedicated dialog which will encourage
        * people to report the bug.
        */
-      dialog = global_critical_dialog ();
+      gboolean gui_error = FALSE;
+
+      g_mutex_lock (&mutex);
+      if (n_errors < MAX_ERRORS)
+        {
+          gui_error = TRUE;
+          n_errors++;
+        }
+      g_mutex_unlock (&mutex);
 
-      if (gimp_critical_dialog_want_errors (dialog))
+      if (gui_error || trace)
         {
           gchar *text;
-          gchar *trace = NULL;
 
-          if (gimp_critical_dialog_want_traces (dialog))
-            gimp_print_stack_trace (NULL, NULL, &trace);
+          dialog = global_critical_dialog ();
 
           text = gui_message_format (severity, domain, message);
           gimp_critical_dialog_add (dialog, text, trace, FALSE, NULL, 0);
@@ -316,8 +340,6 @@ gui_message_error_dialog (Gimp                *gimp,
           gtk_widget_show (dialog);
 
           g_free (text);
-          if (trace)
-            g_free (trace);
 
           return TRUE;
         }
@@ -410,3 +432,51 @@ gui_message_format (GimpMessageSeverity  severity,
 
   return formatted_message;
 }
+
+static GtkWidget *
+global_error_dialog (void)
+{
+  GdkScreen *screen;
+  gint       monitor;
+
+  monitor = gimp_get_monitor_at_pointer (&screen);
+
+  return gimp_dialog_factory_dialog_new (gimp_dialog_factory_get_singleton (),
+                                         screen, monitor,
+                                         NULL /*ui_manager*/,
+                                         "gimp-error-dialog", -1,
+                                         FALSE);
+}
+
+static GtkWidget *
+global_critical_dialog (void)
+{
+  GtkWidget *dialog;
+  GdkScreen *screen;
+  gint       monitor;
+
+  monitor = gimp_get_monitor_at_pointer (&screen);
+
+  dialog = gimp_dialog_factory_dialog_new (gimp_dialog_factory_get_singleton (),
+                                           screen, monitor,
+                                           NULL /*ui_manager*/,
+                                           "gimp-critical-dialog", -1,
+                                           FALSE);
+  g_signal_handlers_disconnect_by_func (dialog,
+                                        gui_message_reset_errors,
+                                        NULL);
+  g_signal_connect (dialog, "destroy",
+                    G_CALLBACK (gui_message_reset_errors),
+                    NULL);
+  return dialog;
+}
+
+static void
+gui_message_reset_errors (GtkObject *object,
+                          gpointer   user_data)
+{
+  g_mutex_lock (&mutex);
+  n_errors = 0;
+  n_traces = 0;
+  g_mutex_unlock (&mutex);
+}
diff --git a/app/widgets/gimpcriticaldialog.c b/app/widgets/gimpcriticaldialog.c
index 5e989ca..20b3164 100644
--- a/app/widgets/gimpcriticaldialog.c
+++ b/app/widgets/gimpcriticaldialog.c
@@ -54,9 +54,6 @@
 #define BUTTON1_TEXT _("Copy Bug Information")
 #define BUTTON2_TEXT _("Open Bug Tracker")
 
-#define MAX_TRACES 3
-#define MAX_ERRORS 10
-
 static void    gimp_critical_dialog_finalize (GObject     *object);
 static void    gimp_critical_dialog_response (GtkDialog   *dialog,
                                               gint         response_id);
@@ -188,8 +185,6 @@ gimp_critical_dialog_init (GimpCriticalDialog *dialog)
 
   dialog->pid      = 0;
   dialog->program  = NULL;
-  dialog->n_errors = 0;
-  dialog->n_traces = 0;
 }
 
 static void
@@ -408,14 +403,6 @@ gimp_critical_dialog_add (GtkWidget   *dialog,
     }
   critical = GIMP_CRITICAL_DIALOG (dialog);
 
-  if (critical->n_errors > MAX_ERRORS ||
-      (trace && critical->n_traces > MAX_TRACES))
-    return;
-
-  critical->n_errors++;
-  if (trace)
-    critical->n_traces++;
-
   /* The user text, which should be localized. */
   if (is_fatal)
     {
@@ -492,15 +479,3 @@ gimp_critical_dialog_add (GtkWidget   *dialog,
       critical->pid     = pid;
     }
 }
-
-gboolean
-gimp_critical_dialog_want_traces (GtkWidget *dialog)
-{
-  return (GIMP_CRITICAL_DIALOG (dialog)->n_traces <= MAX_TRACES);
-}
-
-gboolean
-gimp_critical_dialog_want_errors (GtkWidget *dialog)
-{
-  return (GIMP_CRITICAL_DIALOG (dialog)->n_errors <= MAX_ERRORS);
-}
diff --git a/app/widgets/gimpcriticaldialog.h b/app/widgets/gimpcriticaldialog.h
index 5418e79..7e94ea2 100644
--- a/app/widgets/gimpcriticaldialog.h
+++ b/app/widgets/gimpcriticaldialog.h
@@ -45,9 +45,6 @@ struct _GimpCriticalDialog
 
   gchar           *program;
   gint             pid;
-
-  gint             n_errors;
-  gint             n_traces;
 };
 
 struct _GimpCriticalDialogClass
@@ -65,8 +62,6 @@ void        gimp_critical_dialog_add      (GtkWidget          *dialog,
                                            gboolean            is_fatal,
                                            const gchar        *program,
                                            gint                pid);
-gboolean    gimp_critical_dialog_want_traces (GtkWidget       *dialog);
-gboolean    gimp_critical_dialog_want_errors (GtkWidget       *dialog);
 
 
 G_END_DECLS


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