/* Copyright (C) Slava Astashonok 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 #include #include #include #include #include #ifdef MEM_THREADSAFE #include #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; }