summaryrefslogtreecommitdiff
path: root/accel-pppd/triton/mempool.c
diff options
context:
space:
mode:
Diffstat (limited to 'accel-pppd/triton/mempool.c')
-rw-r--r--accel-pppd/triton/mempool.c338
1 files changed, 338 insertions, 0 deletions
diff --git a/accel-pppd/triton/mempool.c b/accel-pppd/triton/mempool.c
new file mode 100644
index 0000000..855e22e
--- /dev/null
+++ b/accel-pppd/triton/mempool.c
@@ -0,0 +1,338 @@
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <linux/mman.h>
+
+#include "triton_p.h"
+
+#include "memdebug.h"
+
+#ifdef VALGRIND
+#include <valgrind/memcheck.h>
+#define DELAY 5
+#endif
+
+//#define MEMPOOL_DISABLE
+
+#define MAGIC1 0x2233445566778899llu
+
+struct _mempool_t
+{
+ struct list_head entry;
+ int size;
+ struct list_head items;
+#ifdef MEMDEBUG
+ struct list_head ditems;
+#endif
+ spinlock_t lock;
+ uint64_t magic;
+ int mmap:1;
+};
+
+struct _item_t
+{
+ struct list_head entry;
+#ifdef VALGRIND
+ time_t timestamp;
+#endif
+ struct _mempool_t *owner;
+#ifdef MEMDEBUG
+ const char *fname;
+ int line;
+#endif
+ uint64_t magic2;
+ uint64_t magic1;
+ char ptr[0];
+};
+
+static LIST_HEAD(pools);
+static spinlock_t pools_lock = SPINLOCK_INITIALIZER;
+
+mempool_t __export *mempool_create(int size)
+{
+ struct _mempool_t *p = _malloc(sizeof(*p));
+
+ memset(p, 0, sizeof(*p));
+ INIT_LIST_HEAD(&p->items);
+#ifdef MEMDEBUG
+ INIT_LIST_HEAD(&p->ditems);
+#endif
+ spinlock_init(&p->lock);
+ p->size = size;
+ p->magic = (uint64_t)random() * (uint64_t)random();
+
+ spin_lock(&pools_lock);
+ list_add_tail(&p->entry, &pools);
+ spin_unlock(&pools_lock);
+
+ return (mempool_t *)p;
+}
+
+mempool_t __export *mempool_create2(int size)
+{
+ struct _mempool_t *p = (struct _mempool_t *)mempool_create(size);
+
+ p->mmap = 1;
+
+ return (mempool_t *)p;
+}
+
+#ifndef MEMDEBUG
+void __export *mempool_alloc(mempool_t *pool)
+{
+ struct _mempool_t *p = (struct _mempool_t *)pool;
+ struct _item_t *it;
+ uint32_t size = sizeof(*it) + p->size + 8;
+
+ spin_lock(&p->lock);
+ if (!list_empty(&p->items)) {
+ it = list_entry(p->items.next, typeof(*it), entry);
+ list_del(&it->entry);
+ spin_unlock(&p->lock);
+
+ __sync_sub_and_fetch(&triton_stat.mempool_available, size);
+
+ it->magic1 = MAGIC1;
+
+ return it->ptr;
+ }
+ spin_unlock(&p->lock);
+
+ if (p->mmap)
+ it = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_32BIT, -1, 0);
+ else
+ it = _malloc(size);
+
+ if (!it) {
+ triton_log_error("mempool: out of memory\n");
+ return NULL;
+ }
+ it->owner = p;
+ it->magic1 = MAGIC1;
+ it->magic2 = p->magic;
+ *(uint64_t*)(it->data + p->size) = it->magic2;
+
+ __sync_add_and_fetch(&triton_stat.mempool_allocated, size);
+
+ return it->ptr;
+}
+#endif
+
+void __export *mempool_alloc_md(mempool_t *pool, const char *fname, int line)
+{
+ struct _mempool_t *p = (struct _mempool_t *)pool;
+ struct _item_t *it;
+ uint32_t size = sizeof(*it) + p->size + 8;
+ int i, n;
+
+ spin_lock(&p->lock);
+ if (!list_empty(&p->items)) {
+ it = list_entry(p->items.next, typeof(*it), entry);
+#ifdef VALGRIND
+ if (it->timestamp + DELAY < time(NULL)) {
+ VALGRIND_MAKE_MEM_DEFINED(&it->owner, size - sizeof(it->entry) - sizeof(it->timestamp));
+ VALGRIND_MAKE_MEM_UNDEFINED(it->ptr, p->size);
+#endif
+ list_del(&it->entry);
+ list_add(&it->entry, &p->ditems);
+ spin_unlock(&p->lock);
+
+ it->fname = fname;
+ it->line = line;
+
+ __sync_sub_and_fetch(&triton_stat.mempool_available, size);
+
+ it->magic1 = MAGIC1;
+
+ return it->ptr;
+#ifdef VALGRIND
+ }
+#endif
+ }
+ spin_unlock(&p->lock);
+
+ if (p->mmap) {
+ n = (sysconf(_SC_PAGE_SIZE) - 1) / size + 1;
+ it = mmap(NULL, n * size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_32BIT, -1, 0);
+ __sync_add_and_fetch(&triton_stat.mempool_allocated, size * (n - 1));
+ __sync_add_and_fetch(&triton_stat.mempool_available, size * (n - 1));
+ spin_lock(&p->lock);
+ for (i = 0; i < n - 1; i++, it) {
+ it->owner = p;
+ it->magic2 = p->magic;
+ it->magic1 = MAGIC1;
+ *(uint64_t*)(it->ptr + p->size) = it->magic2;
+ list_add_tail(&it->entry,&p->items);
+#ifdef VALGRIND
+ it->timestamp = 0;
+ VALGRIND_MAKE_MEM_NOACCESS(&it->owner, size - sizeof(it->entry) - sizeof(it->timestamp));
+#endif
+ it = (struct _item_t *)((char *)it + size);
+ }
+ spin_unlock(&p->lock);
+#ifdef VALGRIND
+ VALGRIND_MAKE_MEM_UNDEFINED(it, size);
+#endif
+ } else
+ it = md_malloc(size, fname, line);
+
+ if (!it) {
+ triton_log_error("mempool: out of memory\n");
+ return NULL;
+ }
+ it->owner = p;
+ it->magic2 = p->magic;
+ it->magic1 = MAGIC1;
+ it->fname = fname;
+ it->line = line;
+ *(uint64_t*)(it->ptr + p->size) = it->magic2;
+
+ spin_lock(&p->lock);
+ list_add(&it->entry, &p->ditems);
+ spin_unlock(&p->lock);
+
+ __sync_add_and_fetch(&triton_stat.mempool_allocated, size);
+
+ return it->ptr;
+}
+
+
+void __export mempool_free(void *ptr)
+{
+ struct _item_t *it = container_of(ptr, typeof(*it), ptr);
+ struct _mempool_t *p = it->owner;
+ uint32_t size = sizeof(*it) + it->owner->size + 8;
+
+#ifdef MEMDEBUG
+ if (it->magic1 != MAGIC1) {
+ triton_log_error("mempool: memory corruption detected");
+ abort();
+ }
+
+ if (it->magic2 != it->owner->magic) {
+ triton_log_error("mempool: memory corruption detected");
+ abort();
+ }
+
+ if (it->magic2 != *(uint64_t*)(it->ptr + it->owner->size)) {
+ triton_log_error("mempool: memory corruption detected");
+ abort();
+ }
+
+ it->magic1 = 0;
+#endif
+
+ spin_lock(&p->lock);
+#ifdef MEMDEBUG
+ list_del(&it->entry);
+#endif
+#ifndef MEMPOOL_DISABLE
+ list_add_tail(&it->entry,&it->owner->items);
+#endif
+#ifdef VALGRIND
+ time(&it->timestamp);
+ VALGRIND_MAKE_MEM_NOACCESS(&it->owner, size - sizeof(it->entry) - sizeof(it->timestamp));
+#endif
+ spin_unlock(&p->lock);
+
+#ifdef MEMPOOL_DISABLE
+ if (it->owner->mmap)
+ munmap(it, size);
+ else
+ _free(it);
+#endif
+
+ __sync_add_and_fetch(&triton_stat.mempool_available, size);
+}
+
+void __export mempool_clean(mempool_t *pool)
+{
+ struct _mempool_t *p = (struct _mempool_t *)pool;
+ struct _item_t *it;
+ uint32_t size = sizeof(*it) + p->size + 8;
+
+ spin_lock(&p->lock);
+ while (!list_empty(&p->items)) {
+ it = list_entry(p->items.next, typeof(*it), entry);
+#ifdef VALGRIND
+ if (it->timestamp + DELAY < time(NULL)) {
+ VALGRIND_MAKE_MEM_DEFINED(&it->owner, size - sizeof(it->entry) - sizeof(it->timestamp));
+#endif
+ list_del(&it->entry);
+ if (p->mmap)
+ munmap(it, size);
+ else
+ _free(it);
+ __sync_sub_and_fetch(&triton_stat.mempool_allocated, size);
+ __sync_sub_and_fetch(&triton_stat.mempool_available, size);
+#ifdef VALGRIND
+ } else
+ break;
+#endif
+ }
+ spin_unlock(&p->lock);
+}
+
+#ifdef MEMDEBUG
+void __export mempool_show(mempool_t *pool)
+{
+ struct _mempool_t *p = (struct _mempool_t *)pool;
+ struct _item_t *it;
+
+ spin_lock(&p->lock);
+ list_for_each_entry(it, &p->ditems, entry)
+ triton_log_error("%s:%i %p\n", it->fname, it->line, it->ptr);
+ spin_unlock(&p->lock);
+}
+#endif
+
+void sigclean(int num)
+{
+ struct _mempool_t *p;
+ struct _item_t *it;
+ uint32_t size;
+
+ triton_log_error("mempool: clean\n");
+
+ spin_lock(&pools_lock);
+ list_for_each_entry(p, &pools, entry) {
+ if (p->mmap)
+ continue;
+ size = sizeof(*it) + p->size + 8;
+ spin_lock(&p->lock);
+ while (!list_empty(&p->items)) {
+ it = list_entry(p->items.next, typeof(*it), entry);
+#ifdef VALGRIND
+ if (it->timestamp + DELAY < time(NULL)) {
+ VALGRIND_MAKE_MEM_DEFINED(&it->owner, size - sizeof(it->entry) - sizeof(it->timestamp));
+#endif
+ list_del(&it->entry);
+ _free(it);
+ __sync_sub_and_fetch(&triton_stat.mempool_allocated, size);
+ __sync_sub_and_fetch(&triton_stat.mempool_available, size);
+#ifdef VALGRIND
+ } else
+ break;
+#endif
+ }
+ spin_unlock(&p->lock);
+ }
+ spin_unlock(&pools_lock);
+}
+
+static void __init init(void)
+{
+ sigset_t set;
+ sigfillset(&set);
+
+ struct sigaction sa = {
+ .sa_handler = sigclean,
+ .sa_mask = set,
+ };
+
+ sigaction(35, &sa, NULL);
+}
+