apr-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From aa...@apache.org
Subject cvs commit: apr-util/test testreslist.c Makefile.in
Date Mon, 05 Aug 2002 03:25:40 GMT
aaron       2002/08/04 20:25:40

  Modified:    misc     Makefile.in
               test     Makefile.in
  Added:       include  apr_reslist.h
               misc     apr_reslist.c
               test     testreslist.c
  Log:
  Add a new Resource List API for APR-UTIL.
  
  A Resource List is a collection of persistent reusable resources.
  The list controls the construction and destruction of the elements
  in the list, and allows threadsafe access to the elements to the
  list. Imagine a set of persistent database connections that are
  created (and destroyed) based on demand.
  
  Revision  Changes    Path
  1.1                  apr-util/include/apr_reslist.h
  
  Index: apr_reslist.h
  ===================================================================
  /* ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2000-2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Apache" and "Apache Software Foundation" must
   *    not be used to endorse or promote products derived from this
   *    software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    nor may "Apache" appear in their name, without prior written
   *    permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  #ifndef APR_RESLIST_H
  #define APR_RESLIST_H
  
  /** 
   * @file apr_reslist.h
   * @brief APR Resource List Routines
   */
  
  #include "apr.h"
  #include "apu.h"
  #include "apr_pools.h"
  #include "apr_errno.h"
  #include "apr_time.h"
  
  #if APR_HAS_THREADS
  
  /**
   * @defgroup APR_RMM Resource List Routines
   * @ingroup APR
   * @{
   */
  
  #ifdef __cplusplus
  extern "C" {
  #endif /* __cplusplus */
  
  /** Opaque resource list object */
  typedef struct apr_reslist_t apr_reslist_t;
  
  /**
   * Generic prototypes for the constructor and destructor that
   * is called by the resource list any time it needs to create
   * or destroy a resource.
   */
  typedef apr_status_t (*apr_reslist_constructor)(void **resource, void *params,
                                                  apr_pool_t *pool);
  typedef apr_status_t (*apr_reslist_destructor)(void *resource, void *params,
                                                 apr_pool_t *pool);
  
  /**
   * Create a new resource list with the following parameters:
   * @param reslist An address where the pointer to the new resource
   *                list will be stored.
   * @param pool The pool to use for local storage and management
   * @param min Allowed minimum number of available resources. Zero
   *            creates new resources only when needed.
   * @param smax Resources will be destroyed to meet this maximum
   *             restriction as they expire.
   * @param hmaxx Absolute maximum limit on the number of total resources.
   * @param expire If non-zero, sets the maximum amount of time a resource
   *               may be available while exceeding the soft limit.
   * @param con Constructor routine that is called to create a new resource.
   * @param de Destructor routine that is called to destroy an expired resource.
   * @param pool The pool from which to create this resoure list. Also the
   *             same pool that is passed to the constructor and destructor
   *             routines.
   */
  APU_DECLARE(apr_status_t) apr_reslist_create(apr_reslist_t **reslist,
                                               int min, int smax, int hmax,
                                               apr_interval_time_t ttl,
                                               apr_reslist_constructor con,
                                               apr_reslist_destructor de,
                                               void *params,
                                               apr_pool_t *pool);
  
  /**
   * Destroy the given resource list and all resources controlled by
   * this list.
   * FIXME: Should this block until all resources become available,
   *        or maybe just destroy all the free ones, or maybe destroy
   *        them even though they might be in use by something else?
   * @param rmm The relocatable memory block to destroy
   */
  APU_DECLARE(apr_status_t) apr_reslist_destroy(apr_reslist_t *reslist);
  
  /**
   * Retrieve a resource from the list, creating a new one if necessary.
   * If we have met our maximum number of resources, we will block
   * until one becomes available.
   */
  APU_DECLARE(apr_status_t) apr_reslist_acquire(apr_reslist_t *reslist,
                                                void **resource);
  
  /**
   * Return a resource back to the list of available resources.
   */
  APU_DECLARE(apr_status_t) apr_reslist_release(apr_reslist_t *reslist,
                                                void *resource);
  
  #ifdef __cplusplus
  }
  #endif
  
  /** @} */
  
  #endif  /* APR_HAS_THREADS */
  
  #endif  /* ! APR_RESLIST_H */
  
  
  
  1.9       +1 -1      apr-util/misc/Makefile.in
  
  Index: Makefile.in
  ===================================================================
  RCS file: /home/cvs/apr-util/misc/Makefile.in,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- Makefile.in	8 May 2002 22:00:58 -0000	1.8
  +++ Makefile.in	5 Aug 2002 03:25:40 -0000	1.9
  @@ -2,7 +2,7 @@
   
   INCLUDES = @APRUTIL_PRIV_INCLUDES@ @APR_INCLUDES@ @APRUTIL_INCLUDES@
   
  -TARGETS = apr_date.lo apr_rmm.lo
  +TARGETS = apr_date.lo apr_rmm.lo apr_reslist.lo
   
   # bring in rules.mk for standard functionality
   @INCLUDE_RULES@
  
  
  
  1.1                  apr-util/misc/apr_reslist.c
  
  Index: apr_reslist.c
  ===================================================================
  /* ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2000-2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Apache" and "Apache Software Foundation" must
   *    not be used to endorse or promote products derived from this
   *    software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    nor may "Apache" appear in their name, without prior written
   *    permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  #include <assert.h>
  
  #include "apu.h"
  #include "apr_reslist.h"
  #include "apr_errno.h"
  #include "apr_strings.h"
  #include "apr_thread_mutex.h"
  #include "apr_thread_cond.h"
  #include "apr_ring.h"
  
  #if APR_HAS_THREADS
  
  /**
   * A single resource element.
   */
  struct apr_res_t {
      apr_time_t freed;
      void *opaque;
      APR_RING_ENTRY(apr_res_t) link;
  };
  typedef struct apr_res_t apr_res_t;
  
  /**
   * A ring of resources representing the list of available resources.
   */
  APR_RING_HEAD(apr_resring_t, apr_res_t);
  typedef struct apr_resring_t apr_resring_t;
  
  struct apr_reslist_t {
      apr_pool_t *pool; /* the pool used in constructor and destructor calls */
      int ntotal;     /* total number of resources managed by this list */
      int nidle;      /* number of available resources */
      int min;  /* desired minimum number of available resources */
      int smax; /* soft maximum on the total number of resources */
      int hmax; /* hard maximum on the total number of resources */
      apr_interval_time_t ttl; /* TTL when we have too many resources */
      apr_reslist_constructor constructor;
      apr_reslist_destructor destructor;
      void *params; /* opaque data passed to constructor and destructor calls */
      apr_resring_t avail_list;
      apr_resring_t free_list;
      apr_thread_mutex_t *listlock;
      apr_thread_cond_t *avail;
  };
  
  /**
   * Grab a resource from the front of the resource list.
   * Assumes: that the reslist is locked.
   */
  static apr_res_t *pop_resource(apr_reslist_t *reslist)
  {
      apr_res_t *res;
      res = APR_RING_FIRST(&reslist->avail_list);
      APR_RING_REMOVE(res, link);
      reslist->nidle--;
      return res;
  }
  
  /**
   * Add a resource to the end of the list, set the time at which
   * it was added to the list.
   * Assumes: that the reslist is locked.
   */
  static void push_resource(apr_reslist_t *reslist, apr_res_t *resource)
  {
      APR_RING_INSERT_TAIL(&reslist->avail_list, resource, apr_res_t, link);
      resource->freed = apr_time_now();
      reslist->nidle++;
  }
  
  /**
   * Get an empty resource container from the free list.
   */
  static apr_res_t *get_container(apr_reslist_t *reslist)
  {
      apr_res_t *res;
  
      assert(!APR_RING_EMPTY(&reslist->free_list, apr_res_t, link));
  
      res = APR_RING_FIRST(&reslist->free_list);
      APR_RING_REMOVE(res, link);
  
      return res;
  }
  
  /**
   * Free up a resource container by placing it on the free list.
   */
  static void free_container(apr_reslist_t *reslist, apr_res_t *container)
  {
      APR_RING_INSERT_TAIL(&reslist->free_list, container, apr_res_t, link);
  }
  
  /**
   * Create a new resource and return it.
   * Assumes: that the reslist is locked.
   */
  static apr_status_t create_resource(apr_reslist_t *reslist, apr_res_t **ret_res)
  {
      apr_status_t rv;
      apr_res_t *res;
  
      res = apr_pcalloc(reslist->pool, sizeof(*res));
  
      rv = reslist->constructor(&res->opaque, reslist->params, reslist->pool);
      if (rv != APR_SUCCESS) {
          return rv;
      }
  
      *ret_res = res;
      return APR_SUCCESS;
  }
  
  /**
   * Destroy a single idle resource.
   * Assumes: that the reslist is locked.
   */
  static apr_status_t destroy_resource(apr_reslist_t *reslist, apr_res_t *res)
  {
      apr_status_t rv;
  
      rv = reslist->destructor(res->opaque, reslist->params, reslist->pool);
      if (rv != APR_SUCCESS) {
          return rv;
      }
  
      return APR_SUCCESS;
  }
  
  static apr_status_t reslist_cleanup(void *data_)
  {
      apr_status_t rv;
      apr_reslist_t *rl = data_;
      apr_res_t *res;
  
      apr_thread_mutex_lock(rl->listlock);
  
      while (rl->nidle > 0) {
          res = pop_resource(rl);
          rl->ntotal--;
          rv = destroy_resource(rl, res);
          if (rv != APR_SUCCESS) {
              return rv;
          }
          free_container(rl, res);
      }
  
      assert(rl->nidle == 0);
      assert(rl->ntotal == 0);
  
      apr_thread_mutex_destroy(rl->listlock);
      apr_thread_cond_destroy(rl->avail);
  
      return APR_SUCCESS;
  }
  
  /**
   * Perform routine maintenance on the resource list. This call
   * may instantiate new resources or expire old resources.
   */
  static apr_status_t reslist_maint(apr_reslist_t *reslist)
  {
      apr_time_t now;
      apr_status_t rv;
      apr_res_t *res;
      int created_one = 0;
  
      apr_thread_mutex_lock(reslist->listlock);
  
      /* Check if we need to create more resources, and if we are allowed to. */
      while (reslist->nidle < reslist->min && reslist->ntotal <= reslist->hmax)
{
          /* Create the resource */
          rv = create_resource(reslist, &res);
          if (rv != APR_SUCCESS) {
              apr_thread_mutex_unlock(reslist->listlock);
              return rv;
          }
          /* Add it to the list */
          push_resource(reslist, res);
          /* Update our counters */
          reslist->ntotal++;
          /* If someone is waiting on that guy, wake them up. */
          rv = apr_thread_cond_signal(reslist->avail);
          if (rv != APR_SUCCESS) {
              apr_thread_mutex_unlock(reslist->listlock);
              return rv;
          }
          created_one++;
      }
  
      /* We don't need to see if we're over the max if we were under it before */
      if (created_one) {
          apr_thread_mutex_unlock(reslist->listlock);
          return APR_SUCCESS;
      }
  
      /* Check if we need to expire old resources */
      now = apr_time_now();
      while (reslist->nidle > reslist->smax && reslist->nidle > 0)
{
          /* Peak at the first resource in the list */
          res = APR_RING_FIRST(&reslist->avail_list);
          /* See if the oldest entry should be expired */
          if (now - res->freed < reslist->ttl) {
              /* If this entry is too young, none of the others
               * will be ready to be expired either, so we are done. */
              break;
          }
          res = pop_resource(reslist);
          reslist->ntotal--;
          rv = destroy_resource(reslist, res);
          if (rv != APR_SUCCESS) {
              apr_thread_mutex_unlock(reslist->listlock);
              return rv;
          }
          free_container(reslist, res);
      }
  
      apr_thread_mutex_unlock(reslist->listlock);
      return APR_SUCCESS;
  }
  
  APU_DECLARE(apr_status_t) apr_reslist_create(apr_reslist_t **reslist,
                                               int min, int smax, int hmax,
                                               apr_interval_time_t ttl,
                                               apr_reslist_constructor con,
                                               apr_reslist_destructor de,
                                               void *params,
                                               apr_pool_t *pool)
  {
      apr_status_t rv;
      apr_reslist_t *rl;
  
      /* Do some sanity checks so we don't thrash around in the
       * maintenance routine later. */
      if (min >= smax || min >= hmax || smax > hmax || ttl < 0) {
          return APR_EINVAL;
      }
  
      rl = apr_pcalloc(pool, sizeof(*rl));
      rl->pool = pool;
      rl->min = min;
      rl->smax = smax;
      rl->hmax = hmax;
      rl->ttl = ttl;
      rl->constructor = con;
      rl->destructor = de;
      rl->params = params;
  
      APR_RING_INIT(&rl->avail_list, apr_res_t, link);
      APR_RING_INIT(&rl->free_list, apr_res_t, link);
  
      rv = apr_thread_mutex_create(&rl->listlock, APR_THREAD_MUTEX_DEFAULT,
                                   pool);
      if (rv != APR_SUCCESS) {
          return rv;
      }
      rv = apr_thread_cond_create(&rl->avail, pool);
      if (rv != APR_SUCCESS) {
          return rv;
      }
  
      rv = reslist_maint(rl);
      if (rv != APR_SUCCESS) {
          return rv;
      }
  
      apr_pool_cleanup_register(rl->pool, rl, reslist_cleanup,
                                apr_pool_cleanup_null);
  
      *reslist = rl;
  
      return APR_SUCCESS;
  }
  
  APU_DECLARE(apr_status_t) apr_reslist_destroy(apr_reslist_t *reslist)
  {
      return apr_pool_cleanup_run(reslist->pool, reslist, reslist_cleanup);
  }
  
  APU_DECLARE(apr_status_t) apr_reslist_acquire(apr_reslist_t *reslist,
                                                void **resource)
  {
      apr_status_t rv;
      apr_res_t *res;
  
      apr_thread_mutex_lock(reslist->listlock);
      /* If there are idle resources on the available list, use
       * them right away. */
      if (reslist->nidle > 0) {
          /* Pop off the first resource */
          res = pop_resource(reslist);
          *resource = res->opaque;
          free_container(reslist, res);
          apr_thread_mutex_unlock(reslist->listlock);
          return APR_SUCCESS;
      }
      /* If we've hit our max, block until we're allowed to create
       * a new one, or something becomes free. */
      else while (reslist->ntotal >= reslist->hmax
                  && reslist->nidle <= 0) {
          apr_thread_cond_wait(reslist->avail, reslist->listlock);
      }
      /* If we popped out of the loop, first try to see if there
       * are new resources available for immediate use. */
      if (reslist->nidle > 0) {
          res = pop_resource(reslist);
          *resource = res->opaque;
          free_container(reslist, res);
          apr_thread_mutex_unlock(reslist->listlock);
          return APR_SUCCESS;
      }
      /* Otherwise the reason we dropped out of the loop
       * was because there is a new slot available, so create
       * a resource to fill the slot and use it. */
      else {
          rv = create_resource(reslist, &res);
          reslist->ntotal++;
          *resource = res->opaque;
          free_container(reslist, res);
          apr_thread_mutex_unlock(reslist->listlock);
          return APR_SUCCESS;
      }
  }
  
  APU_DECLARE(apr_status_t) apr_reslist_release(apr_reslist_t *reslist,
                                                void *resource)
  {
      apr_res_t *res;
  
      apr_thread_mutex_lock(reslist->listlock);
      res = get_container(reslist);
      res->opaque = resource;
      push_resource(reslist, res);
      apr_thread_cond_signal(reslist->avail);
      apr_thread_mutex_unlock(reslist->listlock);
  
      return reslist_maint(reslist);
  }
  
  #endif  /* APR_HAS_THREADS */
  
  
  
  1.30      +6 -1      apr-util/test/Makefile.in
  
  Index: Makefile.in
  ===================================================================
  RCS file: /home/cvs/apr-util/test/Makefile.in,v
  retrieving revision 1.29
  retrieving revision 1.30
  diff -u -r1.29 -r1.30
  --- Makefile.in	17 Jul 2002 04:11:33 -0000	1.29
  +++ Makefile.in	5 Aug 2002 03:25:40 -0000	1.30
  @@ -2,7 +2,7 @@
   
   INCLUDES = @APRUTIL_PRIV_INCLUDES@ @APR_INCLUDES@ @APRUTIL_INCLUDES@
   
  -PROGRAMS = testdbm testdate testmd4 testmd5 testxml testrmm teststrmatch testuuid
  +PROGRAMS = testdbm testdate testmd4 testmd5 testxml testrmm teststrmatch testuuid testreslist
   TARGETS = $(PROGRAMS)
   
   # bring in rules.mk for standard functionality
  @@ -50,4 +50,9 @@
   testuuid_LDADD =  ../libaprutil.la
   testuuid: $(testuuid_OBJECTS) $(testuuid_LDADD)
   	$(LINK) $(testuuid_OBJECTS) $(testuuid_LDADD) $(PROGRAM_DEPENDENCIES)
  +
  +testreslist_OBJECTS = testreslist.lo
  +testreslist_LDADD =  ../libaprutil.la
  +testreslist: $(testreslist_OBJECTS) $(testreslist_LDADD)
  +	$(LINK) $(testreslist_OBJECTS) $(testreslist_LDADD) $(PROGRAM_DEPENDENCIES)
   
  
  
  
  1.1                  apr-util/test/testreslist.c
  
  Index: testreslist.c
  ===================================================================
  /* ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2000-2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Apache" and "Apache Software Foundation" must
   *    not be used to endorse or promote products derived from this
   *    software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    nor may "Apache" appear in their name, without prior written
   *    permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  #include <stdio.h>
  #include <stdlib.h>
  #include "apr_reslist.h"
  #include "apr_thread_proc.h"
  
  #define RESLIST_MIN   3
  #define RESLIST_SMAX 10
  #define RESLIST_HMAX 20
  #define RESLIST_TTL  (350000LL) /* 35 ms */
  #define CONSUMER_THREADS 25
  #define CONSUMER_ITERATIONS 250
  #define CONSTRUCT_SLEEP_TIME  (250000LL) /* 25 ms */
  #define DESTRUCT_SLEEP_TIME   (100000LL) /* 10 ms */
  #define WORK_DELAY_SLEEP_TIME (150000LL) /* 15 ms */
  
  typedef struct {
      apr_interval_time_t sleep_upon_construct;
      apr_interval_time_t sleep_upon_destruct;
      int c_count;
      int d_count;
  } my_parameters_t;
  
  typedef struct {
      int id;
  } my_resource_t;
  
  static apr_status_t my_constructor(void **resource, void *params,
                                     apr_pool_t *pool)
  {
      my_resource_t *res;
      my_parameters_t *my_params = params;
  
      /* Create some resource */
      res = apr_palloc(pool, sizeof(*res));
      res->id = my_params->c_count++;
  
      printf("++ constructing new resource [id:%d]\n", res->id);
  
      /* Sleep for awhile, to simulate construction overhead. */
      apr_sleep(my_params->sleep_upon_construct);
  
      /* Set the resource so it can be managed by the reslist */
      *resource = res;
      return APR_SUCCESS;
  }
  
  static apr_status_t my_destructor(void *resource, void *params,
                                    apr_pool_t *pool)
  {
      my_resource_t *res = resource;
      my_parameters_t *my_params = params;
  
      printf("-- destructing old resource [id:%d, #%d]\n", res->id,
             my_params->d_count++);
  
      apr_sleep(my_params->sleep_upon_destruct);
  
      return APR_SUCCESS;
  }
  
  typedef struct {
      int tid;
      apr_reslist_t *reslist;
      apr_interval_time_t work_delay_sleep;
  } my_thread_info_t;
  
  static void * APR_THREAD_FUNC resource_consuming_thread(apr_thread_t *thd,
                                                          void *data)
  {
      apr_status_t rv;
      my_thread_info_t *thread_info = data;
      apr_reslist_t *rl = thread_info->reslist;
      int i;
  
      for (i = 0; i < CONSUMER_ITERATIONS; i++) {
          my_resource_t *res;
          rv = apr_reslist_acquire(rl, (void**)&res);
          if (rv != APR_SUCCESS) {
              fprintf(stderr, "Failed to retrieve resource from reslist\n");
              apr_thread_exit(thd, rv);
              return NULL;
          }
          printf("  [tid:%d,iter:%d] using resource id:%d\n", thread_info->tid,
                 i, res->id);
          apr_sleep(thread_info->work_delay_sleep);
          rv = apr_reslist_release(rl, res);
          if (rv != APR_SUCCESS) {
              fprintf(stderr, "Failed to return resource to reslist\n");
              apr_thread_exit(thd, rv);
              return NULL;
          }
      }
  
      return APR_SUCCESS;
  }
  
  static apr_status_t test_reslist(apr_pool_t *parpool)
  {
      apr_status_t rv;
      apr_pool_t *pool;
      apr_reslist_t *rl;
      my_parameters_t *params;
      int i;
      apr_thread_t *my_threads[CONSUMER_THREADS];
      my_thread_info_t my_thread_info[CONSUMER_THREADS];
  
      printf("Creating child pool.......................");
      rv = apr_pool_create(&pool, parpool);
      if (rv != APR_SUCCESS) {
          fprintf(stderr, "Error creating child pool\n");
          return rv;
      }
      printf("OK\n");
  
      /* Create some parameters that will be passed into each
       * constructor and destructor call. */
      params = apr_pcalloc(pool, sizeof(*params));
      params->sleep_upon_construct = CONSTRUCT_SLEEP_TIME;
      params->sleep_upon_destruct = DESTRUCT_SLEEP_TIME;
  
      /* We're going to want 10 blocks of data from our target rmm. */
      printf("Creating resource list:\n"
             " min/smax/hmax: %d/%d/%d\n"
             " ttl: %" APR_TIME_T_FMT "\n", RESLIST_MIN, RESLIST_SMAX,
             RESLIST_HMAX, RESLIST_TTL);
      rv = apr_reslist_create(&rl, RESLIST_MIN, RESLIST_SMAX, RESLIST_HMAX,
                              RESLIST_TTL, my_constructor, my_destructor,
                              params, pool);
      if (rv != APR_SUCCESS) { 
          fprintf(stderr, "Error allocating shared memory block\n");
          return rv;
      }
      fprintf(stdout, "OK\n");
  
      printf("Creating %d threads", CONSUMER_THREADS);
      for (i = 0; i < CONSUMER_THREADS; i++) {
          putchar('.');
          my_thread_info[i].tid = i;
          my_thread_info[i].reslist = rl;
          my_thread_info[i].work_delay_sleep = WORK_DELAY_SLEEP_TIME;
          rv = apr_thread_create(&my_threads[i], NULL,
                                 resource_consuming_thread, &my_thread_info[i],
                                 pool);
          if (rv != APR_SUCCESS) {
              fprintf(stderr, "Failed to create thread %d\n", i);
              return rv;
          }
      }
      printf("\nDone!\n");
  
      printf("Waiting for threads to finish");
      for (i = 0; i < CONSUMER_THREADS; i++) {
          apr_status_t thread_rv;
          putchar('.');
          apr_thread_join(&thread_rv, my_threads[i]);
          if (rv != APR_SUCCESS) {
              fprintf(stderr, "Failed to join thread %d\n", i);
              return rv;
          }
      }
      printf("\nDone!\n");
  
      printf("Destroying resource list.................");
      rv = apr_reslist_destroy(rl);
      if (rv != APR_SUCCESS) {
          printf("FAILED\n");
          return rv;
      }
      printf("OK\n");
  
      apr_pool_destroy(pool);
  
      return APR_SUCCESS;
  }
  
  
  int main(void)
  {
      apr_status_t rv;
      apr_pool_t *pool;
      char errmsg[200];
  
      apr_initialize();
      
      printf("APR Resource List Test\n");
      printf("======================\n\n");
  
      printf("Initializing the pool............................"); 
      if (apr_pool_create(&pool, NULL) != APR_SUCCESS) {
          printf("could not initialize pool\n");
          exit(-1);
      }
      printf("OK\n");
  
      rv = test_reslist(pool);
      if (rv != APR_SUCCESS) {
          printf("Resource list test FAILED: [%d] %s\n",
                 rv, apr_strerror(rv, errmsg, sizeof(errmsg)));
          exit(-2);
      }
      printf("Resource list test passed!\n");
  
      return 0;
  }
  
  
  
  

Mime
View raw message