# error The slab allocator requires that your system have the mmap() system call.
#endif
+#define SLAB_DEBUG_HEADER 1
+#define SLAB_DEBUG_LOG 2
+#define SLAB_DEBUG_PERMS 4
+
#if !defined(SLAB_DEBUG)
-# define SLAB_DEBUG 1
+# define SLAB_DEBUG 0
#endif
#if !defined(SLAB_RESERVE)
# define MAX_SLAB_FREE 1024
#endif
-#if SLAB_DEBUG
+#if SLAB_DEBUG & SLAB_DEBUG_HEADER
#define ALLOC_MAGIC 0x1a
#define FREE_MAGIC 0xcf
# define MAP_ANON 0
#endif
+#if SLAB_DEBUG & SLAB_DEBUG_LOG
+
+FILE *slab_log;
+
+struct slab_log_entry
+{
+ struct timeval tv;
+ void *slab;
+ ssize_t size;
+};
+
+static void
+close_slab_log(void)
+{
+ fclose(slab_log);
+}
+
+static void
+slab_log_alloc(void *slab, size_t size)
+{
+ struct slab_log_entry sle;
+
+ gettimeofday(&sle.tv, NULL);
+ sle.slab = slab;
+ sle.size = (ssize_t)size;
+
+ if (!slab_log)
+ {
+ const char *fname;
+ fname = getenv("SLAB_LOG_FILE");
+ if (!fname)
+ fname = "slab.log";
+ slab_log = fopen(fname, "w");
+ atexit(close_slab_log);
+ }
+
+ fwrite(&sle, sizeof(sle), 1, slab_log);
+}
+
+static void
+slab_log_free(void *slab, size_t size)
+{
+ struct slab_log_entry sle;
+
+ gettimeofday(&sle.tv, NULL);
+ sle.slab = slab;
+ sle.size = -(ssize_t)size;
+ fwrite(&sle, sizeof(sle), 1, slab_log);
+}
+
+static void
+slab_log_unmap(void *slab)
+{
+ struct slab_log_entry sle;
+
+ gettimeofday(&sle.tv, NULL);
+ sle.slab = slab;
+ sle.size = 0;
+ fwrite(&sle, sizeof(sle), 1, slab_log);
+}
+
+#else
+# define slab_log_alloc(SLAB, SIZE)
+# define slab_log_free(SLAB, SIZE)
+# define slab_log_unmap(SLAB)
+#endif
+
+#if (SLAB_DEBUG & SLAB_DEBUG_PERMS) && defined(HAVE_MPROTECT)
+
+static void
+slab_protect(struct slab *slab)
+{
+ mprotect(slab, (char*)(slab + 1) - (char*)slab->base, PROT_NONE);
+}
+
+static void
+slab_unprotect(struct slab *slab)
+{
+ mprotect(slab, (char*)(slab + 1) - (char*)slab->base, PROT_READ | PROT_WRITE);
+}
+
+#else
+# define slab_protect(SLAB) (void)(SLAB)
+# define slab_unprotect(SLAB) (void)(SLAB)
+#endif
+
static size_t
slab_pagesize(void)
{
/* Allocate new slab. */
if (free_slab_head) {
slab = free_slab_head;
+ slab_unprotect(slab);
if (!(free_slab_head = slab->next))
free_slab_tail = NULL;
} else {
slab->base = item;
slab_count++;
}
+ slab_log_alloc(slab, sset->size);
/* Populate free list. */
step = (sset->size + SLAB_ALIGN - 1) & ~(SLAB_ALIGN - 1);
assert(!slab->next || slab == slab->next->prev);
assert(!slab->prev || slab == slab->prev->next);
} else if (!slab->used) {
+ slab_log_free(slab, size);
+
/* Unlink slab from its parent. */
slab->parent->nslabs--;
if (slab->prev)
free_slab_tail = tslab;
if (!free_slab_head)
free_slab_head = tslab;
- else
+ else {
+ slab_unprotect(tslab->prev);
tslab->prev->next = tslab;
+ slab_protect(tslab->prev);
+ }
free_slab_count++;
slab_count++;
}
slab->parent = NULL;
slab->next = NULL;
slab->prev = free_slab_tail;
- free_slab_tail = slab;
- if (free_slab_head)
+ if (slab->prev) {
+ slab_unprotect(slab->prev);
slab->prev->next = slab;
- else
+ slab_protect(slab->prev);
+ } else
free_slab_head = slab;
+ slab_protect(slab);
+ free_slab_tail = slab;
free_slab_count++;
#if MAX_SLAB_FREE >= 0
struct slab *tslab;
tslab = free_slab_tail;
+ slab_unprotect(tslab);
free_slab_tail = tslab->prev;
- if (tslab->prev)
+ if (tslab->prev) {
+ slab_unprotect(tslab->prev);
tslab->prev->next = NULL;
- else
+ slab_protect(tslab->prev);
+ } else
free_slab_head = NULL;
free_slab_count--;
slab_count--;
+ slab_log_unmap(slab);
munmap(slab->base, slab_pagesize());
}
#endif
res = slab_map(slab_round_up(real));
big_alloc_count++;
big_alloc_size += size;
+ slab_log_alloc(res, size);
}
-#if SLAB_DEBUG
+#if SLAB_DEBUG & SLAB_DEBUG_HEADER
res->file_id = get_file_id(file);
res->size = size;
res->line = line;
verify(ptr);
orig = (alloc_header_t*)ptr - 1;
-#if SLAB_DEBUG
+#if SLAB_DEBUG & SLAB_DEBUG_HEADER
osize = orig->size;
#else
osize = *orig;
return;
verify(ptr);
hdr = (alloc_header_t*)ptr - 1;
-#if SLAB_DEBUG
+#if SLAB_DEBUG & SLAB_DEBUG_HEADER
hdr->file_id = get_file_id(file);
hdr->line = line;
hdr->magic = FREE_MAGIC;
munmap(hdr, slab_round_up(real));
big_alloc_count--;
big_alloc_size -= user;
+ slab_log_unmap(hdr);
}
}
return;
hdr = (alloc_header_t*)ptr - 1;
-#if SLAB_DEBUG
+#if SLAB_DEBUG & SLAB_DEBUG_HEADER
real = hdr->size + sizeof(*hdr);
assert(hdr->file_id < file_ids_used);
assert(hdr->magic == ALLOC_MAGIC);
--- /dev/null
+#include "compat.h"
+
+struct slab_log_entry
+{
+ struct timeval tv;
+ void *slab;
+ ssize_t size;
+};
+
+static void
+read_log_file(const char *name)
+{
+ struct slab_log_entry sle;
+ FILE *log;
+
+ log = fopen(name, "r");
+ if (!log)
+ {
+ fprintf(stderr, "Unable to open %s: %s\n", name, strerror(errno));
+ return;
+ }
+
+ while (fread(&sle, sizeof(sle), 1, log) == 1)
+ {
+ fprintf(stdout, "%ld.%06ld %p ", (long)sle.tv.tv_sec, (long)sle.tv.tv_usec, sle.slab);
+ if (sle.size > 0)
+ {
+ fprintf(stdout, "-> %zd\n", sle.size);
+ }
+ else if (sle.size < 0)
+ {
+ fprintf(stdout, "<- %zd\n", -sle.size);
+ }
+ else /* slze.size == 0 */
+ {
+ fprintf(stdout, "unmap\n");
+ }
+ }
+}
+
+int
+main(int argc, char *argv[])
+{
+ int ii;
+
+ if (argc < 2)
+ {
+ fprintf(stderr, "Usage: %s <logfile ...>\n", argv[0]);
+ return 1;
+ }
+
+ for (ii = 1; ii < argc; ++ii)
+ {
+ read_log_file(argv[ii]);
+ }
+ return 0;
+}