Re: Glib::Object::Subclass, embedding and multiple interpreters
- From: muppet <scott asofyet org>
- To: Eduardo M KALINOWSKI <ekalin bol com br>
- Cc: gtk-perl-list gnome org
- Subject: Re: Glib::Object::Subclass, embedding and multiple interpreters
- Date: Wed, 30 Mar 2005 22:59:17 -0500
On Mar 30, 2005, at 1:19 PM, Eduardo M KALINOWSKI wrote:
However, the program can, in fact, have multiple Perl interpreters,
running simultaneously. This in itself does not cause problems, but
one thing happened when I tried to create a subclassed object deriving
from Gtk2::Window, using Glib::Object::Subclass to do that.
Oh dear... was that the sound of a large can of worms opening?
The first time the file that defines this new subclassed widget is
loaded, everything works perfectly, and it can be used normally.
However, if I try to load another interpreter, and to load the file
again in this new interpreter, I get some error messages saying that
the object cannot be registered, because it already it --- what makes
sense, naturally.
Yes, because there's one glib type system being shared by all of the
code in the program, and gtk2-perl creates new types with
g_type_register_static().
My (first) question is if there is a way to check if the type is
already registered, and if it is, to ignore the registration process.
This probably would mean that I would not be able to use
Glib::Object::Subclass and I would need to do things manually, but
that's OK.
If you've peeked at the code of Glib::Object::Subclass, you know that
it's just a thin syntactic wrapper around
Glib::Type->register_object().
What you describe is pretty easy:
package MyObject;
eval {
Glib::Type->list_ancestors (__PACKAGE__);
# if we're alive here, the package is already registered.
} or Glib::Type->register_object ('ParentClass',
__PACKAGE__,
signals => { ... },
...);
# all normal method implementations follow...
However, this brings another question: would that work? Even if the
registration process were skipped for the second time the object is
defined, there might be references somewhere to things of the first
interpreter, and then trying to use the subclassed object from another
interpreter would not work.
To quote a jedi master, your insight serves you well.
When registering new classes, Glib::Type::register_object() calls
g_type_register_static(), which tells the glib type system that this
class will always be around.
Gtk2-Perl also leaks the class references on various types of
GTypeClasses. For classes registered from perl code, the design
decision was "well, perl packages simply exist from the time the parser
hits them until the program exits, so we might as well keep the classes
alive and not worry about cleaning them up." The reason for worrying
about it was that GTypeClasses, once registered, can be instantiated
and destroyed multiple times. The class registration is supposed to
save all the info you need to instantiate the class (the size of the
class and instance structures, the parent type, pointer to a function
to initialize each structure). Figuring out how to weld that to perl
bent my brain (at the time, the bindings barely worked and this was a
fairly esoteric case), and given the assumption above, i decided that
it was a non-issue if we just register once and ensure the class is
never finalized. Of course, the mistake in that logic is the word
"program"... perl packages live until the *interpreter* exits, and
there can be more than one interpreter in a program.
But, given all that, let's examine how and if it would be possible to
limp along.
The first interpreter to register a class will leave it registered with
glib. The next interpreter comes along and tries to use the same
object. (Let's ignore the pathological case of your program trying to
use a perl-derived type when no interpreter is active.) What would
cause this to blow up? Any stored perl data structures. About the
only things we store from class registration are closures. For the
most part, the rest is done with special names (e.g. "INIT_INSTANCE"),
and even the things done with closures can be done with special names
instead.
Glib::Type->register_object
('SomeParentObject', 'Foo',
signals => {
# new signals...
flurblize => {
class_closure => \&_flurblize, # saves a closure
reference
},
frobnicate => {}, # doesn't store any perl data structures
# the method named do_frobnicate will be
invoked
# as the class closure, if it exists
# signal overrides
parent_method1 => \&_override_1, # saves a closure reference
parent_method2 => '_override_2', # ack! still saves an SV,
# which just happens to be a string instead
of a
# reference to a subroutine. (see
add_signals()
# in GType.xs)
# so, er, it looks like there's no way to override signal
closures
# without saving a reference. the ugly workaround is to use
# signal_connect in INIT_INSTANCE. :-(
},
properties => [
# this one stores only C data structures; the
# GET_PROPERTY and SET_PROPERTY marshaling
# happens at runtime.
Glib::ParamSpec->int ('a', 'A', 'A', 0, 10, 4,
G_PARAM_READWRITE),
# the new-fangled inline version stores subroutine references
{
pspec=>Glib::ParamSpec->int (...),
getter => sub {},
setter => sub {},
}
],
interfaces => [ 'Coolio' ], # alters a class structure, but
stores
# no references
);
Armed with this knowledge and the "Test for already-registered class"
snippet from above, you should be able to experiment and find out if
you can get it to work.
Slightly more evil, what if you have an object that outlives the
interpreter? It will still have a perl data structure attached to it.
I ran into this in a binding situation not long ago; i had a C library
that implemented a cache of singletons, and one of the objects stored
in that cache was a perl-derived type... the object didn't get
destroyed until an atexit handler that ran after main() returned, well
after the interpreter and its heap were gone, so the app segfaulted
perl in shutdown when the object's finalizer tried to invoke some perl
code. (I got around this by moving the implementation of the instance
cache functionality to perl.)
And, rather more insidious: while the code snippet above shows you
what does and doesn't store perl references, it doesn't show that
nearly all of this stuff installs into glib pointers to functions
defined in the shared objects that implement the bindings. Something
to which i don't know the answer is "does perl unload the shared
objects that it loaded for its extensions?" if so, then it's likely
that the function pointers point to invalid memory... However, if
you're building the interpreter into your program, you probably have
the option to statically link the Gtk2 extension to it, don't you?
In summary, I don't think it's impossible, you'll just have to be
really careful, and feedback from your experiments may have to be
incorporated into the bindings.
There is a g_type_register_dynamic(), but it is for types defined in
dynamically-loadable plugins. Basically, your app knows somehow
(either through scanning a modules directory or reading a cache file or
something) that the module coolthing.so defines and implements the
GType CoolThing; using g_type_register_dynamic() lets the type system
know that when somebody wants to instantiate an object of that type, it
must load and initialize coolthing.so. I suppose it would be possible
to implement a GTypeModule that launches a perl interpreter, but this
was way beyond the scope of what i was prepared to take into
consideration when trying to get the bindings simply to work at all,
and this isn't the current conventional usage of embedded perl
interpreters.
--
"There's a documentary that i wanted to watch on PBS. I heard about it
in NPR. ... Oh my god, did i just say that?"
-- elysse
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]