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