}
static void drd_pre_cond_wait(const Addr cond, const SizeT cond_size,
- const Addr mutex)
+ const Addr mutex, const MutexT mutex_type)
{
- mutex_unlock(mutex, mutex_type_mutex);
+ mutex_unlock(mutex, mutex_type);
cond_pre_wait(cond, cond_size, mutex);
}
static void drd_post_cond_wait(const Addr cond, const Addr mutex,
- const SizeT size)
+ const SizeT size, const MutexT mutex_type)
{
cond_post_wait(cond);
- mutex_lock(mutex, size, mutex_type_mutex);
+ mutex_lock(mutex, size, mutex_type);
}
static void drd_pre_cond_signal(const Addr cond)
break;
case VG_USERREQ__PRE_PTHREAD_COND_WAIT:
- drd_pre_cond_wait(arg[1]/*cond*/, arg[2]/*cond_size*/, arg[3]/*mutex*/);
+ drd_pre_cond_wait(arg[1]/*cond*/, arg[2]/*cond_size*/,
+ arg[3]/*mutex*/, arg[4]/*mutex_type*/);
break;
case VG_USERREQ__POST_PTHREAD_COND_WAIT:
- drd_post_cond_wait(arg[1]/*cond*/, arg[3]/*mutex*/,
- arg[4]/*mutex_size*/);
+ drd_post_cond_wait(arg[1]/*cond*/, arg[2]/*mutex*/,
+ arg[3]/*mutex_size*/, arg[4]/*mutex_type*/);
break;
case VG_USERREQ__PRE_PTHREAD_COND_SIGNAL:
/* args: Addr */
/* to notify the drd tool of a pthread_cond_destroy call. */
VG_USERREQ__PRE_PTHREAD_COND_DESTROY,
- /* args: Addr cond, SizeT cond_size, Addr mutex, SizeT mutex_size */
+ /* args: Addr cond, SizeT cond_size, Addr mutex, SizeT mutex_size, MutexT mt */
VG_USERREQ__PRE_PTHREAD_COND_WAIT,
- /* args: Addr cond, SizeT cond_size, Addr mutex, SizeT mutex_size */
+ /* args: Addr cond, SizeT cond_size, Addr mutex, MutexT mt */
VG_USERREQ__POST_PTHREAD_COND_WAIT,
- /* args: Addr cond, SizeT cond_size, Addr mutex, SizeT mutex_size */
+ /* args: Addr cond, Addr mutex, SizeT mutex_size, MutexT mt */
VG_USERREQ__PRE_PTHREAD_COND_SIGNAL,
/* args: Addr cond */
VG_USERREQ__PRE_PTHREAD_COND_BROADCAST,
typedef enum
{
- mutex_type_mutex = 1,
- mutex_type_spinlock = 2,
+ mutex_type_recursive_mutex = 1,
+ mutex_type_errorcheck_mutex = 2,
+ mutex_type_default_mutex = 3,
+ mutex_type_spinlock = 4,
} MutexT;
MutexErrInfo* p = (MutexErrInfo*)(VG_(get_error_extra)(e));
tl_assert(p);
VG_(message)(Vg_UserMsg,
- "%s / mutex 0x%lx (recursion count %d, owner %d)",
+ "%s: address 0x%lx, recursion count %d, owner %d.",
VG_(get_error_string)(e),
p->mutex,
p->recursion_count,
// Function definitions.
+static MutexT pthread_to_drd_mutex_type(const int kind)
+{
+ switch (kind)
+ {
+ /* PTHREAD_MUTEX_RECURSIVE_NP */
+ case PTHREAD_MUTEX_RECURSIVE:
+ return mutex_type_recursive_mutex;
+ /* PTHREAD_MUTEX_ERRORCHECK_NP */
+ case PTHREAD_MUTEX_ERRORCHECK:
+ return mutex_type_errorcheck_mutex;
+ /* PTHREAD_MUTEX_TIMED_NP */
+ /* PTHREAD_MUTEX_NORMAL */
+ case PTHREAD_MUTEX_DEFAULT:
+ case PTHREAD_MUTEX_ADAPTIVE_NP:
+ return mutex_type_default_mutex;
+#if 0
+ case -1:
+ printf("Warning: changed mutex type from -1 into %d\n",
+ mutex_type_default_mutex);
+ return mutex_type_default_mutex;
+#endif
+ }
+#if 0
+ printf("mutex->__data.__kind = %d\n", kind);
+ assert(0);
+#endif
+ return mutex_type_default_mutex;
+}
+
+static MutexT mutex_type(pthread_mutex_t* mutex)
+{
+ return pthread_to_drd_mutex_type(mutex->__data.__kind);
+}
+
static void vg_start_suppression(const void* const p, size_t const size)
{
int res;
int ret;
int res;
OrigFn fn;
+ int mt = PTHREAD_MUTEX_DEFAULT;
VALGRIND_GET_ORIG_FN(fn);
+ if (attr)
+ pthread_mutexattr_gettype(attr, &mt);
VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_MUTEX_INIT,
- mutex, sizeof(*mutex), mutex_type_mutex, 0, 0);
+ mutex, sizeof(*mutex),
+ pthread_to_drd_mutex_type(mt), 0, 0);
CALL_FN_W_WW(ret, fn, mutex, attr);
return ret;
}
VALGRIND_GET_ORIG_FN(fn);
CALL_FN_W_W(ret, fn, mutex);
VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_MUTEX_DESTROY,
- mutex, mutex_type_mutex, 0, 0, 0);
+ mutex, mutex_type(mutex), 0, 0, 0);
return ret;
}
OrigFn fn;
VALGRIND_GET_ORIG_FN(fn);
VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__PRE_PTHREAD_MUTEX_LOCK,
- mutex, sizeof(*mutex), mutex_type_mutex, 0, 0);
+ mutex, sizeof(*mutex), mutex_type(mutex), 0, 0);
#if 1
// The only purpose of the system call below is to make drd work on AMD64
// systems. Without this system call, clients crash (SIGSEGV) in
CALL_FN_W_W(ret, fn, mutex);
if (ret == 0)
VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__POST_PTHREAD_MUTEX_LOCK,
- mutex, sizeof(*mutex), mutex_type_mutex, 0, 0);
+ mutex, sizeof(*mutex), mutex_type(mutex), 0, 0);
return ret;
}
if (ret == 0)
{
VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_PTHREAD_MUTEX_LOCK,
- mutex, sizeof(*mutex), mutex_type_mutex, 0, 0);
+ mutex, sizeof(*mutex), mutex_type(mutex), 0, 0);
}
return ret;
}
if (ret == 0)
{
VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_PTHREAD_MUTEX_LOCK,
- mutex, sizeof(*mutex), mutex_type_mutex, 0, 0);
+ mutex, sizeof(*mutex), mutex_type(mutex), 0, 0);
}
return ret;
}
VALGRIND_GET_ORIG_FN(fn);
VALGRIND_DO_CLIENT_REQUEST(res, -1,
VG_USERREQ__PRE_PTHREAD_MUTEX_UNLOCK,
- mutex, sizeof(*mutex), mutex_type_mutex, 0, 0);
+ mutex, sizeof(*mutex), mutex_type(mutex), 0, 0);
CALL_FN_W_W(ret, fn, mutex);
return ret;
}
OrigFn fn;
VALGRIND_GET_ORIG_FN(fn);
VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_PTHREAD_COND_WAIT,
- cond, sizeof(*cond), mutex, sizeof(*mutex), 0);
+ cond, sizeof(*cond), mutex, mutex_type(mutex), 0);
CALL_FN_W_WW(ret, fn, cond, mutex);
VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_PTHREAD_COND_WAIT,
- cond, sizeof(*cond), mutex, sizeof(*mutex), 0);
+ cond, mutex, sizeof(*mutex), mutex_type(mutex), 0);
return ret;
}
OrigFn fn;
VALGRIND_GET_ORIG_FN(fn);
VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_PTHREAD_COND_WAIT,
- cond, sizeof(*cond), mutex, sizeof(*mutex), 0);
+ cond, sizeof(*cond), mutex, mutex_type(mutex), 0);
CALL_FN_W_WWW(ret, fn, cond, mutex, abstime);
VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_PTHREAD_COND_WAIT,
- cond, sizeof(*cond), mutex, sizeof(*mutex), 0);
+ cond, mutex, sizeof(*mutex), mutex_type(mutex), 0);
return ret;
}
// Local functions.
+static Bool mutex_is_locked(struct mutex_info* const p);
static void mutex_destroy(struct mutex_info* const p);
{
tl_assert(mutex != 0);
tl_assert(size > 0);
+#if 0
tl_assert(mutex_type == mutex_type_mutex
|| mutex_type == mutex_type_spinlock);
+#endif
p->mutex = mutex;
p->size = size;
{
int i;
+#if 0
tl_assert(mutex_type == mutex_type_mutex
|| mutex_type == mutex_type_spinlock);
+#endif
for (i = 0; i < sizeof(s_mutex)/sizeof(s_mutex[0]); i++)
{
if (s_mutex[i].mutex == mutex)
{
+ if (s_mutex[i].mutex_type != mutex_type)
+ {
+ VG_(message)(Vg_DebugMsg, "??? mutex %p: type changed from %d into %d",
+ s_mutex[i].mutex, s_mutex[i].mutex_type, mutex_type);
+ }
tl_assert(s_mutex[i].mutex_type == mutex_type);
tl_assert(s_mutex[i].size == size);
return &s_mutex[i];
mutex);
}
+#if 0
tl_assert(mutex_type == mutex_type_mutex
|| mutex_type == mutex_type_spinlock);
+#endif
+
mutex_p = mutex_get(mutex);
if (mutex_p)
{
p->mutex);
}
+ if (mutex_is_locked(p))
+ {
+ MutexErrInfo MEI = { p->mutex, p->recursion_count, p->owner };
+ VG_(maybe_record_error)(VG_(get_running_tid)(),
+ MutexErr,
+ VG_(get_IP)(VG_(get_running_tid)()),
+ "Destroying locked mutex",
+ &MEI);
+ }
+
drd_finish_suppression(p->mutex, p->mutex + p->size);
vc_cleanup(&p->vc);
return 0;
}
+#if 0
tl_assert(mutex_type == mutex_type_mutex
|| mutex_type == mutex_type_spinlock);
+#endif
+
tl_assert(p->mutex_type == mutex_type);
tl_assert(p->size == size);
p->owner);
}
- if (p == 0 || p->owner == DRD_INVALID_THREADID)
+ if (p == 0)
{
GenericErrInfo GEI;
VG_(maybe_record_error)(vg_tid,
return 0;
}
+ if (p->owner == DRD_INVALID_THREADID)
+ {
+ MutexErrInfo MEI = { p->mutex, p->recursion_count, p->owner };
+ VG_(maybe_record_error)(vg_tid,
+ MutexErr,
+ VG_(get_IP)(vg_tid),
+ "Mutex not locked",
+ &MEI);
+ return 0;
+ }
+
tl_assert(p);
+ if (p->mutex_type != mutex_type)
+ {
+ VG_(message)(Vg_DebugMsg, "??? mutex %p: type changed from %d into %d",
+ p->mutex, p->mutex_type, mutex_type);
+ }
tl_assert(p->mutex_type == mutex_type);
tl_assert(p->owner != DRD_INVALID_THREADID);
+#if 0
tl_assert(mutex_type == mutex_type_mutex
|| mutex_type == mutex_type_spinlock);
+#endif
if (p->owner != drd_tid)
{
{
switch (mt)
{
- case mutex_type_mutex:
+ case mutex_type_recursive_mutex:
+ return "recursive mutex";
+ case mutex_type_errorcheck_mutex:
+ return "error checking mutex";
+ case mutex_type_default_mutex:
return "mutex";
case mutex_type_spinlock:
return "spinlock";
return "?";
}
+/** Return true if the specified mutex is locked by any thread. */
+static Bool mutex_is_locked(struct mutex_info* const p)
+{
+ tl_assert(p);
+ return (p->recursion_count > 0);
+}
+
Bool mutex_is_locked_by(const Addr mutex, const DrdThreadId tid)
{
struct mutex_info* const p = mutex_get(mutex);
/**
* Call this function when thread tid stops to exist, such that the
* "last owner" field can be cleared if it still refers to that thread.
- * TO DO: print an error message if a thread exits while it still has some
- * mutexes locked.
*/
void mutex_thread_delete(const DrdThreadId tid)
{
for (i = 0; i < sizeof(s_mutex)/sizeof(s_mutex[0]); i++)
{
struct mutex_info* const p = &s_mutex[i];
- if (p->mutex && p->owner == tid)
+ if (p->mutex && p->owner == tid && p->recursion_count > 0)
{
+ MutexErrInfo MEI
+ = { p->mutex, p->recursion_count, p->owner };
+ VG_(maybe_record_error)(VG_(get_running_tid)(),
+ MutexErr,
+ VG_(get_IP)(VG_(get_running_tid)()),
+ "Mutex still locked at thread exit",
+ &MEI);
p->owner = VG_INVALID_THREADID;
}
}
pth_detached.stdout.exp pth_detached.stderr.exp \
pth_detached2.vgtest \
pth_detached2.stdout.exp pth_detached2.stderr.exp \
+ recursive_mutex.vgtest recursive_mutex.stderr.exp \
sem_as_mutex.vgtest \
sem_as_mutex.stderr.exp sem_as_mutex.stderr.exp2 \
sem_as_mutex2.vgtest \
pth_create_chain \
pth_detached \
sem_as_mutex \
+ recursive_mutex \
sigalrm \
tc01_simple_race \
tc02_simple_tls \
pth_detached_SOURCES = pth_detached.c
pth_detached_LDADD = -lpthread
+recursive_mutex_SOURCES = recursive_mutex.c
+recursive_mutex_LDADD = -lpthread
+
sem_as_mutex_SOURCES = sem_as_mutex.c
sem_as_mutex_LDADD = -lpthread
tc06_two_races_SOURCES = ../../helgrind/tests/tc06_two_races.c
tc06_two_races_LDADD = -lpthread
-tc07_hbl1_SOURCES = ../../helgrind/tests/tc07_hbl1.c
-tc07_hbl1_LDADD = -lpthread
+# tc07_hbl1_SOURCES = ../../helgrind/tests/tc07_hbl1.c
+# tc07_hbl1_LDADD = -lpthread
-tc08_hbl2_SOURCES = ../../helgrind/tests/tc08_hbl2.c
-tc08_hbl2_LDADD = -lpthread
+# tc08_hbl2_SOURCES = ../../helgrind/tests/tc08_hbl2.c
+# tc08_hbl2_LDADD = -lpthread
tc09_bad_unlock_SOURCES = ../../helgrind/tests/tc09_bad_unlock.c
tc09_bad_unlock_LDADD = -lpthread
--- /dev/null
+/** Initialize a recursive mutex and lock it twice.
+ * No error messages may be printed.
+ */
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <pthread.h>
+
+static void lock_twice(pthread_mutex_t* const p)
+{
+ pthread_mutex_lock(p);
+ pthread_mutex_lock(p);
+ pthread_mutex_unlock(p);
+ pthread_mutex_unlock(p);
+}
+
+int main(int argc, char** argv)
+{
+ {
+ pthread_mutex_t m = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
+
+ printf("Recursive mutex (statically initialized).\n");
+ lock_twice(&m);
+ }
+ {
+ pthread_mutex_t m;
+ pthread_mutexattr_t attr;
+
+ printf("Recursive mutex (initialized via mutex attributes).\n");
+ pthread_mutexattr_init(&attr);
+ pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP);
+ pthread_mutex_init(&m, &attr);
+ pthread_mutexattr_destroy(&attr);
+ lock_twice(&m);
+ pthread_mutex_destroy(&m);
+ }
+ {
+ pthread_mutex_t m;
+ pthread_mutexattr_t attr;
+
+ printf("Error checking mutex.\n");
+ pthread_mutexattr_init(&attr);
+ pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK_NP);
+ pthread_mutex_init(&m, &attr);
+ pthread_mutexattr_destroy(&attr);
+ lock_twice(&m);
+ pthread_mutex_destroy(&m);
+ }
+ {
+ pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
+
+ printf("Non-recursive mutex.\n");
+ lock_twice(&m);
+ }
+ return 0;
+}
+Destroying locked mutex: address 0x........, recursion count 1, owner 1.
+ at 0x........: free (vg_replace_malloc.c:...)
+ by 0x........: main (tc04_free_lock.c:24)
-ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
+Destroying locked mutex: address 0x........, recursion count 1, owner 1.
+ at 0x........: bar (tc04_free_lock.c:40)
+ by 0x........: main (tc04_free_lock.c:26)
+
+Destroying locked mutex: address 0x........, recursion count 1, owner 1.
+ at 0x........: foo (tc04_free_lock.c:49)
+ by 0x........: main (tc04_free_lock.c:27)
+
+Destroying locked mutex: address 0x........, recursion count 1, owner 1.
+ at 0x........: bar (tc04_free_lock.c:40)
+ by 0x........: main (tc04_free_lock.c:28)
+
+ERROR SUMMARY: 4 errors from 4 contexts (suppressed: 0 from 0)
-Attempt to unlock a mutex that is not locked / mutex 0x........ (recursion count -1, owner 1)
+Attempt to unlock a mutex that is not locked: address 0x........, recursion count -1, owner 1.
at 0x........: pthread_mutex_unlock (drd_intercepts.c:?)
by 0x........: nearly_main (tc09_bad_unlock.c:27)
by 0x........: main (tc09_bad_unlock.c:49)
Thread 2:
-Mutex not unlocked by owner thread / mutex 0x........ (recursion count 1, owner 1)
+Mutex not unlocked by owner thread: address 0x........, recursion count 1, owner 1.
at 0x........: pthread_mutex_unlock (drd_intercepts.c:?)
by 0x........: child_fn (tc09_bad_unlock.c:11)
by 0x........: vg_thread_wrapper (drd_intercepts.c:?)
by 0x........: nearly_main (tc09_bad_unlock.c:41)
by 0x........: main (tc09_bad_unlock.c:49)
-Attempt to unlock a mutex that is not locked / mutex 0x........ (recursion count -1, owner 1)
+Attempt to unlock a mutex that is not locked: address 0x........, recursion count -1, owner 1.
at 0x........: pthread_mutex_unlock (drd_intercepts.c:?)
by 0x........: nearly_main (tc09_bad_unlock.c:27)
by 0x........: main (tc09_bad_unlock.c:50)
Thread 2:
-Mutex not unlocked by owner thread / mutex 0x........ (recursion count 1, owner 1)
+Mutex not unlocked by owner thread: address 0x........, recursion count 1, owner 1.
at 0x........: pthread_mutex_unlock (drd_intercepts.c:?)
by 0x........: child_fn (tc09_bad_unlock.c:11)
by 0x........: vg_thread_wrapper (drd_intercepts.c:?)
before unlock #2
before unlock #3
before unlock #4
-Attempt to unlock a mutex that is not locked / mutex 0x........ (recursion count -1, owner 1)
+Attempt to unlock a mutex that is not locked: address 0x........, recursion count -1, owner 1.
at 0x........: pthread_mutex_unlock (drd_intercepts.c:?)
by 0x........: nearly_main (tc10_rec_lock.c:42)
by 0x........: main (tc10_rec_lock.c:47)
---------------- pthread_mutex_lock et al ----------------
-Destroying locked mutex / mutex 0x........ (recursion count 1, owner 1)
+Destroying locked mutex: address 0x........, recursion count 1, owner 1.
at 0x........: pthread_mutex_destroy (drd_intercepts.c:?)
by 0x........: main (tc20_verifywrap.c:102)
-Not a mutex
+Destroying locked mutex: address 0x........, recursion count 1, owner 1.
+ at 0x........: pthread_mutex_destroy (drd_intercepts.c:?)
+ by 0x........: main (tc20_verifywrap.c:102)
+
+Mutex not locked: address 0x........, recursion count 0, owner 0.
at 0x........: pthread_mutex_unlock (drd_intercepts.c:?)
by 0x........: main (tc20_verifywrap.c:125)
---------------- pthread_cond_wait et al ----------------
-Not a mutex
+Mutex not locked: address 0x........, recursion count 0, owner 0.
at 0x........: pthread_cond_wait* (drd_intercepts.c:?)
by 0x........: main (tc20_verifywrap.c:147)
------------ dealloc of mem holding locks ------------
-ERROR SUMMARY: 4 errors from 4 contexts (suppressed: 0 from 0)
+Destroying locked mutex: address 0x........, recursion count 1, owner 1.
+ at 0x........: main (tc20_verifywrap.c:261)
+
+ERROR SUMMARY: 6 errors from 6 contexts (suppressed: 0 from 0)
Other segment end (thread 2)
(thread finished, call stack no longer available)
-ERROR SUMMARY: 11 errors from 11 contexts (suppressed: 0 from 0)
+Mutex still locked at thread exit: address 0x........, recursion count 1, owner 3.
+ at 0x........: pthread_join (drd_intercepts.c:?)
+ by 0x........: main (tc22_exit_w_lock.c:43)
+
+ERROR SUMMARY: 12 errors from 12 contexts (suppressed: 0 from 0)
at 0x........: pthread_cond_wait* (drd_intercepts.c:?)
by 0x........: main (tc23_bogus_condwait.c:69)
-Not a mutex
+Mutex not locked: address 0x........, recursion count 0, owner 0.
at 0x........: pthread_cond_wait* (drd_intercepts.c:?)
by 0x........: main (tc23_bogus_condwait.c:72)
by 0x........: clone (in /...libc...)
Thread 1:
-Mutex not unlocked by owner thread / mutex 0x........ (recursion count 1, owner 2)
+Mutex not unlocked by owner thread: address 0x........, recursion count 1, owner 2.
at 0x........: pthread_cond_wait* (drd_intercepts.c:?)
by 0x........: main (tc23_bogus_condwait.c:78)
by 0x........: clone (in /...libc...)
Thread 2:
-Mutex not unlocked by owner thread / mutex 0x........ (recursion count 1, owner 1)
+Mutex not unlocked by owner thread: address 0x........, recursion count 1, owner 1.
at 0x........: pthread_mutex_unlock (drd_intercepts.c:?)
by 0x........: grab_the_lock (tc23_bogus_condwait.c:42)
by 0x........: vg_thread_wrapper (drd_intercepts.c:?)