From: Bart Van Assche Date: Thu, 23 Jul 2009 16:31:39 +0000 (+0000) Subject: Added support for sem_open() and sem_close(). X-Git-Tag: svn/VALGRIND_3_5_0~288 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=e2f8abc15d4daf476af2c26c9a27d2449e8fd693;p=thirdparty%2Fvalgrind.git Added support for sem_open() and sem_close(). git-svn-id: svn://svn.valgrind.org/valgrind/trunk@10560 --- diff --git a/drd/drd_clientreq.c b/drd/drd_clientreq.c index e888e064ed..3aca2d734d 100644 --- a/drd/drd_clientreq.c +++ b/drd/drd_clientreq.c @@ -371,6 +371,24 @@ static Bool handle_client_request(ThreadId vg_tid, UWord* arg, UWord* ret) 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]); diff --git a/drd/drd_clientreq.h b/drd/drd_clientreq.h index 7799b37eb3..190ead5c49 100644 --- a/drd/drd_clientreq.h +++ b/drd/drd_clientreq.h @@ -143,6 +143,18 @@ enum { /* 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 */ diff --git a/drd/drd_pthread_intercepts.c b/drd/drd_pthread_intercepts.c index 4be2e7e5bf..b2ef0184af 100644 --- a/drd/drd_pthread_intercepts.c +++ b/drd/drd_pthread_intercepts.c @@ -838,6 +838,39 @@ PTH_FUNC(int, semZudestroyZa, // sem_destroy* 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) diff --git a/drd/drd_semaphore.c b/drd/drd_semaphore.c index da3d867b3a..f2e38e2f4f 100644 --- a/drd/drd_semaphore.c +++ b/drd/drd_semaphore.c @@ -49,7 +49,7 @@ static ULong s_semaphore_segment_creation_count; /* 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; @@ -63,7 +63,7 @@ static void DRD_(segment_push)(struct semaphore_info* p, Segment* sg) } /** 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; @@ -94,8 +94,8 @@ void DRD_(semaphore_set_trace)(const Bool trace_semaphore) * 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); @@ -129,7 +129,7 @@ static void semaphore_cleanup(struct semaphore_info* p) " 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); } @@ -141,7 +141,7 @@ static void semaphore_cleanup(struct semaphore_info* p) */ static struct semaphore_info* -DRD_(semaphore_get_or_allocate)(const Addr semaphore) +drd_semaphore_get_or_allocate(const Addr semaphore) { struct semaphore_info *p; @@ -151,7 +151,7 @@ DRD_(semaphore_get_or_allocate)(const Addr semaphore) { 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; } @@ -193,14 +193,14 @@ struct semaphore_info* DRD_(semaphore_init)(const Addr semaphore, "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; @@ -238,12 +238,89 @@ void DRD_(semaphore_destroy)(const Addr semaphore) 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++; @@ -289,7 +366,7 @@ void DRD_(semaphore_post_wait)(const DrdThreadId tid, const Addr semaphore, /* * 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. */ @@ -308,7 +385,7 @@ void DRD_(semaphore_post_wait)(const DrdThreadId tid, const Addr semaphore, p->waits_to_skip--; else { - sg = DRD_(segment_pop)(p); + sg = drd_segment_pop(p); tl_assert(sg); if (sg) { @@ -331,7 +408,7 @@ void DRD_(semaphore_pre_post)(const DrdThreadId tid, const Addr semaphore) 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) @@ -347,7 +424,7 @@ void DRD_(semaphore_pre_post)(const DrdThreadId tid, const Addr 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++; } diff --git a/drd/drd_semaphore.h b/drd/drd_semaphore.h index b9cc1e1c5c..3f2b8051c8 100644 --- a/drd/drd_semaphore.h +++ b/drd/drd_semaphore.h @@ -42,6 +42,10 @@ struct semaphore_info* DRD_(semaphore_init)(const Addr semaphore, 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); diff --git a/drd/tests/Makefile.am b/drd/tests/Makefile.am index c030c07dae..0bb893d84c 100644 --- a/drd/tests/Makefile.am +++ b/drd/tests/Makefile.am @@ -148,6 +148,12 @@ EXTRA_DIST = \ 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 \ @@ -245,6 +251,7 @@ check_PROGRAMS = \ rwlock_race \ rwlock_test \ sem_as_mutex \ + sem_open \ sigalrm \ thread_name \ trylock \ diff --git a/drd/tests/sem_open.c b/drd/tests/sem_open.c new file mode 100644 index 0000000000..0920001e8b --- /dev/null +++ b/drd/tests/sem_open.c @@ -0,0 +1,118 @@ +/* Use a semaphore to implement mutual exclusion. */ + +#include +#include /* O_CREAT */ +#include +#include +#include /* printf() */ +#include /* exit() */ +#include /* 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; +} diff --git a/drd/tests/sem_open.stderr.exp b/drd/tests/sem_open.stderr.exp new file mode 100644 index 0000000000..b94d77c828 --- /dev/null +++ b/drd/tests/sem_open.stderr.exp @@ -0,0 +1,20 @@ + +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) diff --git a/drd/tests/sem_open.vgtest b/drd/tests/sem_open.vgtest new file mode 100644 index 0000000000..08bb5ccc17 --- /dev/null +++ b/drd/tests/sem_open.vgtest @@ -0,0 +1,3 @@ +prereq: ./supported_libpthread +vgopts: --check-stack-var=yes --read-var-info=yes +prog: sem_open diff --git a/drd/tests/sem_open2.stderr.exp b/drd/tests/sem_open2.stderr.exp new file mode 100644 index 0000000000..d18786f806 --- /dev/null +++ b/drd/tests/sem_open2.stderr.exp @@ -0,0 +1,3 @@ + + +ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) diff --git a/drd/tests/sem_open2.vgtest b/drd/tests/sem_open2.vgtest new file mode 100644 index 0000000000..a1ece0ef36 --- /dev/null +++ b/drd/tests/sem_open2.vgtest @@ -0,0 +1,4 @@ +prereq: ./supported_libpthread +vgopts: --check-stack-var=yes --read-var-info=yes +prog: sem_open +args: -m diff --git a/drd/tests/sem_open3.stderr.exp b/drd/tests/sem_open3.stderr.exp new file mode 100644 index 0000000000..fb3163df9f --- /dev/null +++ b/drd/tests/sem_open3.stderr.exp @@ -0,0 +1,11 @@ + +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) diff --git a/drd/tests/sem_open3.vgtest b/drd/tests/sem_open3.vgtest new file mode 100644 index 0000000000..02e49d08c1 --- /dev/null +++ b/drd/tests/sem_open3.vgtest @@ -0,0 +1,3 @@ +prereq: ./supported_libpthread +vgopts: --check-stack-var=yes --first-race-only=yes --read-var-info=yes +prog: sem_open