YoushouldhavereceivedacopyoftheGNUGeneralPublicLicense alongwiththisprogram;ifnot,writetotheFreeSoftware
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
/* This makes a wrapper for mutex handling to make it easier to debug mutex */
#include <my_global.h> #ifdefined(TARGET_OS_LINUX) && !defined (__USE_UNIX98) #define __USE_UNIX98 /* To get rw locks under Linux */ #endif
int safe_mutex_lock(safe_mutex_t *mp, myf my_flags, constchar *file,
uint line)
{ int error;
DBUG_PRINT("mutex", ("%s (%p) locking", mp->name, mp));
DBUG_ASSERT(mp->name);
DBUG_PUSH_EMPTY;
pthread_mutex_lock(&mp->global); if (!mp->file)
{
fprintf(stderr, "safe_mutex: Trying to lock uninitialized mutex at %s, line %d\n",
file, line);
fflush(stderr);
abort();
} if (mp->count > 0)
{ /* Checkthatwearenottryingtolockmutextwice.Thisisanerror evenifweareusing'try_lock'asit'snotportablywhathappens ifyoulockthemutexmanytimesandthisisinanycasebad behaviourthatshouldnotbeencouraged
*/ if (pthread_equal(pthread_self(),mp->thread))
{
fprintf(stderr, "safe_mutex: Trying to lock mutex at %s, line %d, when the" " mutex was already locked at %s, line %d in thread %s\n",
file,line,mp->file, mp->line, my_thread_name());
fflush(stderr);
abort();
}
}
pthread_mutex_unlock(&mp->global);
if (!mutex_in_use)
{ /* thread has not called my_thread_init() */
mp->active_flags|= MYF_NO_DEADLOCK_DETECTION;
} else
{
safe_mutex_t *mutex_root; if ((mutex_root= *mutex_in_use)) /* If not first locked */
{ /* Protectlocked_mutexagainstchangesifamutexisdeleted
*/
pthread_mutex_lock(&THR_LOCK_mutex);
if (!my_hash_search(mutex_root->locked_mutex, (uchar*) &mp->id, sizeof(mp->id)))
{
safe_mutex_deadlock_t *deadlock;
safe_mutex_t *mutex;
/* Create object to store mutex info */ if (!(deadlock= my_malloc(PSI_NOT_INSTRUMENTED, sizeof(*deadlock),
MYF(MY_ZEROFILL | MY_WME | MY_FAE)))) goto abort_loop;
deadlock->name= mp->name;
deadlock->id= mp->id;
deadlock->mutex= mp; /* The following is useful for debugging wrong mutex usage */
deadlock->file= file;
deadlock->line= line;
/* Check if potential deadlock */
mutex= mutex_root; do
{ if (my_hash_search(mp->locked_mutex, (uchar*) &mutex->id, sizeof(mutex->id)))
{
print_deadlock_warning(mp, mutex); /* Mark wrong usage to avoid future warnings for same error */
deadlock->warning_only= 1;
add_to_locked_mutex(deadlock, mutex_root);
DBUG_ASSERT(deadlock->count > 0); goto abort_loop;
}
} while ((mutex= mutex->next));
int safe_mutex_unlock(safe_mutex_t *mp,constchar *file, uint line)
{ int error;
DBUG_PRINT("mutex", ("%s (%p) unlocking", mp->name, mp));
pthread_mutex_lock(&mp->global); if (mp->count == 0)
{
fprintf(stderr, "safe_mutex: Trying to unlock mutex %s that wasn't locked at " "%s, line %d\n" "Last used at %s, line: %d\n",
mp->name ? mp->name : "Null", file, line,
mp->file ? mp->file : "Null", mp->line);
fflush(stderr);
abort();
} if (!pthread_equal(pthread_self(),mp->thread))
{
fprintf(stderr, "safe_mutex: Trying to unlock mutex %s at %s, line %d that was " "locked by " "another thread at: %s, line: %d\n",
mp->name, file, line, mp->file, mp->line);
fflush(stderr);
abort();
}
mp->thread= 0;
mp->count--;
remove_from_active_list(mp);
#ifdef _WIN32
pthread_mutex_unlock(&mp->mutex);
error=0; #else
error=pthread_mutex_unlock(&mp->mutex); if (error)
{
fprintf(stderr, "safe_mutex: Got error: %d (%d) when trying to unlock mutex " "%s at %s, line %d\n", error, errno, mp->name, file, line);
fflush(stderr);
abort();
} #endif/* _WIN32 */
pthread_mutex_unlock(&mp->global); return error;
}
int safe_cond_wait(pthread_cond_t *cond, safe_mutex_t *mp, constchar *file,
uint line)
{ int error;
safe_mutex_t save_state;
pthread_mutex_lock(&mp->global); if (mp->count == 0)
{
fprintf(stderr, "safe_mutex: Trying to cond_wait on a unlocked mutex %s at %s, " "line %d\n",
mp->name ? mp->name : "Null", file, line);
fflush(stderr);
abort();
} if (!pthread_equal(pthread_self(),mp->thread))
{
fprintf(stderr, "safe_mutex: Trying to cond_wait on a mutex %s at %s, line %d " "that was locked by another thread at: %s, line: %d\n",
mp->name, file, line, mp->file, mp->line);
fflush(stderr);
abort();
}
if (mp->count-- != 1)
{
fprintf(stderr, "safe_mutex: Count was %d on locked mutex %s at %s, line %d\n",
mp->count+1, mp->name, file, line);
fflush(stderr);
abort();
}
save_state= *mp;
remove_from_active_list(mp);
pthread_mutex_unlock(&mp->global);
error=pthread_cond_wait(cond,&mp->mutex);
pthread_mutex_lock(&mp->global);
if (error)
{
fprintf(stderr, "safe_mutex: Got error: %d (%d) when doing a safe_mutex_wait on " "%s at %s, line %d\n", error, errno, mp->name, file, line);
fflush(stderr);
abort();
} /* Restore state as it was before */
mp->thread= save_state.thread;
mp->active_flags= save_state.active_flags;
mp->next= save_state.next;
mp->prev= save_state.prev;
if (mp->count++)
{
fprintf(stderr, "safe_mutex: Count was %d in thread 0x%lx when locking mutex %s " "at %s, line %d\n",
mp->count-1, (ulong) my_thread_dbug_id(), mp->name, file, line);
fflush(stderr);
abort();
}
mp->file= file;
mp->line=line;
pthread_mutex_unlock(&mp->global); return error;
}
int safe_cond_timedwait(pthread_cond_t *cond, safe_mutex_t *mp, conststruct timespec *abstime, constchar *file, uint line)
{ int error;
safe_mutex_t save_state;
pthread_mutex_lock(&mp->global); if (mp->count != 1 || !pthread_equal(pthread_self(),mp->thread))
{
fprintf(stderr, "safe_mutex: Trying to cond_wait at %s, line %d on a not hold " "mutex %s\n",
file, line, mp->name ? mp->name : "Null");
fflush(stderr);
abort();
}
mp->count--; /* Mutex will be released */
save_state= *mp;
remove_from_active_list(mp);
pthread_mutex_unlock(&mp->global);
error=pthread_cond_timedwait(cond,&mp->mutex,abstime); #ifdef EXTRA_DEBUG if (error && (error != EINTR && error != ETIMEDOUT && error != ETIME))
{
fprintf(stderr, "safe_mutex: Got error: %d (%d) when doing a safe_mutex_timedwait " "on %s at %s, line %d\n",
error, errno, mp->name, file, line);
} #endif/* EXTRA_DEBUG */
pthread_mutex_lock(&mp->global); /* Restore state as it was before */
mp->thread= save_state.thread;
mp->active_flags= save_state.active_flags;
mp->next= save_state.next;
mp->prev= save_state.prev;
if (mp->count++)
{
fprintf(stderr, "safe_mutex: Count was %d in thread 0x%lx when locking mutex " "%s at %s, line %d (error: %d (%d))\n",
mp->count-1, (ulong) my_thread_dbug_id(), mp->name, file, line,
error, error);
fflush(stderr);
abort();
}
mp->file= file;
mp->line=line;
pthread_mutex_unlock(&mp->global); return error;
}
int safe_mutex_destroy(safe_mutex_t *mp, constchar *file, uint line)
{ int error=0;
DBUG_ENTER("safe_mutex_destroy");
DBUG_PRINT("enter", ("mutex: %p name: %s", mp, mp->name)); if (!mp->file)
{
fprintf(stderr, "safe_mutex: Trying to destroy uninitialized mutex at %s, line %d\n",
file, line);
fflush(stderr);
abort();
} if (mp->count != 0)
{
fprintf(stderr, "safe_mutex: Trying to destroy a mutex %s that was locked at %s, " "line %d at %s, line %d\n",
mp->name, mp->file, mp->line, file, line);
fflush(stderr);
abort();
}
/* Free all entries that points to this one */
safe_mutex_free_deadlock_data(mp);
#ifdef _WIN32
pthread_mutex_destroy(&mp->global);
pthread_mutex_destroy(&mp->mutex); #else if (pthread_mutex_destroy(&mp->global))
error=1; if (pthread_mutex_destroy(&mp->mutex))
error=1; #endif/* _WIN32 */
mp->file= 0; /* Mark destroyed */
#ifdef SAFE_MUTEX_DETECT_DESTROY if (mp->info)
{ struct st_safe_mutex_info_t *info= mp->info;
pthread_mutex_lock(&THR_LOCK_mutex);
if (info->prev)
info->prev->next = info->next; else
safe_mutex_create_root = info->next; if (info->next)
info->next->prev = info->prev;
safe_mutex_count--;
void safe_mutex_end(FILE *file __attribute__((unused)))
{ if (!safe_mutex_count) /* safetly */
pthread_mutex_destroy(&THR_LOCK_mutex); #ifdef SAFE_MUTEX_DETECT_DESTROY if (!file) return;
if (safe_mutex_count)
{
fprintf(file, "Warning: Not destroyed mutex: %lu\n", safe_mutex_count);
(void) fflush(file);
}
{ struct st_safe_mutex_info_t *ptr; for (ptr= safe_mutex_create_root ; ptr ; ptr= ptr->next)
{
fprintf(file, "\tMutex %s initiated at line %4u in '%s'\n",
ptr->name, ptr->init_line, ptr->init_file);
(void) fflush(file);
}
} #endif/* SAFE_MUTEX_DETECT_DESTROY */
}
static my_bool add_used_to_locked_mutex(void *used, void *locked)
{
safe_mutex_t *used_mutex= used;
safe_mutex_deadlock_t *locked_mutex= locked; /* Add mutex to all parent of the current mutex */ if (!locked_mutex->warning_only)
{
(void) my_hash_iterate(locked_mutex->mutex->locked_mutex,
add_to_locked_mutex, used_mutex); /* mark that locked_mutex is locked after used_mutex */
(void) add_to_locked_mutex(locked_mutex, used_mutex);
} return0;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.