You should cast self to a requestobject* :

((requestobject*)self)->session

Anyway, I'm currently rewriting the whole request_tp_traverse /
request_tp_clear / request_tp_clear functions like this :

static void request_tp_dealloc(requestobject *self)
{  
    // de-register the object from the GC
    // before its deallocation, to prevent the
    // GC to run on a partially de-allocated object
    PyObject_GC_UnTrack(self);
    
    request_tp_clear(self);

    PyObject_GC_Del(self);
}

/**
 ** request_tp_traverse
 **
 *    Traversal of the request object
 */
static int request_tp_traverse(requestobject* self, visitproc visit,
void *arg) {
    int result;

    if(self->dict) {result = visit(self->dict,arg); if(result) return result;}
    if(self->connection) {result = visit(self->connection,arg);
if(result) return result;}
    if(self->server) {result = visit(self->server,arg); if(result)
return result;}
    if(self->next) {result = visit(self->next,arg); if(result) return result;}
    if(self->prev) {result = visit(self->prev,arg); if(result) return result;}
    if(self->main) {result = visit(self->main,arg); if(result) return result;}
    if(self->headers_in) {result = visit(self->headers_in,arg);
if(result) return result;}
    if(self->headers_out) {result = visit(self->headers_out,arg);
if(result) return result;}
    if(self->err_headers_out) {result =
visit(self->err_headers_out,arg); if(result) return result;}
    if(self->subprocess_env) {result =
visit(self->subprocess_env,arg); if(result) return result;}
    if(self->notes) {result = visit(self->notes,arg); if(result) return result;}
    if(self->phase) {result = visit(self->phase,arg); if(result) return result;}
    
    // no need to Py_DECREF(dict) since the reference is borrowed
    return 0;
}

static int request_tp_clear(requestobject *self)
{  
    PyObject* tmp;
    tmp=self->dict; self->dict=NULL; Py_XDECREF(tmp);
    tmp=self->connection; self->connection=NULL; Py_XDECREF(tmp);
    tmp=self->server; self->server=NULL; Py_XDECREF(tmp);
    tmp=self->next; self->next=NULL; Py_XDECREF(tmp);
    tmp=self->prev; self->prev=NULL; Py_XDECREF(tmp);
    tmp=self->main; self->main=NULL; Py_XDECREF(tmp);
    tmp=self->headers_in; self->headers_in=NULL; Py_XDECREF(tmp);
    tmp=self->headers_out; self->headers_out=NULL; Py_XDECREF(tmp);
    tmp=self->err_headers_out; self->err_headers_out=NULL; Py_XDECREF(tmp);
    tmp=self->subprocess_env; self->subprocess_env=NULL; Py_XDECREF(tmp);
    tmp=self->notes; self->notes=NULL; Py_XDECREF(tmp);
    tmp=self->phase; self->phase=NULL; Py_XDECREF(tmp);
    tmp=self->hlo; self->hlo=NULL; Py_XDECREF(tmp);
    tmp=self->dict; self->dict=NULL; Py_XDECREF(tmp);
    tmp=self->dict; self->dict=NULL; Py_XDECREF(tmp);
    tmp=self->dict; self->dict=NULL; Py_XDECREF(tmp);
    tmp=self->dict; self->dict=NULL; Py_XDECREF(tmp);
    
    return 0;
}

As you can guess from the source code, we'll have to add some code for
the session member when you'll integrate your code in subversion.

Regards,
Nicolas

2005/6/12, Jim Gallacher <[EMAIL PROTECTED]>:
> Nicolas,
> 
> It fails to compile when I add your bit of code. Sure looks like it
> should work though.
> 
> requestobject.c: In function `request_tp_traverse':
> requestobject.c:1539: error: structure has no member named `session'
> requestobject.c:1540: error: structure has no member named `session'
> 
> Just to be clear, it compiles and runs just fine without the extra check
>   added into request_tp_traverse.
> 
> Nicolas Lehuen wrote:
> > I'm re-reading the comment I wrote when I implemented tp_traverse :
> >
> > // 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)
> >
> > Turns out that we should at least traverse the next and prev in case
> > someone does something like req.next.my_prev = req. That's what I
> > meant by "unless you really want it".
> 
> I wondered about that. :)
> 
> Jim
> 
> > It's pretty difficult to get
> > there (you need an internal redirect), but you can.  So I'm going to
> > have a look at re-implementing the tp_traverse handler.
> > Regards,
> > Nicolas
> >
> > 2005/6/12, Nicolas Lehuen <[EMAIL PROTECTED]>:
> >
> >>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