Discussion:
XS and DESTROY
(too old to reply)
Florian Ragwitz
2006-08-07 17:38:07 UTC
Permalink
Hello there,

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
Steven N. Hirsch
2006-08-08 12:05:17 UTC
Permalink
Post by Florian Ragwitz
Hello there,
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
void
DESTROY(c)
my_c_structure_t* c
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.
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
Jeremy White
2006-08-08 12:37:03 UTC
Permalink
Post by Florian Ragwitz
void
DESTROY(c)
my_c_structure_t* c
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?
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.
Florian Ragwitz
2006-08-08 13:10:20 UTC
Permalink
Post by Jeremy White
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?
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);
Jeremy White
2006-08-08 15:01:23 UTC
Permalink
Post by Florian Ragwitz
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;
}
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.
Florian Ragwitz
2006-08-08 20:06:55 UTC
Permalink
Post by Jeremy White
Post by Florian Ragwitz
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;
}
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.
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
Nick Ing-Simmons
2006-08-10 17:19:00 UTC
Permalink
Post by Florian Ragwitz
Post by Jeremy White
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?
SV*
perl_xmmsclient_new_sv_from_ptr(void* ptr, const char* class) {
SV* obj;
SV* sv;
HV* stash;
obj = (SV*)newHV();
obj REFCNT = 1
Post by Florian Ragwitz
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()
Post by Florian Ragwitz
stash = gv_stashpv(class, 1);
sv_bless(sv, stash);
return sv;
}
void
new(class, clientname)
const char* class
const char* clientname
xmmsc_connection_t* con = NULL;
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-----
Florian Ragwitz
2006-08-08 12:12:37 UTC
Permalink
Post by Steven N. Hirsch
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.
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
Jeremy White
2006-08-08 12:56:39 UTC
Permalink
Post by Florian Ragwitz
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.
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.
Nick Ing-Simmons
2006-08-10 17:14:18 UTC
Permalink
Post by Florian Ragwitz
Post by Steven N. Hirsch
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.
package Foo;
sub new { bless {}, 'Foo' }
package main;
{
my $f = Foo->new;
}
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.
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?
Post by Florian Ragwitz
-Flo
Nick Ing-Simmons
2006-08-10 17:10:29 UTC
Permalink
Post by Steven N. Hirsch
Post by Florian Ragwitz
Hello there,
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
void
DESTROY(c)
my_c_structure_t* c
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.
Post by Steven N. Hirsch
Perl cleans up objects without references only when leaving a scope.
i.e. that is when it decrements the REFCOUNT (in the FREETMPS/LEAVE).
Post by Steven N. Hirsch
If
you need more immediate action, just undef them yourself at the point
they're no longer needed.
Steve
Steven N. Hirsch
2006-08-10 18:02:42 UTC
Permalink
Post by Nick Ing-Simmons
Post by Steven N. Hirsch
Post by Florian Ragwitz
DESTROY seems to be the way to do that. So I defined a DESTROY method in
void
DESTROY(c)
my_c_structure_t* c
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.
Post by Steven N. Hirsch
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
Nick Ing-Simmons
2006-08-31 19:48:10 UTC
Permalink
Post by Steven N. Hirsch
Post by Nick Ing-Simmons
Post by Steven N. Hirsch
DESTROY is not necessarily called at the time the refcount hits zero.
Yes it is.
Post by Steven N. Hirsch
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?
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
...
}

Vaclav Barta
2006-08-08 12:10:04 UTC
Permalink
Post by Florian Ragwitz
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".
...
Post by Florian Ragwitz
DESTROY seems to be the way to do that. So I defined a DESTROY method in
...
Post by Florian Ragwitz
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?
In that case, I'd just define DESTROY in perl and have it call the XS
destructor - there might be less manual ways, but I'll leave that to the
experts... :-)

Bye
Vasek
Florian Ragwitz
2006-08-08 12:21:59 UTC
Permalink
Post by Vaclav Barta
Post by Florian Ragwitz
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".
...
Post by Florian Ragwitz
DESTROY seems to be the way to do that. So I defined a DESTROY method in
...
Post by Florian Ragwitz
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?
In that case, I'd just define DESTROY in perl and have it call the XS
destructor - there might be less manual ways, but I'll leave that to the
experts... :-)
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
Vaclav Barta
2006-08-08 19:22:47 UTC
Permalink
Post by Florian Ragwitz
package XSModule;
use XSLoader;
XSLoader::load(__PACKAGE__, $VERSION);
1;
The destructor doesn't get called this way as well.
Yes I did, and yes it doesn't (next time I'll experiment _before_ offering
advice :-/ ), but I managed to get it working by also defining a constructor
in Perl and blessing the pointer returned from XS into the package - in
retrospect, it makes a lot of sense that the reference must be blessed to
behave like an object... perldoc perlxs describes how to bless stuff inside
typemap, but again, perhaps it's easier to do it manually...

Bye
Vasek
Florian Ragwitz
2006-08-08 20:11:15 UTC
Permalink
[...] but I managed to get it working by also defining a constructor
in Perl and blessing the pointer returned from XS into the package -
in retrospect, it makes a lot of sense that the reference must be
blessed to behave like an object... perldoc perlxs describes how to
bless stuff inside typemap, but again, perhaps it's easier to do it
manually...
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.
Nick Ing-Simmons
2006-08-10 17:15:25 UTC
Permalink
Post by Florian Ragwitz
Post by Vaclav Barta
Post by Florian Ragwitz
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".
...
Post by Florian Ragwitz
DESTROY seems to be the way to do that. So I defined a DESTROY method in
...
Post by Florian Ragwitz
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?
In that case, I'd just define DESTROY in perl and have it call the XS
destructor - there might be less manual ways, but I'll leave that to the
experts... :-)
package XSModule;
use XSLoader;
XSLoader::load(__PACKAGE__, $VERSION);
1;
The destructor doesn't get called this way as well.
A further pointer that it is the XS new that is wonky.
Post by Florian Ragwitz
-Flo
Marcus Holland-Moritz
2006-08-09 09:32:10 UTC
Permalink
Post by Florian Ragwitz
[...]
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.
Florian Ragwitz
2006-08-09 13:14:16 UTC
Permalink
Post by Marcus Holland-Moritz
Post by Florian Ragwitz
[...]
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 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.
Nick Ing-Simmons
2006-08-10 17:08:37 UTC
Permalink
Post by Florian Ragwitz
Hello there,
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
void
DESTROY(c)
my_c_structure_t* c
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?
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.
Post by Florian Ragwitz
How can I get my XS DESTROY method called properly?
TIA,
Flo
Loading...