Re: g_idle_add causing segfault from thread on exit.

On Feb 2, 2007, at 2:02 PM, zentara wrote:

I am trying to apply the c wisdom, from the gtk-c maillist,
to my Perl scripts.
I have found that the c handling of threads is easier to deal with
than the Perl, specifically, by allowing global variables and subs,
which the threads can access without having to declare shared vars.

This, of course, is due to the fact that in C, you don't have automatic reference counting controlling the lifetime of your variables, as you do in perl.

Anyways, a recent discussion on the c list, generally said that the
best way to update widgets from a thread is to add a g_idle_add to
the thread. This works fine in c, and is supposedly more reliable
than the threads->enter and ->leave mechanism.

So I tried to do this in the Perl script below, and the script works
fine, but I get weird errors and a segfault when I exit. LIke:

GLib-GObject-WARNING **: instance of invalid non-instantiatable type `(null)'. GLib-GObject-CRITICAL **: g_signal_emit_valist: assertion `G_TYPE_CHECK_INSTANCE
(instance)' failed. GLib-GObject-WARNING **: instance of invalid
non-instantiatable type `(null)'. GLib-GObject-CRITICAL **:
g_signal_handlers_destroy: assertion `G_TYPE_CHECK_INSTANCE (instance)' failed.
..... repeated several more times ........

I ran perl in gdb, and ran the script with --g-fatal-warnings so that the first of the warnings would call abort() and stop in the debugger... at that point, the stack is in destruction of one of the threads, and we're dying on an assertion from within g_object_unref().

#12 0x004bfd68 in XS_Glib__Object_DESTROY (my_perl=0xa0ef118, cv=0xa1ddf24)
    at GObject.xs:884
884             g_object_unref (object);
(gdb) p object->ref_count
$1 = 0

Basically, this object has already been destroyed, and what we're seeing is a double-free.

This is consistent with my previous observations that perl duplicates the scalars that go into spawned threads, but now we have two perl objects pointing at the same C object, and both of them think they own it. One thread's perl object reaches zero references and releases the last reference to the C object, and then the second thread's copy of that perl object reaches zero references and attempts to release its reference to the C object. Kaboom.

So can anyone point out what I can do to quiet the mean little error monster?

In 2004, to solve this problem, Ross put in something called "object tracking". You set a global flag when you start up your program, and this causes every Glib::Object instance wrapped by perl to be stored in a hash table. Then, whenever perl clones the interpreter to create a new thread, all Glib::Object instances that are alive and known to perl at this point get an extra refcount bump, to avoid the double-free problem described above.

This is not enabled by default because of the time and space penalty it incurs. It is implemented in this clunky manner because the only signal you get that a new thread is being created is the call to __PACKAGE__::CLONE() in every package. It is not called on each instance, or anything that would give you context. This does not work for boxed types. This is not panacea. Do not taunt Happy Fun Ball. You have been warned.

This threaded script, violates the general wisdom of creating the thread before any gui calls, and it allows the thread to manipulate the main's widgets. I know I can do it other ways, but I'm searching for that "Holy Grail" of the thread safe gui usage
in Perl.

*cough* fork and pipes *cough*

Thanks, zentara

use warnings;
use strict;
use threads;
use threads::shared;
use Glib qw/TRUE FALSE/;
use Gtk2 qw/-init -threads-init/;

# make sure we don't double-free the C objects.  see discussion.
Glib::Object->set_threadsafe (TRUE);

With that change, your program works fine for me.

(That said, when i tried to switch my environment to use a version of gtk+ with debugging symbols so i could debug the crash, i didn't see the crash even without the set_threadsafe() call. Very bizarre. YMMV.)

I hate to break it to you, but magic data pixies don't exist.
  -- Simon Cozens

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