Nick Ing-Simmons wrote:

>Muppet <[EMAIL PROTECTED]> writes:
>  
>
>>Steve Hay said:
>>    
>>
>>>So: I've entrusted managemnt of foo's memory to Perl by placing it in
>>>the SV, but I still have to free up anything else that was allocated and
>>>is pointed to from within foo.  Is there any way to have Perl free the
>>>members of foo when it frees foo, so that the whole struct is freed
>>>instead of just the outer bit?
>>>      
>>>
>>if it's a blessed SV, so you can set up a DESTROY method.  otherwise, you'll
>>need to use a magic virtual table.  it's described in perlguts ('Magic
>>Variables') and the Embedding and Extending Perl book.
>>    
>>
>
>Tk does exactly this kind of thing, to create "objects" for 
>XEvent structs, as it is an object it cleans up by blessing.
>I think I have used the vtable trick as well.
>
OK, I've had a stab at tidying things up a bit, and played around with 
DESTROY and magic.  I thought I'd mail back to the list for the benefit 
of anyone trawling the archives in the future (which might include me ;)

Firstly, I've changed the SV to store a pointer to the Foo struct rather 
than actually storing the struct in the SV.  This means that the "outer" 
part of the struct is no longer realloc()'ed to the SV so FooFree() now 
free's exactly what FooAlloc() allocated, which makes for a more sane 
design.

The manualfoo() XSUB uses this scheme with an explicit call to FooFree().

The remaining two XSUB's -- objectfoo() and magicfoo() -- arrange to 
have the FooFree() call made automatically when the SV is destroyed.

The object version is simple enough, but somehow I don't really like the 
idea of making the SV an object just to get a DESTROY method.  I guess 
it doesn't really do any harm, it just doesn't "feel right".

The magic version is new to me.  Have I done it right?  I've never used 
magic before, and had a couple of questions about it:

- What is the second arg to sv_magic() for?  Would there be any merit in 
storing the Foo struct in there?  It would still need to be wrapped in 
an SV somehow, though (mg_obj is an SV *), so we're just going round in 
circles then.

- What were the final two args to sv_magic() for?  I just passed (NULL, 
0).  Perlguts gives an example of using PERL_MAGIC_uvar which passed a 
struct in there.  Could I have done something similar to avoid having to 
find the magic and manually assign mg_virtual?

- Perlguts also says this:

"Note that because multiple extensions may be using PERL_MAGIC_ext or 
PERL_MAGIC_uvar magic, it is important for extensions to take extra care 
to avoid conflict. Typically only using the magic on objects blessed 
into the same class as the extension is sufficient. For PERL_MAGIC_ext 
magic, it may also be appropriate to add an I32 'signature' at the top 
of the private data area and check that."

What is the "private data area" to which it refers?  Does it mean 
mg_ptr/mg_len?

- Steve


------------------------------------------------
Radan Computational Ltd.

The information contained in this message and any files transmitted with it are 
confidential and intended for the addressee(s) only.  If you have received this 
message in error or there are any problems, please notify the sender immediately.  The 
unauthorized use, disclosure, copying or alteration of this message is strictly 
forbidden.  Note that any views or opinions presented in this email are solely those 
of the author and do not necessarily represent those of Radan Computational Ltd.  The 
recipient(s) of this message should check it and any attached files for viruses: Radan 
Computational will accept no liability for any damage caused by any virus transmitted 
by this email.
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"

#include "ppport.h"

typedef struct {
  char *buf;
} Foo;

static Foo *FooAlloc(pTHX);
static void FooFree(pTHX_ Foo *foo);
static int MagicFooFree(pTHX_ SV *sv, MAGIC *mg);

static MGVTBL Foo_vtab = {
  NULL,
  NULL,
  NULL,
  NULL,
  MagicFooFree
};

static Foo *FooAlloc(pTHX) {
  Foo *foo;
  Newz(0, foo, 1, Foo);
  Newz(0, foo->buf, 1024, char);
  return foo;
}

static void FooFree(pTHX_ Foo *foo) {
  Safefree(foo->buf);
  Safefree(foo);
}

static int MagicFooFree(pTHX_ SV *sv, MAGIC *mg) {
  FooFree(aTHX_ INT2PTR(Foo *, SvUVX(sv)));
  return 1;
}

MODULE = Foo            PACKAGE = Foo           

void
manualfoo()
PPCODE:
{
  SV *sv;
  Foo *foo;
  foo = FooAlloc(aTHX);
  sv = newSVuv(PTR2UV(foo));
  SvREADONLY_on(sv);
  FooFree(aTHX_ INT2PTR(Foo *, SvUVX(sv)));
  SvREFCNT_dec(sv);
}

void
objectfoo()
PPCODE:
{
  SV *sv, *rv;
  HV *stash;
  Foo *foo;
  foo = FooAlloc(aTHX);
  sv = newSVuv(PTR2UV(foo));
  stash = gv_stashpv("Foo", 1);
  rv = newRV_noinc(sv);
  sv_bless(rv, stash);
  SvREADONLY_on(sv);
  SvREFCNT_dec(rv);
}

void
DESTROY(self)
SV *self;
PPCODE:
{
  SV *sv;
  sv = SvRV(self);
  FooFree(aTHX_ INT2PTR(Foo *, SvUVX(sv)));
}

void
magicfoo()
PPCODE:
{
  SV *sv;
  Foo *foo;
  MAGIC *mg;
  foo = FooAlloc(aTHX);
  sv = newSVuv(PTR2UV(foo));
  sv_magic(sv, NULL, PERL_MAGIC_ext, NULL, 0);
  SvREADONLY_on(sv);
  mg = mg_find(sv, PERL_MAGIC_ext);
  mg->mg_virtual = &Foo_vtab;
  SvREFCNT_dec(sv);
}

Reply via email to