Bojan Smojver
Thu, 17 Jul 2008 23:31:16 -0700
On Fri, 2008-07-18 at 15:59 +1000, Bojan Smojver wrote: > Hmm, not safe after all... OK, I'm going to stop spamming the list now. I promise... This appears to work with both pre and regular cleanup. The trick is to zero the pool pointer in the resource cleanup function, so that destructor can make a choice depending on what happened with the sub-pool already. -- Bojan
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <apr.h>
#include <apr_pools.h>
#include <apr_strings.h>
#include <apr_reslist.h>
struct res{
apr_pool_t *p;
char *r;
};
struct sub{
struct res *r; /* parent resource */
char *s;
};
static apr_status_t res_clean(void *data){
struct res *r=data;
free(r->r);
r->r=NULL;
r->p=NULL;
return APR_SUCCESS;
}
static apr_status_t sub_clean(void *data){
struct sub *s=data;
/* use parent resource a bit */
printf("%s\n",s->r->r);
free(s->s);
s->s=NULL;
return APR_SUCCESS;
}
static apr_status_t con(void **res,void *parm,apr_pool_t *pool){
apr_pool_t *rpool,*spool;
struct res **r=(struct res **)res;
struct sub *s;
apr_pool_create(&rpool,pool);
*r=apr_pcalloc(rpool,sizeof(**r));
(*r)->p=rpool;
(*r)->r=malloc(5);
memcpy((*r)->r,"data",5);
apr_pool_cleanup_register(rpool,*r,res_clean,apr_pool_cleanup_null);
apr_pool_create(&spool,rpool);
s=apr_pcalloc(spool,sizeof(*s));
s->r=*r;
s->s=malloc(5);
memcpy(s->s,"data",5);
apr_pool_cleanup_register(spool,s,sub_clean,apr_pool_cleanup_null);
return APR_SUCCESS;
}
static apr_status_t de(void *res,void *parm,apr_pool_t *pool){
struct res *r=res;
if(r->p)
apr_pool_destroy(r->p);
return APR_SUCCESS;
}
int main(int argc,char **argv){
int i,j,k;
struct res *r[10];
apr_pool_t *pool;
apr_reslist_t *list;
apr_initialize();
for(k=0;k<100000;k++){
apr_pool_create(&pool,NULL);
apr_reslist_create(&list,0,k%11,10,0,con,de,NULL,pool);
for(j=1;j<=10;j++){
for(i=0;i<j;i++)
apr_reslist_acquire(list,(void **)&r[i]);
for(i=0;i<j;i++)
apr_reslist_release(list,r[i]);
}
apr_pool_destroy(pool);
}
apr_terminate();
return 0;
}