[2/7] nptl: Add POSIX-proposed sem_clockwait
Commit Message
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
Comments
On Wed, 27 Feb 2019, Mike Crowe wrote:
> * conform/data/semaphore.h-data: Likewise.
No, that's not appropriate; conform/ baselines are always for existing
standards, not what might appear in a new standard version. These
functions are not part of any current version of POSIX. If a future
version of POSIX (issue 8) adds them, the conform/ expectations will need
to be conditional so that the functions are only expected for POSIXyyyy ||
XOPENyyyy (where yyyy is the year of the new POSIX version in
_POSIX_C_SOURCE), not for any previous standard version.
The same of course applies to declarations in installed headers - they
should initially be conditional on __USE_GNU, potentially changing to a
new __USE_* macro when there's a new verison of POSIX. That applies to
all the functions, in all the patches.
On 27/02/2019 15:23, Mike Crowe wrote:
> 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
> + <http://www.gnu.org/licenses/>. */
> +
> +#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 <pthread.h>
> #include <internaltypes.h>
Not a requisite, but since you are touching the testcase it might a
good time to change it to use libsupport.
>
> +/* 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;
> }
Use TEST_VERIFY_EXIT (waitfn (&u.s, &ts) >= 0).
> if (errno != EINVAL)
> {
> - perror ("sem_timedwait did not fail with EINVAL");
> + printf ("%s did not fail with EINVAL: %m\n", fnname);
> return 1;
> }
Use TEST_COMPARE (errno, EINVAL).
> #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;
> }
Use TEST_COMPARE (nwaiters, 0).
>
> 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;
> }
As before.
> if (errno != ETIMEDOUT)
> {
> - perror ("2nd sem_timedwait did not fail with ETIMEDOUT");
> + printf ("2nd %s did not fail with ETIMEDOUT\n", fnname);
> return 1;
> }
As before.
> #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;
> }
As before.
>
> +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;
> +}
> +
Using libsupport there is no need to actually keep track of failure
statue. Just call each do_test_wait and return 0.
> #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 @@
Missing first line description.
> +/* 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
> + <http://www.gnu.org/licenses/>. */
> +
> +#include <errno.h>
> +#include <semaphore.h>
> +#include <stdio.h>
> +#include <time.h>
> +#include <unistd.h>
> +#include <sys/time.h>
> +
> +#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;
> + }
TEST_COMPARE (sem_init (&s, 0, 1), 0).
> +
> + 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;
> + }
TEST_VERIFY_EXIT (sem_clockwait (&s, NOT_A_VALID_CLOCK, &ts) != 0).
> + if (errno != EINVAL)
> + {
> + printf ("sem_clockwait yielded incorrect errno for invalid clock: %d\n",
> + errno);
> + return 1;
> + }
TEST_COMPARE (errno, EINVAL)).
> +
> + return 0;
> +}
> +
> +#include <support/test-driver.c>
> 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 <unistd.h>
> #include <sys/time.h>
As for tst-sem13.c, I think it would be good to adapt to libsupport.
>
> +/* 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
>
Hi,
Le mercredi 27 février 2019 à 18:23 +0000, Mike Crowe a écrit :
>
> 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);
Maybe it can be added with __nonnull ((3)) attribute ?
> #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
Why is it only added to linux x86_64 ?
Regards
On Thursday 14 March 2019 at 15:09:35 +0100, Yann Droneaud wrote:
> Hi,
>
> Le mercredi 27 février 2019 à 18:23 +0000, Mike Crowe a écrit :
> >
> > 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);
>
> Maybe it can be added with __nonnull ((3)) attribute ?
I was just copying sem_timedwait, but I don't believe there's a reason why
I can't add that.
> > #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
>
> Why is it only added to linux x86_64 ?
Because I wanted to wait to see if the patches were acceptable before
updating all the abilist files.
Mike.
@@ -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*)
@@ -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
@@ -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 \
@@ -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;
new file mode 100644
@@ -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
+ <http://www.gnu.org/licenses/>. */
+
+#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);
+}
@@ -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);
}
@@ -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);
@@ -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);
@@ -5,9 +5,14 @@
#include <pthread.h>
#include <internaltypes.h>
+/* 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"
new file mode 100644
@@ -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
+ <http://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <semaphore.h>
+#include <stdio.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/time.h>
+
+#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 <support/test-driver.c>
@@ -23,13 +23,15 @@
#include <unistd.h>
#include <sys/time.h>
+/* 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"
@@ -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. */
@@ -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