From: Paul Floyd Date: Sun, 31 Mar 2024 16:04:04 +0000 (+0200) Subject: FreeBSD DRD and Helgrind: add sem_clockwait_np wrappers X-Git-Tag: VALGRIND_3_23_0~74 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=554b82753c0dcac947774aaf19b41759d1bfc8a5;p=thirdparty%2Fvalgrind.git FreeBSD DRD and Helgrind: add sem_clockwait_np wrappers Helgrind wrapper was complicated because sem_wait calls sem_clockwait_np. --- diff --git a/.gitignore b/.gitignore index 347be07de..abc693c82 100644 --- a/.gitignore +++ b/.gitignore @@ -691,6 +691,7 @@ /helgrind/tests/pth_mempcpy_false_races /helgrind/tests/rwlock_race /helgrind/tests/rwlock_test +/helgrind/tests/sem_clockwait_np /helgrind/tests/sem_timedwait /helgrind/tests/shmem_abits /helgrind/tests/stackteardown diff --git a/configure.ac b/configure.ac index e7bfe4185..21ec7a07f 100755 --- a/configure.ac +++ b/configure.ac @@ -4972,7 +4972,8 @@ AC_CHECK_FUNCS([ \ free_aligned_sized \ wcpncpy \ wcsxfrm \ - sem_timedwait + sem_timedwait \ + sem_clockwait_np ]) # AC_CHECK_LIB adds any library found to the variable LIBS, and links these @@ -5018,6 +5019,8 @@ AM_CONDITIONAL([HAVE_WCSXFRM], [test x$ac_cv_func_wcsxfrm = xyes]) AM_CONDITIONAL([HAVE_SEM_TIMEDWAIT], [test x$ac_cv_func_sem_timedwait = xyes]) +AM_CONDITIONAL([HAVE_SEM_CLOCKWAIT_NP], + [test x$ac_cv_func_sem_clockwait_np = xyes]) if test x$VGCONF_PLATFORM_PRI_CAPS = xMIPS32_LINUX \ -o x$VGCONF_PLATFORM_PRI_CAPS = xMIPS64_LINUX \ diff --git a/drd/drd_pthread_intercepts.c b/drd/drd_pthread_intercepts.c index f3077d626..a4000b467 100644 --- a/drd/drd_pthread_intercepts.c +++ b/drd/drd_pthread_intercepts.c @@ -1636,6 +1636,28 @@ PTH_FUNCS(int, semaZureltimedwait, sem_timedwait_intercept, (sem, timeout)); #endif /* VGO_solaris */ +#if defined(VGO_freebsd) +static __always_inline + int sem_clockwait_np_intercept(sem_t* sem, clockid_t clock_id, int flags, + const struct timespec * rqtp, struct timespec * rmtp) +{ + int ret; + OrigFn fn; + VALGRIND_GET_ORIG_FN(fn); + VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_PRE_SEM_WAIT, + sem, 0, 0, 0, 0); + CALL_FN_W_5W(ret, fn, sem, clock_id, flags, rqtp, rmtp); + VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ_DRD_POST_SEM_WAIT, + sem, ret == 0, 0, 0, 0); + return ret; +} + +LIBC_FUNC(int, semZuclockwaitZunp, sem_clockwait_np_intercept, + (sem_t* sem, clockid_t clock_id, int flags, + const struct timespec * rqtp, struct timespec * rmtp), + (sem, clock_id, flags, rqtp, rmtp)); +#endif + static __always_inline int sem_post_intercept(sem_t *sem) { int ret; diff --git a/drd/tests/Makefile.am b/drd/tests/Makefile.am index 13d94df3b..e12ab5fb2 100755 --- a/drd/tests/Makefile.am +++ b/drd/tests/Makefile.am @@ -269,6 +269,9 @@ EXTRA_DIST = \ sem_as_mutex3.stderr.exp-mips32-be \ sem_as_mutex3.stderr.exp-mips32-le \ sem_as_mutex3.vgtest \ + sem_clockwait_np.stderr.exp \ + sem_clockwait_np.stdout.exp \ + sem_clockwait_np.vgtest \ sem_open.stderr.exp \ sem_open.stderr.exp-mips32-be \ sem_open.stderr.exp-mips32-le \ diff --git a/drd/tests/sem_clockwait_np.stderr.exp b/drd/tests/sem_clockwait_np.stderr.exp new file mode 100644 index 000000000..e69de29bb diff --git a/drd/tests/sem_clockwait_np.stdout.exp b/drd/tests/sem_clockwait_np.stdout.exp new file mode 100644 index 000000000..1264c9437 --- /dev/null +++ b/drd/tests/sem_clockwait_np.stdout.exp @@ -0,0 +1 @@ +Finished! diff --git a/drd/tests/sem_clockwait_np.vgtest b/drd/tests/sem_clockwait_np.vgtest new file mode 100644 index 000000000..9bfa7509d --- /dev/null +++ b/drd/tests/sem_clockwait_np.vgtest @@ -0,0 +1,3 @@ +prereq: test -e ../../helgrind/tests/sem_clockwait_np +vgopts: -q +prog: ../../helgrind/tests/sem_clockwait_np diff --git a/helgrind/hg_intercepts.c b/helgrind/hg_intercepts.c index 8f883e6af..50bbc90b6 100644 --- a/helgrind/hg_intercepts.c +++ b/helgrind/hg_intercepts.c @@ -3263,8 +3263,9 @@ PTH_FUNC(int, semaZutrywait, sem_t *sem) { /* sema_trywait */ // Solaris: sema_timedwait (sem_timedwait is built on top of sema_timedwait) // FreeBSD: sem_timedwait (libc) // -/* trywait: decrement semaphore if non-zero otherwise return error */ #if !defined(VGO_darwin) +/* timedwait: decrement semaphore if non-zero otherwise wait for specified + time then return an error */ __attribute__((noinline)) static int sem_timedwait_WRK(sem_t* sem, const struct timespec* abs_timeout) { @@ -3316,6 +3317,53 @@ PTH_FUNC(int, semaZutimedwait, sem_t *sem, const struct timespec* abs_timeout) { #endif #endif // not VGO_darwin +//----------------------------------------------------------- +// glibc: does not exist +// darwin: does not exist +// Solaris: does not exist +// FreeBSD: sem_clockwait_np (libc) +// +/* clockwait_np: decrement semaphore if non-zero otherwise wait for specified + time then return an error with a flag to select the kind of clock and + a timespec for the remaining time */ +#if defined (VGO_freebsd) +__attribute__((noinline)) +static int sem_clockwait_np_WRK(sem_t* sem, clockid_t clock_id, int flags, + const struct timespec * rqtp, struct timespec * rmtp) +{ + OrigFn fn; + int ret; + VALGRIND_GET_ORIG_FN(fn); + + if (TRACE_SEM_FNS) { + fprintf(stderr, "<< sem_clockwait_np(%p, %d, %d, %p, %p) ", sem, clock_id, flags, rqtp, rmtp); + fflush(stderr); + } + + DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_WAIT_PRE, sem_t*,sem); + + CALL_FN_W_5W(ret, fn, sem, clock_id, flags, rqtp, rmtp); + + DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_WAIT_POST, sem_t*,sem, + long, (ret == 0) ? True : False); + + if (ret != 0) { + DO_PthAPIerror( "sem_clockwait_np", SEM_ERROR ); + } + + if (TRACE_SEM_FNS) { + fprintf(stderr, " sem_clockwait_np -> %d >>\n", ret); + fflush(stderr); + } + + return ret; +} + +LIBC_FUNC(int, semZuclockwaitZunp, sem_t* sem, clockid_t clock_id, int flags, + const struct timespec * rqtp, struct timespec * rmtp) { /* sem_clockwait_np */ + return sem_clockwait_np_WRK(sem, clock_id, flags, rqtp, rmtp); +} +#endif //----------------------------------------------------------- // glibc: sem_post diff --git a/helgrind/hg_main.c b/helgrind/hg_main.c index 3146cc437..3ac5d6bc8 100644 --- a/helgrind/hg_main.c +++ b/helgrind/hg_main.c @@ -715,18 +715,25 @@ static void map_threads_delete ( ThreadId coretid ) static void HG_(thread_enter_synchr)(Thread *thr) { tl_assert(thr->synchr_nesting >= 0); -#if defined(VGO_solaris) +#if defined(VGO_solaris) || defined(VGO_freebsd) thr->synchr_nesting += 1; #endif /* VGO_solaris */ } static void HG_(thread_leave_synchr)(Thread *thr) { -#if defined(VGO_solaris) +#if defined(VGO_solaris) || defined(VGO_freebsd) thr->synchr_nesting -= 1; #endif /* VGO_solaris */ tl_assert(thr->synchr_nesting >= 0); } +#if defined(VGO_freebsd) +static Int HG_(get_pthread_synchr_nesting_level)(ThreadId tid) { + Thread *thr = map_threads_maybe_lookup(tid); + return thr->synchr_nesting; +} +#endif + static void HG_(thread_enter_pthread_create)(Thread *thr) { tl_assert(thr->pthread_create_nesting_level >= 0); thr->pthread_create_nesting_level += 1; @@ -5373,6 +5380,11 @@ Bool hg_handle_client_request ( ThreadId tid, UWord* args, UWord* ret) map_pthread_t_to_Thread_INIT(); my_thr = map_threads_maybe_lookup( tid ); tl_assert(my_thr); /* See justification above in SET_MY_PTHREAD_T */ +#if defined(VGO_freebsd) + if (HG_(get_pthread_synchr_nesting_level)(tid) >= 1) { + break; + } +#endif HG_(record_error_PthAPIerror)( my_thr, (HChar*)args[1], (UWord)args[2], (HChar*)args[3] ); break; @@ -5603,8 +5615,13 @@ Bool hg_handle_client_request ( ThreadId tid, UWord* args, UWord* ret) break; case _VG_USERREQ__HG_POSIX_SEM_WAIT_POST: /* sem_t*, long tookLock */ +#if defined(VGO_freebsd) + if (args[2] == True && HG_(get_pthread_synchr_nesting_level)(tid) == 1) + evh__HG_POSIX_SEM_WAIT_POST( tid, (void*)args[1] ); +#else if (args[2] == True) evh__HG_POSIX_SEM_WAIT_POST( tid, (void*)args[1] ); +#endif HG_(thread_leave_synchr)(map_threads_maybe_lookup(tid)); break; diff --git a/helgrind/tests/Makefile.am b/helgrind/tests/Makefile.am index 927e11116..0f2a5ef85 100755 --- a/helgrind/tests/Makefile.am +++ b/helgrind/tests/Makefile.am @@ -72,6 +72,8 @@ EXTRA_DIST = \ pth_spinlock.vgtest pth_spinlock.stdout.exp pth_spinlock.stderr.exp \ rwlock_race.vgtest rwlock_race.stdout.exp rwlock_race.stderr.exp \ rwlock_test.vgtest rwlock_test.stdout.exp rwlock_test.stderr.exp \ + sem_clockwait_np.vgtest sem_clockwait_np.stdout.exp \ + sem_clockwait_np.stderr.exp \ sem_timedwait.vgtest sem_timedwait.stdout.exp sem_timedwait.stderr.exp \ shared_timed_mutex.vgtest shared_timed_mutex.stderr.exp \ shmem_abits.vgtest shmem_abits.stdout.exp shmem_abits.stderr.exp \ @@ -247,6 +249,10 @@ if HAVE_GETADDRINFO check_PROGRAMS += getaddrinfo endif +if HAVE_SEM_CLOCKWAIT_NP +check_PROGRAMS += sem_clockwait_np +endif + if HAVE_SEM_TIMEDWAIT check_PROGRAMS += sem_timedwait endif diff --git a/helgrind/tests/sem_clockwait_np.c b/helgrind/tests/sem_clockwait_np.c new file mode 100644 index 000000000..65dbb8d2d --- /dev/null +++ b/helgrind/tests/sem_clockwait_np.c @@ -0,0 +1,36 @@ +// this is a variation of bug484480.c using sem_clockwait_np + +#include +#include +#include +#include +#include +#include + +static char* result; +static sem_t sem; + +static void* func(void* data) +{ + result = "Finished!"; + sem_post(&sem); + return NULL; +} + +int main(void) +{ + sem_init(&sem, 0, 0); + + pthread_t tid; + pthread_create(&tid, NULL, func, NULL); + + struct timespec ts = {0, 100000}; + struct timespec ts_remain; + + while (sem_clockwait_np(&sem, CLOCK_REALTIME, 0, &ts, &ts_remain)) + ; // do nothing but keep retrying + + printf("%s\n", result); + + pthread_join(tid, NULL); +} diff --git a/helgrind/tests/sem_clockwait_np.stderr.exp b/helgrind/tests/sem_clockwait_np.stderr.exp new file mode 100644 index 000000000..e69de29bb diff --git a/helgrind/tests/sem_clockwait_np.stdout.exp b/helgrind/tests/sem_clockwait_np.stdout.exp new file mode 100644 index 000000000..1264c9437 --- /dev/null +++ b/helgrind/tests/sem_clockwait_np.stdout.exp @@ -0,0 +1 @@ +Finished! diff --git a/helgrind/tests/sem_clockwait_np.vgtest b/helgrind/tests/sem_clockwait_np.vgtest new file mode 100644 index 000000000..d66be46cd --- /dev/null +++ b/helgrind/tests/sem_clockwait_np.vgtest @@ -0,0 +1,3 @@ +prereq: test -e ./sem_clockwait_np +vgopts: -q +prog: sem_clockwait_np