[Qt-interest] how to debug a deadlock
Gabriel M. Beddingfield
gabrbedd at gmail.com
Wed Jul 14 16:00:16 CEST 2010
On Wed, 14 Jul 2010, Matthias Pospiech wrote:
> By putting a breakpoint at every locker (20+) I found the reason
> (calling a function with locking from a locked function).
> However I still wonder if it would be possible to get to know otherwise
> in which line the deadlock was caused.
I once had a central lock where I wanted this kind of
tracing.[1][2][3] I created a macro like this (see [1],
lines 34ff):
/**
* Convenience macro for locking the Engine.
*/
#ifndef RIGHT_HERE
#define RIGHT_HERE __FILE__, __LINE__, __PRETTY_FUNCTION__
#endif
And member variables to save the location where the mutex was
last locked (see [3], lines 203ff):
struct _locker_struct {
const char* file;
unsigned int line;
const char* function;
} __locker;
And then lines 120ff:
///////////////////////////////////////
// THE BIG LOCK
///////////////////////////////////////
/* Mutex locking and unlocking
*
* Easy usage: Use the RIGHT_HERE macro like this...
* engine->lock( RIGHT_HERE );
*
* More complex usage: The parameters file and function
* need to be pointers to null-terminated strings that are
* persistent for the entire session. This does *not*
* include the return value of std::string::c_str(), or
* QString::toLocal8Bit().data().
*
* Notes: The order of the parameters match GCC's
* implementation of the assert() macros.
*/
void lock( const char* file, unsigned int line, const char* function );
bool try_lock( const char* file, unsigned int line, const char* function );
void unlock();
And the implementation (see [2], lines 909ff.):
void Engine::lock( const char* file, unsigned int line, const char* function )
{
d->__engine_mutex.lock();
d->__locker.file = file;
d->__locker.line = line;
d->__locker.function = function;
}
bool Engine::try_lock( const char* file, unsigned int line, const char* function )
{
bool locked = d->__engine_mutex.tryLock();
if ( ! locked ) {
// Lock not obtained
return false;
}
d->__locker.file = file;
d->__locker.line = line;
d->__locker.function = function;
return true;
}
void Engine::unlock()
{
// Leave "d->__locker" dirty.
d->__engine_mutex.unlock();
}
This doesn't help with every deadlock, but with some kinds
of coding errors it saves a lot of time. In general, this
is considered too much overhead for your standard-duty
mutex... and slows the mutex down.
Hope this helps...
-gabriel
[1] http://gitorious.org/composite/composite/blobs/master/src/Tritium/Tritium/Engine.hpp
[2] http://gitorious.org/composite/composite/blobs/master/src/Tritium/src/Engine.cpp
[3] http://gitorious.org/composite/composite/blobs/master/src/Tritium/src/EnginePrivate.hpp
More information about the Qt-interest-old
mailing list