DRD_(semaphore_destroy)(arg[1]);
break;
+ case VG_USERREQ__PRE_SEM_OPEN:
+ DRD_(thread_enter_synchr)(drd_tid);
+ break;
+
+ case VG_USERREQ__POST_SEM_OPEN:
+ if (DRD_(thread_leave_synchr)(drd_tid) == 0)
+ DRD_(semaphore_open)(arg[1], (Char*)arg[2], arg[3], arg[4], arg[5]);
+ break;
+
+ case VG_USERREQ__PRE_SEM_CLOSE:
+ if (DRD_(thread_enter_synchr)(drd_tid) == 0)
+ DRD_(semaphore_close)(arg[1]);
+ break;
+
+ case VG_USERREQ__POST_SEM_CLOSE:
+ DRD_(thread_leave_synchr)(drd_tid);
+ break;
+
case VG_USERREQ__PRE_SEM_WAIT:
if (DRD_(thread_enter_synchr)(drd_tid) == 0)
DRD_(semaphore_pre_wait)(arg[1]);
/* To notify the drd tool of a sem_destroy call. */
VG_USERREQ__POST_SEM_DESTROY,
/* args: Addr sem */
+ /* To notify the drd tool of a sem_open call. */
+ VG_USERREQ__PRE_SEM_OPEN,
+ /* args: Addr name, Word oflag, Word mode, Word value */
+ /* To notify the drd tool of a sem_open call. */
+ VG_USERREQ__POST_SEM_OPEN,
+ /* args: Addr sem, Word oflag, Word mode, Word value */
+ /* To notify the drd tool of a sem_close call. */
+ VG_USERREQ__PRE_SEM_CLOSE,
+ /* args: Addr sem */
+ /* To notify the drd tool of a sem_close call. */
+ VG_USERREQ__POST_SEM_CLOSE,
+ /* args: Addr sem */
/* To notify the drd tool of a sem_wait call. */
VG_USERREQ__PRE_SEM_WAIT,
/* args: Addr sem */
return ret;
}
+// sem_open
+PTH_FUNC(sem_t *, semZuopen, // sem_open
+ const char *name, int oflag, mode_t mode, unsigned int value)
+{
+ sem_t *ret;
+ int res;
+ OrigFn fn;
+ VALGRIND_GET_ORIG_FN(fn);
+ VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SEM_OPEN,
+ name, oflag, mode, value, 0);
+ CALL_FN_W_WWWW(ret, fn, name, oflag, mode, value);
+ VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_OPEN,
+ ret != SEM_FAILED ? ret : 0,
+ name, oflag, mode, value);
+ return ret;
+}
+
+// sem_close
+PTH_FUNC(int, semZuclose, // sem_close
+ sem_t *sem)
+{
+ int ret;
+ int res;
+ OrigFn fn;
+ VALGRIND_GET_ORIG_FN(fn);
+ VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SEM_CLOSE,
+ sem, 0, 0, 0, 0);
+ CALL_FN_W_W(ret, fn, sem);
+ VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_CLOSE,
+ sem, 0, 0, 0, 0);
+ return ret;
+}
+
// sem_wait
PTH_FUNC(int, semZuwaitZa, // sem_wait*
sem_t *sem)
/* Function definitions. */
/** Push a segment at the end of the queue 'p->last_sem_post_seg'. */
-static void DRD_(segment_push)(struct semaphore_info* p, Segment* sg)
+static void drd_segment_push(struct semaphore_info* p, Segment* sg)
{
Word n;
}
/** Pop a segment from the beginning of the queue 'p->last_sem_post_seg'. */
-static Segment* DRD_(segment_pop)(struct semaphore_info* p)
+static Segment* drd_segment_pop(struct semaphore_info* p)
{
Word sz;
Segment* sg;
* client semaphore at client addres 'semaphore'.
*/
static
-void DRD_(semaphore_initialize)(struct semaphore_info* const p,
- const Addr semaphore)
+void drd_semaphore_initialize(struct semaphore_info* const p,
+ const Addr semaphore)
{
tl_assert(semaphore != 0);
tl_assert(p->a1 == semaphore);
" upon",
&sei);
}
- while ((sg = DRD_(segment_pop)(p)))
+ while ((sg = drd_segment_pop(p)))
DRD_(sg_put)(sg);
VG_(deleteXA)(p->last_sem_post_seg);
}
*/
static
struct semaphore_info*
-DRD_(semaphore_get_or_allocate)(const Addr semaphore)
+drd_semaphore_get_or_allocate(const Addr semaphore)
{
struct semaphore_info *p;
{
tl_assert(offsetof(DrdClientobj, semaphore) == 0);
p = &(DRD_(clientobj_add)(semaphore, ClientSemaphore)->semaphore);
- DRD_(semaphore_initialize)(p, semaphore);
+ drd_semaphore_initialize(p, semaphore);
}
return p;
}
"Semaphore reinitialization",
&SEI);
// Remove all segments from the segment stack.
- while ((sg = DRD_(segment_pop)(p)))
+ while ((sg = drd_segment_pop(p)))
{
DRD_(sg_put)(sg);
}
}
else
{
- p = DRD_(semaphore_get_or_allocate)(semaphore);
+ p = drd_semaphore_get_or_allocate(semaphore);
}
tl_assert(p);
p->waits_to_skip = value;
DRD_(clientobj_remove)(semaphore, ClientSemaphore);
}
+/** Called after sem_open(). */
+struct semaphore_info* DRD_(semaphore_open)(const Addr semaphore,
+ const Char* name, const Word oflag,
+ const Word mode, const UInt value)
+{
+ struct semaphore_info* p;
+ Segment* sg;
+
+ if (s_trace_semaphore)
+ {
+ VG_(message)(Vg_UserMsg,
+ "[%d] semaphore_open 0x%lx name %s"
+ " oflag %ld mode 0%lo value %u\n",
+ DRD_(thread_get_running_tid)(),
+ semaphore, name, oflag, mode, value);
+ }
+
+ /* Return if the sem_open() call failed. */
+ if (! semaphore)
+ return NULL;
+
+ p = semaphore_get(semaphore);
+ if (p)
+ {
+ const ThreadId vg_tid = VG_(get_running_tid)();
+ SemaphoreErrInfo SEI = { DRD_(thread_get_running_tid)(), semaphore };
+ VG_(maybe_record_error)(vg_tid,
+ SemaphoreErr,
+ VG_(get_IP)(vg_tid),
+ "Semaphore reinitialization",
+ &SEI);
+ // Remove all segments from the segment stack.
+ while ((sg = drd_segment_pop(p)))
+ {
+ DRD_(sg_put)(sg);
+ }
+ }
+ else
+ {
+ p = drd_semaphore_get_or_allocate(semaphore);
+ }
+ tl_assert(p);
+ p->waits_to_skip = value;
+ p->value = value;
+ return p;
+}
+
+/** Called before sem_close(). */
+void DRD_(semaphore_close)(const Addr semaphore)
+{
+ struct semaphore_info* p;
+
+ p = semaphore_get(semaphore);
+
+ if (s_trace_semaphore)
+ {
+ VG_(message)(Vg_UserMsg,
+ "[%d] semaphore_close 0x%lx value %u\n",
+ DRD_(thread_get_running_tid)(),
+ semaphore,
+ p ? p->value : 0);
+ }
+
+ if (p == 0)
+ {
+ GenericErrInfo GEI = { DRD_(thread_get_running_tid)() };
+ VG_(maybe_record_error)(VG_(get_running_tid)(),
+ GenericErr,
+ VG_(get_IP)(VG_(get_running_tid)()),
+ "Not a semaphore",
+ &GEI);
+ return;
+ }
+
+ DRD_(clientobj_remove)(semaphore, ClientSemaphore);
+}
+
/** Called before sem_wait(). */
void DRD_(semaphore_pre_wait)(const Addr semaphore)
{
struct semaphore_info* p;
- p = DRD_(semaphore_get_or_allocate)(semaphore);
+ p = drd_semaphore_get_or_allocate(semaphore);
tl_assert(p);
p->waiters++;
/*
* Note: if another thread destroyed and reinitialized a semaphore while
* the current thread was waiting in sem_wait, p->waiters may have been
- * set to zero by DRD_(semaphore_initialize)() after
+ * set to zero by drd_semaphore_initialize() after
* DRD_(semaphore_pre_wait)() has finished before
* DRD_(semaphore_post_wait)() has been called.
*/
p->waits_to_skip--;
else
{
- sg = DRD_(segment_pop)(p);
+ sg = drd_segment_pop(p);
tl_assert(sg);
if (sg)
{
struct semaphore_info* p;
Segment* sg;
- p = DRD_(semaphore_get_or_allocate)(semaphore);
+ p = drd_semaphore_get_or_allocate(semaphore);
p->value++;
if (s_trace_semaphore)
sg = 0;
DRD_(thread_get_latest_segment)(&sg, tid);
tl_assert(sg);
- DRD_(segment_push)(p, sg);
+ drd_segment_push(p, sg);
DRD_(thread_new_segment)(tid);
s_semaphore_segment_creation_count++;
}
const Word pshared,
const UInt value);
void DRD_(semaphore_destroy)(const Addr semaphore);
+struct semaphore_info* DRD_(semaphore_open)(const Addr semaphore,
+ const Char* name, const Word oflag,
+ const Word mode, const UInt value);
+void DRD_(semaphore_close)(const Addr semaphore);
void DRD_(semaphore_pre_wait)(const Addr semaphore);
void DRD_(semaphore_post_wait)(const DrdThreadId tid, const Addr semaphore,
const Bool waited);
sem_as_mutex2.vgtest \
sem_as_mutex3.stderr.exp \
sem_as_mutex3.vgtest \
+ sem_open.stderr.exp \
+ sem_open.vgtest \
+ sem_open2.stderr.exp \
+ sem_open2.vgtest \
+ sem_open3.stderr.exp \
+ sem_open3.vgtest \
sigalrm.stderr.exp \
sigalrm.vgtest \
tc01_simple_race.stderr.exp \
rwlock_race \
rwlock_test \
sem_as_mutex \
+ sem_open \
sigalrm \
thread_name \
trylock \
--- /dev/null
+/* Use a semaphore to implement mutual exclusion. */
+
+#include <assert.h>
+#include <fcntl.h> /* O_CREAT */
+#include <pthread.h>
+#include <semaphore.h>
+#include <stdio.h> /* printf() */
+#include <stdlib.h> /* exit() */
+#include <unistd.h> /* sleep() */
+
+/* Local functions declarations. */
+
+static void* thread_func(void*);
+
+
+/* Local variables. */
+
+/* s_sem protects s_d3. */
+static sem_t* s_sem;
+
+static double s_d1; /* accessed before thread creation and in the created */
+ /* thread (not a race). */
+static double s_d2; /* accessed in the created thread and after the join */
+ /* (not a race). */
+static double s_d3; /* accessed simultaneously from both threads (race). */
+static int s_debug = 0;
+static int s_do_printf = 0;
+static int s_do_mutual_exclusion = 0;
+
+
+/* Function definitions. */
+
+int main(int argc, char** argv)
+{
+ int optchar;
+ pthread_t threadid;
+ char semaphore_name[32];
+
+ while ((optchar = getopt(argc, argv, "dmp")) != EOF)
+ {
+ switch (optchar)
+ {
+ case 'd':
+ s_debug = 1;
+ break;
+ case 'm':
+ s_do_mutual_exclusion = 1;
+ break;
+ case 'p':
+ s_do_printf = 1;
+ break;
+ default:
+ assert(0);
+ }
+ }
+
+ /*
+ * Use the ipcs and ipcrm commands to clean up named semaphores left by
+ * aborted instances of this process.
+ */
+ snprintf(semaphore_name, sizeof(semaphore_name), "sem_open-%d", getpid());
+ s_sem = sem_open(semaphore_name, O_CREAT, 0600, 1);
+ if (s_sem == SEM_FAILED)
+ {
+ fprintf(stderr, "Failed to create a semaphore with name %s\n",
+ semaphore_name);
+ exit(1);
+ }
+
+ /*
+ * Switch to line-buffered mode, such that timing information can be
+ * obtained for each printf() call with strace.
+ */
+ setlinebuf(stdout);
+
+ if (s_debug)
+ {
+ printf("&s_d1 = %p; &s_d2 = %p; &s_d3 = %p\n", &s_d1, &s_d2, &s_d3);
+ }
+
+ s_d1 = 1;
+ s_d3 = 3;
+
+ pthread_create(&threadid, 0, thread_func, 0);
+
+ sleep(1); /* Wait until thread_func() finished. */
+
+ {
+ if (s_do_mutual_exclusion) sem_wait(s_sem);
+ s_d3++;
+ if (s_do_mutual_exclusion) sem_post(s_sem);
+ }
+
+ /* Wait until the thread finished. */
+ pthread_join(threadid, 0);
+ if (s_do_printf) printf("s_d2 = %g (should be 2)\n", s_d2);
+ if (s_do_printf) printf("s_d3 = %g (should be 5)\n", s_d3);
+
+ sem_close(s_sem);
+ sem_unlink(semaphore_name);
+
+ return 0;
+}
+
+static void* thread_func(void* thread_arg)
+{
+ if (s_do_printf)
+ {
+ printf("s_d1 = %g (should be 1)\n", s_d1);
+ }
+ s_d2 = 2;
+ {
+ if (s_do_mutual_exclusion) sem_wait(s_sem);
+ s_d3++;
+ if (s_do_mutual_exclusion) sem_post(s_sem);
+ }
+ return 0;
+}
--- /dev/null
+
+Conflicting load by thread 1 at 0x........ size 8
+ at 0x........: main (sem_open.c:?)
+Location 0x........ is 0 bytes inside local var "s_d3"
+declared at sem_open.c:25, in frame #? of thread 1
+Other segment start (thread 2)
+ (thread finished, call stack no longer available)
+Other segment end (thread 2)
+ (thread finished, call stack no longer available)
+
+Conflicting store by thread 1 at 0x........ size 8
+ at 0x........: main (sem_open.c:?)
+Location 0x........ is 0 bytes inside local var "s_d3"
+declared at sem_open.c:25, in frame #? of thread 1
+Other segment start (thread 2)
+ (thread finished, call stack no longer available)
+Other segment end (thread 2)
+ (thread finished, call stack no longer available)
+
+ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
--- /dev/null
+prereq: ./supported_libpthread
+vgopts: --check-stack-var=yes --read-var-info=yes
+prog: sem_open
--- /dev/null
+
+
+ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
--- /dev/null
+prereq: ./supported_libpthread
+vgopts: --check-stack-var=yes --read-var-info=yes
+prog: sem_open
+args: -m
--- /dev/null
+
+Conflicting load by thread 1 at 0x........ size 8
+ at 0x........: main (sem_open.c:?)
+Location 0x........ is 0 bytes inside local var "s_d3"
+declared at sem_open.c:25, in frame #? of thread 1
+Other segment start (thread 2)
+ (thread finished, call stack no longer available)
+Other segment end (thread 2)
+ (thread finished, call stack no longer available)
+
+ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
--- /dev/null
+prereq: ./supported_libpthread
+vgopts: --check-stack-var=yes --first-race-only=yes --read-var-info=yes
+prog: sem_open