problems creating C extension types

Robert Roy rjroy at takingcontrol.com
Sun Feb 25 02:43:40 EST 2001


Hi,
I am having problems with some C extension types I am building. The
objects are a Python interface to a database. To access the database I
need to initiate a session. Once the session is established, then
queries on the database will return sets. I have created a Session
object to encapsulate the session. Once a session is instantiated,
calls to its query method return instances of the Set extension type.
The sets keep a pointer to the session object for later use. The
session object is passed into the set constructor, assigned to a
variable and the reference count is increased.

This seems to work fine if I instantiate only one set. However if I
instantiate more than one set object, and do not explicitly delete
them,  the application crashes on exit (WINNT) with a memory error.

thus
o = mymodule.Session()
s = o.query('foo')
t = o.query('bar')
will crash on exit after deleting "s" sucessfully. In the general
case, n-1 objects seem to destroy successfully. Using sys.getrefcount
after each query, the ref counts on "o" seem to be consistent with
what would be expected.


and 
o = mymodule.Session()
s = o.query('foo')
t = o.query('bar')

s=t=None
will exit gracefully.

In my first cut at this, the Set object only stored the raw hSession
handle from the DBinit function. But this caused the same problem as I
am seing now since the Session instance was being destroyed first and
was closing the DB session before the Sets could be deallocated. The
solution seemed obvious so I decided to store a pointer to the Session
instance in each Set and use the reference counting mechanism to keep
the object alive until all Set instances were destroyed. I am puzzled
as to why this does not seem to work. 

The following is stripped down version of my code. I would appreciate
any suggestions. Perhaps I am missing something obvious?

Bob

/* Session object */
typedef struct {
  PyObject_HEAD
  HSession        hSession;
} Session;

/* Set object */
typedef struct {
  PyObject_HEAD
  PyObject*         pSession;
  HSet        hSet;
  TBaseInt   nSetSize;
} Set;

static PyObject*
Set_NEW(PyObject* pSession, char* lpQuery)
    {	
	Set* object;

	object = PyObject_NEW(OTPYSet, &OTPYSet_Type);
	if (object == NULL)
		{
		PyErr_SetString(PyExc_TypeError, " failed");
		return NULL;
		}
	
	// initialise members
	object->hSet = 0;
	object->nSetSize = 0;

	object->pSession = pSession;
	// keep a reference to the calling object
	Py_INCREF(pSession);

	status = DBGetSet(((Session*)pSession)->hSession, \
	        &(object->hSet), &(object->nSetSize),  lpQuery);

	return (PyObject*) object;
    }


static void
OTPYSet_dealloc(PyObject* self)
    {
	PyObject * object;
	HSession hSession;
	HSet hSet;
	hSet = ((Set*)self)->hSet;

	object = ((Set*)self)->pSession;
	hSearch = ((Session*)object)->hSearch;

    DBFreeSet(hSearch, hSet);
    PyMem_DEL(self);
	Py_DECREF(object);
    }





static PyObject*
Session_NEW(PyObject* args)
    {
	// a few local vars
    HSession        hSession;	
	OTPYSearch* object;

    if (!PyArg_NoArgs(args))
        return NULL;

	object = PyObject_NEW(Session, &Session_Type);
	if (object == NULL)
		{
		PyErr_SetString(PyExc_TypeError, " error");
		return NULL;
		}

	DBSessionInit( &(object->hSession), NULL, NULL );

	return (PyObject*) object;
    }

static PyObject*
Session_query(PyObject* self, PyObject* args)
    {
	PyObject* object;
	char* lpQuery = NULL;
    PyArg_ParseTuple(args, "s", &lpQuery);
	if (lpQuery == NULL)
		{
		Py_INCREF(Py_None);
		return Py_None;
		}
	else
		{
		object = Set_NEW(self, lpQuery);
		return object;
		}
	}

static void
Session_dealloc(PyObject* self)
    {
    HSearch        hSearch;
	hSearch = ((Session*)self)->hSearch;
    
    DBSessionFree( hSearch );
    PyMem_DEL(self);
    }






More information about the Python-list mailing list