#include "valgrind.h" /* For the request-passing mechanism */
#include "vg_include.h" /* For the VG_USERREQ__* constants */
-#include <pthread.h>
#include <unistd.h>
#include <string.h>
Pass pthread_ calls to Valgrind's request mechanism.
------------------------------------------------------------------ */
+#include <pthread.h>
+#include <stdio.h>
+#include <errno.h>
+
+/* ---------------------------------------------------
+ THREAD ATTRIBUTES
+ ------------------------------------------------ */
+
int pthread_attr_init(pthread_attr_t *attr)
{
ignored("pthread_attr_init");
}
+
+/* ---------------------------------------------------
+ THREADs
+ ------------------------------------------------ */
+
int
pthread_create (pthread_t *__restrict __thread,
__const pthread_attr_t *__restrict __attr,
}
-/* What are these? Anybody know? I don't. */
-
-void _pthread_cleanup_push_defer ( void )
-{
- // char* str = "_pthread_cleanup_push_defer\n";
- // write(2, str, strlen(str));
-}
-
-void _pthread_cleanup_pop_restore ( void )
-{
- // char* str = "_pthread_cleanup_pop_restore\n";
- // write(2, str, strlen(str));
-}
-
static int thread_specific_errno[VG_N_THREADS];
}
+/* ---------------------------------------------------
+ MUTEX ATTRIBUTES
+ ------------------------------------------------ */
+
int pthread_mutexattr_init(pthread_mutexattr_t *attr)
{
- ignored("pthread_mutexattr_init");
+ attr->__mutexkind = PTHREAD_MUTEX_ERRORCHECK_NP;
return 0;
}
-int pthread_mutex_init(pthread_mutex_t *mutex,
- const pthread_mutexattr_t *mutexattr)
+int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
{
- int res;
- ensure_valgrind("pthread_mutex_init");
- VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
- VG_USERREQ__PTHREAD_MUTEX_INIT,
- mutex, mutexattr, 0, 0);
- return res;
+ switch (type) {
+ case PTHREAD_MUTEX_TIMED_NP:
+ case PTHREAD_MUTEX_RECURSIVE_NP:
+ case PTHREAD_MUTEX_ERRORCHECK_NP:
+ case PTHREAD_MUTEX_ADAPTIVE_NP:
+ attr->__mutexkind = type;
+ return 0;
+ default:
+ return EINVAL;
+ }
}
int pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
{
- ignored("pthread_mutexattr_destroy");
return 0;
}
-int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
+
+/* ---------------------------------------------------
+ MUTEXes
+ ------------------------------------------------ */
+
+int pthread_mutex_init(pthread_mutex_t *mutex,
+ const pthread_mutexattr_t *mutexattr)
{
- ignored("pthread_mutexattr_settype");
- return 0;
+ int res;
+ ensure_valgrind("pthread_mutex_init");
+ VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
+ VG_USERREQ__PTHREAD_MUTEX_INIT,
+ mutex, mutexattr, 0, 0);
+ return res;
}
int pthread_mutex_lock(pthread_mutex_t *mutex)
}
}
-pthread_t pthread_self(void)
-{
- int tid;
- ensure_valgrind("pthread_self");
- VALGRIND_MAGIC_SEQUENCE(tid, 0 /* default */,
- VG_USERREQ__PTHREAD_GET_THREADID,
- 0, 0, 0, 0);
- if (tid < 0 || tid >= VG_N_THREADS)
- barf("pthread_self: invalid ThreadId");
- return tid;
-}
-
int pthread_mutex_destroy(pthread_mutex_t *mutex)
{
int res;
}
+/* ---------------------------------------------------
+ CANCELLATION
+ ------------------------------------------------ */
+
int pthread_setcanceltype(int type, int *oldtype)
{
ignored("pthread_setcanceltype");
}
+/* ---------------------------------------------------
+ THREAD-SPECIFICs
+ ------------------------------------------------ */
int pthread_key_create(pthread_key_t *key,
void (*destr_function) (void *))
return NULL;
}
+
+/* ---------------------------------------------------
+ MISC
+ ------------------------------------------------ */
+
+/* What are these? Anybody know? I don't. */
+
+void _pthread_cleanup_push_defer ( void )
+{
+ // char* str = "_pthread_cleanup_push_defer\n";
+ // write(2, str, strlen(str));
+}
+
+void _pthread_cleanup_pop_restore ( void )
+{
+ // char* str = "_pthread_cleanup_pop_restore\n";
+ // write(2, str, strlen(str));
+}
+
+
+pthread_t pthread_self(void)
+{
+ int tid;
+ ensure_valgrind("pthread_self");
+ VALGRIND_MAGIC_SEQUENCE(tid, 0 /* default */,
+ VG_USERREQ__PTHREAD_GET_THREADID,
+ 0, 0, 0, 0);
+ if (tid < 0 || tid >= VG_N_THREADS)
+ barf("pthread_self: invalid ThreadId");
+ return tid;
+}
+
+
/* ---------------------------------------------------------------------
These are here (I think) because they are deemed cancellation
points by POSIX. For the moment we'll simply pass the call along
to the corresponding thread-unaware (?) libc routine.
------------------------------------------------------------------ */
-#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
-#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include "valgrind.h" /* For the request-passing mechanism */
#include "vg_include.h" /* For the VG_USERREQ__* constants */
-#include <pthread.h>
#include <unistd.h>
#include <string.h>
Pass pthread_ calls to Valgrind's request mechanism.
------------------------------------------------------------------ */
+#include <pthread.h>
+#include <stdio.h>
+#include <errno.h>
+
+/* ---------------------------------------------------
+ THREAD ATTRIBUTES
+ ------------------------------------------------ */
+
int pthread_attr_init(pthread_attr_t *attr)
{
ignored("pthread_attr_init");
}
+
+/* ---------------------------------------------------
+ THREADs
+ ------------------------------------------------ */
+
int
pthread_create (pthread_t *__restrict __thread,
__const pthread_attr_t *__restrict __attr,
}
-/* What are these? Anybody know? I don't. */
-
-void _pthread_cleanup_push_defer ( void )
-{
- // char* str = "_pthread_cleanup_push_defer\n";
- // write(2, str, strlen(str));
-}
-
-void _pthread_cleanup_pop_restore ( void )
-{
- // char* str = "_pthread_cleanup_pop_restore\n";
- // write(2, str, strlen(str));
-}
-
static int thread_specific_errno[VG_N_THREADS];
}
+/* ---------------------------------------------------
+ MUTEX ATTRIBUTES
+ ------------------------------------------------ */
+
int pthread_mutexattr_init(pthread_mutexattr_t *attr)
{
- ignored("pthread_mutexattr_init");
+ attr->__mutexkind = PTHREAD_MUTEX_ERRORCHECK_NP;
return 0;
}
-int pthread_mutex_init(pthread_mutex_t *mutex,
- const pthread_mutexattr_t *mutexattr)
+int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
{
- int res;
- ensure_valgrind("pthread_mutex_init");
- VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
- VG_USERREQ__PTHREAD_MUTEX_INIT,
- mutex, mutexattr, 0, 0);
- return res;
+ switch (type) {
+ case PTHREAD_MUTEX_TIMED_NP:
+ case PTHREAD_MUTEX_RECURSIVE_NP:
+ case PTHREAD_MUTEX_ERRORCHECK_NP:
+ case PTHREAD_MUTEX_ADAPTIVE_NP:
+ attr->__mutexkind = type;
+ return 0;
+ default:
+ return EINVAL;
+ }
}
int pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
{
- ignored("pthread_mutexattr_destroy");
return 0;
}
-int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
+
+/* ---------------------------------------------------
+ MUTEXes
+ ------------------------------------------------ */
+
+int pthread_mutex_init(pthread_mutex_t *mutex,
+ const pthread_mutexattr_t *mutexattr)
{
- ignored("pthread_mutexattr_settype");
- return 0;
+ int res;
+ ensure_valgrind("pthread_mutex_init");
+ VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
+ VG_USERREQ__PTHREAD_MUTEX_INIT,
+ mutex, mutexattr, 0, 0);
+ return res;
}
int pthread_mutex_lock(pthread_mutex_t *mutex)
}
}
-pthread_t pthread_self(void)
-{
- int tid;
- ensure_valgrind("pthread_self");
- VALGRIND_MAGIC_SEQUENCE(tid, 0 /* default */,
- VG_USERREQ__PTHREAD_GET_THREADID,
- 0, 0, 0, 0);
- if (tid < 0 || tid >= VG_N_THREADS)
- barf("pthread_self: invalid ThreadId");
- return tid;
-}
-
int pthread_mutex_destroy(pthread_mutex_t *mutex)
{
int res;
}
+/* ---------------------------------------------------
+ CANCELLATION
+ ------------------------------------------------ */
+
int pthread_setcanceltype(int type, int *oldtype)
{
ignored("pthread_setcanceltype");
}
+/* ---------------------------------------------------
+ THREAD-SPECIFICs
+ ------------------------------------------------ */
int pthread_key_create(pthread_key_t *key,
void (*destr_function) (void *))
return NULL;
}
+
+/* ---------------------------------------------------
+ MISC
+ ------------------------------------------------ */
+
+/* What are these? Anybody know? I don't. */
+
+void _pthread_cleanup_push_defer ( void )
+{
+ // char* str = "_pthread_cleanup_push_defer\n";
+ // write(2, str, strlen(str));
+}
+
+void _pthread_cleanup_pop_restore ( void )
+{
+ // char* str = "_pthread_cleanup_pop_restore\n";
+ // write(2, str, strlen(str));
+}
+
+
+pthread_t pthread_self(void)
+{
+ int tid;
+ ensure_valgrind("pthread_self");
+ VALGRIND_MAGIC_SEQUENCE(tid, 0 /* default */,
+ VG_USERREQ__PTHREAD_GET_THREADID,
+ 0, 0, 0, 0);
+ if (tid < 0 || tid >= VG_N_THREADS)
+ barf("pthread_self: invalid ThreadId");
+ return tid;
+}
+
+
/* ---------------------------------------------------------------------
These are here (I think) because they are deemed cancellation
points by POSIX. For the moment we'll simply pass the call along
to the corresponding thread-unaware (?) libc routine.
------------------------------------------------------------------ */
-#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
-#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
struct {
/* Is this slot in use, or free? */
Bool in_use;
- /* If in_use, is this mutex held by some thread, or not? */
- Bool held;
- /* if held==True, owner indicates who by. */
+ /* When == 0, indicated not locked.
+ When > 0, number of times it has been locked by the owner. */
+ UInt count;
+ /* if count > 0, owner indicates who by. */
ThreadId owner;
+ /* True if a recursive mutex. When False, count must never
+ exceed 1. */
+ Bool is_rec;
}
VgMutex;
*/
static
-void initialise_mutex ( ThreadId tid, pthread_mutex_t *mutex )
+void initialise_mutex ( ThreadId tid,
+ pthread_mutex_t *mutex )
{
MutexId mid;
Char msg_buf[100];
+ Bool is_rec;
/* vg_alloc_MutexId aborts if we can't allocate a mutex, for
whatever reason. */
mid = vg_alloc_VgMutex();
vg_mutexes[mid].in_use = True;
- vg_mutexes[mid].held = False;
+ vg_mutexes[mid].count = 0;
vg_mutexes[mid].owner = VG_INVALID_THREADID; /* irrelevant */
+ is_rec = mutex->__m_kind == PTHREAD_MUTEX_RECURSIVE_NP;
+ vg_mutexes[mid].is_rec = is_rec;
+ vg_mutexes[mid].count = 0;
mutex->__m_reserved = mid;
mutex->__m_count = 1; /* initialised */
if (VG_(clo_trace_pthread_level) >= 1) {
- VG_(sprintf)(msg_buf, "(initialise mutex) (%p) -> %d",
- mutex, mid );
+ VG_(sprintf)(msg_buf, "(initialise mutex) (%p, %s) -> %d",
+ mutex, is_rec ? "RECURSIVE" : "NORMAL",
+ mid );
print_pthread_event(tid, msg_buf);
}
}
/* Paranoia ... */
vg_assert(sizeof(pthread_mutex_t) >= sizeof(UInt));
+ if (mutexattr)
+ mutex->__m_kind = mutexattr->__mutexkind;
initialise_mutex(tid, mutex);
if (VG_(clo_trace_pthread_level) >= 1) {
}
if (mutex->__m_count == 0) {
+ /* The mutex->__m_kind will have been set by the static
+ initialisation. */
initialise_mutex(tid, mutex);
}
/* Assume tid valid. */
vg_assert(vg_threads[tid].status == VgTs_Runnable);
- if (vg_mutexes[mid].held) {
+ if (vg_mutexes[mid].count > 0) {
+
+ /* Someone has it already. */
if (vg_mutexes[mid].owner == tid) {
- vg_threads[tid].m_edx = EDEADLK;
+ /* It's locked -- by me! */
+ if (vg_mutexes[mid].is_rec) {
+ /* return 0 (success). */
+ vg_mutexes[mid].count++;
+ vg_threads[tid].m_edx = 0;
+ VG_(printf)("!!!!!! tid %d, mutex %d -> locked %d\n",
+ tid, mid, vg_mutexes[mid].count);
+ return;
+ } else {
+ vg_threads[tid].m_edx = EDEADLK;
+ return;
+ }
+ } else {
+ /* Someone else has it; we have to wait. */
+ vg_threads[tid].status = VgTs_WaitMX;
+ vg_threads[tid].waited_on_mid = mid;
+ /* No assignment to %EDX, since we're blocking. */
+ if (VG_(clo_trace_pthread_level) >= 1) {
+ VG_(sprintf)(msg_buf, "pthread_mutex_lock %d: BLOCK",
+ mid );
+ print_pthread_event(tid, msg_buf);
+ }
return;
}
- /* Someone else has it; we have to wait. */
- vg_threads[tid].status = VgTs_WaitMX;
- vg_threads[tid].waited_on_mid = mid;
- /* No assignment to %EDX, since we're blocking. */
- if (VG_(clo_trace_pthread_level) >= 1) {
- VG_(sprintf)(msg_buf, "pthread_mutex_lock %d: BLOCK",
- mid );
- print_pthread_event(tid, msg_buf);
- }
+
} else {
- /* We get it! */
- vg_mutexes[mid].held = True;
+ /* We get it! [for the first time]. */
+ vg_mutexes[mid].count = 1;
vg_mutexes[mid].owner = tid;
/* return 0 (success). */
vg_threads[tid].m_edx = 0;
}
+
}
vg_assert(vg_threads[tid].status == VgTs_Runnable);
/* Barf if we don't currently hold the mutex. */
- if (!vg_mutexes[mid].held || vg_mutexes[mid].owner != tid) {
+ if (vg_mutexes[mid].count == 0 /* nobody holds it */
+ || vg_mutexes[mid].owner != tid /* we don't hold it */) {
vg_threads[tid].m_edx = EPERM;
return;
}
+ /* If it's a multiply-locked recursive mutex, just decrement the
+ lock count and return. */
+ if (vg_mutexes[mid].count > 1) {
+ vg_assert(vg_mutexes[mid].is_rec);
+ vg_mutexes[mid].count --;
+ vg_threads[tid].m_edx = 0; /* success */
+ return;
+ }
+
+ /* Now we're sure mid is locked exactly once, and by the thread who
+ is now doing an unlock on it. */
+ vg_assert(vg_mutexes[mid].count == 1);
+
/* Find some arbitrary thread waiting on this mutex, and make it
runnable. If none are waiting, mark the mutex as not held. */
for (i = 0; i < VG_N_THREADS; i++) {
vg_assert(i <= VG_N_THREADS);
if (i == VG_N_THREADS) {
/* Nobody else is waiting on it. */
- vg_mutexes[mid].held = False;
+ vg_mutexes[mid].count = 0;
} else {
/* Notionally transfer the hold to thread i, whose
pthread_mutex_lock() call now returns with 0 (success). */
+ /* The .count is already == 1. */
vg_mutexes[mid].owner = i;
vg_threads[i].status = VgTs_Runnable;
vg_threads[i].m_edx = 0; /* pth_lock() success */
vg_assert(vg_threads[tid].status == VgTs_Runnable);
/* Barf if the mutex is currently held. */
- if (vg_mutexes[mid].held) {
+ if (vg_mutexes[mid].count > 0) {
vg_threads[tid].m_edx = EBUSY;
return;
}
#include "valgrind.h" /* For the request-passing mechanism */
#include "vg_include.h" /* For the VG_USERREQ__* constants */
-#include <pthread.h>
#include <unistd.h>
#include <string.h>
Pass pthread_ calls to Valgrind's request mechanism.
------------------------------------------------------------------ */
+#include <pthread.h>
+#include <stdio.h>
+#include <errno.h>
+
+/* ---------------------------------------------------
+ THREAD ATTRIBUTES
+ ------------------------------------------------ */
+
int pthread_attr_init(pthread_attr_t *attr)
{
ignored("pthread_attr_init");
}
+
+/* ---------------------------------------------------
+ THREADs
+ ------------------------------------------------ */
+
int
pthread_create (pthread_t *__restrict __thread,
__const pthread_attr_t *__restrict __attr,
}
-/* What are these? Anybody know? I don't. */
-
-void _pthread_cleanup_push_defer ( void )
-{
- // char* str = "_pthread_cleanup_push_defer\n";
- // write(2, str, strlen(str));
-}
-
-void _pthread_cleanup_pop_restore ( void )
-{
- // char* str = "_pthread_cleanup_pop_restore\n";
- // write(2, str, strlen(str));
-}
-
static int thread_specific_errno[VG_N_THREADS];
}
+/* ---------------------------------------------------
+ MUTEX ATTRIBUTES
+ ------------------------------------------------ */
+
int pthread_mutexattr_init(pthread_mutexattr_t *attr)
{
- ignored("pthread_mutexattr_init");
+ attr->__mutexkind = PTHREAD_MUTEX_ERRORCHECK_NP;
return 0;
}
-int pthread_mutex_init(pthread_mutex_t *mutex,
- const pthread_mutexattr_t *mutexattr)
+int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
{
- int res;
- ensure_valgrind("pthread_mutex_init");
- VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
- VG_USERREQ__PTHREAD_MUTEX_INIT,
- mutex, mutexattr, 0, 0);
- return res;
+ switch (type) {
+ case PTHREAD_MUTEX_TIMED_NP:
+ case PTHREAD_MUTEX_RECURSIVE_NP:
+ case PTHREAD_MUTEX_ERRORCHECK_NP:
+ case PTHREAD_MUTEX_ADAPTIVE_NP:
+ attr->__mutexkind = type;
+ return 0;
+ default:
+ return EINVAL;
+ }
}
int pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
{
- ignored("pthread_mutexattr_destroy");
return 0;
}
-int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
+
+/* ---------------------------------------------------
+ MUTEXes
+ ------------------------------------------------ */
+
+int pthread_mutex_init(pthread_mutex_t *mutex,
+ const pthread_mutexattr_t *mutexattr)
{
- ignored("pthread_mutexattr_settype");
- return 0;
+ int res;
+ ensure_valgrind("pthread_mutex_init");
+ VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
+ VG_USERREQ__PTHREAD_MUTEX_INIT,
+ mutex, mutexattr, 0, 0);
+ return res;
}
int pthread_mutex_lock(pthread_mutex_t *mutex)
}
}
-pthread_t pthread_self(void)
-{
- int tid;
- ensure_valgrind("pthread_self");
- VALGRIND_MAGIC_SEQUENCE(tid, 0 /* default */,
- VG_USERREQ__PTHREAD_GET_THREADID,
- 0, 0, 0, 0);
- if (tid < 0 || tid >= VG_N_THREADS)
- barf("pthread_self: invalid ThreadId");
- return tid;
-}
-
int pthread_mutex_destroy(pthread_mutex_t *mutex)
{
int res;
}
+/* ---------------------------------------------------
+ CANCELLATION
+ ------------------------------------------------ */
+
int pthread_setcanceltype(int type, int *oldtype)
{
ignored("pthread_setcanceltype");
}
+/* ---------------------------------------------------
+ THREAD-SPECIFICs
+ ------------------------------------------------ */
int pthread_key_create(pthread_key_t *key,
void (*destr_function) (void *))
return NULL;
}
+
+/* ---------------------------------------------------
+ MISC
+ ------------------------------------------------ */
+
+/* What are these? Anybody know? I don't. */
+
+void _pthread_cleanup_push_defer ( void )
+{
+ // char* str = "_pthread_cleanup_push_defer\n";
+ // write(2, str, strlen(str));
+}
+
+void _pthread_cleanup_pop_restore ( void )
+{
+ // char* str = "_pthread_cleanup_pop_restore\n";
+ // write(2, str, strlen(str));
+}
+
+
+pthread_t pthread_self(void)
+{
+ int tid;
+ ensure_valgrind("pthread_self");
+ VALGRIND_MAGIC_SEQUENCE(tid, 0 /* default */,
+ VG_USERREQ__PTHREAD_GET_THREADID,
+ 0, 0, 0, 0);
+ if (tid < 0 || tid >= VG_N_THREADS)
+ barf("pthread_self: invalid ThreadId");
+ return tid;
+}
+
+
/* ---------------------------------------------------------------------
These are here (I think) because they are deemed cancellation
points by POSIX. For the moment we'll simply pass the call along
to the corresponding thread-unaware (?) libc routine.
------------------------------------------------------------------ */
-#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
-#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
struct {
/* Is this slot in use, or free? */
Bool in_use;
- /* If in_use, is this mutex held by some thread, or not? */
- Bool held;
- /* if held==True, owner indicates who by. */
+ /* When == 0, indicated not locked.
+ When > 0, number of times it has been locked by the owner. */
+ UInt count;
+ /* if count > 0, owner indicates who by. */
ThreadId owner;
+ /* True if a recursive mutex. When False, count must never
+ exceed 1. */
+ Bool is_rec;
}
VgMutex;
*/
static
-void initialise_mutex ( ThreadId tid, pthread_mutex_t *mutex )
+void initialise_mutex ( ThreadId tid,
+ pthread_mutex_t *mutex )
{
MutexId mid;
Char msg_buf[100];
+ Bool is_rec;
/* vg_alloc_MutexId aborts if we can't allocate a mutex, for
whatever reason. */
mid = vg_alloc_VgMutex();
vg_mutexes[mid].in_use = True;
- vg_mutexes[mid].held = False;
+ vg_mutexes[mid].count = 0;
vg_mutexes[mid].owner = VG_INVALID_THREADID; /* irrelevant */
+ is_rec = mutex->__m_kind == PTHREAD_MUTEX_RECURSIVE_NP;
+ vg_mutexes[mid].is_rec = is_rec;
+ vg_mutexes[mid].count = 0;
mutex->__m_reserved = mid;
mutex->__m_count = 1; /* initialised */
if (VG_(clo_trace_pthread_level) >= 1) {
- VG_(sprintf)(msg_buf, "(initialise mutex) (%p) -> %d",
- mutex, mid );
+ VG_(sprintf)(msg_buf, "(initialise mutex) (%p, %s) -> %d",
+ mutex, is_rec ? "RECURSIVE" : "NORMAL",
+ mid );
print_pthread_event(tid, msg_buf);
}
}
/* Paranoia ... */
vg_assert(sizeof(pthread_mutex_t) >= sizeof(UInt));
+ if (mutexattr)
+ mutex->__m_kind = mutexattr->__mutexkind;
initialise_mutex(tid, mutex);
if (VG_(clo_trace_pthread_level) >= 1) {
}
if (mutex->__m_count == 0) {
+ /* The mutex->__m_kind will have been set by the static
+ initialisation. */
initialise_mutex(tid, mutex);
}
/* Assume tid valid. */
vg_assert(vg_threads[tid].status == VgTs_Runnable);
- if (vg_mutexes[mid].held) {
+ if (vg_mutexes[mid].count > 0) {
+
+ /* Someone has it already. */
if (vg_mutexes[mid].owner == tid) {
- vg_threads[tid].m_edx = EDEADLK;
+ /* It's locked -- by me! */
+ if (vg_mutexes[mid].is_rec) {
+ /* return 0 (success). */
+ vg_mutexes[mid].count++;
+ vg_threads[tid].m_edx = 0;
+ VG_(printf)("!!!!!! tid %d, mutex %d -> locked %d\n",
+ tid, mid, vg_mutexes[mid].count);
+ return;
+ } else {
+ vg_threads[tid].m_edx = EDEADLK;
+ return;
+ }
+ } else {
+ /* Someone else has it; we have to wait. */
+ vg_threads[tid].status = VgTs_WaitMX;
+ vg_threads[tid].waited_on_mid = mid;
+ /* No assignment to %EDX, since we're blocking. */
+ if (VG_(clo_trace_pthread_level) >= 1) {
+ VG_(sprintf)(msg_buf, "pthread_mutex_lock %d: BLOCK",
+ mid );
+ print_pthread_event(tid, msg_buf);
+ }
return;
}
- /* Someone else has it; we have to wait. */
- vg_threads[tid].status = VgTs_WaitMX;
- vg_threads[tid].waited_on_mid = mid;
- /* No assignment to %EDX, since we're blocking. */
- if (VG_(clo_trace_pthread_level) >= 1) {
- VG_(sprintf)(msg_buf, "pthread_mutex_lock %d: BLOCK",
- mid );
- print_pthread_event(tid, msg_buf);
- }
+
} else {
- /* We get it! */
- vg_mutexes[mid].held = True;
+ /* We get it! [for the first time]. */
+ vg_mutexes[mid].count = 1;
vg_mutexes[mid].owner = tid;
/* return 0 (success). */
vg_threads[tid].m_edx = 0;
}
+
}
vg_assert(vg_threads[tid].status == VgTs_Runnable);
/* Barf if we don't currently hold the mutex. */
- if (!vg_mutexes[mid].held || vg_mutexes[mid].owner != tid) {
+ if (vg_mutexes[mid].count == 0 /* nobody holds it */
+ || vg_mutexes[mid].owner != tid /* we don't hold it */) {
vg_threads[tid].m_edx = EPERM;
return;
}
+ /* If it's a multiply-locked recursive mutex, just decrement the
+ lock count and return. */
+ if (vg_mutexes[mid].count > 1) {
+ vg_assert(vg_mutexes[mid].is_rec);
+ vg_mutexes[mid].count --;
+ vg_threads[tid].m_edx = 0; /* success */
+ return;
+ }
+
+ /* Now we're sure mid is locked exactly once, and by the thread who
+ is now doing an unlock on it. */
+ vg_assert(vg_mutexes[mid].count == 1);
+
/* Find some arbitrary thread waiting on this mutex, and make it
runnable. If none are waiting, mark the mutex as not held. */
for (i = 0; i < VG_N_THREADS; i++) {
vg_assert(i <= VG_N_THREADS);
if (i == VG_N_THREADS) {
/* Nobody else is waiting on it. */
- vg_mutexes[mid].held = False;
+ vg_mutexes[mid].count = 0;
} else {
/* Notionally transfer the hold to thread i, whose
pthread_mutex_lock() call now returns with 0 (success). */
+ /* The .count is already == 1. */
vg_mutexes[mid].owner = i;
vg_threads[i].status = VgTs_Runnable;
vg_threads[i].m_edx = 0; /* pth_lock() success */
vg_assert(vg_threads[tid].status == VgTs_Runnable);
/* Barf if the mutex is currently held. */
- if (vg_mutexes[mid].held) {
+ if (vg_mutexes[mid].count > 0) {
vg_threads[tid].m_edx = EBUSY;
return;
}