Added support for detecting locks that have been held too long.
git-svn-id: svn://svn.valgrind.org/valgrind/trunk@8079 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/exp-drd/drd_mutex.c b/exp-drd/drd_mutex.c
index dca84a7..dd009de 100644
--- a/exp-drd/drd_mutex.c
+++ b/exp-drd/drd_mutex.c
@@ -27,10 +27,12 @@
#include "drd_error.h"
#include "drd_mutex.h"
#include "priv_drd_clientreq.h"
+#include "pub_tool_vki.h"
#include "pub_tool_errormgr.h" // VG_(maybe_record_error)()
#include "pub_tool_libcassert.h" // tl_assert()
#include "pub_tool_libcbase.h" // VG_(strlen)
#include "pub_tool_libcprint.h" // VG_(message)()
+#include "pub_tool_libcproc.h" // VG_(read_millisecond_timer)()
#include "pub_tool_machine.h" // VG_(get_IP)()
#include "pub_tool_threadstate.h" // VG_(get_running_tid)()
@@ -46,6 +48,7 @@
static Bool s_trace_mutex;
static ULong s_mutex_lock_count;
static ULong s_mutex_segment_creation_count;
+static UInt s_mutex_lock_threshold_ms = 1000 * 1000;
// Function definitions.
@@ -56,6 +59,11 @@
s_trace_mutex = trace_mutex;
}
+void mutex_set_lock_threshold(const UInt lock_threshold_ms)
+{
+ s_mutex_lock_threshold_ms = lock_threshold_ms;
+}
+
static
void mutex_initialize(struct mutex_info* const p,
const Addr mutex, const MutexT mutex_type)
@@ -68,6 +76,8 @@
p->recursion_count = 0;
p->owner = DRD_INVALID_THREADID;
p->last_locked_segment = 0;
+ p->acquiry_time_ms = 0;
+ p->acquired_at = 0;
}
/** Deallocate the memory that was allocated by mutex_initialize(). */
@@ -287,7 +297,9 @@
thread_new_segment(drd_tid);
s_mutex_segment_creation_count++;
- p->owner = drd_tid;
+ p->owner = drd_tid;
+ p->acquiry_time_ms = VG_(read_millisecond_timer)();
+ p->acquired_at = VG_(record_ExeContext)(VG_(get_running_tid)(), 0);
s_mutex_lock_count++;
}
else if (p->owner != drd_tid)
@@ -302,14 +314,16 @@
p->recursion_count++;
}
-/**
- * Update mutex_info state when unlocking the pthread_mutex_t mutex.
- * Note: this function must be called before pthread_mutex_unlock() is called,
- * or a race condition is triggered !
- * @return New value of the mutex recursion count.
- * @param mutex Pointer to pthread_mutex_t data structure in the client space.
- * @param tid ThreadId of the thread calling pthread_mutex_unlock().
- * @param vc Pointer to the current vector clock of thread tid.
+/** Update mutex_info state when unlocking the pthread_mutex_t mutex.
+ *
+ * @param mutex Pointer to pthread_mutex_t data structure in the client space.
+ * @param tid ThreadId of the thread calling pthread_mutex_unlock().
+ * @param vc Pointer to the current vector clock of thread tid.
+ *
+ * @return New value of the mutex recursion count.
+ *
+ * @note This function must be called before pthread_mutex_unlock() is called,
+ * or a race condition is triggered !
*/
void mutex_unlock(const Addr mutex, const MutexT mutex_type)
{
@@ -370,12 +384,28 @@
if (p->recursion_count == 0)
{
+ if (s_mutex_lock_threshold_ms > 0)
+ {
+ ULong held = VG_(read_millisecond_timer)() - p->acquiry_time_ms;
+ if (held > s_mutex_lock_threshold_ms)
+ {
+ HoldtimeErrInfo HEI
+ = { mutex, p->acquired_at, held, s_mutex_lock_threshold_ms };
+ VG_(maybe_record_error)(vg_tid,
+ HoldtimeErr,
+ VG_(get_IP)(vg_tid),
+ "mutex",
+ &HEI);
+ }
+ }
+
/* This pthread_mutex_unlock() call really unlocks the mutex. Save the */
/* current vector clock of the thread such that it is available when */
/* this mutex is locked again. */
thread_get_latest_segment(&p->last_locked_segment, drd_tid);
thread_new_segment(drd_tid);
+ p->acquired_at = 0;
s_mutex_segment_creation_count++;
}
}