/* Copyright (c) 2000-2010, Dirk Krause All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above opyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the Dirk Krause nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @file dkmem.c Memory allocation routines. */ #include "dk.h" #if DK_HAVE_STRING_H #include #else #if DK_HAVE_STRINGS_H #include #endif #endif #if DK_HAVE_SYS_TYPES_H #include #endif #if DK_HAVE_STDLIB_H #include #endif #if DK_HAVE_UNISTD_H #include #endif #if DK_HAVE_ALLOC_H #include #endif /** Inside the dkmem module. */ #define DK_MEM_C 1 #include "dkmem.h" $(trace-include) #if !DKMEM_NO_TRACK /** Maximum unsigned long value. */ #define MAXUL 0xFFFFFFFFUL /** Upper 32 bits of amount of memory allocated. */ static unsigned long hb = 0UL; /** Lower 32 bits of amount of memory allocated. */ static unsigned long lb = 0UL; /** Track the number of bytes allocated. @param sz Number of bytes to add. */ static void track_bytes DK_P1(size_t,sz) { unsigned long newval; newval = (unsigned long)sz; if(lb >= (MAXUL - newval)) { hb++; } lb += newval; lb &= MAXUL; } #endif /** Get number of allocated bytes. @param usehb Flag: Use higher 32 bits (1) or lower 32 bits (0). @return 32-bit value. */ unsigned long dkmem_get_track DK_P1(int,usehb) { unsigned long back = 0UL; back = (usehb ? hb : lb); return back; } /** Check whether the product of elsize and nelem fits into a size_t. @param elsize Element size. @param nelem Number of elements. @return Product elsize*nelem or 0 on overflow. */ static size_t check_size DK_P2(size_t, elsize, size_t, nelem) { size_t back = 0UL; unsigned long i, j, k; i = elsize; j = nelem; if(i < (0xFFFFFFFFUL / j)) { k = i * j; if(k <= ((size_t)0xFFFFFFFFUL)) { back = ((size_t)k); } } $? "= check_size %lu * %lu = %lu", (unsigned long)elsize, (unsigned long)nelem, (unsigned long)back return back; } /** Reset memory. @param ptr Pointer to memory. @param bytes Number of bytes. */ void dkmem_res DK_P2(void *, ptr, size_t, bytes) { if(ptr && bytes) { #if DK_HAVE_MEMSET memset(ptr,0,bytes); #else #if DK_HAVE_BZERO bzero(ptr,bytes); #else char *x; size_t y; x = (char *)ptr; y = bytes; while(y--) { *(x++) = '\0'; } #endif #endif } } /** Copy memory region. @param d Destination. @param s Source. @param n Number of bytes to copy. */ void dkmem_cpy DK_P3(void *, d, void *, s, size_t, n) { if(d && s && n) { #if DK_HAVE_MEMCPY memcpy(d,s,n); #else #if DK_HAVE_BCOPY bcopy(s,d,n); #else char *x, *y; size_t z; z = n; x = (char *)s; y = (char *)d; while(z--) { *(y++) = *(x++); } #endif #endif } } /** Compare memory regions. @param s1 Left memory region. @param s2 Right memory region. @param n Number of bytes. @return Comparison result. */ int dkmem_cmp DK_P3(void *, s1, void *, s2, size_t, n) { int back = 0; if(s1 && s2 && n) { #if DK_HAVE_MEMCMP back = memcmp(s1,s2,n); #else #if DK_HAVE_BCMP back = bcmp(s1,s2,n); #else char *x, *y; size_t z; z = n; x = (char *)s1; y = (char *)s2; while((z--) && (!back)) { if((*(x++)) != (*(y++))) { back = 1; } } #endif #endif } return back; } /** Allocate memory. @param elsize Element size. @param nelem Number of elements. @return Pointer on success, NULL on error. */ void * dkmem_alloc DK_P2(size_t, elsize, size_t, nelem) { void *back = NULL; size_t bytes; $? "+ dkmem_alloc %lu %lu", (unsigned long)elsize, (unsigned long)nelem if(elsize && nelem) { bytes = check_size(elsize,nelem); $? ". bytes %lu", (unsigned long)bytes if(bytes) { #if DK_HAVE_FARMALLOC $? ". far allocation" #if DK_HAVE_FARCORELEFT $? ". comparing against farcoreleft %lu", (unsigned long)farcoreleft() if(bytes < farcoreleft()) { #endif $? ". trying to farmalloc" back = farmalloc(bytes); #if DK_HAVE_FARCORELEFT } #endif #else $? ". near allocation" #if DK_HAVE_MALLOC #if DK_HAVE_CORELEFT $? ". comparing against coreleft %lu", (unsigned long)coreleft() if(bytes < coreleft()) { #endif $? ". trying to malloc" back = malloc(bytes); #if DK_HAVE_CORELEFT } #endif #endif #endif } } if(back) { $? ". allocation successfull" #if DK_HAVE_MEMSET $? ". memset" memset(back, 0, bytes); #else #if DK_HAVE_BZERO $? ". bzero" bzero(back,bytes); #else $? ". dkmem_res" dkmem_res(back,bytes); #endif #endif } $? "- dkmem_alloc %s", TR_PTR(back) return back; } /** Allocate memory, track memory usage. @param elsize Element size. @param nelem Number of elements. @return Pointer on success, NULL on error. */ void * dkmem_alloc_tracked DK_P2(size_t, elsize, size_t, nelem) { void *back = NULL; size_t bytes; $? "+ dkmem_alloc_tracked %lu %lu", (unsigned long)elsize, (unsigned long)nelem if(elsize && nelem) { bytes = check_size(elsize,nelem); $? ". bytes %lu", (unsigned long)bytes if(bytes) { back = dkmem_alloc(elsize, nelem); } } #if !DKMEM_NO_TRACK if(back) { $? ". allocation successfull" track_bytes(bytes); } #endif $? "- dkmem_alloc_tracked %s", TR_PTR(back) return back; } /** Release memory. @param ptr Memory to release. */ void dkmem_free DK_P1(void *, ptr) { $? "+ dkmem_free %s", TR_PTR(ptr) if(ptr) { #if DK_HAVE_FARMALLOC farfree(ptr); #else #if DK_HAVE_MALLOC free(ptr); #endif #endif } $? "- dkmem_free" }