I wrote bindings for a small C library using XS. In those bindings I map
some c structures to a perl objects, which are blesed into
"Audio::XMMSClient".
The new() method allocates a new c structure structure and my bindings
wrap it into an object. Now I'd like to free the memory allocated in
new() when the perl object isn't used anymore.
DESTROY seems to be the way to do that. So I defined a DESTROY method in
my XS code:
void
DESTROY(c)
my_c_structure_t* c
CODE:
my_c_structure_unref(c);
Unfortunately DESTROY won't be called when the perl objects reference
count reaches zero as it seems to be the case in pure-perl world. What's
the difference between pure-perl code and XS code with regard to
DESTROY? How can I get my XS DESTROY method called properly?
TIA,
Flo
--
BOFH excuse #41:
interrupt configuration error
Bye
Vasek
DESTROY is not necessarily called at the time the refcount hits zero.
Perl cleans up objects without references only when leaving a scope. If
you need more immediate action, just undef them yourself at the point
they're no longer needed.
Steve
There should be no difference between a Perl or XS DESTROY method (in terms
of when it's called). How are you creating the object?
Cheers,
jez.
Given the following piece of code:
package Foo;
sub new { bless {}, 'Foo' }
sub DESTROY { print "Destroying @_\n" }
package main;
{
my $f = Foo->new;
}
This produced the following output:
Destroying Foo=HASH(0x814f720)
If I run the same code as in main with my class created using XS code,
which has a similar constructor and deconstructor doesn't give me any
output.
Is the reason for DESTROY not being called in the code which uses it or
in the XS code itself? I suspect the latter as the same code calls
DESTROY if the class I use is declared with pure-perl.
-Flo
--
BOFH excuse #239:
CPU needs bearings repacked
There should be no difference between Perl and XS object destruction. What
logic are you using to create your object in XS? Are you sure your
namespaces are correct?
Cheers,
jez.
So you suggest something like this:
package XSModule;
use XSLoader;
XSLoader::load(__PACKAGE__, $VERSION);
sub DESTROY { print "Destroying @_\n" }
1;
The destructor doesn't get called this way as well.
-Flo
--
BOFH excuse #434:
Please state the nature of the technical emergency
I wrote a function which packs the c data structure into a perl object:
SV*
perl_xmmsclient_new_sv_from_ptr(void* ptr, const char* class) {
SV* obj;
SV* sv;
HV* stash;
obj = (SV*)newHV();
sv_magic(obj, 0, PERL_MAGIC_ext, (const char*)ptr, 0);
sv = newRV_inc(obj);
stash = gv_stashpv(class, 1);
sv_bless(sv, stash);
return sv;
}
Which is invoked in the XS new method:
void
new(class, clientname)
const char* class
const char* clientname
PREINIT:
xmmsc_connection_t* con = NULL;
PPCODE:
con = xmmsc_init(clientname);
if (con == NULL) {
ST(0) = &PL_sv_undef;
} else {
ST(0) = perl_xmmsclient_new_sv_from_ptr(con, class);
}
sv_2mortal(ST(0));
XSRETURN(1);
Ok - is there a reason why you are using a HV? If not, then you should use a
SV via a typemap to simplify the whole object creation process - the typemap
would use sv_setref_pv - to create the blessed object in one step.
Cheers,
jez.
Bye
Vasek
As you can see from another of my messages in this thread I do bless by
object (a HV reference with some magic) into the right class. It would
be interesting if perl does anything different when calling it's builtin
'bless' than I do in my wrapper code. I did it in pretty much the same
way that perlxs describes.
-Flo
--
BOFH excuse #418:
Sysadmins busy fighting SPAM.
I use a hash + magic to allow the user to store arbitrary data inside
the object. I don't really want to change that to a blessed integer
value which stores the address of the c stucture I'd like to wrap.
Also I don't see the relation to the actualy problem here.
-Flo
--
BOFH excuse #170:
popper unable to process jumbo kernel
> [...]
>
> Unfortunately DESTROY won't be called when the perl objects reference
> count reaches zero as it seems to be the case in pure-perl world. What's
> the difference between pure-perl code and XS code with regard to
> DESTROY? How can I get my XS DESTROY method called properly?
There's no difference, I guess there's something just slightly
wrong with your code. Please have a look at the Tie::Hash::Indexed
module on CPAN. It implements a tied hash purely in XS, including
a DESTROY method. You can see that DESTROY is being called by
running one of the module's tests while setting THI_DEBUG_OPT:
$ perl Makefile.PL enable-debug
$ make
$ THI_DEBUG_OPT=all perl -Mblib t/101_basic.t
[...]
0=Tie::Hash::Indexed::DESTROY
HTH,
Marcus
--
Lawrence Radiation Laboratory keeps all its data in an old gray trunk.
You were right. The problem was that I used newRV_inc() during the
construction of the perl object, which resulted in a too high REFCNT.
Using newRV_noinc() fixed it.
Thanks,
Flo
--
BOFH excuse #142:
new guy cross-connected phone lines with ac power bus.
None as far as I know.
Are you sure REFCNT has gone to zero?
Most common reason for DESTROY not being called is accidental
REFCNT too high.
Yes it is.
>Perl cleans up objects without references only when leaving a scope.
i.e. that is when it decrements the REFCOUNT (in the FREETMPS/LEAVE).
A further pointer that it is the XS new that is wonky.
>
>
>-Flo
If I had to guess one of two things are wrong:
1. In your XS new you are accidentally returning a reference
to an object which has REFCNT too high - either the reference
or the object may be inflated.
2. You haven't don the bless() quite right and so class object
is in doesn't have a DESTROY.
It is easy to both these - so can we see your 'new' code?
>
>
>-Flo
obj REFCNT = 1
> sv_magic(obj, 0, PERL_MAGIC_ext, (const char*)ptr, 0);
> sv = newRV_inc(obj);
obj REFCNT = 2
You didn't mean that - you meant newRV_noinc()
> stash = gv_stashpv(class, 1);
> sv_bless(sv, stash);
>
> return sv;
>}
>
>Which is invoked in the XS new method:
>
>void
>new(class, clientname)
> const char* class
> const char* clientname
> PREINIT:
> xmmsc_connection_t* con = NULL;
> PPCODE:
> con = xmmsc_init(clientname);
>
> if (con == NULL) {
> ST(0) = &PL_sv_undef;
> } else {
> ST(0) = perl_xmmsclient_new_sv_from_ptr(con, class);
> }
>
> sv_2mortal(ST(0));
> XSRETURN(1);
>-----BEGIN PGP SIGNATURE-----
>Version: GnuPG v1.4.1 (GNU/Linux)
>
>iD8DBQFE2I08dC8qQo5jWl4RAs1pAJ9P8jSYarNjb283zsRSK+u+YPqFZwCfZFR0
>Yc7U1DnqBpf9IHIjQDaNvhs=
>=iPWi
>-----END PGP SIGNATURE-----
> >> DESTROY seems to be the way to do that. So I defined a DESTROY method in
> >> my XS code:
> >>
> >> void
> >> DESTROY(c)
> >> my_c_structure_t* c
> >> CODE:
> >> my_c_structure_unref(c);
> >>
> >>
> >> Unfortunately DESTROY won't be called when the perl objects reference
> >> count reaches zero as it seems to be the case in pure-perl world. What's
> >> the difference between pure-perl code and XS code with regard to
> >> DESTROY? How can I get my XS DESTROY method called properly?
> >
> >DESTROY is not necessarily called at the time the refcount hits zero.
>
> Yes it is.
>
> >Perl cleans up objects without references only when leaving a scope.
>
> i.e. that is when it decrements the REFCOUNT (in the FREETMPS/LEAVE).
D'oh. Sorry, I confused things with the way 'mortal' objects are treated.
Unless I really _am_ growing senile, aren't these recorded on a list of
things to be cleaned up on exit from a scope?
Steve
Yes. And "cleaned up" means doing an SvREFCOUNT_dec().
If when that is done count is zero the DESTROY happens.
But if something else has incremented REFCOUNT then SV lives on.
e.g. this makes
foo($a.$b) # pass a mortal as 1st arg
; # mortals cleaned up on ';'
sub foo
{
push @save,$_[0]; # REFCOUNT up
...
}