After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 350076 - Multithreaded GTK applications crash in most/all idle callbacks
Multithreaded GTK applications crash in most/all idle callbacks
Status: RESOLVED DUPLICATE of bug 321886
Product: gtk+
Classification: Platform
Component: Widget: Other
2.10.x
Other All
: Normal critical
: ---
Assigned To: gtk-bugs
gtk-bugs
Depends on:
Blocks:
 
 
Reported: 2006-08-05 16:19 UTC by Harald Hopfes
Modified: 2006-08-05 18:26 UTC
See Also:
GNOME target: ---
GNOME version: ---



Description Harald Hopfes 2006-08-05 16:19:48 UTC
Steps to reproduce:
#include <gtk/gtk.h>
#include <unistd.h>
#include <pthread.h>

static GtkWidget *vbox;
static bool program_quit=false;

void *thread_function(void *)
{
  sleep(3);

  while(!program_quit){
    gdk_threads_enter ();
    printf("Create widget\n");
    GtkWidget *entry=gtk_entry_new();
    gtk_box_pack_start(GTK_BOX(vbox),
                       entry,
                       true, // expand
                       true, // fill
                       0);   // padding
    gtk_widget_show(entry);
    gdk_threads_leave ();
    usleep(5*1000);
    gdk_threads_enter ();
    gtk_entry_set_alignment (GTK_ENTRY(entry), 0.75);
    printf("Destroy widget\n");
    gtk_widget_destroy(entry);
    gdk_threads_leave ();
  }
  return NULL;
}

static gboolean delete_event( GtkWidget *widget,
                              GdkEvent  *event,
                              gpointer   data )
{
    gtk_main_quit ();
    return FALSE;
}

int main( int   argc,
          char *argv[] )
{
    pthread_t tid;

    gtk_init (&argc, &argv);

    GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    g_signal_connect (G_OBJECT (window), "delete_event",
                      G_CALLBACK (delete_event), NULL);

    vbox = gtk_vbox_new(FALSE,0);

    gtk_container_add (GTK_CONTAINER (window), vbox);

    gtk_widget_show_all (window);

    pthread_create(&tid,NULL,thread_function,NULL);

    gtk_main ();

    program_quit=true;

    sleep(3);

    return 0;
}


Stack trace:
Run the test case for some seconds (up to one minute) and it will crash.

The crash will occur inside the function recompute_idle_func of GtkEntry.c

This function is called from the Gtkmain thread, but if during waiting inside GDK_THREADS_ENTER another thread deletes the GtkEntry (of course being locked by GDK_THREADS_ENTER/GDK_THREADS_LEAVE), this function will still continue after GDK_THREADS_ENTER and crash. In my oppinion this is a general problem for all idle functions used in all GtkObjects. The Glib should provide a function to check if the callback is still valid somehing like the following. This function should be called directly after GDK_THREADS_ENTER in each idle_callback and return if not valid (of course after calling GDK_THREADS_LEAVE).

BOOL is_callback_valid(gpointer data)
{
  GMainContext *context=g_main_context_default();
  GSource *src=g_main_context_find_source_by_user_data (GMainContext *context,
                                                        gpointer user_data);
  return (src!=NULL);
}

##############################################################################
Code from GtkEntry.c:

static gboolean
recompute_idle_func (gpointer data)
{
  GtkEntry *entry;

  GDK_THREADS_ENTER ();

  entry = GTK_ENTRY (data);

  entry->recompute_idle = 0;
  
  if (gtk_widget_has_screen (GTK_WIDGET (entry)))
    {
      gtk_entry_adjust_scroll (entry);
      gtk_entry_queue_draw (entry);
      
      update_im_cursor_location (entry);
    }

  GDK_THREADS_LEAVE ();

  return FALSE;
}

Other information:
No.
Comment 1 Matthias Clasen 2006-08-05 18:26:50 UTC
See bug 321886 for the required changes to make this work more reliably. 

*** This bug has been marked as a duplicate of 321886 ***