Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

XS and DESTROY

2 views
Skip to first unread message

Florian Ragwitz

unread,
Aug 7, 2006, 1:38:07 PM8/7/06
to per...@perl.org
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

signature.asc

Vaclav Barta

unread,
Aug 8, 2006, 8:10:04 AM8/8/06
to Florian Ragwitz, per...@perl.org
Florian Ragwitz wrote:
> 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".
...

> DESTROY seems to be the way to do that. So I defined a DESTROY method in
> my XS code:
...

> 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

Steven N. Hirsch

unread,
Aug 8, 2006, 8:05:17 AM8/8/06
to Florian Ragwitz, per...@perl.org

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

unread,
Aug 8, 2006, 8:37:03 AM8/8/06
to shi...@adelphia.net, ra...@debian.org, per...@perl.org

> > 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?

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

unread,
Aug 8, 2006, 8:12:37 AM8/8/06
to per...@perl.org
On Tue, Aug 08, 2006 at 08:05:17AM -0400, Steven N. Hirsch wrote:
> 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

signature.asc

Jeremy White

unread,
Aug 8, 2006, 8:56:39 AM8/8/06
to ra...@debian.org, per...@perl.org

>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.


Florian Ragwitz

unread,
Aug 8, 2006, 8:21:59 AM8/8/06
to per...@perl.org

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

signature.asc

Florian Ragwitz

unread,
Aug 8, 2006, 9:10:20 AM8/8/06
to per...@perl.org
On Tue, Aug 08, 2006 at 12:37:03PM +0000, Jeremy White wrote:
> 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);

signature.asc

Jeremy White

unread,
Aug 8, 2006, 11:01:23 AM8/8/06
to ra...@debian.org, per...@perl.org

>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;
>}

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.


Vaclav Barta

unread,
Aug 8, 2006, 3:22:47 PM8/8/06
to per...@perl.org, Florian Ragwitz
On Tuesday 08 August 2006 14:21, Florian Ragwitz wrote:
> 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.
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

unread,
Aug 8, 2006, 4:11:15 PM8/8/06
to per...@perl.org
On Tue, Aug 08, 2006 at 09:22:47PM +0200, Vaclav Barta wrote:
> [...] 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.

signature.asc

Florian Ragwitz

unread,
Aug 8, 2006, 4:06:55 PM8/8/06
to per...@perl.org

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

signature.asc

Marcus Holland-Moritz

unread,
Aug 9, 2006, 5:32:10 AM8/9/06
to Florian Ragwitz, per...@perl.org
On 2006-08-07, at 19:38:07 +0200, Florian Ragwitz wrote:

> [...]

>
> 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

unread,
Aug 9, 2006, 9:14:16 AM8/9/06
to per...@perl.org
On Wed, Aug 09, 2006 at 11:32:10AM +0200, Marcus Holland-Moritz wrote:
> On 2006-08-07, at 19:38:07 +0200, Florian Ragwitz wrote:
>
> > [...]
> >
> > 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.

signature.asc

Nick Ing-Simmons

unread,
Aug 10, 2006, 1:08:37 PM8/10/06
to ra...@debian.org, per...@perl.org
Florian Ragwitz <ra...@debian.org> writes:
>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?

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.

Nick Ing-Simmons

unread,
Aug 10, 2006, 1:10:29 PM8/10/06
to shi...@adelphia.net, per...@perl.org, Florian Ragwitz
Steven N. Hirsch <shi...@adelphia.net> writes:
>On Mon, 7 Aug 2006, Florian Ragwitz wrote:
>
>> 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?
>
>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).

Nick Ing-Simmons

unread,
Aug 10, 2006, 1:15:25 PM8/10/06
to ra...@debian.org, per...@perl.org

A further pointer that it is the XS new that is wonky.

>
>
>-Flo

Nick Ing-Simmons

unread,
Aug 10, 2006, 1:14:18 PM8/10/06
to ra...@debian.org, per...@perl.org

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

Nick Ing-Simmons

unread,
Aug 10, 2006, 1:19:00 PM8/10/06
to ra...@debian.org, per...@perl.org
Florian Ragwitz <ra...@debian.org> writes:
>On Tue, Aug 08, 2006 at 12:37:03PM +0000, Jeremy White wrote:
>> 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();

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-----

Steven N. Hirsch

unread,
Aug 10, 2006, 2:02:42 PM8/10/06
to per...@perl.org
On Thu, 10 Aug 2006, Nick Ing-Simmons wrote:

> >> 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

Nick Ing-Simmons

unread,
Aug 31, 2006, 3:48:10 PM8/31/06
to shi...@adelphia.net, per...@perl.org
Steven N. Hirsch <shi...@adelphia.net> writes:
>> >
>> >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?

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
...
}


0 new messages