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

Reply via email to