dev  

Re: svn commit: r677505 - /apr/apr-util/trunk/misc/apr_reslist.c

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;
}