|There's more than one way to do things|
Managing C library memory in XSby petermogensen (Sexton)
|on May 05, 2014 at 12:08 UTC||Need Help??|
petermogensen has asked for the
wisdom of the Perl Monks concerning the following question:
I thought this was an FAQ, but since I've not been able to find a single mention of the problem, I try here.Suppose I have a C library like this:
In other words... There's several API calls. Sometime I get a pointer to an object I must free myself later - and at other times I just get to borrow a pointer to a "person" and must NOT free it.
I want to expose "person" and "record" objects to Perl through XS.
So I have an XS wrapper whit a typemap converting the returned pointers to IV and returning a blessed reference to the pointer:
This all works fine. But when such an object reached refcount 0 and DESTROY is called I have to decide whether to call the C library free_*() functions.
And the problem is that I can't see when I get a "person" pointer I get back in DESTROY whether I'm allowed to free it.
Free'ing all "person" pointers would corrupt "record" objects still alive. Not free'ing them would leak. I would have thought there was an idiomatic way of doing this. But I haven't found one. One solution I could imagine is to use PERL_MAGIC_ext and make a note about whether to free or not. But Magic doesn't survive assignments, so it's easy to loose that information as the object is handled in Perl code.
Also, - it have to take into account both the scenarios where "record" survives the "person" and where "person" survives the "record". I know that latter is not how you would normally use this in C, but Perl code usually expects to be able to take any reference it gets with it an let reference counting handle postponing any cleanup.
So: The hackerish solution... What if the XS function returning a "person" which must not be free'd incremented the reference count on the "record" SV (thus postponing its deletion) and at the same time put a pointer to the "record" SV into the NV slot of the "person" SV. ... so when I get a "person" SV in DESTROY, I check whether it has a NV value and if it does, I don't delete it, but instead decrement the reference count on the SV pointed to by the NV value?
It's a hack ... but I don't see where else to store the back-reference for making reference counting handling this. (weakening doesn't survive copy either). NV values seem to survive assignment
But surely, there's an official recommended way to do this? ;-)