dnxHeap.c

Go to the documentation of this file.
00001 /*--------------------------------------------------------------------------
00002 
00003    Copyright (c) 2006-2007, Intellectual Reserve, Inc. All rights reserved.
00004 
00005    This program is free software; you can redistribute it and/or modify
00006    it under the terms of the GNU General Public License version 2 as
00007    published by the Free Software Foundation.
00008 
00009    This program is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012    GNU General Public License for more details.
00013 
00014    You should have received a copy of the GNU General Public License
00015    along with this program; if not, write to the Free Software
00016    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017 
00018   --------------------------------------------------------------------------*/
00019 
00028 #include "dnxHeap.h"
00029 
00030 #include <stddef.h>
00031 #include <stdlib.h>
00032 #include <stdio.h>
00033 #include <string.h>
00034 #include <assert.h>
00035 #include <pthread.h>
00036 
00037 #define PICKETSZ  8        
00038 
00039 #define PICKET1   0xAA     
00040 #define PICKET2   0xBB     
00041 #define PICKET3   0xCC     
00042 #define ALIGNED   0xDD     
00043 #define ALLOCED   0xEE     
00044 #define FREED     0xFF     
00045 
00046 
00050 #define ALIGNSZ(sz)  (((sz) + 15) & (-1L << 4))
00051 
00053 typedef struct overhead_
00054 {
00055    char picket1[PICKETSZ]; 
00056    struct overhead_ * next;
00057    size_t reqsz;           
00058    size_t actualsz;        
00059    char * file;            
00060    int line;               
00061    char picket2[PICKETSZ]; 
00062 } overhead;
00063 
00064 static overhead * head = 0;
00065 static int blkcnt = 0;     
00066 static pthread_mutex_t list_lock = PTHREAD_MUTEX_INITIALIZER;
00068 
00069 /*--------------------------------------------------------------------------
00070                               IMPLEMENTATION
00071   --------------------------------------------------------------------------*/
00072 
00077 static void link_block(overhead * ohp)
00078 {
00079    pthread_mutex_lock(&list_lock);
00080    ohp->next = head;
00081    head = ohp;
00082    blkcnt++;
00083    pthread_mutex_unlock(&list_lock);
00084 }
00085 
00086 //----------------------------------------------------------------------------
00087 
00094 static int unlink_block(overhead * ohp)
00095 {
00096    int found = 0;
00097    overhead ** cpp;
00098    pthread_mutex_lock(&list_lock);
00099    for (cpp = &head; *cpp; cpp = &(*cpp)->next)
00100       if (*cpp == ohp)
00101       {
00102          *cpp = ohp->next;
00103          blkcnt--;
00104          found = 1;
00105          break;
00106       }
00107    pthread_mutex_unlock(&list_lock);
00108    return found;
00109 }
00110 
00111 //----------------------------------------------------------------------------
00112 
00123 static size_t hex_dump(char * buf, void * p, size_t sz)
00124 {
00125    unsigned char * ucp = (unsigned char *)p;
00126    char * cp = buf;
00127 
00128    while (sz--)
00129       cp += sprintf(cp, " %02x", *ucp++);
00130 
00131    *cp = 0;
00132 
00133    return cp - buf;
00134 }
00135 
00136 //----------------------------------------------------------------------------
00137 
00143 static void dump_block(overhead * ohp, char * msg)
00144 {
00145    char buf[512];
00146    char * p = buf;
00147 
00148    // format heap block...
00149    p +=  sprintf(p, "dnxHeap:");
00150    if (msg) p += sprintf(p, " %s -", msg);
00151    p+= sprintf(p, " %d bytes allocated at %s(%d): ",
00152          ohp->reqsz, ohp->file, ohp->line);
00153    p += hex_dump(p, ohp->picket1, sizeof ohp->picket1);
00154    p +=  sprintf(p, " |");
00155    p += hex_dump(p, ohp->picket2, sizeof ohp->picket2);
00156    p +=  sprintf(p, " |");
00157    if (ohp->reqsz <= 16)
00158       p += hex_dump(p, &ohp[1], ohp->reqsz);
00159    else  // for blocks > 16 bytes, display only first and last 8 bytes
00160    {
00161       p += hex_dump(p, &ohp[1], 8);
00162       p += sprintf (p, " ...");
00163       p += hex_dump(p, (char *)&ohp[1] + ohp->reqsz - 8, 8);
00164    }
00165    p +=  sprintf(p, " |");
00166    p += hex_dump(p, (char *)&ohp[1] + ohp->reqsz, PICKETSZ);
00167 
00168    // ...and display it
00169    dnxDebug(1, "%s", buf);
00170 }
00171 
00172 //----------------------------------------------------------------------------
00173 
00183 static int memscan(void * p, unsigned char ch, size_t sz)
00184 {
00185    unsigned char * bp = (unsigned char *)p;
00186    unsigned char * ep = bp + sz;
00187    while (bp < ep) if (*bp++ != ch) return -1;
00188    return 0;
00189 }
00190 
00191 //----------------------------------------------------------------------------
00192 
00199 static int check_block(overhead * ohp)
00200 {
00201    int rc1, rc2, rc3;
00202 
00203    if ((rc1 = memscan(ohp->picket1, PICKET1, sizeof ohp->picket1)) != 0)
00204       dump_block(ohp, "corrupt pre-header fence");
00205    if ((rc2 = memscan(ohp->picket2, PICKET2, sizeof ohp->picket2)) != 0)
00206       dump_block(ohp, "corrupt post-header fence");
00207    if ((rc3 = memscan((char *)&ohp[1] + ohp->reqsz, PICKET3, PICKETSZ)) != 0)
00208       dump_block(ohp, "corrupt post-user fence");
00209 
00210    assert(!rc1 && !rc2 && !rc3);
00211 
00212    return !rc1 && !rc2 && !rc3 ? 1 : 0;
00213 }
00214 
00215 /*--------------------------------------------------------------------------
00216                                  INTERFACE
00217   --------------------------------------------------------------------------*/
00218 
00219 void * dnxMalloc(size_t sz, char * file, int line)
00220 {
00221    overhead * ohp;
00222    size_t blksz = ALIGNSZ(sizeof *ohp + sz + PICKETSZ);
00223 
00224    assert(sz);
00225    assert(file && line);
00226 
00227    ohp = malloc(blksz);
00228    assert(ohp);
00229    if (!ohp) return NULL;
00230 
00231    memset(ohp->picket1, PICKET1, sizeof ohp->picket1);
00232    ohp->next = 0;
00233    ohp->reqsz = sz;
00234    ohp->actualsz = blksz;
00235    ohp->file = strdup(file);
00236    ohp->line = line;
00237    memset(ohp->picket2, PICKET2, sizeof ohp->picket2);
00238 
00239    memset(&ohp[1], ALLOCED, sz);
00240    memset((char *)&ohp[1] + sz, PICKET3, PICKETSZ);
00241    memset((char *)&ohp[1] + sz + PICKETSZ, ALIGNED,
00242          blksz - (sizeof *ohp + sz + PICKETSZ));
00243 
00244    link_block(ohp);
00245 
00246    dnxDebug(10, "dnxHeap: alloc(%ld) == %p.", sz, &ohp[1]);
00247 
00248    return &ohp[1];
00249 }
00250 
00251 //----------------------------------------------------------------------------
00252 
00253 void * dnxCalloc(size_t n, size_t sz, char * file, int line)
00254 {
00255    size_t blksz = n * sz;
00256    void * p;
00257 
00258    assert(n && sz);
00259    assert(file && line);
00260 
00261    p = dnxMalloc(blksz, file, line);
00262 
00263    memset(p, 0, blksz);
00264 
00265    return p;
00266 }
00267 
00268 //----------------------------------------------------------------------------
00269 
00270 void * dnxRealloc(void * p, size_t sz, char * file, int line)
00271 {
00272    assert(p || sz);
00273    assert(file && line);
00274 
00275    if (!sz)
00276       dnxFree(p), p = 0;
00277    else if (!p)
00278       p = dnxMalloc(sz, file, line);
00279    else
00280    {
00281       overhead * ohp = &((overhead *)p)[-1];
00282       void * np = dnxMalloc(sz, file, line);
00283       memcpy(np, p, sz < ohp->reqsz? sz: ohp->reqsz);
00284       dnxFree(p);
00285       p = np;
00286    }
00287    return p;
00288 }
00289 
00290 //----------------------------------------------------------------------------
00291 
00292 char * dnxStrdup(char * str, char * file, int line)
00293 {
00294    char * s;
00295    size_t allocsz;
00296 
00297    assert(str);
00298    assert(file && line);
00299 
00300    allocsz = strlen(str) + 1;
00301 
00302    if ((s = (char *)dnxMalloc(allocsz, file, line)) == 0)
00303       return 0;
00304 
00305    memcpy(s, str, allocsz);
00306    return s;
00307 }
00308 
00309 //----------------------------------------------------------------------------
00310 
00311 void dnxFree(void * p)
00312 {
00313    if (p)
00314    {
00315       overhead * ohp = &((overhead *)p)[-1];
00316       if (!unlink_block(ohp))
00317       {
00318          dnxDebug(1, "dnxHeap: free(%p) - attempt to free non-heap address.", p);
00319          assert(0);
00320          return;
00321       }
00322       if (!check_block(ohp))
00323          return;
00324       free(ohp->file);
00325       free(ohp);
00326       ohp = NULL;
00327       dnxDebug(10, "dnxHeap: free(%p).", p);
00328       p = NULL;
00329    }
00330 }
00331 
00332 //----------------------------------------------------------------------------
00333 
00334 int dnxCheckHeap(void)
00335 {
00336    overhead * cp;
00337    pthread_mutex_lock(&list_lock);
00338    dnxDebug(1, "dnxCheckHeap: %d unfreed blocks remaining...", blkcnt);
00339    for (cp = head; cp; cp = cp->next)
00340    {
00341       dump_block(cp, "unfreed memory block");
00342       if (!check_block(cp))
00343          break;
00344    }
00345    pthread_mutex_unlock(&list_lock);
00346    return blkcnt? -1: 0;
00347 }
00348 
00349 /*--------------------------------------------------------------------------*/
00350 

Generated on Tue Apr 13 15:48:07 2010 for DNX by  doxygen 1.5.6