calisto-20000323/
calisto-20000323/lib/
calisto-20000323/lib/etc/
calisto-20000323/lib/players/
calisto-20000323/lib/text/
calisto-20000323/log/
/*
 Calisto (c) 1998-1999 Peter Howkins, Matthew Howkins, Simon Howkins

 $Id: pool.c,v 1.3 1999/12/28 19:50:34 peter Exp $

 $Log: pool.c,v $
 Revision 1.3  1999/12/28 19:50:34  peter
 Created pool_stat() to return information for debugging

 Revision 1.2  1999/12/12 19:20:13  peter
 Added guards, changed blk to blkhead and blktail

 Revision 1.1  1999/12/12 18:52:08  peter
 Initial revision


 */
static char rcsid[] = "$Id: pool.c,v 1.3 1999/12/28 19:50:34 peter Exp $";

#include <stdio.h>
#include <stdlib.h>
#include "pool.h"

#define BLKS_PER_GRP 10

#define GUARD1 0x12345678
#define GUARD2 0x87654321

typedef struct blkhead blkhead;
struct blkhead {
  pool *p;
  blkhead *nextfree;
  unsigned guard1;
};

typedef struct {
  unsigned guard2;
} blktail;

typedef struct blkgrp blkgrp;
struct blkgrp {
  blkgrp *next;
/*  blkhead b[UNKNOWN];*/
};

struct pool {
  blkgrp *first;
  blkhead *free;
  size_t block_size;
  unsigned usage;
  unsigned capacity;
};

pool *pool_create(size_t block_size) {
  pool *p;

  p = malloc(sizeof(pool));
  if (p) {
    p->free = NULL;
    p->first = NULL;
    p->block_size = block_size + sizeof(blkhead) + sizeof(blktail);
    p->usage = 0;
    p->capacity = 0;
  }
  return p;
}

/* void pool_destroy(pool *pool); */

void *pool_malloc(pool *p) {
  if (!p->free)
  {
    blkgrp *bg;
    bg = malloc(sizeof(blkgrp) + BLKS_PER_GRP * p->block_size);
    if (!bg)
      return NULL;
    {
      blkhead *b = (blkhead *)(bg + 1);
      int i;

      /* Add blks in this group to free list */
      for (i = 0; i < BLKS_PER_GRP; i++)
      {
        blktail *bt; /* pointer to tail of current blk */

        b->guard1 = GUARD1;
        b->nextfree = p->free;
        p->free = b;
        /* Move b to next blkhead */
        b = (blkhead *) ( (char *)b + p->block_size);
        /* Move back from next blkhead to previous blktail */
        bt = (blktail *) ((char *) b - sizeof(blktail));
        bt->guard2 = GUARD2;
      }
      p->capacity += BLKS_PER_GRP;
    }
  }
  {
    blkhead *b;
    b = p->free;
    p->free = b->nextfree;
    b->p = p;
    p->usage++;
    return b + 1;
  }
}

void pool_free(void *ptr) {
  if (ptr) {
    blkhead *bh = (blkhead *) (((char *) ptr) - sizeof(blkhead));
    pool *p     = bh->p;

    /* Check guard1 */
    if (bh->guard1 != GUARD1) {
      fprintf(stderr, "Pool: overran start of block %p\n", ptr);
      return;
    }

    {
      blktail *bt = (blktail *) ((char *) bh + p->block_size - sizeof(blktail));

      /* Check guard2 */
      if (bt->guard2 != GUARD2) {
        fprintf(stderr, "Pool: overran end of block %p\n", ptr);
        return;
      }
    }

    /* Free up block */
    bh->nextfree = p->free;
    p->free = bh;
    p->usage--;
  }
}

void pool_debug(const pool *p)
{
  printf("block size: %d\n", p->block_size - sizeof(blkhead) - sizeof(blktail));
  printf("usage     : %d\n", p->usage);
  printf("capacity  : %d\n", p->capacity);
}

pool_stat_t pool_stat(const pool *p)
{
  pool_stat_t ps;

  ps.block_size = p->block_size;
  ps.usage      = p->usage;
  ps.capacity   = p->capacity;
  return ps;
}