mirror of https://github.com/GNOME/gimp.git
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! :-)
This commit is contained in:
parent
5d200c2c4b
commit
b0cd4412e0
|
@ -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;
|
||||
|
||||
if (gimp_critical_dialog_want_errors (dialog))
|
||||
g_mutex_lock (&mutex);
|
||||
if (n_errors < MAX_ERRORS)
|
||||
{
|
||||
gui_error = TRUE;
|
||||
n_errors++;
|
||||
}
|
||||
g_mutex_unlock (&mutex);
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue