2007-11-29 14:18:54 +00:00
/* -*- mode: C; c-basic-offset: 4 -*- */
2008-01-24 15:10:32 +00:00
# ident "Copyright (c) 2007, 2008 Tokutek Inc. All rights reserved."
2007-11-29 14:18:54 +00:00
2007-07-13 19:37:47 +00:00
# include "memory.h"
# include <assert.h>
# include <string.h>
# include <stdlib.h>
# include <errno.h>
# include <stdio.h>
2007-11-29 15:34:49 +00:00
int toku_memory_check = 0 ;
2007-07-13 19:37:47 +00:00
2007-11-29 15:34:49 +00:00
# define WHEN_MEM_DEBUG(x) ({if (toku_memory_check) ({x});})
2007-07-13 19:37:47 +00:00
2007-11-29 15:41:46 +00:00
static long long n_items_malloced = 0 ;
2007-07-13 19:37:47 +00:00
/* Memory checking */
enum { items_limit = 1000 } ;
2007-11-29 15:34:49 +00:00
static int overflowed = 0 ;
2007-07-13 19:37:47 +00:00
static void * items [ items_limit ] ;
static long sizes [ items_limit ] ;
2007-11-29 15:34:49 +00:00
static void note_did_malloc ( void * p , long size ) {
2007-07-24 03:28:48 +00:00
static long long count = 0 ;
2007-07-13 19:37:47 +00:00
WHEN_MEM_DEBUG (
if ( n_items_malloced < items_limit ) { items [ n_items_malloced ] = p ; sizes [ n_items_malloced ] = size ; }
else overflowed = 1 ;
2007-07-23 15:11:54 +00:00
//printf("%s:%d %p=malloc(%ld)\n", __FILE__, __LINE__, p, size);
2007-07-13 19:37:47 +00:00
) ;
n_items_malloced + + ;
2007-07-24 03:28:48 +00:00
count + + ;
2007-07-13 19:37:47 +00:00
}
2007-11-29 15:34:49 +00:00
static void note_did_free ( void * p ) {
2007-07-13 19:37:47 +00:00
WHEN_MEM_DEBUG (
if ( ! overflowed ) {
int i ;
//printf("not overflowed\n");
for ( i = 0 ; i < n_items_malloced ; i + + ) {
if ( items [ i ] = = p ) {
items [ i ] = items [ n_items_malloced - 1 ] ;
sizes [ i ] = sizes [ n_items_malloced - 1 ] ;
// printf("items[%d] replaced, now %p\n", i, items[i]);
goto ok ;
}
}
printf ( " %s:%d freed something (%p) not alloced \n " , __FILE__ , __LINE__ , p ) ;
abort ( ) ;
ok : ;
}
2007-07-23 15:11:54 +00:00
//printf("%s:%d free(%p)\n", __FILE__, __LINE__, p);
2007-07-13 19:37:47 +00:00
) ;
n_items_malloced - - ;
}
//#define BUFFERED_MALLOC
# ifdef BUFFERED_MALLOC
2007-12-10 11:28:00 +00:00
# error "Turning on BUFFERED_MALLOC will probably break things. For example, DBT's are DB_DBT_MALLOC'd using toku_malloc(), but then the user calls free() (rather than toku_free)."
2007-07-13 19:37:47 +00:00
enum { BUFFERING = 4096 } ;
void mark_buffer ( char * p , int size ) {
unsigned int * pl = ( unsigned int * ) p ;
int i ;
for ( i = 0 ; i < BUFFERING / 4 ; i + + ) {
pl [ i ] = 0xdeadbeef ;
}
pl [ BUFFERING / 8 ] = size ;
}
int check_buffer ( char * p ) {
unsigned int * pl = ( unsigned int * ) p ;
int i ;
for ( i = 0 ; i < BUFFERING / 4 ; i + + ) {
if ( i ! = BUFFERING / 8 ) {
assert ( pl [ i ] = = 0xdeadbeef ) ;
}
}
return pl [ BUFFERING / 8 ] ;
}
void check_all_buffers ( void ) {
int i ;
if ( ! overflowed ) {
for ( i = 0 ; i < n_items_malloced ; i + + ) {
int size = check_buffer ( ( ( char * ) items [ i ] ) - BUFFERING ) ;
check_buffer ( ( ( char * ) items [ i ] ) + size ) ;
}
}
}
void * actual_malloc ( long size ) {
char * r = malloc ( size + BUFFERING * 2 ) ;
mark_buffer ( r , size ) ;
mark_buffer ( r + size + BUFFERING , size ) ;
check_all_buffers ( ) ;
return r + BUFFERING ;
}
void actual_free ( void * pv ) {
char * p = pv ;
int size = check_buffer ( p - BUFFERING ) ;
check_buffer ( p + size ) ;
check_all_buffers ( ) ;
//free(p-BUFFERING);
}
void * actual_realloc ( void * pv , long size ) {
check_all_buffers ( ) ;
{
char * p = pv ;
char * r = realloc ( p - BUFFERING , size + BUFFERING * 2 ) ;
mark_buffer ( r , size ) ;
mark_buffer ( r + size + BUFFERING , size ) ;
return r + BUFFERING ;
}
}
void * actual_calloc ( long nmemb , long size ) {
return actual_malloc ( nmemb * size ) ;
}
void do_memory_check ( void ) {
check_all_buffers ( ) ;
}
# else
# define actual_malloc malloc
# define actual_free free
# define actual_realloc realloc
# define actual_calloc calloc
# endif
2008-01-23 18:35:54 +00:00
void * toku_calloc ( size_t nmemb , size_t size ) {
2007-07-13 19:37:47 +00:00
void * r ;
errno = 0 ;
r = actual_calloc ( nmemb , size ) ;
//printf("%s:%d calloc(%ld,%ld)->%p\n", __FILE__, __LINE__, nmemb, size, r);
note_did_malloc ( r , nmemb * size ) ;
//if ((long)r==0x80523f8) { printf("%s:%d %p\n", __FILE__, __LINE__, r); }
return r ;
}
2007-08-08 15:06:51 +00:00
# define FREELIST_LIMIT (64+1)
2007-11-28 19:09:24 +00:00
static void * freelist [ FREELIST_LIMIT ] ;
2007-08-07 23:38:05 +00:00
2007-08-08 15:12:15 +00:00
# define MALLOC_SIZE_COUNTING_LIMIT 512
2007-11-29 15:41:46 +00:00
static int malloc_counts [ MALLOC_SIZE_COUNTING_LIMIT ] ; // We rely on static variables being initialized to 0.
static int fresh_malloc_counts [ MALLOC_SIZE_COUNTING_LIMIT ] ; // We rely on static variables being initialized to 0.
static int other_malloc_count = 0 , fresh_other_malloc_count = 0 ;
2008-01-24 20:31:16 +00:00
void * toku_malloc ( size_t size ) {
2007-07-13 19:37:47 +00:00
void * r ;
errno = 0 ;
2007-08-07 23:14:09 +00:00
if ( size < MALLOC_SIZE_COUNTING_LIMIT ) malloc_counts [ size ] + + ;
else other_malloc_count + + ;
2007-08-07 23:38:05 +00:00
if ( size > = sizeof ( void * ) & & size < FREELIST_LIMIT ) {
if ( freelist [ size ] ) {
r = freelist [ size ] ;
freelist [ size ] = * ( void * * ) r ;
note_did_malloc ( r , size ) ;
return r ;
}
}
2007-08-08 14:29:31 +00:00
if ( size < MALLOC_SIZE_COUNTING_LIMIT ) fresh_malloc_counts [ size ] + + ;
else fresh_other_malloc_count + + ;
2007-07-13 19:37:47 +00:00
r = actual_malloc ( size ) ;
2007-07-23 15:11:54 +00:00
//printf("%s:%d malloc(%ld)->%p\n", __FILE__, __LINE__, size,r);
2007-07-13 19:37:47 +00:00
note_did_malloc ( r , size ) ;
//if ((long)r==0x80523f8) { printf("%s:%d %p size=%ld\n", __FILE__, __LINE__, r, size); }
return r ;
}
2008-01-24 20:31:16 +00:00
void * toku_tagmalloc ( size_t size , int typtag ) {
2007-07-23 15:11:54 +00:00
//printf("%s:%d tagmalloc\n", __FILE__, __LINE__);
2007-07-20 18:00:14 +00:00
void * r = toku_malloc ( size ) ;
2007-07-13 19:37:47 +00:00
assert ( size > sizeof ( int ) ) ;
( ( int * ) r ) [ 0 ] = typtag ;
return r ;
}
2008-01-23 18:35:54 +00:00
void * toku_realloc ( void * p , size_t size ) {
2007-07-13 19:37:47 +00:00
void * newp ;
note_did_free ( p ) ;
errno = 0 ;
newp = actual_realloc ( p , size ) ;
//printf("%s:%d realloc(%p,%ld)-->%p\n", __FILE__, __LINE__, p, size, newp);
note_did_malloc ( newp , size ) ;
return newp ;
}
2007-07-20 18:00:14 +00:00
void toku_free ( void * p ) {
2007-07-13 19:37:47 +00:00
//printf("%s:%d free(%p)\n", __FILE__, __LINE__, p);
note_did_free ( p ) ;
actual_free ( p ) ;
}
2008-01-24 20:31:16 +00:00
void toku_free_n ( void * p , size_t size ) {
2007-08-07 23:38:05 +00:00
//printf("%s:%d free(%p)\n", __FILE__, __LINE__, p);
note_did_free ( p ) ;
if ( size > = sizeof ( void * ) & & size < FREELIST_LIMIT ) {
//printf("freelist[%lu] ||= %p\n", size, p);
* ( void * * ) p = freelist [ size ] ;
freelist [ size ] = p ;
} else {
actual_free ( p ) ;
}
}
2008-01-23 18:35:54 +00:00
void * toku_memdup ( const void * v , size_t len ) {
2007-07-20 18:00:14 +00:00
void * r = toku_malloc ( len ) ;
2007-07-13 19:37:47 +00:00
memcpy ( r , v , len ) ;
return r ;
}
2007-08-01 02:37:21 +00:00
char * toku_strdup ( const char * s ) {
2007-11-29 15:41:46 +00:00
return toku_memdup ( s , strlen ( s ) + 1 ) ;
2007-07-13 19:37:47 +00:00
}
2007-11-29 15:34:49 +00:00
void toku_memory_check_all_free ( void ) {
2007-07-13 19:37:47 +00:00
if ( n_items_malloced > 0 ) {
printf ( " n_items_malloced=%lld \n " , n_items_malloced ) ;
2007-11-29 15:34:49 +00:00
if ( toku_memory_check )
2007-07-13 19:37:47 +00:00
printf ( " one item is %p size=%ld \n " , items [ 0 ] , sizes [ 0 ] ) ;
}
assert ( n_items_malloced = = 0 ) ;
}
2007-11-29 15:41:46 +00:00
int toku_get_n_items_malloced ( void ) { return n_items_malloced ; }
2007-11-29 15:34:49 +00:00
void toku_print_malloced_items ( void ) {
2007-07-13 19:37:47 +00:00
int i ;
for ( i = 0 ; i < n_items_malloced ; i + + ) {
printf ( " %p size=%ld \n " , items [ i ] , sizes [ i ] ) ;
}
}
2007-08-07 23:14:09 +00:00
2007-11-29 15:41:46 +00:00
void toku_malloc_report ( void ) {
2007-08-07 23:14:09 +00:00
int i ;
printf ( " malloc report: \n " ) ;
for ( i = 0 ; i < MALLOC_SIZE_COUNTING_LIMIT ; i + + ) {
2007-08-08 14:29:31 +00:00
if ( malloc_counts [ i ] | | fresh_malloc_counts [ i ] ) printf ( " %d: %d (%d fresh) \n " , i , malloc_counts [ i ] , fresh_malloc_counts [ i ] ) ;
2007-08-07 23:14:09 +00:00
}
2007-08-08 14:29:31 +00:00
printf ( " Other: %d (%d fresh) \n " , other_malloc_count , fresh_other_malloc_count ) ;
2007-08-07 23:14:09 +00:00
}
2007-08-07 23:38:05 +00:00
2007-11-29 15:34:49 +00:00
void toku_malloc_cleanup ( void ) {
2007-08-07 23:38:05 +00:00
int i ;
for ( i = 0 ; i < FREELIST_LIMIT ; i + + ) {
void * p ;
while ( ( p = freelist [ i ] ) ) {
freelist [ i ] = * ( void * * ) p ;
actual_free ( p ) ;
}
}
}