const SizeT size, const MutexT mutex_type)
{
cond_post_wait(cond);
- mutex_lock(mutex, size, mutex_type);
+ mutex_post_lock(mutex, size, mutex_type);
}
static void drd_pre_cond_signal(const Addr cond)
const SizeT size,
const MutexT mutex_type)
{
- if (mutex_get(mutex) == 0)
- {
- mutex_init(mutex, size, mutex_type);
- }
+ mutex_pre_lock(mutex, size, mutex_type);
}
void drd_post_mutex_lock(const DrdThreadId drd_tid,
const SizeT size,
const MutexT mutex_type)
{
- mutex_lock(mutex, size, mutex_type);
+ mutex_post_lock(mutex, size, mutex_type);
}
void drd_pre_mutex_unlock(const DrdThreadId drd_tid,
return 0;
}
+/** Called before pthread_mutex_lock() is invoked. If a data structure for
+ * the client-side object was not yet created, do this now. Also check whether
+ * an attempt is made to lock recursively a synchronization object that must
+ * not be locked recursively.
+ */
+void mutex_pre_lock(const Addr mutex, const SizeT size, MutexT mutex_type)
+{
+ struct mutex_info* p = mutex_get(mutex);
+ if (p == 0)
+ {
+ mutex_init(mutex, size, mutex_type);
+ p = mutex_get(mutex);
+ }
+ tl_assert(p);
+
+ if (p->owner == thread_get_running_tid()
+ && p->recursion_count >= 1
+ && mutex_type != mutex_type_recursive_mutex)
+ {
+ 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)()),
+ "Recursive locking not allowed",
+ &MEI);
+ }
+}
+
/**
* Update mutex_info state when locking the pthread_mutex_t mutex.
* Note: this function must be called after pthread_mutex_lock() has been
* called, or a race condition is triggered !
*/
-int mutex_lock(const Addr mutex, const SizeT size, MutexT mutex_type)
+int mutex_post_lock(const Addr mutex, const SizeT size, MutexT mutex_type)
{
const DrdThreadId drd_tid = VgThreadIdToDrdThreadId(VG_(get_running_tid)());
struct mutex_info* const p = mutex_get_or_allocate(mutex, size, mutex_type);
tl_assert(p->mutex_type == mutex_type);
tl_assert(p->size == size);
- if (p->recursion_count >= 1 && mutex_type == mutex_type_spinlock)
- {
- // TO DO: tell the user in a more friendly way that it is not allowed to
- // lock spinlocks recursively.
- tl_assert(0);
- }
-
if (p->recursion_count == 0)
{
p->owner = drd_tid;
void mutex_pre_destroy(struct mutex_info* const p);
void mutex_post_destroy(const Addr mutex);
struct mutex_info* mutex_get(const Addr mutex);
-int mutex_lock(const Addr mutex, const SizeT size, const MutexT mutex_type);
+void mutex_pre_lock(const Addr mutex, const SizeT size, const MutexT mutex_type);
+int mutex_post_lock(const Addr mutex, const SizeT size, const MutexT mutex_type);
int mutex_unlock(const Addr mutex, const MutexT mutex_type);
const char* mutex_get_typename(struct mutex_info* const p);
const char* mutex_type_name(const MutexT mt);
-/** Initialize a recursive mutex and lock it twice.
- * No error messages may be printed.
+/** Initialize several kinds of mutexes and lock each mutex twice.
+ * Note: locking a regular mutex twice causes a deadlock.
*/
#define _GNU_SOURCE
int main(int argc, char** argv)
{
+ /* Let the program abort after 3 seconds instead of leaving it deadlocked. */
+ alarm(3);
+
{
pthread_mutex_t m = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
printf("Non-recursive mutex.\n");
+ fflush(stdout);
lock_twice(&m);
}
+ printf("Done.\n");
return 0;
}
--- /dev/null
+
+Recursive locking not allowed: address 0x........, recursion count 1, owner 1.
+ at 0x........: pthread_mutex_lock (drd_intercepts.c:?)
+ by 0x........: lock_twice (recursive_mutex.c:?)
+ by 0x........: main (recursive_mutex.c:?)
+
+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........: lock_twice (recursive_mutex.c:?)
+ by 0x........: main (recursive_mutex.c:?)
+
+Recursive locking not allowed: address 0x........, recursion count 1, owner 1.
+ at 0x........: pthread_mutex_lock (drd_intercepts.c:?)
+ by 0x........: lock_twice (recursive_mutex.c:?)
+ by 0x........: main (recursive_mutex.c:?)
+
+ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0)
--- /dev/null
+Recursive mutex (statically initialized).
+Recursive mutex (initialized via mutex attributes).
+Error checking mutex.
+Non-recursive mutex.
--- /dev/null
+prog: recursive_mutex