eina: improve on/off and debugging lock.

Now if a lock is still taken when shutdown occur, you will know
where it come from !


SVN revision: 59191
This commit is contained in:
Cedric BAIL 2011-05-04 13:53:22 +00:00
parent 2b52e0b758
commit 25550183e0
5 changed files with 77 additions and 25 deletions

View File

@ -117,13 +117,13 @@ AC_SUBST(EINA_CONFIGURE_HAVE_THREADS)
AM_CONDITIONAL([EINA_HAVE_THREADS], [! test "x${have_threads}" = "xno"])
if ! test "x${have_debug_threads}" = "xno"; then
EINA_CONFIGURE_HAVE_DEBUG_THREADS="#define EINA_DEBUG_THREADS"
EINA_CONFIGURE_HAVE_DEBUG_THREADS="#define EINA_HAVE_DEBUG_THREADS"
fi
AC_SUBST(EINA_CONFIGURE_HAVE_DEBUG_THREADS)
AM_CONDITIONAL([EINA_DEBUG_THREADS], [! test "x${have_debug_threads}" = "xno"])
if ! test "x${have_on_off_threads}" = "xno"; then
EINA_CONFIGURE_HAVE_ON_OFF_THREADS="#define EINA_ON_OFF_THREADS"
EINA_CONFIGURE_HAVE_ON_OFF_THREADS="#define EINA_HAVE_ON_OFF_THREADS"
fi
AC_SUBST(EINA_CONFIGURE_HAVE_ON_OFF_THREADS)
AM_CONDITIONAL([EINA_ON_OFF_THREADS], [! test "x${have_on_off_threads}" = "xno"])

View File

