buffer.c of buffer.patch

From: George (greerga@DRAGON.HAM.MUOHIO.EDU)
Date: 07/28/97


Here's the heart of the improved buffer system, buffer.c.  I'm still
hunting down functions that don't properly release_buffer() but I'll post
the preliminary patch on my web page.  Not releasing the buffers doesn't
leak memory though, release_all_buffers() will take care of those forgotten
about.  (in other words, the patch is usable)

Usage: buffer_p = get_buffer(size_needed);
       release_buffer(buffer_p);
Add: release_all_buffers(); (somewhere in game_loop)

buffer.c
-=-=-=-=-
#include "conf.h"
#include "sysdep.h"
#include "structs.h"
#include "utils.h"

/* #include "buffer.h" - already done from structs.h */

struct buf_data *buffers;

#if 1
#define PARANOID_BUFFER 1       /* memset vs '\0' */
#endif
#define MAX_BUFFERS     10      /* Not used */
#define BUFFER_LIFE     (5*SECS_PER_REAL_MIN*PASSES_PER_SEC) /* 5 mins */
#if 1
#define QUIET   1       /* Non-verbose logging, only expired/forgot */
#endif

void send_to_char(char *, struct char_data *);

void init_buffers(void)
{
  buffers = NULL;
  new_buffer(8192);
  new_buffer(1024);
  new_buffer(16384);
  new_buffer(512);
  new_buffer(128);
  new_buffer(256);
}

void release_all_buffers()
{
  struct buf_data *clear, *next_clear, *prev = NULL;
  int freed = FALSE;

  for (clear = get_buffer_head(); clear; clear = next_clear) {
    next_clear = clear->next;
    if (clear->used) {
      char buf[128];
      sprintf(buf, "BUFFER: %s forgot to release %d bytes.",
                clear->who, clear->size);
      log(buf);
      clear_buffer(clear);
    } else if (clear->life > 0)
      clear->life--;
    else if (!freed) {
      if (prev)
        prev->next = clear->next;
      else
        buffers = clear->next;
      free_buffer(clear);
      freed = TRUE;
    }
    prev = clear;
  }
}

void clear_buffer(struct buf_data *clearme)
{
  if (!clearme) {
    log("BUFFER: Ack! NULL buf_data in clear_buffer.");
    return;
  }

#if defined(PARANOID_BUFFER)
  memset(clearme->data, 0, clearme->size);
#else
  *clearme->data = '\0';
#endif
#if !defined(QUIET)
  if ((*clearme->who != 'f' && *(clearme->who + 1) != 'r') && /* fread_string */
      (*clearme->who != 'g' && *(clearme->who + 1) != 'e')) {
    char buf[128];
    sprintf(buf, "BUFFER: %s released %d bytes.", clearme->who, clearme->size);
    log(buf);
  }
#endif
  clearme->who = NULL;
  clearme->life = BUFFER_LIFE;
  clearme->used = FALSE;
}

void release_buffer(char *data)
{
  struct buf_data *clear;

  for (clear = get_buffer_head(); clear; clear = clear->next)
    if (clear->data == data)
      break;

  if (clear)
    clear_buffer(clear);
  else
    log("BUFFER: release_buffer: no such buffer found.");
}

void free_buffer(struct buf_data *f)
{
  char buf[128];

  sprintf(buf, "BUFFER: Freeing %d bytes in expired buffer.", f->size);
  log(buf);

  if (f->data)
    free(f->data);
  free(f);
}

struct buf_data *get_buffer_head()
{
  return buffers;
}

struct buf_data *new_buffer(ush_int size)
{
  struct buf_data *buft = get_buffer_head(), *potential, *prev = NULL;

  /* There aren't any buffers. */
  if (!buft) {
    buffers = malloc_buffer(size);
    return buffers;
  }

  /* Insert a buffer */
  for (; buft; buft = buft->next) {
    if (size < buft->size) { // insert here
      potential = malloc_buffer(size);
      if (get_buffer_head() == buft)
        buffers = potential;
      potential->next = buft;
      if (prev)
        prev->next = potential;
      return potential;
    }
    prev = buft;
  }

  /* Append */
  if (prev->next)
    log("BUFFER: Overwrote a buffer.");
  prev->next = malloc_buffer(size);
  return prev->next;
}

struct buf_data *malloc_buffer(ush_int size)
{
#if !defined(QUIET)
  static char buf[128];
#endif

  struct buf_data *new_buf = (struct buf_data *)malloc(sizeof(struct buf_data));

  new_buf->data = (char *)malloc(size);
  new_buf->used = FALSE;
  new_buf->who = NULL;
  new_buf->life = BUFFER_LIFE;
  new_buf->next = NULL;
  new_buf->size = size;

#if !defined(QUIET)
  sprintf(buf, "BUFFER: Allocated %d byte buffer, %d bytes overhead.",
                new_buf->size, sizeof(struct buf_data));
  log(buf);
#endif
  return new_buf;
}

char *acquire_buffer(ush_int size, const char *who)
{
  struct buf_data *give;

  for (give = get_buffer_head(); give; give = give->next)
    if (!give->used && give->size >= size)
      break;

  if (!give) {
    char buf[128];
    sprintf(buf, "BUFFER: Didn't find %d byte buffer! Making a new one.", size);
    log(buf);
    give = new_buffer(size);
  }
  give->used = TRUE;
  give->who = who;
#if !defined(QUIET)
  if ((*give->who != 'f' && *(give->who + 1) != 'r') && /* fread_string */
      (*give->who != 'g' && *(give->who + 1) != 'e')) {
    char buf[128];
    sprintf(buf, "BUFFER: %s requested %d bytes, received %d.", who, size, give->size);
    log(buf);
  }
#endif
  return give->data;
}

void show_buffers(struct char_data *ch)
{
  struct buf_data *disp;
  char *buf = get_buffer(MAX_STRING_LENGTH);
  int pos = 0, i = 0;
  *buf = '\0';

  for (disp = get_buffer_head(); disp; disp = disp->next)
    pos += sprintf(buf + pos, "%3d. %5d bytes, %5d life, %s.\r\n", ++i,
                disp->size, disp->life, disp->used ? disp->who : "unused");

  if (ch)
    send_to_char(buf, ch);
  else
    log(buf);

  release_buffer(buf);
}

buffer.h
-=-=-=-=-
struct buf_data {
  bool used;
  ush_int size;
  ush_int life;
  char *data;
  const char *who;
  struct buf_data *next;
};

#define get_buffer(a)   acquire_buffer((a), __FUNCTION__)

void init_buffers(void);
void release_all_buffers();
void clear_buffer(struct buf_data *clearme);
void release_buffer(char *data);
struct buf_data *new_buffer(ush_int size);
struct buf_data *malloc_buffer(ush_int size);
struct buf_data *get_buffer_head(void);
char *acquire_buffer(ush_int size, const char *who);
void show_buffers(struct char_data *ch);
void free_buffer(struct buf_data *f);

(This would be a lot easier in C++...the destructor could just
release_buffer() instead of having to do it yourself.  Ah well, CircleMUD
4.0...)

--
greerga@muohio.edu me@null.net | Genius may have its limitations, but stupidity
http://www.muohio.edu/~greerga | is not thus handicapped. -- Elbert Hubbard


     +------------------------------------------------------------+
     | Ensure that you have read the CircleMUD Mailing List FAQ:  |
     | http://democracy.queensu.ca/~fletcher/Circle/list-faq.html |
     +------------------------------------------------------------+



This archive was generated by hypermail 2b30 : 12/08/00 PST