commit 57cede2e1a4902f3833af79d1330160686c215dd
parent e7299d91751363b8eefe9256f7f5ec86797a4ec9
Author: sin <sin@2f30.org>
Date: Thu, 1 Aug 2013 15:04:00 +0100
Only free `oldp' if it is non-NULL
Diffstat:
2 files changed, 244 insertions(+), 1 deletion(-)
diff --git a/random/alloc.c b/random/alloc.c
@@ -92,7 +92,7 @@ realloc(void *oldp, size_t nbytes)
size_t n;
long i;
- if (!nbytes) {
+ if (!nbytes && oldp) {
free(oldp);
return NULL;
}
diff --git a/random/rballoc.c b/random/rballoc.c
@@ -0,0 +1,243 @@
+#include <sys/mman.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include "tree.h"
+
+enum { PAGESIZE = 4096 };
+
+struct node {
+ void *buf;
+ size_t siz;
+ RB_ENTRY(node) entry;
+};
+
+RB_HEAD(free_tree, node) ft = RB_INITIALIZER(&ft);
+RB_HEAD(alloc_tree, node) at = RB_INITIALIZER(&at);
+
+static int ft_cmp(struct node *a, struct node *b);
+RB_PROTOTYPE(free_tree, node, entry, ft_cmp);
+
+static int at_cmp(struct node *a, struct node *b);
+RB_PROTOTYPE(alloc_tree, node, entry, at_cmp);
+
+RB_GENERATE(free_tree, node, entry, ft_cmp);
+/* These are ordered by `siz' */
+static int
+ft_cmp(struct node *a, struct node *b)
+{
+ if (a->siz < b->siz)
+ return -1;
+ if (a->siz > b->siz)
+ return 1;
+ return 0;
+}
+
+RB_GENERATE(alloc_tree, node, entry, at_cmp);
+/* These are ordered by address */
+static int
+at_cmp(struct node *a, struct node *b)
+{
+ if (a->buf < b->buf)
+ return -1;
+ if (a->buf > b->buf)
+ return 1;
+ return 0;
+}
+
+static void
+dump_alloc_tree(void)
+{
+ struct node *n;
+
+ RB_FOREACH(n, alloc_tree, &at)
+ fprintf(stderr, "%s: buf: %p, size: %zu\n",
+ __func__, n->buf, n->siz);
+}
+
+static void
+dump_free_tree(void)
+{
+ struct node *n;
+
+ RB_FOREACH(n, free_tree, &ft)
+ fprintf(stderr, "%s: buf: %p, size: %zu\n",
+ __func__, n->buf, n->siz);
+}
+
+static void *
+alloc_object(size_t siz)
+{
+ void *p;
+
+ p = mmap(0, siz, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANON, -1, 0);
+ if (p == MAP_FAILED)
+ return NULL;
+ return p;
+}
+
+static void
+free_object(void *p, size_t siz)
+{
+ munmap(p, siz);
+}
+
+static void *
+mmap_pages(size_t siz)
+{
+ void *addr;
+
+ if (siz % PAGESIZE)
+ siz = (siz + PAGESIZE) & ~(PAGESIZE - 1);
+
+ addr = mmap(0, siz, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANON, -1, 0);
+ if (addr == MAP_FAILED)
+ return NULL;
+ return addr;
+}
+
+void *
+malloc(size_t siz)
+{
+ struct node n, *an, *res;
+ void *p;
+
+ if (!siz)
+ return NULL;
+ /* Lookup in the free tree for a block greater
+ * than or equal to `siz' bytes */
+ n.siz = siz;
+ res = RB_NFIND(free_tree, &ft, &n);
+ if (!res) {
+ /* No available free block, create a new block
+ * and add it to the alloc tree */
+ an = alloc_object(sizeof(*an));
+ if (!an)
+ return NULL;
+ p = mmap_pages(siz);
+ if (!p) {
+ free_object(an, sizeof(*an));
+ return NULL;
+ }
+ an->buf = p;
+ an->siz = siz;
+ RB_INSERT(alloc_tree, &at, an);
+ return an->buf;
+ }
+ an = RB_REMOVE(free_tree, &ft, res);
+ RB_INSERT(alloc_tree, &at, an);
+ return an->buf;
+}
+
+void *
+realloc(void *oldp, size_t siz)
+{
+ struct node n, *res;
+ void *p;
+
+ if (!oldp)
+ return malloc(siz);
+
+ if (!siz && oldp) {
+ free(oldp);
+ return NULL;
+ }
+
+ n.buf = oldp;
+ /* Search the alloc tree for an allocation starting
+ * at address `oldp' */
+ res = RB_FIND(alloc_tree, &at, &n);
+ if (res) {
+ p = malloc(siz);
+ if (!p)
+ return NULL;
+ memcpy(p, res->buf, siz < res->siz ? siz : res->siz);
+ free(res->buf);
+ return p;
+ }
+ return NULL;
+}
+
+void *
+calloc(size_t nmemb, size_t siz)
+{
+ void *p;
+
+ p = malloc(nmemb * siz);
+ if (!p)
+ return NULL;
+ memset(p, 0, nmemb * siz);
+ return p;
+}
+
+void
+free(void *p)
+{
+ struct node n, *fn, *res;
+
+ if (!p)
+ return;
+ n.buf = p;
+ res = RB_FIND(alloc_tree, &at, &n);
+ /* Lookup this allocation in the alloc tree.
+ * If it is located, remove it from the alloc tree
+ * and insert it in the free tree. */
+ if (res) {
+ fn = RB_REMOVE(alloc_tree, &at, res);
+ RB_INSERT(free_tree, &ft, fn);
+ }
+}
+
+void
+cfree(void *p)
+{
+ free(p);
+}
+
+int
+posix_memalign(void **memptr, size_t align, size_t size)
+{
+ void *mem;
+
+ if (((align - 1) & align))
+ return EINVAL;
+ if (align < sizeof(void *))
+ return EINVAL;
+
+ if (PAGESIZE % align) {
+ fprintf(stderr, "%s: %zu alignment not supported!\n",
+ __func__, align);
+ abort();
+ }
+
+ mem = malloc(size);
+ if (!mem)
+ return ENOMEM;
+
+ *memptr = mem;
+ return 0;
+}
+
+size_t
+malloc_usable_size(void *p)
+{
+ struct node n, *res;
+
+ if (!p)
+ return 0;
+ n.buf = p;
+ res = RB_FIND(alloc_tree, &at, &n);
+ if (res)
+ return res->siz;
+ return 0;
+}
+
+size_t
+malloc_size(void *p)
+{
+ return malloc_usable_size(p);
+}