diff options
author | sasha@mysql.sashanet.com <> | 2002-03-26 22:19:23 -0700 |
---|---|---|
committer | sasha@mysql.sashanet.com <> | 2002-03-26 22:19:23 -0700 |
commit | f28f8d086d3f5e1ede685b86ce64da5641437bcf (patch) | |
tree | ab4d73690dcb8e3ef54e70015f1838cf17a2577a /mysys | |
parent | 2e6b48afd31008809439900db2d577ea0ff9d90f (diff) | |
download | mariadb-git-f28f8d086d3f5e1ede685b86ce64da5641437bcf.tar.gz |
coverted my_thread_init() /end to use my_malloc()/my_free() to help track
down replication corruption
Diffstat (limited to 'mysys')
-rw-r--r-- | mysys/my_static.h | 6 | ||||
-rw-r--r-- | mysys/my_thr_init.c | 39 | ||||
-rw-r--r-- | mysys/safemalloc.c | 70 |
3 files changed, 109 insertions, 6 deletions
diff --git a/mysys/my_static.h b/mysys/my_static.h index 4f944938b8d..ca384009063 100644 --- a/mysys/my_static.h +++ b/mysys/my_static.h @@ -38,6 +38,7 @@ struct irem { my_string _sFileName; /* File in which memory was new'ed */ uint _uLineNum; /* Line number in above file */ uint _uDataSize; /* Size requested */ + pthread_t thread_id; long _lSpecialValue; /* Underrun marker value */ }; @@ -56,6 +57,11 @@ extern const char *soundex_map; extern USED_MEM* my_once_root_block; extern uint my_once_extra; +/* these threads are exept from safemalloc leak scrutiny unless + PEDANTIC_SAFEMALLOC is defined +*/ +extern pthread_t signal_thread,kill_thread; + #ifndef HAVE_TEMPNAM extern int _my_tempnam_used; #endif diff --git a/mysys/my_thr_init.c b/mysys/my_thr_init.c index b4d98feeeb6..2c7fd098c63 100644 --- a/mysys/my_thr_init.c +++ b/mysys/my_thr_init.c @@ -105,19 +105,33 @@ static long thread_id=0; my_bool my_thread_init(void) { struct st_my_thread_var *tmp; +#ifdef EXTRA_DEBUG + fprintf(stderr,"my_thread_init(): thread_id=%ld\n",pthread_self()); +#endif #if !defined(__WIN__) || defined(USE_TLS) || ! defined(SAFE_MUTEX) pthread_mutex_lock(&THR_LOCK_lock); #endif #if !defined(__WIN__) || defined(USE_TLS) if (my_pthread_getspecific(struct st_my_thread_var *,THR_KEY_mysys)) { +#ifdef EXTRA_DEBUG + fprintf(stderr,"my_thread_init() called more than once in thread %ld\n", + pthread_self()); +#endif pthread_mutex_unlock(&THR_LOCK_lock); return 0; /* Safequard */ } /* We must have many calloc() here because these are freed on pthread_exit */ + /* + Sasha: the above comment does not make sense. I have changed calloc() to + equivalent my_malloc() but it was calloc() before. It seems like the + comment is out of date - we always call my_thread_end() before + pthread_exit() to clean up. Note that I have also fixed up DBUG + code to be able to call it from my_thread_init() + */ if (!(tmp=(struct st_my_thread_var *) - calloc(1,sizeof(struct st_my_thread_var)))) + my_malloc(sizeof(struct st_my_thread_var),MYF(MY_WME|MY_ZEROFILL)))) { pthread_mutex_unlock(&THR_LOCK_lock); return 1; @@ -125,6 +139,9 @@ my_bool my_thread_init(void) pthread_setspecific(THR_KEY_mysys,tmp); #else + /* Sasha: TODO - explain what exactly we are doing on Windows + At first glance, I have a hard time following the code + */ if (THR_KEY_mysys.id) /* Already initialized */ { #if !defined(__WIN__) || defined(USE_TLS) || ! defined(SAFE_MUTEX) @@ -146,9 +163,18 @@ my_bool my_thread_init(void) void my_thread_end(void) { struct st_my_thread_var *tmp=my_thread_var; +#ifdef EXTRA_DEBUG + fprintf(stderr,"my_thread_end(): tmp=%p,thread_id=%ld\n", + tmp,pthread_self()); +#endif if (tmp) { #if !defined(DBUG_OFF) + /* Sasha: tmp->dbug is allocated inside DBUG library + so for now we will not mess with trying to use my_malloc()/ + my_free(), but in the future it would be nice to figure out a + way to do it + */ if (tmp->dbug) { free(tmp->dbug); @@ -160,12 +186,15 @@ void my_thread_end(void) #endif pthread_mutex_destroy(&tmp->mutex); #if (!defined(__WIN__) && !defined(OS2)) || defined(USE_TLS) - free(tmp); + /* we need to setspecific to 0 BEFORE we call my_free, as my_free + uses some DBUG_ macros that will use the follow the specific + pointer after the block it is pointing to has been freed if + specific does not get reset first + */ + pthread_setspecific(THR_KEY_mysys,0); + my_free((gptr)tmp,MYF(MY_WME)); #endif } -#if (!defined(__WIN__) && !defined(OS2)) || defined(USE_TLS) - pthread_setspecific(THR_KEY_mysys,0); -#endif } struct st_my_thread_var *_my_thread_var(void) diff --git a/mysys/safemalloc.c b/mysys/safemalloc.c index d8c089c2ff0..062f9b9db02 100644 --- a/mysys/safemalloc.c +++ b/mysys/safemalloc.c @@ -73,14 +73,25 @@ #include "mysys_err.h" ulonglong safemalloc_mem_limit = ~(ulonglong)0; +pthread_t shutdown_th=0,main_th=0,signal_th=0; #define pNext tInt._pNext #define pPrev tInt._pPrev #define sFileName tInt._sFileName #define uLineNum tInt._uLineNum #define uDataSize tInt._uDataSize +#define thread_id tInt.thread_id #define lSpecialValue tInt._lSpecialValue +#ifndef PEDANTIC_SAFEMALLOC +static int sf_malloc_tampered = 0; /* set to 1 after TERMINATE() if we had + to fiddle with cNewCount and the linked + list of blocks so that _sanity() will + not fuss when it is not supposed to + */ +#endif + + /* Static functions prototypes */ static int check_ptr(const char *where, byte *ptr, const char *sFile, @@ -174,6 +185,7 @@ gptr _mymalloc (uint uSize, const char *sFile, uint uLine, myf MyFlags) pTmp -> sFileName = (my_string) sFile; pTmp -> uLineNum = uLine; pTmp -> uDataSize = uSize; + pTmp->thread_id = pthread_self(); pTmp -> pPrev = NULL; /* Add this remember structure to the linked list */ @@ -359,6 +371,12 @@ static int check_ptr(const char *where, byte *ptr, const char *sFile, return 0; } +static int legal_leak(struct remember* pPtr) +{ + return pthread_self() == pPtr->thread_id || main_th == pPtr->thread_id + || shutdown_th == pPtr->thread_id + || signal_th == pPtr->thread_id; +} /* * TERMINATE(FILE *file) @@ -376,6 +394,47 @@ void TERMINATE (FILE *file) /* NEW and the number of calls to FREE. >0 means more */ /* NEWs than FREEs. <0, etc. */ +#ifndef PEDANTIC_SAFEMALLOC + /* Avoid false alarms for blocks that we cannot free before my_end() + This does miss some positives, but that is ok. This will only miss + failures to free things allocated in the main thread which + performs only one-time allocations. If you really need to + debug memory allocations in the main thread, + #define PEDANTIC_SAFEMALLOC + */ + if ((pPtr=pRememberRoot)) + { + while (pPtr) + { + if (legal_leak(pPtr)) + { + sf_malloc_tampered=1; + cNewCount--; + lCurMemory -= pPtr->uDataSize; + if (pPtr->pPrev) + { + struct remember* tmp; + tmp = pPtr->pPrev->pNext = pPtr->pNext; + if (tmp) + tmp->pPrev = pPtr->pPrev; + pPtr->pNext = pPtr->pPrev = 0; + pPtr = tmp; + } + else + { + pRememberRoot = pPtr->pNext; + pPtr->pNext = pPtr->pPrev = 0; + pPtr = pRememberRoot; + if (pPtr) + pPtr->pPrev=0; + } + } + else + pPtr = pPtr->pNext; + } + } +#endif + if (cNewCount) { if (file) @@ -402,10 +461,14 @@ void TERMINATE (FILE *file) if (file) { fprintf (file, - "\t%6u bytes at 0x%09lx, allocated at line %4u in '%s'\n", + "\t%6u bytes at 0x%09lx, allocated at line %4u in '%s'", pPtr -> uDataSize, (ulong) &(pPtr -> aData[sf_malloc_prehunc]), pPtr -> uLineNum, pPtr -> sFileName); +#ifdef THREAD + fprintf(file, " in thread %ld", pPtr->thread_id); +#endif + fprintf(file, "\n"); (void) fflush(file); } DBUG_PRINT("safe", @@ -484,6 +547,10 @@ int _sanity (const char *sFile, uint uLine) uint count=0; pthread_mutex_lock(&THR_LOCK_malloc); +#ifndef PEDANTIC_SAFEMALLOC + if (sf_malloc_tampered && cNewCount < 0) + cNewCount=0; +#endif count=cNewCount; for (pTmp = pRememberRoot; pTmp != NULL && count-- ; pTmp = pTmp -> pNext) flag+=_checkchunk (pTmp, sFile, uLine); @@ -492,6 +559,7 @@ int _sanity (const char *sFile, uint uLine) { const char *format="Safemalloc link list destroyed, discovered at '%s:%d'"; fprintf (stderr, format, sFile, uLine); fputc('\n',stderr); + fprintf (stderr, "root=%p,count=%d,pTmp=%p\n", pRememberRoot,count,pTmp); (void) fflush(stderr); DBUG_PRINT("safe",(format, sFile, uLine)); flag=1; |