From patchwork Wed Feb 27 18:23:52 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mike Crowe X-Patchwork-Id: 31625 Received: (qmail 108859 invoked by alias); 27 Feb 2019 18:24:51 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 108394 invoked by uid 89); 27 Feb 2019 18:24:36 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-26.6 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_LAZY_DOMAIN_SECURITY, KAM_SHORT, RCVD_IN_DNSWL_LOW autolearn=ham version=3.3.2 spammy=u.s, sem, H*r:smtp, SEM X-HELO: avasout02.plus.net X-CM-Score: 0.00 From: Mike Crowe To: libc-alpha@sourceware.org Cc: Mike Crowe Subject: [PATCH 2/7] nptl: Add POSIX-proposed sem_clockwait Date: Wed, 27 Feb 2019 18:23:52 +0000 Message-Id: <47415e51fea8d960fc993cf0e0b8db6a19511d28.1551291557.git-series.mac@mcrowe.com> In-Reply-To: References: In-Reply-To: References: Add: int sem_clockwait (sem_t *sem, clockid_t clock, const struct timespec *abstime) which behaves just like sem_timedwait, but measures abstime against the specified clock. Currently supports CLOCK_REALTIME and CLOCK_MONOTONIC and sets errno == EINVAL if any other clock is specified. * nptl/sem_waitcommon.c (do_futex_wait, __new_sem_wait_slow): Add clockid parameters to indicate the clock which abstime should be measured against. * nptl/sem_timedwait.c (sem_timedwait), nptl/sem_wait.c (__new_sem_wait): Pass CLOCK_REALTIME as clockid to __new_sem_wait_slow. * nptl/sem_clockwait.c: New file to implement sem_clockwait based on sem_timedwait.c. * nptl/Makefile: Add sem_clockwait.c source file. Add CFLAGS for sem_clockwait.c to match those used for sem_timedwait.c. * sysdeps/pthread/semaphore.h: Add sem_clockwait. * nptl/Versions (GLIBC_2.30): Likewise. * conform/data/semaphore.h-data: Likewise. * sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist: Likewise. * nptl/tst-sem17.c: Add new test for passing invalid clock to sem_clockwait. * nptl/tst-sem13.c, tst-sem5: Modify existing sem_timedwait tests to also test sem_clockwait. * manual/threads.texi: Document sem_clockwait. --- conform/data/semaphore.h-data | 1 +- manual/threads.texi | 10 ++- nptl/Makefile | 5 +- nptl/Versions | 4 +- nptl/sem_clockwait.c | 45 ++++++++++- nptl/sem_timedwait.c | 3 +- nptl/sem_wait.c | 3 +- nptl/sem_waitcommon.c | 15 +-- nptl/tst-sem13.c | 50 +++++++++-- nptl/tst-sem17.c | 57 +++++++++++++- nptl/tst-sem5.c | 30 ++++--- sysdeps/pthread/semaphore.h | 4 +- sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist | 1 +- 13 files changed, 197 insertions(+), 31 deletions(-) create mode 100644 nptl/sem_clockwait.c create mode 100644 nptl/tst-sem17.c diff --git a/conform/data/semaphore.h-data b/conform/data/semaphore.h-data index 066c2f7..019aaa1 100644 --- a/conform/data/semaphore.h-data +++ b/conform/data/semaphore.h-data @@ -11,6 +11,7 @@ function {sem_t*} sem_open (const char*, int, ...) function int sem_post (sem_t*) # if !defined POSIX && !defined UNIX98 function int sem_timedwait (sem_t*, const struct timespec*) +function int sem_clockwait (sem_t*, clockid_t, const struct timespec*) # endif function int sem_trywait (sem_t*) function int sem_unlink (const char*) diff --git a/manual/threads.texi b/manual/threads.texi index 87fda7d..674267c 100644 --- a/manual/threads.texi +++ b/manual/threads.texi @@ -669,6 +669,16 @@ The system does not have sufficient memory. @end table @end deftypefun +@comment semaphore.h +@comment POSIX-proposed +@deftypefun int sem_clockwait (sem_t *@var{sem}, clockid_t @var{clockid}, + const struct timespec *@var{abstime}) +Behaves like @code{sem_timedwait} except the time @var{abstime} is measured +against the clock specified by @var{clockid} rather than +@code{CLOCK_REALTIME}. Currently, @var{clockid} must be either +@code{CLOCK_MONOTONIC} or @code{CLOCK_REALTIME}. +@end deftypefun + @c FIXME these are undocumented: @c pthread_atfork @c pthread_attr_destroy diff --git a/nptl/Makefile b/nptl/Makefile index 5acfdcc..4c9f5d3 100644 --- a/nptl/Makefile +++ b/nptl/Makefile @@ -114,7 +114,7 @@ libpthread-routines = nptl-init nptlfreeres vars events version pt-interp \ sem_init sem_destroy \ sem_open sem_close sem_unlink \ sem_getvalue \ - sem_wait sem_timedwait sem_post \ + sem_wait sem_timedwait sem_clockwait sem_post \ cleanup cleanup_defer cleanup_compat \ cleanup_defer_compat unwind \ pt-longjmp pt-cleanup\ @@ -194,6 +194,7 @@ CFLAGS-pthread_once.c += $(uses-callbacks) -fexceptions \ CFLAGS-pthread_cond_wait.c += -fexceptions -fasynchronous-unwind-tables CFLAGS-sem_wait.c += -fexceptions -fasynchronous-unwind-tables CFLAGS-sem_timedwait.c += -fexceptions -fasynchronous-unwind-tables +CFLAGS-sem_clockwait.c = -fexceptions -fasynchronous-unwind-tables # These are the function wrappers we have to duplicate here. CFLAGS-fcntl.c += -fexceptions -fasynchronous-unwind-tables @@ -263,7 +264,7 @@ tests = tst-attr1 tst-attr2 tst-attr3 tst-default-attr \ tst-key1 tst-key2 tst-key3 tst-key4 \ tst-sem1 tst-sem2 tst-sem3 tst-sem4 tst-sem5 tst-sem6 tst-sem7 \ tst-sem8 tst-sem9 tst-sem10 tst-sem14 \ - tst-sem15 tst-sem16 \ + tst-sem15 tst-sem16 tst-sem17 \ tst-barrier1 tst-barrier2 tst-barrier3 tst-barrier4 \ tst-align tst-align3 \ tst-basic1 tst-basic2 tst-basic3 tst-basic4 tst-basic5 tst-basic6 \ diff --git a/nptl/Versions b/nptl/Versions index e7f691d..cd1806c 100644 --- a/nptl/Versions +++ b/nptl/Versions @@ -277,6 +277,10 @@ libpthread { cnd_timedwait; cnd_wait; tss_create; tss_delete; tss_get; tss_set; } + GLIBC_2.30 { + sem_clockwait; + } + GLIBC_PRIVATE { __pthread_initialize_minimal; __pthread_clock_gettime; __pthread_clock_settime; diff --git a/nptl/sem_clockwait.c b/nptl/sem_clockwait.c new file mode 100644 index 0000000..c0cd667 --- /dev/null +++ b/nptl/sem_clockwait.c @@ -0,0 +1,45 @@ +/* sem_clockwait -- wait on a semaphore with timeout using + the specified clock. + + Copyright (C) 2003-2019 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include "sem_waitcommon.c" + +int +sem_clockwait (sem_t *sem, clockid_t clockid, + const struct timespec *abstime) +{ + /* Check that supplied clockid is one we support, even if we don't + end up waiting. */ + if (!futex_abstimed_supported_clockid (clockid)) + { + __set_errno (EINVAL); + return -1; + } + + if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) + { + __set_errno (EINVAL); + return -1; + } + + if (__new_sem_wait_fast ((struct new_sem *) sem, 0) == 0) + return 0; + else + return __new_sem_wait_slow ((struct new_sem *) sem, clockid, abstime); +} diff --git a/nptl/sem_timedwait.c b/nptl/sem_timedwait.c index 3dd71ab..0918d8b 100644 --- a/nptl/sem_timedwait.c +++ b/nptl/sem_timedwait.c @@ -36,5 +36,6 @@ sem_timedwait (sem_t *sem, const struct timespec *abstime) if (__new_sem_wait_fast ((struct new_sem *) sem, 0) == 0) return 0; else - return __new_sem_wait_slow((struct new_sem *) sem, abstime); + return __new_sem_wait_slow ((struct new_sem *) sem, + CLOCK_REALTIME, abstime); } diff --git a/nptl/sem_wait.c b/nptl/sem_wait.c index 6a2d26b..20a8b9d 100644 --- a/nptl/sem_wait.c +++ b/nptl/sem_wait.c @@ -39,7 +39,8 @@ __new_sem_wait (sem_t *sem) if (__new_sem_wait_fast ((struct new_sem *) sem, 0) == 0) return 0; else - return __new_sem_wait_slow((struct new_sem *) sem, NULL); + return __new_sem_wait_slow ((struct new_sem *) sem, + CLOCK_REALTIME, NULL); } versioned_symbol (libpthread, __new_sem_wait, sem_wait, GLIBC_2_1); diff --git a/nptl/sem_waitcommon.c b/nptl/sem_waitcommon.c index 425d040..cad56e9 100644 --- a/nptl/sem_waitcommon.c +++ b/nptl/sem_waitcommon.c @@ -103,19 +103,19 @@ __sem_wait_cleanup (void *arg) users don't seem to need it. */ static int __attribute__ ((noinline)) -do_futex_wait (struct new_sem *sem, const struct timespec *abstime) +do_futex_wait (struct new_sem *sem, clockid_t clockid, + const struct timespec *abstime) { int err; #if __HAVE_64B_ATOMICS err = futex_abstimed_wait_cancelable ( (unsigned int *) &sem->data + SEM_VALUE_OFFSET, 0, - CLOCK_REALTIME, abstime, + clockid, abstime, sem->private); #else err = futex_abstimed_wait_cancelable (&sem->value, SEM_NWAITERS_MASK, - CLOCK_REALTIME, abstime, - sem->private); + clockid, abstime, sem->private); #endif return err; @@ -162,7 +162,8 @@ __new_sem_wait_fast (struct new_sem *sem, int definitive_result) /* Slow path that blocks. */ static int __attribute__ ((noinline)) -__new_sem_wait_slow (struct new_sem *sem, const struct timespec *abstime) +__new_sem_wait_slow (struct new_sem *sem, clockid_t clockid, + const struct timespec *abstime) { int err = 0; @@ -180,7 +181,7 @@ __new_sem_wait_slow (struct new_sem *sem, const struct timespec *abstime) /* If there is no token available, sleep until there is. */ if ((d & SEM_VALUE_MASK) == 0) { - err = do_futex_wait (sem, abstime); + err = do_futex_wait (sem, clockid, abstime); /* A futex return value of 0 or EAGAIN is due to a real or spurious wake-up, or due to a change in the number of tokens. We retry in these cases. @@ -281,7 +282,7 @@ __new_sem_wait_slow (struct new_sem *sem, const struct timespec *abstime) if ((v >> SEM_VALUE_SHIFT) == 0) { /* See __HAVE_64B_ATOMICS variant. */ - err = do_futex_wait(sem, abstime); + err = do_futex_wait (sem, clockid, abstime); if (err == ETIMEDOUT || err == EINTR) { __set_errno (err); diff --git a/nptl/tst-sem13.c b/nptl/tst-sem13.c index 1560e91..0f76100 100644 --- a/nptl/tst-sem13.c +++ b/nptl/tst-sem13.c @@ -5,9 +5,14 @@ #include #include +/* A bogus clock value that tells run_test to use + sem_timedwait rather than sem_clockwait */ +#define CLOCK_USE_TIMEDWAIT (-1) + +typedef int (*waitfn_t)(sem_t *, struct timespec *); static int -do_test (void) +do_test_wait (waitfn_t waitfn, const char *fnname) { union { @@ -23,14 +28,14 @@ do_test (void) struct timespec ts = { 0, 1000000001 }; /* Invalid. */ errno = 0; - if (sem_timedwait (&u.s, &ts) >= 0) + if (waitfn (&u.s, &ts) >= 0) { - puts ("sem_timedwait did not fail"); + printf ("%s did not fail\n", fnname); return 1; } if (errno != EINVAL) { - perror ("sem_timedwait did not fail with EINVAL"); + printf ("%s did not fail with EINVAL: %m\n", fnname); return 1; } #if __HAVE_64B_ATOMICS @@ -40,21 +45,21 @@ do_test (void) #endif if (nwaiters != 0) { - printf ("sem_timedwait modified nwaiters: %d\n", nwaiters); + printf ("%s modified nwaiters: %d\n", fnname, nwaiters); return 1; } ts.tv_sec = /* Invalid. */ -2; ts.tv_nsec = 0; errno = 0; - if (sem_timedwait (&u.s, &ts) >= 0) + if (waitfn (&u.s, &ts) >= 0) { - puts ("2nd sem_timedwait did not fail"); + printf ("2nd %s did not fail\n", fnname); return 1; } if (errno != ETIMEDOUT) { - perror ("2nd sem_timedwait did not fail with ETIMEDOUT"); + printf ("2nd %s did not fail with ETIMEDOUT\n", fnname); return 1; } #if __HAVE_64B_ATOMICS @@ -64,12 +69,39 @@ do_test (void) #endif if (nwaiters != 0) { - printf ("2nd sem_timedwait modified nwaiters: %d\n", nwaiters); + printf ("2nd %s modified nwaiters: %d\n", fnname, nwaiters); return 1; } return 0; } +int test_sem_timedwait (sem_t *sem, struct timespec *ts) +{ + return sem_timedwait (sem, ts); +} + +int test_sem_clockwait_monotonic (sem_t *sem, struct timespec *ts) +{ + return sem_clockwait (sem, CLOCK_MONOTONIC, ts); +} + +int test_sem_clockwait_realtime (sem_t *sem, struct timespec *ts) +{ + return sem_clockwait (sem, CLOCK_REALTIME, ts); +} + +static int do_test (void) +{ + int result = 0; + result |= do_test_wait (&test_sem_timedwait, + "sem_timedwait"); + result |= do_test_wait (&test_sem_clockwait_monotonic, + "sem_clockwait(monotonic)"); + result |= do_test_wait (&test_sem_clockwait_realtime, + "sem_clockwait(realtime)"); + return result; +} + #define TEST_FUNCTION do_test () #include "../test-skeleton.c" diff --git a/nptl/tst-sem17.c b/nptl/tst-sem17.c new file mode 100644 index 0000000..a24ad0f --- /dev/null +++ b/nptl/tst-sem17.c @@ -0,0 +1,57 @@ +/* Copyright (C) 2019 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include +#include + +#define NOT_A_VALID_CLOCK 123456 + +static int +do_test (void) +{ + sem_t s; + struct timespec ts; + + if (sem_init (&s, 0, 1) == -1) + { + puts ("sem_init failed"); + return 1; + } + + ts.tv_sec = 0; + ts.tv_nsec = 0; + + if (sem_clockwait (&s, NOT_A_VALID_CLOCK, &ts) == 0) + { + puts ("sem_clockwait succeeded with an invalid clock"); + return 1; + } + if (errno != EINVAL) + { + printf ("sem_clockwait yielded incorrect errno for invalid clock: %d\n", + errno); + return 1; + } + + return 0; +} + +#include diff --git a/nptl/tst-sem5.c b/nptl/tst-sem5.c index 2149ade..7f1031d 100644 --- a/nptl/tst-sem5.c +++ b/nptl/tst-sem5.c @@ -23,13 +23,15 @@ #include #include +/* A bogus clock value that tells run_test to use + sem_timedwait rather than sem_clockwait */ +#define CLOCK_USE_TIMEDWAIT (-1) static int -do_test (void) +do_test_clock (clockid_t clockid) { sem_t s; struct timespec ts; - struct timeval tv; if (sem_init (&s, 0, 1) == -1) { @@ -43,13 +45,8 @@ do_test (void) return 1; } - if (gettimeofday (&tv, NULL) != 0) - { - puts ("gettimeofday failed"); - return 1; - } - - TIMEVAL_TO_TIMESPEC (&tv, &ts); + (void) clock_gettime (clockid == CLOCK_USE_TIMEDWAIT + ? CLOCK_REALTIME : clockid, &ts); /* We wait for half a second. */ ts.tv_nsec += 500000000; @@ -60,7 +57,9 @@ do_test (void) } errno = 0; - if (TEMP_FAILURE_RETRY (sem_timedwait (&s, &ts)) != -1) + if (TEMP_FAILURE_RETRY ((clockid == CLOCK_USE_TIMEDWAIT) + ? sem_timedwait (&s, &ts) + : sem_clockwait (&s, clockid, &ts)) != -1) { puts ("sem_timedwait succeeded"); return 1; @@ -73,7 +72,8 @@ do_test (void) } struct timespec ts2; - if (clock_gettime (CLOCK_REALTIME, &ts2) != 0) + if (clock_gettime (clockid == CLOCK_USE_TIMEDWAIT + ? CLOCK_REALTIME : clockid, &ts2) != 0) { puts ("clock_gettime failed"); return 1; @@ -89,5 +89,13 @@ do_test (void) return 0; } +static int do_test (void) +{ + do_test_clock (CLOCK_USE_TIMEDWAIT); + do_test_clock (CLOCK_REALTIME); + do_test_clock (CLOCK_MONOTONIC); + return 0; +} + #define TEST_FUNCTION do_test () #include "../test-skeleton.c" diff --git a/sysdeps/pthread/semaphore.h b/sysdeps/pthread/semaphore.h index 41ff927..2e68b16 100644 --- a/sysdeps/pthread/semaphore.h +++ b/sysdeps/pthread/semaphore.h @@ -59,6 +59,10 @@ extern int sem_wait (sem_t *__sem); __THROW. */ extern int sem_timedwait (sem_t *__restrict __sem, const struct timespec *__restrict __abstime); + +extern int sem_clockwait (sem_t *__restrict __sem, + clockid_t clock, + const struct timespec *__restrict __abstime); #endif /* Test whether SEM is posted. */ diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist index 931c827..454d340 100644 --- a/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist +++ b/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist @@ -245,6 +245,7 @@ GLIBC_2.3.4 pthread_attr_setaffinity_np F GLIBC_2.3.4 pthread_getaffinity_np F GLIBC_2.3.4 pthread_setaffinity_np F GLIBC_2.3.4 pthread_setschedprio F +GLIBC_2.30 sem_clockwait F GLIBC_2.4 pthread_mutex_consistent_np F GLIBC_2.4 pthread_mutex_getprioceiling F GLIBC_2.4 pthread_mutex_setprioceiling F