+/*
+ Copyright (C) Slava Astashonok <sla@0n.ru>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License.
+
+ $Id: mem.c,v 1.4.2.2.2.1 2005/01/29 19:30:41 sla Exp $
+*/
+
+#include <common.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <my_log.h>
+#include <errno.h>
+#include <mem.h>
+
+#ifdef MEM_THREADSAFE
+#include <pthread.h>
+#endif
+
+#ifdef MEM_THREADSAFE
+static pthread_mutex_t mem_mutex = PTHREAD_MUTEX_INITIALIZER;
+#endif
+static struct Mem *root;
+unsigned int total_elements;
+unsigned int free_elements;
+static unsigned int element_size;
+static unsigned int bulk_quantity;
+static unsigned int limit_memory;
+unsigned int total_memory;
+static unsigned int mem_index_table_size;
+static unsigned int element_table_size;
+static unsigned int malloc_size;
+
+void *mem_alloc()
+{
+ unsigned int i;
+ struct Mem *mptr;
+ mem_index_t *iptr;
+#if MEM_BITS == 0
+ void *eptr;
+#endif
+
+#ifdef MEM_THREADSAFE
+ pthread_mutex_lock(&mem_mutex);
+#endif
+ if (!free_elements) {
+ if (limit_memory && (total_memory + malloc_size) > limit_memory) {
+#if ((DEBUG) & DEBUG_M)
+ my_log(LOG_DEBUG, "M: limit exhausted");
+#endif
+ mptr = 0;
+ errno = ENOMEM;
+ goto done;
+ }
+ if (!(mptr = calloc(malloc_size, 1))) goto done;
+ iptr = (void *) mptr + sizeof(struct Mem);
+#if MEM_BITS == 0
+ eptr = (void *) iptr + mem_index_table_size;
+#endif
+ for (i = 0; i < bulk_quantity; i++) {
+#if MEM_BITS == 0
+ *iptr++ = eptr;
+ eptr += element_size;
+#else
+ *iptr++ = i;
+#endif
+ }
+ mptr->free = bulk_quantity - 1;
+ free_elements += mptr->free;
+ total_elements += bulk_quantity;
+ total_memory += malloc_size;
+ mptr->first = iptr;
+ mptr->last = (void *) iptr + element_table_size - element_size;
+ mptr->next = root;
+ root = mptr;
+#if ((DEBUG) & DEBUG_M)
+ my_log(LOG_DEBUG, "M: alloc bulk: base:%x first:%x last:%x",
+ mptr, mptr->first, mptr->last);
+ my_log(LOG_DEBUG, "M: mem: total: %d (%dKB), free: %d",
+ total_elements, total_memory >> 10, free_elements);
+#endif
+ mptr = mptr->last;
+ goto done;
+ }
+
+ mptr = root;
+ while (mptr->free == 0) mptr = mptr->next;
+ mptr->free--;
+ free_elements--;
+ iptr = (void *) mptr + sizeof(struct Mem);
+#if MEM_BITS == 0
+ mptr = iptr[mptr->free];
+#else
+ mptr = mptr->first + iptr[mptr->free] * element_size;
+#endif
+
+done:
+#if ((DEBUG) & DEBUG_M)
+ my_log(LOG_DEBUG, "M: alloc: %x", mptr);
+#endif
+#ifdef MEM_THREADSAFE
+ pthread_mutex_unlock(&mem_mutex);
+#endif
+ return mptr;
+}
+
+void mem_free(void *eptr)
+{
+ mem_index_t *iptr;
+ struct Mem *mptr, **pptr;
+
+#ifdef MEM_THREADSAFE
+ pthread_mutex_lock(&mem_mutex);
+#endif
+#if ((DEBUG) & DEBUG_M)
+ my_log(LOG_DEBUG, "M: free: %x", eptr);
+#endif
+ mptr = root;
+ pptr = &root;
+ while (mptr->first > eptr || mptr->last < eptr) {
+ pptr = &mptr->next;
+ mptr = mptr->next;
+ }
+ iptr = (void *) mptr + sizeof(struct Mem);
+#if MEM_BITS == 0
+ iptr[mptr->free] = eptr;
+#else
+ iptr[mptr->free] = (eptr - mptr->first) / element_size;
+#endif
+ mptr->free++;
+ free_elements++;
+ if (mptr->free == bulk_quantity) {
+#if ((DEBUG) & DEBUG_M)
+ my_log(LOG_DEBUG, "M: free bulk: base:%x first:%x last:%x",
+ mptr, mptr->first, mptr->last);
+#endif
+ *pptr = mptr->next;
+ free(mptr);
+ total_elements -= bulk_quantity;
+ free_elements -= bulk_quantity;
+ total_memory -= malloc_size;
+#if ((DEBUG) & DEBUG_M)
+ my_log(LOG_DEBUG, "M: mem: total: %d (%dKB), free: %d",
+ total_elements, total_memory >> 10, free_elements);
+#endif
+ }
+#ifdef MEM_THREADSAFE
+ pthread_mutex_unlock(&mem_mutex);
+#endif
+}
+
+int mem_init(unsigned int element, unsigned int bulk, unsigned int limit)
+{
+ bulk_quantity = (unsigned) (mem_index_t) bulk; /* for safety: movzbl, movzwl */
+ mem_index_table_size = sizeof(mem_index_t) * bulk_quantity;
+ element_size = element;
+ element_table_size = element_size * bulk_quantity;
+ malloc_size = sizeof(struct Mem) + mem_index_table_size + element_table_size;
+ limit_memory = limit;
+#if ((DEBUG) & DEBUG_M)
+ my_log(LOG_DEBUG, "M: init: element size:%d quantity:%d bulk size:%d limit:%d",
+ element_size, bulk_quantity, malloc_size, limit_memory);
+#endif
+ return 0;
+}