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