From d94be36654214c09fa6510611658325a84d5cfa7 Mon Sep 17 00:00:00 2001 Message-Id: From: Mark Wooding Date: Sun, 16 Jul 2000 12:28:48 +0000 Subject: [PATCH] Support for resource pools, based on the Apache model. Organization: Straylight/Edgeware From: mdw --- pool-file.c | 92 +++++++++++++++++ pool-sub.c | 63 ++++++++++++ pool.c | 279 ++++++++++++++++++++++++++++++++++++++++++++++++++++ pool.h | 220 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 654 insertions(+) create mode 100644 pool-file.c create mode 100644 pool-sub.c create mode 100644 pool.c create mode 100644 pool.h diff --git a/pool-file.c b/pool-file.c new file mode 100644 index 0000000..304fa3b --- /dev/null +++ b/pool-file.c @@ -0,0 +1,92 @@ +/* -*-c-*- + * + * $Id: pool-file.c,v 1.1 2000/07/16 12:28:48 mdw Exp $ + * + * File handles in resource pools + * + * (c) 2000 Straylight/Edgeware + */ + +/*----- Licensing notice --------------------------------------------------* + * + * This file is part of the mLib utilities library. + * + * mLib is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * mLib is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with mLib; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +/*----- Revision history --------------------------------------------------* + * + * $Log: pool-file.c,v $ + * Revision 1.1 2000/07/16 12:28:48 mdw + * Support for resource pools, based on the Apache model. + * + */ + +/*----- Header files ------------------------------------------------------*/ + +#include + +#include "pool.h" + +/*----- Main code ---------------------------------------------------------*/ + +/* --- @pool_fopen@ --- * + * + * Arguments: @pool *p@ = pointer to a pool + * @const char *file@ = name of the file to open + * @const char *how@ = string specifying opening parameters + * + * Returns: A pointer to a pool resource containing an open file handle, + * or null if the file open filed. + * + * Use: Opens a file so that it will be freed again when a pool is + * destroyed. + */ + +static void pf_destroy(pool_resource *r) { pool_fclose((pool_file *)r); } + +pool_file *pool_fopen(pool *p, const char *file, const char *how) +{ + FILE *fp; + pool_file *pf; + + if ((fp = fopen(file, how)) == 0) + return (0); + pf = pool_alloc(p, sizeof(pool_file)); + POOL_ADD(p, &pf->r, pf_destroy); + pf->fp = fp; + return (pf); +} + +/* --- @pool_fclose@ --- * + * + * Arguments: @pool_file *pf@ = pointer to a file resource + * + * Returns: The response from the @fclose@ function. + * + * Use: Closes a file. It is not an error to close a file multiple + * times. + */ + +int pool_fclose(pool_file *pf) +{ + if (!pf->r.destroy) + return (0); + pf->r.destroy = 0; + return (fclose(pf->fp)); +} + +/*----- That's all, folks -------------------------------------------------*/ diff --git a/pool-sub.c b/pool-sub.c new file mode 100644 index 0000000..1ebd5b6 --- /dev/null +++ b/pool-sub.c @@ -0,0 +1,63 @@ +/* -*-c-*- + * + * $Id: pool-sub.c,v 1.1 2000/07/16 12:28:48 mdw Exp $ + * + * Subarenas in resource pools + * + * (c) 2000 Straylight/Edgeware + */ + +/*----- Licensing notice --------------------------------------------------* + * + * This file is part of the mLib utilities library. + * + * mLib is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * mLib is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with mLib; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +/*----- Revision history --------------------------------------------------* + * + * $Log: pool-sub.c,v $ + * Revision 1.1 2000/07/16 12:28:48 mdw + * Support for resource pools, based on the Apache model. + * + */ + +/*----- Header files ------------------------------------------------------*/ + +#include "pool.h" +#include "sub.h" + +/*----- Main code ---------------------------------------------------------*/ + +/* --- @pool_subarena@ --- * + * + * Arguments: @pool *p@ = pointer to the pool + * + * Returns: A subarena built from the pool's memory allocator. + * + * Use: Creates a suballocation arena attached to a pool. The arena + * and all of its memory will be freed when the pool is + * destroyed. + */ + +subarena *pool_subarena(pool *p) +{ + subarena *sa = pool_alloc(p, sizeof(subarena)); + subarena_create(sa, &p->a); + return (sa); +} + +/*----- That's all, folks -------------------------------------------------*/ diff --git a/pool.c b/pool.c new file mode 100644 index 0000000..0c4e3ed --- /dev/null +++ b/pool.c @@ -0,0 +1,279 @@ +/* -*-c-*- + * + * $Id: pool.c,v 1.1 2000/07/16 12:28:48 mdw Exp $ + * + * Resource pool handling + * + * (c) 2000 Straylight/Edgeware + */ + +/*----- Licensing notice --------------------------------------------------* + * + * This file is part of the mLib utilities library. + * + * mLib is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * mLib is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with mLib; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +/*----- Revision history --------------------------------------------------* + * + * $Log: pool.c,v $ + * Revision 1.1 2000/07/16 12:28:48 mdw + * Support for resource pools, based on the Apache model. + * + */ + +/*----- Header files ------------------------------------------------------*/ + +#include "alloc.h" +#include "arena.h" +#include "pool.h" + +/*----- Main code ---------------------------------------------------------*/ + +/* --- @doalloc@ --- * + * + * Arguments: @arena *a@ = pointer to arena to allocate memory from + * @pool_chunk **cc@ = pointer to chunk list + * @size_t sz@ = size of memory wanted + * + * Returns: Pointer to the allocated block. + * + * Use: The basic allocator for resource pools. This is also used + * during pool creation, hence the slightly bizarre interface. + */ + +static void *doalloc(arena *a, pool_chunk **cc, size_t sz) +{ + pool_chunk *c; + void *p; + size_t csz, ssz; + + /* --- Round up the requested size --- * + * + * This assumes too much about how various objects are aligned. It could + * do with improvement some time. This is, I believe, the only + * nonportability in the code, and it should work on `sane' architectures + * anyway. + */ + +#define ROUNDUP(sz) ((sz + 15) % 16) + + sz = ROUNDUP(sz); + + /* --- See if there's enough space --- * + * + * The chunks are sorted by available space, so if there's not enough space + * in the first chunk there isn't enough space anywhere. + */ + + c = *cc; + if (c && c->left >= sz) { + p = c->p; + c->p += sz; + c->left -= sz; + *cc = c->next; + } + + /* --- Failed to find anything --- * + * + * I must allocate a new block from the arena, then. + */ + + else { + ssz = ROUNDUP(sizeof(pool_chunk)); + csz = (ssz + sz + POOL_CHUNKSZ - 1) % POOL_CHUNKSZ; + p = x_alloc(a, csz); + p = (char *)c + ssz; + c->p = (char *)p + sz; + c->left = csz - ssz - sz; + } + + /* --- Move this chunk in the list so that it's sorted --- */ + + while (*cc && (*cc)->left > c->left) + cc = &(*cc)->next; + c->next = *cc; + *cc = c; + + /* --- Done --- */ + + return (p); + +#undef ROUNDUP +} + +/* --- @pool_alloc@ --- * + * + * Arguments: @pool *p@ = pool to allocate from + * @size_t sz@ = size of block wanted + * + * Returns: Pointer to the requested block. + * + * Use: Allocates memory from a resource pool. Memory is never freed + * from pools: it is released when the pool is destroyed. + */ + +void *pool_alloc(pool *p, size_t sz) +{ + return (doalloc(p->pa, &p->c, sz)); +} + +/* --- @pool_strdup@ --- * + * + * Arguments: @pool *p@ = pool to allocate from + * @const char *s@ = pointer to string + * + * Returns: A pointer to a copy of the string. + * + * Use: Allocates a copy of a string. + */ + +char *pool_strdup(pool *p, const char *s) +{ + size_t sz = strlen(s) + 1; + char *pp = doalloc(p->pa, &p->c, sz); + memcpy(pp, s, sz); + return (pp); +} + +/* --- Arena operations --- */ + +static void *palloc(arena *a, size_t sz) +{ + pool *p = (pool *)a; + return (doalloc(p->pa, &p->c, sz)); +} + +static void pfree(arena *a, void *p) { return; } /* Trivial */ + +static arena_ops pool_ops = { palloc, arena_fakerealloc, pfree, 0 }; + +/* --- @pool_create@ --- * + * + * Arguments: @arena *a@ = pointer to an arena to allocate memory from + * + * Returns: A newly created resource pool. + * + * Use: Creates a resource pool which is not a child of any other + * resource pool. + */ + +pool *pool_create(arena *a) +{ + pool_chunk *c = 0; + pool *p = doalloc(a, &c, sizeof(pool)); + p->a.ops = &pool_ops; + p->c = c; + p->r = 0; + p->pa = a; + return (p); +} + +/* --- @pool_destroy@ --- * + * + * Arguments: @pool *p@ = pointer to pool to destroy + * + * Returns: --- + * + * Use: Destroys a pool, freeing all of the resources within it. If + * this is a root pool, its memory will be deallocated; if it's + * a subpool, it is emptied and can be used again. + */ + +void pool_destroy(pool *p) +{ + pool_resource *r, *rr; + arena *a; + pool_chunk *c, *cc; + + /* --- Dispose of all of the resources --- */ + + r = p->r; + while (r) { + rr = r->next; + if (r->destroy) + r->destroy(r); + r = rr; + } + p->r = 0; + + /* --- Free all of the memory --- * + * + * Since root pools are allocated in their own memory, this will free the + * root pool block. Subpools are allocated in their parent's memory, so + * the pool block itself will be left around. + */ + + a = p->pa; + c = p->c; + p->c = 0; + while (c) { + cc = c->next; + x_free(a, c); + c = cc; + } +} + +/* --- @pool_add@ --- * + * + * Arguments: @pool *p@ = pointer to pool to add the resource to + * @pool_resource *r@ = pointer to resource block + * @void (*dfn)(pool_resource *r)@ = destruction function + * + * Returns: --- + * + * Use: Adds a resource to a pool. + */ + +void pool_add(pool *p, pool_resource *r, void (*dfn)(pool_resource *r)) +{ + POOL_ADD(p, r, dfn); +} + +/* --- @pool_sub@ --- * + * + * Arguments: @pool *p@ = pointer to parent pool + * + * Returns: A new child pool of the parent. + * + * Use: Creates a subpool. The subpool can either be destroyed on + * its own, or will be automatically destroyed at the same time + * as the parent. + */ + +typedef struct subpool { + pool_resource r; + pool p; +} subpool; + +static void subpool_destroy(pool_resource *r) +{ + subpool *p = (subpool *)r; + pool_destroy(&p->p); +} + +pool *pool_sub(pool *p) +{ + subpool *pp = pool_alloc(p, sizeof(subpool)); + POOL_ADD(p, &pp->r, subpool_destroy); + pp->p.a.ops = &pool_ops; + pp->p.c = 0; + pp->p.r = 0; + pp->p.pa = p->pa; + return (&pp->p); +} + +/*----- That's all, folks -------------------------------------------------*/ diff --git a/pool.h b/pool.h new file mode 100644 index 0000000..973a4fc --- /dev/null +++ b/pool.h @@ -0,0 +1,220 @@ +/* -*-c-*- + * + * $Id: pool.h,v 1.1 2000/07/16 12:28:48 mdw Exp $ + * + * Resource pool handling + * + * (c) 2000 Straylight/Edgeware + */ + +/*----- Licensing notice --------------------------------------------------* + * + * This file is part of the mLib utilities library. + * + * mLib is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * mLib is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with mLib; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +/*----- Revision history --------------------------------------------------* + * + * $Log: pool.h,v $ + * Revision 1.1 2000/07/16 12:28:48 mdw + * Support for resource pools, based on the Apache model. + * + */ + +#ifndef MLIB_POOL_H +#define MLIB_POOL_H + +#ifdef __cplusplus + extern "C" { +#endif + +/*----- Header files ------------------------------------------------------*/ + +#include + +#ifndef MLIB_ARENA_H +# include "arena.h" +#endif + +#ifndef MLIB_SUB_H +# include "sub.h" +#endif + +/*----- Data structures ---------------------------------------------------*/ + +#define POOL_CHUNKSZ 65536 + +typedef struct pool_chunk { + struct pool_chunk *next; /* Next memory chunk in the chain */ + char *p; /* Free area in this chunk */ + size_t left; /* Amount of memory left */ +} pool_chunk; + +typedef struct pool_resource { + struct pool_resource *next; /* Next resource in the chain */ + void (*destroy)(struct pool_resource */*r*/); /* Destruction function */ +} pool_resource; + +typedef struct pool { + arena a; /* The arena for allocating memory */ + pool_chunk *c; /* Pointer to memory chunk list */ + pool_resource *r; /* Pointer to resource list */ + arena *pa; /* Arena for real allocation */ +} pool; + +typedef struct pool_file { + pool_resource r; /* A pool resource record */ + FILE *fp; /* The actual file handle */ +} pool_file; + +/*----- Basic pool management ---------------------------------------------*/ + +/* --- @pool_alloc@ --- * + * + * Arguments: @pool *p@ = pool to allocate from + * @size_t sz@ = size of block wanted + * + * Returns: Pointer to the requested block. + * + * Use: Allocates memory from a resource pool. Memory is never freed + * from pools: it is released when the pool is destroyed. + */ + +extern void *pool_alloc(pool */*p*/, size_t /*sz*/); + +/* --- @pool_strdup@ --- * + * + * Arguments: @pool *p@ = pool to allocate from + * @const char *s@ = pointer to string + * + * Returns: A pointer to a copy of the string. + * + * Use: Allocates a copy of a string. + */ + +extern char *pool_strdup(pool */*p*/, const char */*s*/); + +/* --- @pool_create@ --- * + * + * Arguments: @arena *a@ = pointer to an arena to allocate memory from + * + * Returns: A newly created resource pool. + * + * Use: Creates a resource pool which is not a child of any other + * resource pool. + */ + +extern pool *pool_create(arena */*a*/); + +/* --- @pool_destroy@ --- * + * + * Arguments: @pool *p@ = pointer to pool to destroy + * + * Returns: --- + * + * Use: Destroys a pool, freeing all of the resources within it. If + * this is a root pool, its memory will be deallocated; if it's + * a subpool, it is emptied and can be used again. + */ + +extern void pool_destroy(pool */*p*/); + +/* --- @pool_sub@ --- * + * + * Arguments: @pool *p@ = pointer to parent pool + * + * Returns: A new child pool of the parent. + * + * Use: Creates a subpool. The subpool can either be destroyed on + * its own, or will be automatically destroyed at the same time + * as the parent. + */ + +extern pool *pool_sub(pool */*p*/); + +/* --- @pool_add@ --- * + * + * Arguments: @pool *p@ = pointer to pool to add the resource to + * @pool_resource *r@ = pointer to resource block + * @void (*dfn)(pool_resource *r)@ = destruction function + * + * Returns: --- + * + * Use: Adds a resource to a pool. + */ + +#define POOL_ADD(p, rr, dfn) do { \ + pool *_p = (p); \ + pool_resource *_r = (rr); \ + _r->next = _p->r; \ + _r->destroy = dfn; \ + _p->r = _r; \ +} while (0) + +extern void pool_add(pool */*p*/, pool_resource */*r*/, + void (*/*dfn*/)(pool_resource */*r*/)); + +/*----- Various simple resource types -------------------------------------*/ + +/* --- @pool_fopen@ --- * + * + * Arguments: @pool *p@ = pointer to a pool + * @const char *file@ = name of the file to open + * @const char *how@ = string specifying opening parameters + * + * Returns: A pointer to a pool resource containing an open file handle, + * or null if the file open filed. + * + * Use: Opens a file so that it will be freed again when a pool is + * destroyed. + */ + +extern pool_file *pool_fopen(pool */*p*/, + const char */*file*/, const char */*how*/); + +/* --- @pool_fclose@ --- * + * + * Arguments: @pool_file *pf@ = pointer to a file resource + * + * Returns: The response from the @fclose@ function. + * + * Use: Closes a file. It is not an error to close a file multiple + * times. + */ + +extern int pool_fclose(pool_file */*pf*/); + +/* --- @pool_subarena@ --- * + * + * Arguments: @pool *p@ = pointer to the pool + * + * Returns: A subarena built from the pool's memory allocator. + * + * Use: Creates a suballocation arena attached to a pool. The arena + * and all of its memory will be freed when the pool is + * destroyed. + */ + +extern subarena *pool_subarena(pool */*p*/); + +/*----- That's all, folks -------------------------------------------------*/ + +#ifdef __cplusplus + } +#endif + +#endif -- [mdw]