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