ctypes and garbage collection

J

Joakim Hove

Hello,

I have used ctypes to wrap a C-library - it has been a really painless
experience!

The C-library instantiates a quite large "container-like" structure.
There are then several functions to inspect the content of the
container, get at items and free the whole thing:

/* C - code */
c_container_type * c_container_alloc( const char * filename );
c_node_type * c_container_get_node( c_container_type *
container , const char * node_id );
void c_container_free( c_container_type *
container );
.....

Observe that the c_container_get_node() function does _not_ allocate
memory, it just returns a opaque handle to a node structure, still
fully owned by the container structure. I have wrapped this with
Python/ctypes roughly like this (severly trimmed pseudo code):

class Container:
def __init__(self , filename):
self.c_ptr = c_container_alloc( filename )

def __del__( self ):
c_container_free( self.c_ptr )

def get_node( self , node_id):
Node( c_container_get_node( self , node_id ))


class Node:
def __init__( self , c_ptr ):
self.c_ptr = c_ptr

def __del__( self ):
pass


Now, a use scenario might be like this:

1. Instantiate a Container() instance.
2. Instantiate a Node() instance with the Container.get_node()
function.
3. Forget about the Container instance and work happily with the Node
instance.
4. Out of the blue comes the gc - and then? Will the Node instance be
enough to protect the Container instance from beeing garbage
collected?

I thought maybe the get_node() function should have something like a
incref() call, and the Node.__del__() function a corresponding
decref()? Or ??


Regards

Joakim Hove
 
U

Ulrich Eckhardt

Joakim said:
I have used ctypes to wrap a C-library
[...]
Observe that the c_container_get_node() function does _not_ allocate
memory, it just returns a opaque handle to a node structure, still
fully owned by the container structure. [...]

class Container:
def __init__(self , filename):
self.c_ptr = c_container_alloc( filename )

def __del__( self ):
c_container_free( self.c_ptr )

def get_node( self , node_id):
Node( c_container_get_node( self , node_id ))


class Node:
def __init__( self , c_ptr ):
self.c_ptr = c_ptr

def __del__( self ):
pass


Now, a use scenario might be like this:

1. Instantiate a Container() instance.
2. Instantiate a Node() instance with the Container.get_node()
function.
3. Forget about the Container instance and work happily with the Node
instance.
4. Out of the blue comes the gc - and then? Will the Node instance be
enough to protect the Container instance from beeing garbage
collected?

No. You should be able to even see that by logging calls to alloc/free of
your library.
I thought maybe the get_node() function should have something like a
incref() call, and the Node.__del__() function a corresponding
decref()? Or ??

I'd add an "__owner" field to the node, initialised with the owning
container instance.

Uli
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top