- Print an error message when memory is freed that contains a locked
reader-writer synchronization object.
- Print an error message when a semaphore is freed that is being waited upon.
-- Eliminate the upper bounds on the number of condition variables,
- semaphores, barriers and threads by converting arrays into OSet's.
- Implement segment merging, such that the number of segments per thread
remains limited even when there is no synchronization between threads.
- Add locking order checking.
a crash on AMD64. Is this an exp-drd or a VEX bug ?
- On x86 and amd64 platforms, add support for implicit locking arising from
the use of the LOCK instruction prefix.
+- Add test programs for freeing memory that contains a condition variable /
+ destroying a condition variable being waited upon.
+- Convert the array in drd_thread.c with thread information into an OSet.
Testing
#include "drd_barrier.h"
+#include "drd_clientobj.h"
#include "drd_error.h"
#include "drd_suppression.h"
#include "priv_drd_clientreq.h"
// Type definitions.
-/* Information associated with a client-side pthread_barrier_t object. */
-struct barrier_info
-{
- Addr barrier; // Client address of barrier.
- SizeT size; // Size in bytes of client-side object.
- Word count; // Participant count in a barrier wait.
- Word pre_iteration; // pthread_barrier_wait() call count modulo two.
- Word post_iteration; // pthread_barrier_wait() call count modulo two.
- Word pre_waiters_left; // number of waiters left for a complete barrier.
- Word post_waiters_left; // number of waiters left for a complete barrier.
- OSet* oset; // Thread-specific barrier information.
-};
-
/* Information associated with one thread participating in a barrier. */
struct barrier_thread_info
{
};
+// Local functions.
+
+void barrier_cleanup(struct barrier_info* p);
+
+
// Local variables.
static Bool s_trace_barrier = False;
-/* To do: eliminate the upper limit on the number of barriers (4). */
-struct barrier_info s_barrier[4];
// Function definitions.
tl_assert(barrier != 0);
tl_assert(size > 0);
tl_assert(count > 0);
+ tl_assert(p->a1 == barrier);
+ tl_assert(p->a2 - p->a1 == size);
- p->barrier = barrier;
- p->size = size;
+ p->cleanup = (void(*)(DrdClientobj*))barrier_cleanup;
p->count = count;
p->pre_iteration = 0;
p->post_iteration = 0;
p->oset = VG_(OSetGen_Create)(0, 0, VG_(malloc), VG_(free));
}
-/** Deallocate the memory allocated by barrier_initialize() and in p->oset. */
-void barrier_destroy(struct barrier_info* const p)
+/** Deallocate the memory allocated by barrier_initialize() and in p->oset.
+ * Called by drd_clientobj_destroy().
+ */
+void barrier_cleanup(struct barrier_info* p)
{
struct barrier_thread_info* q;
tl_assert(p);
- drd_finish_suppression(p->barrier, p->barrier + p->size);
+ if (p->pre_waiters_left != p->count || p->post_waiters_left != p->count)
+ {
+ VG_(message)(Vg_UserMsg, "Destruction of barrier 0x%lx being waited upon",
+ p->a1);
+ }
VG_(OSetGen_ResetIter)(p->oset);
for ( ; (q = VG_(OSetGen_Next)(p->oset)) != 0; )
barrier_thread_destroy(q);
}
VG_(OSetGen_Destroy)(p->oset);
- p->barrier = 0;
- p->size = 0;
- p->count = 0;
- p->pre_iteration = 0;
- p->post_iteration = 0;
- p->pre_waiters_left = 0;
- p->post_waiters_left = 0;
}
/** Look up the client-side barrier address barrier in s_barrier[]. If not
struct barrier_info*
barrier_get_or_allocate(const Addr barrier, const SizeT size, const Word count)
{
- int i;
+ struct barrier_info *p;
- for (i = 0; i < sizeof(s_barrier)/sizeof(s_barrier[0]); i++)
+ tl_assert(offsetof(DrdClientobj, barrier) == 0);
+ p = &drd_clientobj_get(barrier, ClientBarrier)->barrier;
+ if (p == 0)
{
- if (s_barrier[i].barrier == barrier)
- {
- tl_assert(s_barrier[i].size == size);
- return &s_barrier[i];
- }
- }
- for (i = 0; i < sizeof(s_barrier)/sizeof(s_barrier[0]); i++)
- {
- if (s_barrier[i].barrier == 0)
- {
- barrier_initialize(&s_barrier[i], barrier, size, count);
- drd_start_suppression(barrier, barrier + size, "barrier");
- return &s_barrier[i];
- }
+ p = &drd_clientobj_add(barrier, barrier + size, ClientBarrier)->barrier;
+ barrier_initialize(p, barrier, size, count);
}
- tl_assert(0);
- return 0;
+ return p;
+}
+
+/** Look up the address of the information associated with the client-side
+ * barrier object. */
+struct barrier_info* barrier_get(const Addr barrier)
+{
+ tl_assert(offsetof(DrdClientobj, barrier) == 0);
+ return &drd_clientobj_get(barrier, ClientBarrier)->barrier;
}
/** Initialize a barrier with client address barrier, client size size, and
- * where count threads participate in each barrier. */
+ * where count threads participate in each barrier.
+ * Called before pthread_barrier_init().
+ */
struct barrier_info*
barrier_init(const Addr barrier, const SizeT size, const Word count)
{
return barrier_get_or_allocate(barrier, size, count);
}
-/** Look up the address of the information associated with the client-side
- * barrier object. */
-struct barrier_info* barrier_get(const Addr barrier)
+/** Called after pthread_barrier_destroy(). */
+void barrier_destroy(struct barrier_info* const p)
{
- int i;
- for (i = 0; i < sizeof(s_barrier)/sizeof(s_barrier[0]); i++)
- if (s_barrier[i].barrier == barrier)
- return &s_barrier[i];
- return 0;
+ tl_assert(p);
+ drd_clientobj_remove(p->a1, ClientBarrier);
}
+/** Called before pthread_barrier_wait(). */
void barrier_pre_wait(const DrdThreadId tid, const Addr barrier)
{
struct barrier_info* p;
}
}
+/** Called after pthread_barrier_wait(). */
void barrier_post_wait(const DrdThreadId tid, const Addr barrier,
const Bool waited)
{
/** Call this function when thread tid stops to exist. */
void barrier_thread_delete(const DrdThreadId tid)
{
- int i;
-
- for (i = 0; i < sizeof(s_barrier)/sizeof(s_barrier[0]); i++)
- {
- struct barrier_info* const p = &s_barrier[i];
- if (p->barrier)
- {
- struct barrier_thread_info* q;
- const UWord word_tid = tid;
- q = VG_(OSetGen_Remove)(p->oset, &word_tid);
- barrier_thread_destroy(q);
- VG_(OSetGen_FreeNode)(p->oset, q);
- }
- }
-}
+ struct barrier_info* p;
-void barrier_stop_using_mem(const Addr a1, const Addr a2)
-{
- unsigned i;
- for (i = 0; i < sizeof(s_barrier)/sizeof(s_barrier[0]); i++)
+ drd_clientobj_resetiter();
+ for ( ; (p = &drd_clientobj_next(ClientBarrier)->barrier) != 0; )
{
- if (a1 <= s_barrier[i].barrier && s_barrier[i].barrier < a2)
- {
- tl_assert(s_barrier[i].barrier + s_barrier[i].size <= a2);
- barrier_destroy(&s_barrier[i]);
- }
+ struct barrier_thread_info* q;
+ const UWord word_tid = tid;
+ q = VG_(OSetGen_Remove)(p->oset, &word_tid);
+ barrier_thread_destroy(q);
+ VG_(OSetGen_FreeNode)(p->oset, q);
}
}
// Barrier state information.
-#ifndef __BARRIER_H
-#define __BARRIER_H
+#ifndef __DRD_BARRIER_H
+#define __DRD_BARRIER_H
#include "drd_thread.h" // DrdThreadId
void barrier_stop_using_mem(const Addr a1, const Addr a2);
-#endif /* __BARRIER_H */
+#endif /* __DRD_BARRIER_H */
return p;
}
-Bool drd_clientobj_remove(const Addr addr)
+Bool drd_clientobj_remove(const Addr addr, const ObjType t)
{
DrdClientobj* p;
+ p = VG_(OSetGen_Lookup)(s_clientobj, &addr);
+ tl_assert(p->any.type == t);
p = VG_(OSetGen_Remove)(s_clientobj, &addr);
if (p)
{
a1, a2);
#endif
removed_at = p->any.a1;
- drd_clientobj_remove(p->any.a1);
+ drd_clientobj_remove(p->any.a1, p->any.type);
/* The above call removes an element from the oset and hence invalidates */
/* the iterator. Set the iterator back. */
VG_(OSetGen_ResetIter)(s_clientobj);
#include "drd_clientreq.h" /* MutexT */
#include "drd_thread.h" /* DrdThreadId */
#include "pub_tool_basics.h"
+#include "pub_tool_oset.h"
// Forward declarations.
// Type definitions.
-typedef enum { ClientMutex = 1, } ObjType;
+typedef enum {
+ ClientMutex = 1,
+ ClientCondvar = 2,
+ ClientSemaphore = 3,
+ ClientBarrier = 4,
+} ObjType;
struct any
{
VectorClock vc; // vector clock associated with last unlock.
};
+struct cond_info
+{
+ Addr a1;
+ Addr a2;
+ ObjType type;
+ void (*cleanup)(union drd_clientobj*);
+ int waiter_count;
+ Addr mutex; // Client mutex specified in pthread_cond_wait() call, and null
+ // if no client threads are currently waiting on this cond.var.
+};
+
+struct semaphore_info
+{
+ Addr a1;
+ Addr a2;
+ ObjType type;
+ void (*cleanup)(union drd_clientobj*);
+ UWord value; // Semaphore value.
+ UWord waiters; // Number of threads inside sem_wait().
+ DrdThreadId last_sem_post_tid; // Thread ID associated with last sem_post().
+ VectorClock vc; // Vector clock of last sem_post() call.
+};
+
+struct barrier_info
+{
+ Addr a1;
+ Addr a2;
+ ObjType type;
+ void (*cleanup)(union drd_clientobj*);
+ Word count; // Participant count in a barrier wait.
+ Word pre_iteration; // pthread_barrier_wait() call count modulo two.
+ Word post_iteration; // pthread_barrier_wait() call count modulo two.
+ Word pre_waiters_left; // number of waiters left for a complete barrier.
+ Word post_waiters_left; // number of waiters left for a complete barrier.
+ OSet* oset; // Thread-specific barrier information.
+};
+
typedef union drd_clientobj
{
- struct any any;
- struct mutex_info mutex;
+ struct any any;
+ struct mutex_info mutex;
+ struct cond_info cond;
+ struct semaphore_info semaphore;
+ struct barrier_info barrier;
} DrdClientobj;
DrdClientobj* drd_clientobj_get(const Addr addr, const ObjType t);
Bool drd_clientobj_present(const Addr a1, const Addr a2);
DrdClientobj* drd_clientobj_add(const Addr a1, const Addr a2, const ObjType t);
-Bool drd_clientobj_remove(const Addr addr);
+Bool drd_clientobj_remove(const Addr addr, const ObjType t);
void drd_clientobj_stop_using_mem(const Addr a1, const Addr a2);
void drd_clientobj_resetiter(void);
DrdClientobj* drd_clientobj_next(const ObjType t);
drd_semaphore_destroy(arg[1]);
break;
+ case VG_USERREQ__PRE_SEM_WAIT:
+ drd_semaphore_pre_wait(thread_get_running_tid(), arg[1], arg[2]);
+ break;
+
case VG_USERREQ__POST_SEM_WAIT:
drd_semaphore_post_wait(thread_get_running_tid(), arg[1], arg[2]);
break;
VG_USERREQ__SEM_DESTROY,
/* args: Addr sem */
/* To notify the drd tool of a sem_wait call. */
- VG_USERREQ__POST_SEM_WAIT,
+ VG_USERREQ__PRE_SEM_WAIT,
/* args: Addr sem, SizeT sem_size */
+ /* To notify the drd tool of a sem_wait call. */
+ VG_USERREQ__POST_SEM_WAIT,
+ /* args: Addr sem, Bool waited */
/* To notify the drd tool before a sem_post call. */
VG_USERREQ__PRE_SEM_POST,
/* args: Addr sem, SizeT sem_size */
*/
+#include "drd_clientobj.h"
#include "drd_cond.h"
#include "drd_error.h"
#include "drd_mutex.h"
#include "pub_tool_threadstate.h" // VG_(get_running_tid)()
-static struct cond_info s_cond[256];
+// Local functions.
+
+static void cond_cleanup(struct cond_info* p);
+
+
+// Local variables.
+
static Bool s_trace_cond;
+// Function definitions.
+
void cond_set_trace(const Bool trace_cond)
{
s_trace_cond = trace_cond;
const SizeT size)
{
tl_assert(cond != 0);
+ tl_assert(p->a1 == cond);
+ tl_assert(p->a2 - p->a1 == size);
+ tl_assert(p->type == ClientCondvar);
- p->cond = cond;
- p->size = size;
+ p->cleanup = (void(*)(DrdClientobj*))cond_cleanup;
p->waiter_count = 0;
p->mutex = 0;
}
-static struct cond_info*
-cond_get_or_allocate(const Addr cond, const SizeT size)
+/** Free the memory that was allocated by cond_initialize(). Called by
+ * drd_clientobj_remove().
+ */
+static void cond_cleanup(struct cond_info* p)
{
- int i;
- for (i = 0; i < sizeof(s_cond)/sizeof(s_cond[0]); i++)
+ tl_assert(p);
+ if (p->mutex)
{
- if (s_cond[i].cond == cond)
- {
- tl_assert(s_cond[i].size == size);
- return &s_cond[i];
- }
+ struct mutex_info* q;
+ q = &drd_clientobj_get(p->mutex, ClientMutex)->mutex;
+ VG_(message)(Vg_UserMsg,
+ "Error: destroying condition variable 0x%lx while thread %d"
+ " is waiting on it.\n",
+ p->a1, q ? q->owner : -1);
}
- for (i = 0; i < sizeof(s_cond)/sizeof(s_cond[0]); i++)
+}
+
+static struct cond_info*
+cond_get_or_allocate(const Addr cond, const SizeT size)
+{
+ struct cond_info *p;
+
+ tl_assert(offsetof(DrdClientobj, cond) == 0);
+ p = &drd_clientobj_get(cond, ClientCondvar)->cond;
+ if (p == 0)
{
- if (s_cond[i].cond == 0)
- {
- cond_initialize(&s_cond[i], cond, size);
- /* TO DO: replace the constant below by a symbolic constant referring */
- /* to sizeof(pthread_cond_t). */
- drd_start_suppression(cond, cond + size, "cond");
- return &s_cond[i];
- }
+ p = &drd_clientobj_add(cond, cond + size, ClientCondvar)->cond;
+ cond_initialize(p, cond, size);
}
- tl_assert(0);
- return 0;
+ return p;
}
+struct cond_info* cond_get(const Addr cond)
+{
+ tl_assert(offsetof(DrdClientobj, cond) == 0);
+ return &drd_clientobj_get(cond, ClientCondvar)->cond;
+}
+
+/** Called before pthread_cond_init(). */
void cond_init(const Addr cond, const SizeT size)
{
if (s_trace_cond)
{
VG_(message)(Vg_UserMsg, "Initializing condition variable 0x%lx", cond);
- VG_(get_and_pp_StackTrace)(VG_(get_running_tid)(),
- VG_(clo_backtrace_size));
+ VG_(get_and_pp_StackTrace)(VG_(get_running_tid)(), VG_(clo_backtrace_size));
}
tl_assert(cond_get(cond) == 0);
tl_assert(size > 0);
cond_get_or_allocate(cond, size);
}
+/** Called after pthread_cond_destroy(). */
void cond_destroy(struct cond_info* const p)
{
if (s_trace_cond)
{
- VG_(message)(Vg_UserMsg, "Destroying condition variable 0x%lx", p->cond);
- VG_(get_and_pp_StackTrace)(VG_(get_running_tid)(),
- VG_(clo_backtrace_size));
+ VG_(message)(Vg_UserMsg, "Destroying condition variable 0x%lx", p->a1);
+ VG_(get_and_pp_StackTrace)(VG_(get_running_tid)(), VG_(clo_backtrace_size));
}
// TO DO: print a proper error message if waiter_count != 0.
tl_assert(p->waiter_count == 0);
- drd_finish_suppression(p->cond, p->cond + p->size);
-
- p->cond = 0;
- p->waiter_count = 0;
- p->mutex = 0;
-}
-
-struct cond_info* cond_get(const Addr cond)
-{
- int i;
- for (i = 0; i < sizeof(s_cond)/sizeof(s_cond[0]); i++)
- if (s_cond[i].cond == cond)
- return &s_cond[i];
- return 0;
+ drd_clientobj_remove(p->a1, ClientCondvar);
}
+/** Called before pthread_cond_wait(). */
int cond_pre_wait(const Addr cond, const SizeT cond_size, const Addr mutex)
{
struct cond_info* p;
return ++p->waiter_count;
}
+/** Called after pthread_cond_wait(). */
int cond_post_wait(const Addr cond)
{
struct cond_info* p;
return p->waiter_count;
}
+/** Called before pthread_cond_signal(). */
void cond_pre_signal(Addr const cond)
{
const ThreadId vg_tid = VG_(get_running_tid)();
const DrdThreadId drd_tid = VgThreadIdToDrdThreadId(vg_tid);
struct cond_info* const cond_p = cond_get(cond);
-#if 0
- VG_(message)(Vg_DebugMsg, "cond_pre_signal cond %d, w.c. %d, mutex %d",
- cond,
- cond_p ? cond_p->waiter_count : 0,
- cond_p ? cond_p->mutex : 0);
-#endif
if (cond_p && cond_p->waiter_count > 0)
{
if (! mutex_is_locked_by(cond_p->mutex, drd_tid))
}
}
+/** Called before pthread_cond_broadcast(). */
void cond_pre_broadcast(Addr const cond)
{
cond_pre_signal(cond);
}
+/** Called after pthread_cond_destroy(). */
void cond_thread_delete(const DrdThreadId tid)
{ }
-
-void cond_stop_using_mem(const Addr a1, const Addr a2)
-{
- unsigned i;
- for (i = 0; i < sizeof(s_cond)/sizeof(s_cond[0]); i++)
- {
- if (a1 <= s_cond[i].cond && s_cond[i].cond < a2)
- {
- tl_assert(s_cond[i].cond + s_cond[i].size <= a2);
- cond_destroy(&s_cond[i]);
- }
- }
-}
// call.
-#ifndef __COND_H
-#define __COND_H
+#ifndef __DRD_COND_H
+#define __DRD_COND_H
-#include "pub_tool_basics.h" // Addr, SizeT
-#include "drd_vc.h"
-#include "drd_thread.h" // DrdThreadId
+#include "drd_thread.h" // DrdThreadid
+#include "pub_tool_basics.h" // Addr, SizeT
-struct cond_info
-{
- Addr cond; // Pointer to client condition variable.
- SizeT size; // sizeof(pthread_cond_t)
- int waiter_count;
- Addr mutex; // Client mutex specified in pthread_cond_wait() call, and null
- // if no client threads are currently waiting on this cond.var.
-};
+struct cond_info;
+
void cond_set_trace(const Bool trace_cond);
void cond_init(const Addr cond, const SizeT size);
void cond_pre_signal(const Addr cond);
void cond_pre_broadcast(const Addr cond);
void cond_thread_delete(const DrdThreadId tid);
-void cond_stop_using_mem(const Addr a1, const Addr a2);
-#endif /* __COND_H */
+#endif /* __DRD_COND_H */
int res;
OrigFn fn;
VALGRIND_GET_ORIG_FN(fn);
+ VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SEM_WAIT,
+ sem, 0, 0, 0, 0);
CALL_FN_W_W(ret, fn, sem);
- if (ret == 0)
- {
- VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_WAIT,
- sem, sizeof(*sem), 0, 0, 0);
- }
+ VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_WAIT,
+ sem, ret == 0, 0, 0, 0);
return ret;
}
+// sem_wait
PTH_FUNC(int, sem_waitZa, // sem_wait*
sem_t *sem)
{
int res;
OrigFn fn;
VALGRIND_GET_ORIG_FN(fn);
+ VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SEM_WAIT,
+ sem, 0, 0, 0, 0);
CALL_FN_W_W(ret, fn, sem);
- if (ret == 0)
- {
- VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_WAIT,
- sem, sizeof(*sem), 0, 0, 0);
- }
+ VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_WAIT,
+ sem, ret == 0, 0, 0, 0);
return ret;
}
int res;
OrigFn fn;
VALGRIND_GET_ORIG_FN(fn);
+ VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SEM_WAIT,
+ sem, 0, 0, 0, 0);
CALL_FN_W_W(ret, fn, sem);
- if (ret == 0)
- {
- VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_WAIT,
- sem, sizeof(*sem), 0, 0, 0);
- }
+ VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_WAIT,
+ sem, ret == 0, 0, 0, 0);
return ret;
}
int res;
OrigFn fn;
VALGRIND_GET_ORIG_FN(fn);
+ VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SEM_WAIT,
+ sem, 0, 0, 0, 0);
CALL_FN_W_W(ret, fn, sem);
- if (ret == 0)
- {
- VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_WAIT,
- sem, sizeof(*sem), 0, 0, 0);
- }
+ VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_WAIT,
+ sem, ret == 0, 0, 0, 0);
return ret;
}
int res;
OrigFn fn;
VALGRIND_GET_ORIG_FN(fn);
+ VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SEM_WAIT,
+ sem, 0, 0, 0, 0);
CALL_FN_W_WW(ret, fn, sem, abs_timeout);
- if (ret == 0)
- {
- VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_WAIT,
- sem, sizeof(*sem), 0, 0, 0);
- }
+ VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_WAIT,
+ sem, ret == 0, 0, 0, 0);
return ret;
}
Bool trace_danger_set = False;
Bool trace_mutex = False;
Bool trace_segment = False;
+ Bool trace_semaphore = False;
Bool trace_suppression = False;
Char* trace_address = 0;
else VG_BOOL_CLO(arg, "--trace-mem", drd_trace_mem)
else VG_BOOL_CLO(arg, "--trace-mutex", trace_mutex)
else VG_BOOL_CLO(arg, "--trace-segment", trace_segment)
+ else VG_BOOL_CLO(arg, "--trace-semaphore", trace_semaphore)
else VG_BOOL_CLO(arg, "--trace-suppression", trace_suppression)
else VG_STR_CLO (arg, "--trace-address", trace_address)
else
mutex_set_trace(trace_mutex);
if (trace_segment)
sg_set_trace(trace_segment);
+ if (trace_semaphore)
+ semaphore_set_trace(trace_semaphore);
if (trace_suppression)
suppression_set_trace(trace_suppression);
}
thread_stop_using_mem(a1, a2);
drd_clientobj_stop_using_mem(a1, a2);
- cond_stop_using_mem(a1, a2);
- semaphore_stop_using_mem(a1, a2);
- barrier_stop_using_mem(a1, a2);
drd_suppression_stop_using_mem(a1, a2);
}
}
}
+void drd_semaphore_pre_wait(const DrdThreadId tid, const Addr semaphore,
+ const SizeT size)
+{
+ semaphore_pre_wait(semaphore, size);
+}
+
void drd_semaphore_post_wait(const DrdThreadId tid, const Addr semaphore,
- const SizeT size)
+ const Bool waited)
{
- semaphore_post_wait(tid, semaphore, size);
+ semaphore_post_wait(tid, semaphore, waited);
}
void drd_semaphore_pre_post(const DrdThreadId tid, const Addr semaphore,
static void mutex_destroy(struct mutex_info* const p)
{
- drd_clientobj_remove(p->a1);
+ drd_clientobj_remove(p->a1, ClientMutex);
}
/** Called after pthread_mutex_destroy(). */
*/
+#include "drd_clientobj.h"
#include "drd_error.h"
#include "drd_semaphore.h"
#include "drd_suppression.h"
#include "pub_tool_threadstate.h" // VG_(get_running_tid)()
-// Type definitions.
+// Local functions.
-struct semaphore_info
-{
- Addr semaphore; // Pointer to client semaphore.
- SizeT size; // Size in bytes of client-side object.
- UWord value; // Semaphore value.
- DrdThreadId last_sem_post_tid; // Thread ID associated with last sem_post().
- VectorClock vc; // Vector clock of last sem_post() call.
-};
+static void semaphore_cleanup(struct semaphore_info* p);
// Local variables.
static Bool s_trace_semaphore;
-struct semaphore_info s_semaphore[256];
// Function definitions.
{
tl_assert(semaphore != 0);
tl_assert(size > 0);
+ tl_assert(p->a1 == semaphore);
+ tl_assert(p->a2 - p->a1 == size);
+ tl_assert(p->type == ClientSemaphore);
- p->semaphore = semaphore;
- p->size = size;
+ p->cleanup = (void(*)(DrdClientobj*))semaphore_cleanup;
p->value = value;
+ p->waiters = 0;
p->last_sem_post_tid = DRD_INVALID_THREADID;
vc_init(&p->vc, 0, 0);
}
+/** Free the memory that was allocated by semaphore_initialize(). Called by
+ * drd_clientobj_remove().
+ */
+static void semaphore_cleanup(struct semaphore_info* p)
+{
+ if (p->waiters > 0)
+ {
+ VG_(message)(Vg_UserMsg, "Error: destroying semaphore while %d threads are"
+ "still waiting on the semaphore.\n", p->waiters);
+ }
+ vc_cleanup(&p->vc);
+}
+
static
struct semaphore_info*
semaphore_get_or_allocate(const Addr semaphore, const SizeT size)
{
- int i;
+ struct semaphore_info *p;
- for (i = 0; i < sizeof(s_semaphore)/sizeof(s_semaphore[0]); i++)
- {
- if (s_semaphore[i].semaphore == semaphore)
- {
- tl_assert(s_semaphore[i].size == size);
- return &s_semaphore[i];
- }
- }
- for (i = 0; i < sizeof(s_semaphore)/sizeof(s_semaphore[0]); i++)
+ tl_assert(offsetof(DrdClientobj, semaphore) == 0);
+ p = &drd_clientobj_get(semaphore, ClientSemaphore)->semaphore;
+ if (p == 0)
{
- if (s_semaphore[i].semaphore == 0)
- {
- semaphore_initialize(&s_semaphore[i], semaphore, size, 0);
- drd_start_suppression(semaphore, semaphore + size, "semaphore");
- return &s_semaphore[i];
- }
+ tl_assert(offsetof(DrdClientobj, semaphore) == 0);
+ p = &drd_clientobj_add(semaphore, semaphore + size,
+ ClientSemaphore)->semaphore;
+ semaphore_initialize(p, semaphore, size, 0);
}
- tl_assert(0);
- return 0;
+ return p;
+}
+
+struct semaphore_info* semaphore_get(const Addr semaphore)
+{
+ tl_assert(offsetof(DrdClientobj, semaphore) == 0);
+ return &drd_clientobj_get(semaphore, ClientSemaphore)->semaphore;
}
+/** Called before sem_init(). */
struct semaphore_info* semaphore_init(const Addr semaphore, const SizeT size,
const Word pshared, const UWord value)
{
return p;
}
+/** Called after sem_destroy(). */
void semaphore_destroy(struct semaphore_info* const p)
{
- drd_finish_suppression(p->semaphore, p->semaphore + p->size);
-
- vc_cleanup(&p->vc);
- p->semaphore = 0;
+ drd_clientobj_remove(p->a1, ClientSemaphore);
}
-struct semaphore_info* semaphore_get(const Addr semaphore)
+/** Called before sem_wait(). */
+void semaphore_pre_wait(const Addr semaphore, const SizeT size)
{
- int i;
- for (i = 0; i < sizeof(s_semaphore)/sizeof(s_semaphore[0]); i++)
- if (s_semaphore[i].semaphore == semaphore)
- return &s_semaphore[i];
- return 0;
+ struct semaphore_info* p;
+
+ p = semaphore_get_or_allocate(semaphore, size);
+ if (s_trace_semaphore)
+ {
+ VG_(message)(Vg_UserMsg, "semaphore_pre_wait(0x%lx, %d)", semaphore, size);
+ }
+ tl_assert(p);
+ tl_assert(p->waiters >= 0);
+ p->waiters++;
+ tl_assert(p->waiters > 0);
}
-/** Called after sem_wait() finished successfully. */
+/** Called after sem_wait() finished.
+ * @note Do not rely on the value of 'waited' -- some glibc versions do
+ * not set it correctly.
+ */
void semaphore_post_wait(const DrdThreadId tid, const Addr semaphore,
- const SizeT size)
+ const Bool waited)
{
struct semaphore_info* p;
- p = semaphore_get_or_allocate(semaphore, size);
+ p = semaphore_get(semaphore);
+ if (s_trace_semaphore)
+ {
+ VG_(message)(Vg_UserMsg, "semaphore_post_wait(0x%lx, %d)", semaphore);
+ }
+ tl_assert(p->waiters > 0);
+ p->waiters--;
+ tl_assert(p->waiters >= 0);
tl_assert(p->value >= 0);
+ if (p->value == 0)
+ {
+ VG_(message)(Vg_UserMsg, "Invalid semaphore 0x%lx", semaphore);
+ return;
+ }
p->value--;
tl_assert(p->value >= 0);
if (p->last_sem_post_tid != tid)
void semaphore_thread_delete(const DrdThreadId threadid)
{ }
-
-void semaphore_stop_using_mem(const Addr a1, const Addr a2)
-{
- unsigned i;
- for (i = 0; i < sizeof(s_semaphore)/sizeof(s_semaphore[0]); i++)
- {
- if (a1 <= s_semaphore[i].semaphore && s_semaphore[i].semaphore < a2)
- {
- tl_assert(s_semaphore[i].semaphore + s_semaphore[i].size <= a2);
- semaphore_destroy(&s_semaphore[i]);
- }
- }
-}
// Semaphore state information: owner thread and recursion count.
-#ifndef __SEMAPHORE_H
-#define __SEMAPHORE_H
+#ifndef __DRD_SEMAPHORE_H
+#define __DRD_SEMAPHORE_H
#include "drd_thread.h" // DrdThreadId
const Word pshared, const UWord value);
void semaphore_destroy(struct semaphore_info* const p);
struct semaphore_info* semaphore_get(const Addr semaphore);
+void semaphore_pre_wait(const Addr semaphore, const SizeT size);
void semaphore_post_wait(const DrdThreadId tid, const Addr semaphore,
- const SizeT size);
+ const Bool waited);
void semaphore_pre_post(const DrdThreadId tid, const Addr semaphore,
const SizeT size);
void semaphore_post_post(const DrdThreadId tid, const Addr semaphore,
const SizeT size, const Bool waited);
void semaphore_thread_delete(const DrdThreadId tid);
-void semaphore_stop_using_mem(const Addr a1, const Addr a2);
-#endif /* __SEMAPHORE_H */
+#endif /* __DRD_SEMAPHORE_H */
void drd_semaphore_init(const Addr semaphore, const SizeT size,
const Word pshared, const Word value);
void drd_semaphore_destroy(const Addr semaphore);
+void drd_semaphore_pre_wait(const DrdThreadId tid, const Addr semaphore,
+ const SizeT size);
void drd_semaphore_post_wait(const DrdThreadId tid, const Addr semaphore,
- const SizeT size);
+ const Bool waited);
void drd_semaphore_pre_post(const DrdThreadId tid, const Addr semaphore,
const SizeT size);
void drd_semaphore_post_post(const DrdThreadId tid, const Addr semaphore,