Duh, I get it. If you add a member to the request object, and this
member is not referenced in the request object's dictionary, then you
have to add a special case for it in the tp_traverse handler. In
requestobject.c :
/**
** request_tp_traverse
**
* Traversal of the request object
*/
static int request_tp_traverse(PyObject *self, visitproc visit, void *arg) {
PyObject *dict,*values,*item,*str;
int i,size;
// only traverse its dictionary since other fields defined in
request_rec_mbrs with type T_OBJECT
// cannot be the source of memory leaks (unless you really want it)
dict=*_PyObject_GetDictPtr(self);
if(dict) {
// this check is not needed, I guess, _PyObject_GetDictPtr
always give a pointer to a dict object.
if(PyDict_Check(dict)) {
i = visit(dict,arg);
if(i) {
ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0,
((requestobject*)self)->request_rec, "%s:%i Call to visit()
failed",__LINE__,__FILE__);
// no need to Py_DECREF(dict) since the reference is borrowed
return i;
}
}
else {
ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0,
((requestobject*)self)->request_rec, "%s:%i Expected a
dictionary",__LINE__,__FILE__);
}
}
else {
ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0,
((requestobject*)self)->request_rec, "%s:%i Expected a
dictionary",__LINE__,__FILE__);
}
/* This is the new code that needs to be added to support the new
session member */
if(self->session) {
i = visit(self->session,arg);
if(i) {
ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0,
((requestobject*)self)->request_rec, "%s:%i Call to visit()
failed",__LINE__,__FILE__);
return i;
}
}
// no need to Py_DECREF(dict) since the reference is borrowed
return 0;
}
Regards,
Nicolas
2005/6/12, Jim Gallacher <[EMAIL PROTECTED]>:
Hi Nicolas,
Nicolas Lehuen wrote:
Hi Jim,
How where you creating the session object in requestobject.c ? If you
were using PythonObject_New, then this may explain the memory leak.
Objects that must be managed by the garbage collector have to be
created with PyObject_GC_New.
The c-code loads the python module and calls a function which generates
the session object.
src/requestobject.c
static PyObject *req_get_session(requestobject *self, PyObject *args)
{
PyObject *m; // session module
PyObject *sid; // session id
PyObject *result;
if (!self->session) {
sid = PyObject_CallMethod(self->subprocess_env, "get",
"(ss)","REDIRECT_PYSID", "");
/********
* This is where the session instance is created
********/
m = PyImport_ImportModule("mod_python.session2.TestSession");
self->session = PyObject_CallMethod(m, "create_session", "(OO)",
self, sid);
Py_DECREF(m);
Py_DECREF(sid);
if (self->session == NULL)
return NULL;
}
result = self->session;
Py_INCREF(result);
return result;
}
----------------------------------------------------------------
mod_python/session2/TestSession.py
# emulate a simple test session
import _apache
from mod_python.Session import _new_sid
class TestSession(object):
def __init__(self, req, sid=0, secret=None, timeout=0, lock=1):
req.log_error("TestSession.__init__")
# Circular Reference causes problem
self._req = req
# keeping a reference to the server object does
# NOT cause a problem
self._server = req.server
self._lock = 1
self._locked = 0
self._sid = _new_sid(req)
self.lock()
self.unlock()
def lock(self):
if self._lock:
_apache._global_lock(self._req.server, self._sid)
self._locked = 1
def unlock(self):
# unlock will ocassionally segfault
if self._lock and self._locked:
_apache._global_unlock(self._req.server, self._sid)
self._locked = 0
def create_session(req,sid):
return TestSession(req,sid)