Drizzled Public API Documentation

CSMemory.cc
00001 /* Copyright (C) 2008 PrimeBase Technologies GmbH, Germany
00002  *
00003  * PrimeBase Media Stream for MySQL
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 as published by
00007  * the Free Software Foundation; either version 2 of the License, or
00008  * (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program; if not, write to the Free Software
00017  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
00018  *
00019  * Original author: Paul McCullagh (H&G2JCtL)
00020  * Continued development: Barry Leslie
00021  *
00022  * 2007-06-15
00023  *
00024  * CORE SYSTEM:
00025  * Memory allocation
00026  *
00027  * For debugging memory leaks search for "DEBUG-BREAK-POINT" and watch mm_tracking_id
00028  */
00029 
00030 #include "CSConfig.h"
00031 
00032 #include <assert.h>
00033 #include <string.h>
00034 #include <stddef.h>
00035 #include <stdlib.h>
00036 #include <inttypes.h>
00037 
00038 #include "CSException.h"
00039 #include "CSMemory.h"
00040 #include "CSThread.h"
00041 #include "CSStrUtil.h"
00042 #include "CSGlobal.h"
00043 
00044 #ifdef DEBUG
00045 #undef cs_malloc
00046 #undef cs_calloc
00047 #undef cs_realloc
00048 #undef cs_free
00049 #undef new
00050 #endif
00051 
00052 void *cs_malloc(size_t size)
00053 {
00054   void *ptr;
00055 
00056   if (!(ptr = malloc(size)))
00057     CSException::throwOSError(CS_CONTEXT, ENOMEM);
00058   return ptr;
00059 }
00060 
00061 void *cs_calloc(size_t size)
00062 {
00063   void *ptr;
00064 
00065   if (!(ptr = malloc(size)))
00066     CSException::throwOSError(CS_CONTEXT, ENOMEM);
00067   memset(ptr, 0, size);
00068   return ptr;
00069 }
00070 
00071 void cs_realloc(void **ptr, size_t size)
00072 {
00073   void *new_ptr;
00074   
00075   if (!(new_ptr = realloc(*ptr, size)))
00076     CSException::throwOSError(CS_CONTEXT, ENOMEM);
00077   *ptr = new_ptr;
00078 }
00079 
00080 void cs_free(void *ptr)
00081 {
00082   free(ptr);
00083 }
00084 
00085 /*
00086  * -----------------------------------------------------------------------
00087  * DEBUG MEMORY ALLOCATION AND HEAP CHECKING
00088  */
00089 
00090 #ifdef DEBUG
00091 
00092 #define RECORD_MM
00093 
00094 #define ADD_TOTAL_ALLOCS      4000
00095 
00096 #define SHIFT_RIGHT(ptr, n)     memmove(((char *) (ptr)) + sizeof(MissingMemoryRec), (ptr), (long) (n) * sizeof(MissingMemoryRec))
00097 #define SHIFT_LEFT(ptr, n)      memmove((ptr), ((char *) (ptr)) + sizeof(MissingMemoryRec), (long) (n) * sizeof(MissingMemoryRec))
00098 
00099 typedef struct MissingMemory {
00100   void      *ptr;
00101   uint32_t      id;
00102   const char    *func_name;
00103   const char    *file_name;
00104   uint32_t      line_nr;
00105 } MissingMemoryRec, *MissingMemoryPtr;
00106 
00107 static MissingMemoryRec *mm_addresses = NULL;
00108 static uint32_t     mm_nr_in_use = 0L;
00109 static uint32_t     mm_total_allocated = 0L;
00110 static uint32_t     mm_alloc_count = 0;
00111 static pthread_mutex_t  mm_mutex;
00112 
00113 /* Set this variable to the ID of the memory you want
00114  * to track.
00115  */
00116 static uint32_t     mm_tracking_id = 0;
00117 
00118 static void mm_println(const char *str)
00119 {
00120   printf("%s\n", str);
00121 }
00122 
00123 static long mm_find_pointer(void *ptr)
00124 {
00125   register long i, n, guess;
00126 
00127   i = 0;
00128   n = mm_nr_in_use;
00129   while (i < n) {
00130     guess = (i + n - 1) >> 1;
00131     if (ptr == mm_addresses[guess].ptr)
00132       return(guess);
00133     if (ptr < mm_addresses[guess].ptr)
00134       n = guess;
00135     else
00136       i = guess + 1;
00137   }
00138   return(-1);
00139 }
00140 
00141 static long mm_add_pointer(void *ptr)
00142 {
00143   register int  i, n, guess;
00144 
00145   if (mm_nr_in_use == mm_total_allocated) {
00146     /* Not enough space, add more: */
00147     MissingMemoryRec *new_addresses;
00148 
00149     new_addresses = (MissingMemoryRec *) malloc(sizeof(MissingMemoryRec) * (mm_total_allocated + ADD_TOTAL_ALLOCS));
00150     if (!new_addresses)
00151       return(-1);
00152 
00153     if (mm_addresses) {
00154       memcpy(new_addresses, mm_addresses, sizeof(MissingMemoryRec) * mm_total_allocated);
00155       free(mm_addresses);
00156     }
00157 
00158     mm_addresses = new_addresses;
00159     mm_total_allocated += ADD_TOTAL_ALLOCS;
00160   }
00161 
00162   i = 0;
00163   n = mm_nr_in_use;
00164   while (i < n) {
00165     guess = (i + n - 1) >> 1;
00166     if (ptr < mm_addresses[guess].ptr)
00167       n = guess;
00168     else
00169       i = guess + 1;
00170   }
00171 
00172   SHIFT_RIGHT(&mm_addresses[i], mm_nr_in_use - i);
00173   mm_nr_in_use++;
00174   mm_addresses[i].ptr = ptr;
00175   return(i);
00176 }
00177 
00178 static char *cs_mm_watch_point = 0;
00179 
00180 static long mm_remove_pointer(void *ptr)
00181 {
00182   register int  i, n, guess;
00183 
00184   if (cs_mm_watch_point == ptr)
00185     printf("Hit watch point\n");
00186 
00187   i = 0;
00188   n = mm_nr_in_use;
00189   while (i < n) {
00190     guess = (i + n - 1) >> 1;
00191     if (ptr == mm_addresses[guess].ptr)
00192       goto remove;
00193     if (ptr < mm_addresses[guess].ptr)
00194       n = guess;
00195     else
00196       i = guess + 1;
00197   }
00198   return(-1);
00199 
00200   remove:
00201   /* Decrease the number of sets, and shift left: */
00202   mm_nr_in_use--;
00203   SHIFT_LEFT(&mm_addresses[guess], mm_nr_in_use - guess); 
00204   return(guess);
00205 }
00206 
00207 static void mm_throw_assertion(MissingMemoryPtr mm_ptr, void *p, const char *message)
00208 {
00209   char str[200];
00210 
00211   if (mm_ptr) {
00212     snprintf(str, 200, "MM ERROR: %8p (#%"PRId32") %s:%"PRId32" %s",
00213              mm_ptr->ptr,
00214              mm_ptr->id,
00215              cs_last_name_of_path(mm_ptr->file_name),
00216              mm_ptr->line_nr,
00217              message);
00218   }
00219   else
00220     snprintf(str, 200, "MM ERROR: %8p %s", p, message);
00221   mm_println(str);
00222 }
00223 
00224 static uint32_t mm_add_core_ptr(void *ptr, const char *func, const char *file, int line)
00225 {
00226   long  mm;
00227   uint32_t  id;
00228 
00229   mm = mm_add_pointer(ptr);
00230   if (mm < 0) {
00231     mm_println("MM ERROR: Cannot allocate table big enough!");
00232     return 0;
00233   }
00234 
00235   /* Record the pointer: */
00236   if (mm_alloc_count == mm_tracking_id) { 
00237     /* Enable you to set a breakpoint: */
00238     id = mm_alloc_count++; // DEBUG-BREAK-POINT
00239   }
00240   else {
00241     id = mm_alloc_count++;
00242   }
00243   mm_addresses[mm].ptr = ptr;
00244   mm_addresses[mm].id = id;
00245   mm_addresses[mm].func_name = func;
00246   if (file)
00247     mm_addresses[mm].file_name = file;
00248   else
00249     mm_addresses[mm].file_name = "?";
00250   mm_addresses[mm].line_nr = line;
00251   return id;
00252 }
00253 
00254 static void mm_remove_core_ptr(void *ptr)
00255 {
00256   long mm;
00257 
00258   mm = mm_remove_pointer(ptr);
00259   if (mm < 0) {
00260     mm_println("MM ERROR: Pointer not allocated");
00261     return;
00262   }
00263 }
00264 
00265 static long mm_find_core_ptr(void *ptr)
00266 {
00267   long mm;
00268 
00269   mm = mm_find_pointer(ptr);
00270   if (mm < 0)
00271     mm_throw_assertion(NULL, ptr, "Pointer not allocated");
00272   return(mm);
00273 }
00274 
00275 static void mm_replace_core_ptr(long i, void *ptr)
00276 {
00277   MissingMemoryRec  tmp = mm_addresses[i];
00278   long        mm;
00279 
00280   mm_remove_pointer(mm_addresses[i].ptr);
00281   mm = mm_add_pointer(ptr);
00282   if (mm < 0) {
00283     mm_println("MM ERROR: Cannot allocate table big enough!");
00284     return;
00285   }
00286   mm_addresses[mm] = tmp;
00287   mm_addresses[mm].ptr = ptr;
00288 }
00289 
00290 /*
00291  * -----------------------------------------------------------------------
00292  * MISSING MEMORY PUBLIC ROUTINES
00293  */
00294 
00295 #define MEM_DEBUG_HDR_SIZE    offsetof(MemoryDebugRec, data)
00296 #define MEM_TRAILER_SIZE    2
00297 #define MEM_HEADER        0x01010101
00298 #define MEM_FREED       0x03030303
00299 #define MEM_TRAILER_BYTE    0x02
00300 #define MEM_FREED_BYTE      0x03
00301 
00302 typedef struct MemoryDebug {
00303   uint32_t    check;
00304   uint32_t    md_id;        /* The memory ID! */
00305   uint32_t    size;
00306   char    data[200];
00307 } MemoryDebugRec, *MemoryDebugPtr;
00308 
00309 static size_t mm_check_and_free(MissingMemoryPtr mm_ptr, void *p, bool freeme)
00310 {
00311   unsigned char *ptr = (unsigned char *) p - MEM_DEBUG_HDR_SIZE;
00312   MemoryDebugPtr  debug_ptr = (MemoryDebugPtr) ptr;
00313   size_t      size = debug_ptr->size;
00314   long      a_value;  /* Added to simplfy debugging. */
00315 
00316   if (!ASSERT(p)) 
00317     return(0);
00318   if (!ASSERT(((size_t) p & 1L) == 0)) 
00319     return(0);
00320   a_value = MEM_FREED;
00321   if (debug_ptr->check == MEM_FREED) { 
00322     mm_println("MM ERROR: Pointer already freed 'debug_ptr->check != MEM_FREED'");
00323     return(0);
00324   }
00325   a_value = MEM_HEADER;
00326   if (debug_ptr->check != MEM_HEADER) {
00327     mm_println("MM ERROR: Header not valid 'debug_ptr->check != MEM_HEADER'");
00328     return(0);
00329   }
00330   a_value = MEM_TRAILER_BYTE;
00331   if (!(*((unsigned char *) ptr + size + MEM_DEBUG_HDR_SIZE) == MEM_TRAILER_BYTE &&
00332       *((unsigned char *) ptr + size + MEM_DEBUG_HDR_SIZE + 1L) == MEM_TRAILER_BYTE)) { 
00333     mm_throw_assertion(mm_ptr, p, "Trailer overwritten");
00334     return(0);
00335   }
00336 
00337   if (freeme) {
00338     debug_ptr->check = MEM_FREED;
00339     *((unsigned char *) ptr + size + MEM_DEBUG_HDR_SIZE) = MEM_FREED_BYTE;
00340     *((unsigned char *) ptr + size + MEM_DEBUG_HDR_SIZE + 1L) = MEM_FREED_BYTE;
00341 
00342     memset(((unsigned char *) ptr) + MEM_DEBUG_HDR_SIZE, 0xF5, size);
00343     cs_free(ptr);
00344   }
00345 
00346   return size;
00347 }
00348 
00349 bool cs_mm_scan_core(void)
00350 {
00351   uint32_t mm;
00352   bool rtc = true;
00353 
00354   if (!mm_addresses)
00355     return true;
00356 
00357   pthread_mutex_lock(&mm_mutex);
00358 
00359   for (mm=0; mm<mm_nr_in_use; mm++) {
00360     if (!mm_check_and_free(&mm_addresses[mm], mm_addresses[mm].ptr, false))
00361       rtc = false;
00362   }
00363   
00364   pthread_mutex_unlock(&mm_mutex);
00365   return rtc;
00366 }
00367 
00368 void cs_mm_memmove(void *block, void *dest, void *source, size_t size)
00369 {
00370   if (block) {
00371     MemoryDebugPtr  debug_ptr = (MemoryDebugPtr) ((char *) block - MEM_DEBUG_HDR_SIZE);
00372 
00373 #ifdef RECORD_MM
00374     pthread_mutex_lock(&mm_mutex);
00375     mm_find_core_ptr(block);
00376     pthread_mutex_unlock(&mm_mutex);
00377 #endif
00378     mm_check_and_free(NULL, block, false);
00379 
00380     if (dest < block || (char *) dest > (char *) block + debug_ptr->size) {
00381       mm_println("MM ERROR: Destination not in block");
00382       return;
00383     }
00384     if ((char *) dest + size > (char *) block + debug_ptr->size) {
00385       mm_println("MM ERROR: Copy will overwrite memory");
00386       return;
00387     }
00388   }
00389 
00390   memmove(dest, source, size);
00391 }
00392 
00393 void cs_mm_memcpy(void *block, void *dest, void *source, size_t size)
00394 {
00395   if (block) {
00396     MemoryDebugPtr  debug_ptr = (MemoryDebugPtr) ((char *) block - MEM_DEBUG_HDR_SIZE);
00397 
00398 #ifdef RECORD_MM
00399     pthread_mutex_lock(&mm_mutex);
00400     mm_find_core_ptr(block);
00401     pthread_mutex_unlock(&mm_mutex);
00402 #endif
00403     mm_check_and_free(NULL, block, false);
00404 
00405     if (dest < block || (char *) dest > (char *) block + debug_ptr->size)
00406       mm_throw_assertion(NULL, block, "Destination not in block");
00407     if ((char *) dest + size > (char *) block + debug_ptr->size)
00408       mm_throw_assertion(NULL, block, "Copy will overwrite memory");
00409   }
00410 
00411   memcpy(dest, source, size);
00412 }
00413 
00414 void cs_mm_memset(void *block, void *dest, int value, size_t size)
00415 {
00416   if (block) {
00417     MemoryDebugPtr  debug_ptr = (MemoryDebugPtr) ((char *) block - MEM_DEBUG_HDR_SIZE);
00418 
00419 #ifdef RECORD_MM
00420     pthread_mutex_lock(&mm_mutex);
00421     mm_find_core_ptr(block);
00422     pthread_mutex_unlock(&mm_mutex);
00423 #endif
00424     mm_check_and_free(NULL, block, false);
00425 
00426     if (dest < block || (char *) dest > (char *) block + debug_ptr->size)
00427       mm_throw_assertion(NULL, block, "Destination not in block");
00428     if ((char *) dest + size > (char *) block + debug_ptr->size)
00429       mm_throw_assertion(NULL, block, "Copy will overwrite memory");
00430   }
00431 
00432   memset(dest, value, size);
00433 }
00434 
00435 void *cs_mm_malloc(const char *func, const char *file, int line, size_t size)
00436 {
00437   unsigned char *p = (unsigned char *) cs_malloc(size + MEM_DEBUG_HDR_SIZE + MEM_TRAILER_SIZE);
00438 
00439   if (!p)
00440     return NULL;
00441 
00442   memset(p, 0x55, size + MEM_DEBUG_HDR_SIZE + MEM_TRAILER_SIZE);
00443 
00444   ((MemoryDebugPtr) p)->check = MEM_HEADER;
00445   ((MemoryDebugPtr) p)->md_id = 0;
00446   ((MemoryDebugPtr) p)->size = (uint32_t) size;
00447   *(p + size + MEM_DEBUG_HDR_SIZE) = MEM_TRAILER_BYTE;
00448   *(p + size + MEM_DEBUG_HDR_SIZE + 1L) = MEM_TRAILER_BYTE;
00449 
00450 #ifdef RECORD_MM
00451   pthread_mutex_lock(&mm_mutex);
00452   ((MemoryDebugPtr) p)->md_id = mm_add_core_ptr(p + MEM_DEBUG_HDR_SIZE, func, file, line);
00453   pthread_mutex_unlock(&mm_mutex);
00454 #endif
00455 
00456   return p + MEM_DEBUG_HDR_SIZE;
00457 }
00458 
00459 void *cs_mm_calloc(const char *func, const char *file, int line, size_t size)
00460 {
00461   unsigned char *p = (unsigned char *) cs_calloc(size + MEM_DEBUG_HDR_SIZE + MEM_TRAILER_SIZE);
00462 
00463   if (!p) 
00464     return NULL;
00465 
00466   ((MemoryDebugPtr) p)->check = MEM_HEADER;
00467   ((MemoryDebugPtr) p)->md_id = 0;
00468   ((MemoryDebugPtr) p)->size  = (uint32_t) size;
00469   *(p + size + MEM_DEBUG_HDR_SIZE) = MEM_TRAILER_BYTE;
00470   *(p + size + MEM_DEBUG_HDR_SIZE + 1L) = MEM_TRAILER_BYTE;
00471 
00472 #ifdef RECORD_MM
00473   pthread_mutex_lock(&mm_mutex);
00474   ((MemoryDebugPtr) p)->md_id = mm_add_core_ptr(p + MEM_DEBUG_HDR_SIZE, func, file, line);
00475   pthread_mutex_unlock(&mm_mutex);
00476 #endif
00477 
00478   return p + MEM_DEBUG_HDR_SIZE;
00479 }
00480 
00481 void cs_mm_realloc(const char *func, const char *file, int line, void **ptr, size_t newsize)
00482 {
00483   unsigned char *oldptr = (unsigned char *) *ptr;
00484   size_t      size;
00485   long      mm;
00486   unsigned char *pnew;
00487 
00488   if (!oldptr) {
00489     *ptr = cs_mm_malloc(func, file, line, newsize);
00490     return;
00491   }
00492 
00493 #ifdef RECORD_MM
00494   // The lock must be held until the realloc has completed otherwise
00495   // a scan of the memory may report a bad memory header.
00496   pthread_mutex_lock(&mm_mutex);
00497   if ((mm = mm_find_core_ptr(oldptr)) < 0) {
00498     pthread_mutex_unlock(&mm_mutex);
00499     CSException::throwOSError(CS_CONTEXT, ENOMEM);
00500   }
00501   // pthread_mutex_unlock(&mm_mutex); It will be unlocked below
00502 #endif
00503 
00504   oldptr = oldptr - MEM_DEBUG_HDR_SIZE;
00505   size = ((MemoryDebugPtr) oldptr)->size;
00506 
00507   ASSERT(((MemoryDebugPtr) oldptr)->check == MEM_HEADER);
00508   ASSERT(*((unsigned char *) oldptr + size + MEM_DEBUG_HDR_SIZE) == MEM_TRAILER_BYTE && 
00509       *((unsigned char *) oldptr + size + MEM_DEBUG_HDR_SIZE + 1L) == MEM_TRAILER_BYTE);
00510 
00511   /* Grow allways moves! */
00512   pnew = (unsigned char *) cs_malloc(newsize + MEM_DEBUG_HDR_SIZE + MEM_TRAILER_SIZE);
00513   if (!pnew) {
00514 #ifdef RECORD_MM
00515     pthread_mutex_unlock(&mm_mutex); 
00516 #endif
00517     CSException::throwOSError(CS_CONTEXT, ENOMEM);
00518     return;
00519   }
00520 
00521   if (newsize > size) {
00522     memcpy(((MemoryDebugPtr) pnew)->data, ((MemoryDebugPtr) oldptr)->data, size);
00523     memset(((MemoryDebugPtr) pnew)->data + size, 0x55, newsize - size);
00524   }
00525   else
00526     memcpy(((MemoryDebugPtr) pnew)->data, ((MemoryDebugPtr) oldptr)->data, newsize);
00527   memset(oldptr, 0x55, size + MEM_DEBUG_HDR_SIZE + MEM_TRAILER_SIZE);
00528 
00529 #ifdef RECORD_MM
00530   // pthread_mutex_lock(&mm_mutex); It was locked above
00531   if ((mm = mm_find_core_ptr(oldptr + MEM_DEBUG_HDR_SIZE)) < 0) {
00532     pthread_mutex_unlock(&mm_mutex);
00533     CSException::throwOSError(CS_CONTEXT, ENOMEM);
00534     return;
00535   }
00536   mm_replace_core_ptr(mm, pnew + MEM_DEBUG_HDR_SIZE);
00537   pthread_mutex_unlock(&mm_mutex);
00538 #endif
00539 
00540   cs_free(oldptr);
00541 
00542   ((MemoryDebugPtr) pnew)->check = MEM_HEADER;
00543   ((MemoryDebugPtr) pnew)->size = (uint32_t) newsize;
00544   *(pnew + newsize + MEM_DEBUG_HDR_SIZE) = MEM_TRAILER_BYTE;
00545   *(pnew + newsize + MEM_DEBUG_HDR_SIZE + 1L) = MEM_TRAILER_BYTE;
00546 
00547   *ptr = pnew + MEM_DEBUG_HDR_SIZE;
00548 }
00549 
00550 void cs_mm_free(void *ptr)
00551 {
00552   bool my_pointer = false;
00553 
00554 #ifdef RECORD_MM
00555   pthread_mutex_lock(&mm_mutex);
00556   if (mm_find_pointer(ptr) >= 0) {
00557     my_pointer = true;
00558     mm_remove_core_ptr(ptr);
00559   }
00560   pthread_mutex_unlock(&mm_mutex);
00561 #endif
00562   if (my_pointer)
00563     mm_check_and_free(NULL, ptr, true);
00564   else
00565     free(ptr);
00566 }
00567 
00568 void cs_mm_pfree(void **ptr)
00569 {
00570   if (*ptr) {
00571     void *p = *ptr;
00572 
00573     *ptr = NULL;
00574     cs_mm_free(p);
00575   }
00576 }
00577 
00578 size_t cs_mm_malloc_size(void *ptr)
00579 {
00580   size_t size = 0;
00581 
00582 #ifdef RECORD_MM
00583   pthread_mutex_lock(&mm_mutex);
00584   mm_find_core_ptr(ptr);
00585   pthread_mutex_unlock(&mm_mutex);
00586 #endif
00587   size = mm_check_and_free(NULL, ptr, false);
00588   return size;
00589 }
00590 
00591 void cs_mm_print_track(const char *func, const char *file, uint32_t line, void *p, bool inc, uint32_t ref_cnt, int track_me)
00592 {
00593   unsigned char *ptr = (unsigned char *) p - MEM_DEBUG_HDR_SIZE;
00594   MemoryDebugPtr  debug_ptr = (MemoryDebugPtr) ptr;
00595   CSThread    *self = CSThread::getSelf();
00596   char      buffer[300];
00597   int       cnt = 0;
00598 
00599   if (!track_me && !mm_tracking_id)
00600     return;
00601 
00602   if (func) {
00603     cs_format_context(300, buffer, func, file, line);
00604     fprintf(stderr, "TRACKING (%"PRIu32"): %s %2"PRIu32" %s", debug_ptr->md_id, inc ? "INC" : "DEC", ref_cnt, buffer);
00605   }
00606   else
00607     fprintf(stderr, "TRACKING (%"PRIu32"): %s %2"PRIu32"", debug_ptr->md_id, inc ? "INC" : "DEC", ref_cnt);
00608 
00609   for (int i = self->callTop-1; i>=0 && cnt < 4; i--) {
00610     cs_format_context(300, buffer, self->callStack[i].cs_func, self->callStack[i].cs_file, self->callStack[i].cs_line);
00611     fprintf(stderr," %s", buffer);
00612     cnt++;
00613   }
00614   fprintf(stderr,"\n");
00615 }
00616 
00617 void cs_mm_track_memory(const char *func, const char *file, uint32_t line, void *p, bool inc, uint32_t ref_cnt, int track_me)
00618 {
00619   unsigned char *ptr = (unsigned char *) p - MEM_DEBUG_HDR_SIZE;
00620   MemoryDebugPtr  debug_ptr = (MemoryDebugPtr) ptr;
00621 
00622   if (track_me || (mm_tracking_id && debug_ptr->md_id == mm_tracking_id))
00623     cs_mm_print_track(func, file, line, p, inc, ref_cnt, track_me);
00624 }
00625 
00626 #endif
00627 
00628 /*
00629  * -----------------------------------------------------------------------
00630  * INIT/EXIT MEMORY
00631  */
00632 
00633 bool cs_init_memory(void)
00634 {
00635 #ifdef DEBUG
00636   pthread_mutex_init(&mm_mutex, NULL);
00637   mm_addresses = (MissingMemoryRec *) malloc(sizeof(MissingMemoryRec) * ADD_TOTAL_ALLOCS);
00638   if (!mm_addresses) {
00639     mm_println("MM ERROR: Insuffient memory to allocate MM table");
00640     pthread_mutex_destroy(&mm_mutex);
00641     return false;
00642   }
00643 
00644   memset(mm_addresses, 0, sizeof(MissingMemoryRec) * ADD_TOTAL_ALLOCS);
00645   mm_total_allocated = ADD_TOTAL_ALLOCS;
00646   mm_nr_in_use = 0L;
00647   mm_alloc_count = 0L;
00648 #endif
00649   return true;
00650 }
00651 
00652 void cs_exit_memory(void)
00653 {
00654 #ifdef DEBUG
00655   uint32_t mm;
00656 
00657   if (!mm_addresses)
00658     return;
00659 
00660   pthread_mutex_lock(&mm_mutex);
00661   for (mm=0; mm<mm_nr_in_use; mm++)
00662     mm_throw_assertion(&mm_addresses[mm], mm_addresses[mm].ptr, "Not freed");
00663   free(mm_addresses);
00664   mm_addresses = NULL;
00665   mm_nr_in_use = 0L;
00666   mm_total_allocated = 0L;
00667   mm_alloc_count = 0L;
00668   pthread_mutex_unlock(&mm_mutex);
00669 
00670   pthread_mutex_destroy(&mm_mutex);
00671 #endif
00672 }
00673 
00674 #ifdef DEBUG
00675 uint32_t cs_mm_get_check_point()
00676 {
00677   return mm_alloc_count;
00678 }
00679 
00680 // Reports any memory allocated after the check_point
00681 // but has not been freed.
00682 void cs_mm_assert_check_point(uint32_t check_point)
00683 {
00684   uint32_t mm;
00685 
00686   if (!mm_addresses)
00687     return;
00688 
00689   pthread_mutex_lock(&mm_mutex);
00690   for (mm=0; mm<mm_nr_in_use; mm++) {
00691     if (mm_addresses[mm].id >= check_point)
00692       mm_throw_assertion(&mm_addresses[mm], mm_addresses[mm].ptr, "Not freed");
00693   }
00694 
00695   pthread_mutex_unlock(&mm_mutex);
00696 
00697 }
00698 #endif