@ -29,15 +29,23 @@
#endif
#ifdef EINA_HAVE_DEBUG_THREADS
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <execinfo.h>
#define EINA_LOCK_DEBUG_BT_NUM 64
typedef void (*Eina_Lock_Bt_Func) ();
#include "eina_inlist.h"
#endif
typedef struct _Eina_Lock Eina_Lock;
struct _Eina_Lock
{
#ifdef EINA_HAVE_DEBUG_THREADS
EINA_INLIST;
#endif
pthread_mutex_t mutex;
#ifdef EINA_HAVE_DEBUG_THREADS
pthread_t lock_thread_id;
@ -54,6 +62,8 @@ EAPI extern Eina_Bool _eina_threads_activated;
EAPI extern int _eina_threads_debug;
EAPI extern pthread_t _eina_main_loop;
EAPI extern pthread_mutex_t _eina_tracking_lock;
EAPI extern Eina_Inlist *_eina_tracking;
#endif
static inline Eina_Bool
@ -67,12 +77,8 @@ eina_lock_new(Eina_Lock *mutex)
if (pthread_mutexattr_init(&attr) != 0)
return EINA_FALSE;
/* use errorcheck locks. detect deadlocks.
#ifdef PTHREAD_MUTEX_RECURSIVE
if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) != 0)
return EINA_FALSE;
#endif
*/
/* NOTE: PTHREAD_MUTEX_RECURSIVE is not allowed at all, you will break on/off
feature for sure with that change. */
if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK) != 0)
return EINA_FALSE;
#ifdef EINA_HAVE_DEBUG_THREADS
@ -111,7 +117,7 @@ eina_lock_take(Eina_Lock *mutex)
#ifdef EINA_HAVE_DEBUG_THREADS
assert(pthread_equal(_eina_main_loop, pthread_self()));
#endif
return EINA_LOCK_FAIL;
return EINA_LOCK_SUCCEED;
}
#endif
@ -122,7 +128,7 @@ eina_lock_take(Eina_Lock *mutex)
int dt;
gettimeofday(&t0, NULL);
pthread_mutex_lock(&(x));
ok = pthread_mutex_lock(&(mutex->mutex));
gettimeofday(&t1, NULL);
dt = (t1.tv_sec - t0.tv_sec) * 1000000;
@ -134,19 +140,32 @@ eina_lock_take(Eina_Lock *mutex)
if (dt > _eina_threads_debug) abort();
}
else
{
#endif
ok = pthread_mutex_lock(&(mutex->mutex));
ok = pthread_mutex_lock(&(mutex->mutex));
#ifdef EINA_HAVE_DEBUG_THREADS
}
#endif
if (ok == 0) ret = EINA_LOCK_SUCCEED;
else if (ok == EDEADLK)
{
printf("ERROR ERROR: DEADLOCK on lock %p\n", mutex);
ret = EINA_LOCK_DEADLOCK; // magic
}
#ifdef EINA_HAVE_DEBUG_THREADS
mutex->locked = 1;
mutex->lock_thread_id = pthread_self();
mutex->lock_bt_num = backtrace((void **)(mutex->lock_bt), EINA_LOCK_DEBUG_BT_NUM);
pthread_mutex_lock(&_eina_tracking_lock);
_eina_tracking = eina_inlist_append(_eina_tracking,
EINA_INLIST_GET(mutex));
pthread_mutex_unlock(&_eina_tracking_lock);
#endif
return ret;
}
@ -162,7 +181,7 @@ eina_lock_take_try(Eina_Lock *mutex)
#ifdef EINA_HAVE_DEBUG_THREADS
assert(pthread_equal(_eina_main_loop, pthread_self()));
#endif
return EINA_LOCK_FAIL;
return EINA_LOCK_SUCCEED;
}
#endif
@ -184,6 +203,11 @@ eina_lock_take_try(Eina_Lock *mutex)
mutex->locked = 1;
mutex->lock_thread_id = pthread_self();
mutex->lock_bt_num = backtrace((void **)(mutex->lock_bt), EINA_LOCK_DEBUG_BT_NUM);
pthread_mutex_lock(&_eina_tracking_lock);
_eina_tracking = eina_inlist_append(_eina_tracking,
EINA_INLIST_GET(mutex));
pthread_mutex_unlock(&_eina_tracking_lock);
}
#endif
return ret;
@ -200,11 +224,16 @@ eina_lock_release(Eina_Lock *mutex)
#ifdef EINA_HAVE_DEBUG_THREADS
assert(pthread_equal(_eina_main_loop, pthread_self()));
#endif
return EINA_LOCK_FAIL;
return EINA_LOCK_SUCCEED;
}
#endif
#ifdef EINA_HAVE_DEBUG_THREADS
pthread_mutex_lock(&_eina_tracking_lock);
_eina_tracking = eina_inlist_remove(_eina_tracking,
EINA_INLIST_GET(mutex));
pthread_mutex_unlock(&_eina_tracking_lock);
mutex->locked = 0;
mutex->lock_thread_id = 0;
memset(mutex->lock_bt, 0, EINA_LOCK_DEBUG_BT_NUM * sizeof(Eina_Lock_Bt_Func));
@ -216,7 +245,7 @@ eina_lock_release(Eina_Lock *mutex)
}
static inline void
eina_lock_debug(Eina_Lock *mutex)
eina_lock_debug(const Eina_Lock *mutex)
{
#ifdef EINA_HAVE_DEBUG_THREADS
printf("lock %p, locked: %i, by %i\n",

View File

@ -58,7 +58,7 @@ static inline void eina_lock_free(Eina_Lock *mutex);
static inline Eina_Lock_Result eina_lock_take(Eina_Lock *mutex);
static inline Eina_Lock_Result eina_lock_take_try(Eina_Lock *mutex);
static inline Eina_Lock_Result eina_lock_release(Eina_Lock *mutex);
static inline void eina_lock_debug(Eina_Lock *mutex);
static inline void eina_lock_debug(const Eina_Lock *mutex);
/**
* @}

View File

@ -78,7 +78,9 @@ EAPI Eina_Bool _eina_threads_activated = EINA_FALSE;
#ifdef EINA_HAVE_DEBUG_THREADS
EAPI int _eina_threads_debug = 0;
EAPI pthread_t _eina_main_loop = NULL;
EAPI pthread_t _eina_main_loop;;
EAPI pthread_mutex_t _eina_tracking_lock;
EAPI Eina_Inlist *_eina_tracking = NULL;
#endif
static Eina_Lock _mutex;
@ -205,6 +207,14 @@ eina_init(void)
return 0;
}
#ifdef EINA_HAVE_DEBUG_THREADS
_eina_main_loop = pthread_self();
pthread_mutex_init(&_eina_tracking_lock, NULL);
if (getenv("EINA_DEBUG_THREADS"))
_eina_threads_debug = atoi(getenv("EINA_DEBUG_THREADS"));
#endif
itr = _eina_desc_setup;
itr_end = itr + _eina_desc_setup_len;
for (; itr < itr_end; itr++)
@ -217,14 +227,7 @@ eina_init(void)
}
}
eina_lock_new(&_mutex);
#ifdef EINA_HAVE_DEBUG_THREADS
_eina_main_loop = pthread_self();
if (getenv("EINA_DEBUG_THREADS"))
_eina_threads_debug = atoi(getenv("EINA_DEBUG_THREADS");
#endif
_eina_main_count = 1;
return 1;
@ -238,6 +241,10 @@ eina_shutdown(void)
{
_eina_shutdown_from_desc(_eina_desc_setup + _eina_desc_setup_len);
#ifdef EINA_HAVE_DEBUG_THREADS
pthread_mutex_destroy(&_eina_tracking_lock);
#endif
eina_lock_free(&_mutex);
}
@ -284,8 +291,25 @@ eina_threads_shutdown(void)
int ret;
#ifdef EINA_HAVE_DEBUG_THREADS
const Eina_Lock *lk;
assert(pthread_equal(_eina_main_loop, pthread_self()));
assert(_eina_main_thread_count > 0);
pthread_mutex_lock(&_eina_tracking_lock);
if (_eina_tracking)
{
fprintf(stderr, "*************************\n");
fprintf(stderr, "* The IMPOSSIBLE HAPPEN *\n");
fprintf(stderr, "* LOCK STILL TAKEN : *\n");
fprintf(stderr, "*************************\n");
EINA_INLIST_FOREACH(_eina_tracking, lk)
eina_lock_debug(lk);
fprintf(stderr, "*************************\n");
abort();
}
pthread_mutex_unlock(&_eina_tracking_lock);
#endif
eina_lock_take(&_mutex);

View File

@ -676,8 +676,7 @@ eina_class_repack(Eina_Class *class)
if (!eina_lock_take(&class->mutex))
{
#ifdef EINA_HAVE_DEBUG_THREADS
else
assert(pthread_equal(class->self, pthread_self()));
assert(pthread_equal(class->self, pthread_self()));
#endif
}