nptl: Add POSIX-proposed pthread_rwlock_clockrdlock & pthread_rwlock_clockwrlock

Add:
 int pthread_rwlock_clockrdlock (pthread_rwlock_t *rwlock,
                                 clockid_t clockid,
                                 const struct timespec *abstime)
and:
 int pthread_rwlock_clockwrlock (pthread_rwlock_t *rwlock,
                                 clockid_t clockid,
                                 const struct timespec *abstime)

which behave like pthread_rwlock_timedrdlock and
pthread_rwlock_timedwrlock respectively, except they always measure
abstime against the supplied clockid. The functions currently support
CLOCK_REALTIME and CLOCK_MONOTONIC and return EINVAL if any other
clock is specified.

	* sysdeps/nptl/pthread.h: Add pthread_rwlock_clockrdlock and
	pthread_wrlock_clockwrlock.
	* nptl/Makefile: Build pthread_rwlock_clockrdlock.c and
	pthread_rwlock_clockwrlock.c.
	* nptl/pthread_rwlock_clockrdlock.c: Implement
	pthread_rwlock_clockrdlock.
	* nptl/pthread_rwlock_clockwrlock.c: Implement
	pthread_rwlock_clockwrlock.
	* nptl/pthread_rwlock_common.c (__pthread_rwlock_rdlock_full): Add
	clockid parameter and verify that it indicates a supported clock on
	entry so that we fail even if it doesn't end up being used. Pass
	that clock on to futex_abstimed_wait when necessary.
	(__pthread_rwlock_wrlock_full): Likewise.
	* nptl/pthread_rwlock_rdlock.c: (__pthread_rwlock_rdlock): Pass
	CLOCK_REALTIME to __pthread_rwlock_rdlock_full even though it won't
	be used because there's no timeout.
	* nptl/pthread_rwlock_wrlock.c (__pthread_rwlock_wrlock): Pass
	CLOCK_REALTIME to __pthread_rwlock_wrlock_full even though it won't
	be used because there is no timeout.
	* nptl/pthread_rwlock_timedrdlock.c (pthread_rwlock_timedrdlock):
	Pass CLOCK_REALTIME to __pthread_rwlock_rdlock_full since abstime
	uses that clock.
	* nptl/pthread_rwlock_timedwrlock.c (pthread_rwlock_timedwrlock):
	Pass CLOCK_REALTIME to __pthread_rwlock_wrlock_full since abstime
	uses that clock.
	* sysdeps/unix/sysv/linux/aarch64/libpthread.abilist (GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/alpha/libpthread.abilist (GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/arm/libpthread.abilist (GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/csky/libpthread.abilist (GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/hppa/libpthread.abilist (GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/i386/libpthread.abilist (GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/ia64/libpthread.abilist (GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/m68k/coldfire/libpthread.abilist
	(GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/m68k/m680x0/libpthread.abilist
	(GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/microblaze/libpthread.abilist
	(GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/mips/mips32/libpthread.abilist
	(GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/mips/mips64/libpthread.abilist
	(GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/nios2/libpthread.abilist (GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc32/libpthread.abilist
	(GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libpthread.abilist
	(GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libpthread.abilist
	(GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/riscv/rv64/libpthread.abilist
	(GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/s390/s390-32/libpthread.abilist
	(GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/s390/s390-64/libpthread.abilist
	(GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/sh/libpthread.abilist (GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/sparc/sparc32/libpthread.abilist
	(GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/sparc/sparc64/libpthread.abilist
	(GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist
	(GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/x86_64/x32/libpthread.abilist
	(GLIBC_2.30): Likewise.
	* nptl/tst-abstime.c (th): Add pthread_rwlock_clockrdlock and
	pthread_rwlock_clockwrlock timeout tests to match the existing
	pthread_rwlock_timedrdloock and pthread_rwlock_timedwrlock tests.
	* nptl/tst-rwlock14.c (do_test): Likewise.
	* nptl/tst-rwlock6.c Invent verbose_printf macro, and use for
	ancillary output throughout. (tf): Accept thread_args structure so
	that rwlock, a clockid and function name can be passed to the
	thread. (do_test_clock): Rename from do_test. Accept clockid
	parameter to specify test clock. Use the magic clockid value of
	CLOCK_USE_TIMEDLOCK to indicate that pthread_rwlock_timedrdlock and
	pthread_rwlock_timedwrlock should be tested, otherwise pass the
	specified clockid to pthread_rwlock_clockrdlock and
	pthread_rwlock_clockwrlock. Use xpthread_create and xpthread_join.
	(do_test): Call do_test_clock to test each clockid in turn.
	* nptl/tst-rwlock7.c: Likewise.
	* nptl/tst-rwlock9.c (writer_thread, reader_thread): Accept
	thread_args structure so that the (now int) thread number, the
	clockid and the function name can be passed to the thread.
	(do_test_clock): Renamed from do_test. Pass the necessary
	thread_args when creating the reader and writer threads. Use
	xpthread_create and xpthread_join.
	(do_test): Call do_test_clock to test each clockid in turn.
	* manual/threads.texi: Add documentation for
	pthread_rwlock_clockrdlock and pthread_rwlock_clockwrclock.

Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
This commit is contained in:
Mike Crowe 2019-06-24 13:05:27 +00:00 committed by Adhemerval Zanella
parent 600b4be4d9
commit e996fa72a9
41 changed files with 490 additions and 97 deletions

View File

@ -1,5 +1,101 @@
2019-07-12 Mike Crowe <mac@mcrowe.com> 2019-07-12 Mike Crowe <mac@mcrowe.com>
nptl: Add POSIX-proposed pthread_rwlock_clockrdlock &
pthread_rwlock_clockwrlock which behave like
pthread_rwlock_timedrdlock and pthread_rwlock_timedwrlock
respectively, except they always measure abstime against the
supplied clockid. The functions currently support CLOCK_REALTIME
and CLOCK_MONOTONIC and return EINVAL if any other clock is
specified.
* sysdeps/nptl/pthread.h: Add pthread_rwlock_clockrdlock and
pthread_wrlock_clockwrlock.
* nptl/Makefile: Build pthread_rwlock_clockrdlock.c and
pthread_rwlock_clockwrlock.c.
* nptl/pthread_rwlock_clockrdlock.c: Implement
pthread_rwlock_clockrdlock.
* nptl/pthread_rwlock_clockwrlock.c: Implement
pthread_rwlock_clockwrlock.
* nptl/pthread_rwlock_common.c (__pthread_rwlock_rdlock_full): Add
clockid parameter and verify that it indicates a supported clock on
entry so that we fail even if it doesn't end up being used. Pass
that clock on to futex_abstimed_wait when necessary.
(__pthread_rwlock_wrlock_full): Likewise.
* nptl/pthread_rwlock_rdlock.c: (__pthread_rwlock_rdlock): Pass
CLOCK_REALTIME to __pthread_rwlock_rdlock_full even though it won't
be used because there's no timeout.
* nptl/pthread_rwlock_wrlock.c (__pthread_rwlock_wrlock): Pass
CLOCK_REALTIME to __pthread_rwlock_wrlock_full even though it won't
be used because there is no timeout.
* nptl/pthread_rwlock_timedrdlock.c (pthread_rwlock_timedrdlock):
Pass CLOCK_REALTIME to __pthread_rwlock_rdlock_full since abstime
uses that clock.
* nptl/pthread_rwlock_timedwrlock.c (pthread_rwlock_timedwrlock):
Pass CLOCK_REALTIME to __pthread_rwlock_wrlock_full since abstime
uses that clock.
* sysdeps/unix/sysv/linux/aarch64/libpthread.abilist (GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/alpha/libpthread.abilist (GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/arm/libpthread.abilist (GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/csky/libpthread.abilist (GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/hppa/libpthread.abilist (GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/i386/libpthread.abilist (GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/ia64/libpthread.abilist (GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/m68k/coldfire/libpthread.abilist
(GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/m68k/m680x0/libpthread.abilist
(GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/microblaze/libpthread.abilist
(GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/mips/mips32/libpthread.abilist
(GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/mips/mips64/libpthread.abilist
(GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/nios2/libpthread.abilist (GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/powerpc/powerpc32/libpthread.abilist
(GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libpthread.abilist
(GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libpthread.abilist
(GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/riscv/rv64/libpthread.abilist
(GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/s390/s390-32/libpthread.abilist
(GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/s390/s390-64/libpthread.abilist
(GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/sh/libpthread.abilist (GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/sparc/sparc32/libpthread.abilist
(GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/sparc/sparc64/libpthread.abilist
(GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist
(GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/x86_64/x32/libpthread.abilist
(GLIBC_2.30): Likewise.
* nptl/tst-abstime.c (th): Add pthread_rwlock_clockrdlock and
pthread_rwlock_clockwrlock timeout tests to match the existing
pthread_rwlock_timedrdloock and pthread_rwlock_timedwrlock tests.
* nptl/tst-rwlock14.c (do_test): Likewise.
* nptl/tst-rwlock6.c Invent verbose_printf macro, and use for
ancillary output throughout. (tf): Accept thread_args structure so
that rwlock, a clockid and function name can be passed to the
thread. (do_test_clock): Rename from do_test. Accept clockid
parameter to specify test clock. Use the magic clockid value of
CLOCK_USE_TIMEDLOCK to indicate that pthread_rwlock_timedrdlock and
pthread_rwlock_timedwrlock should be tested, otherwise pass the
specified clockid to pthread_rwlock_clockrdlock and
pthread_rwlock_clockwrlock. Use xpthread_create and xpthread_join.
(do_test): Call do_test_clock to test each clockid in turn.
* nptl/tst-rwlock7.c: Likewise.
* nptl/tst-rwlock9.c (writer_thread, reader_thread): Accept
thread_args structure so that the (now int) thread number, the
clockid and the function name can be passed to the thread.
(do_test_clock): Renamed from do_test. Pass the necessary
thread_args when creating the reader and writer threads. Use
xpthread_create and xpthread_join.
(do_test): Call do_test_clock to test each clockid in turn.
* manual/threads.texi: Add documentation for
pthread_rwlock_clockrdlock and pthread_rwlock_clockwrclock.
nptl: pthread_rwlock: Move timeout validation into _full functions nptl: pthread_rwlock: Move timeout validation into _full functions
* nptl/pthread_rwlock_common.c (__pthread_rwlock_rdlock_full): * nptl/pthread_rwlock_common.c (__pthread_rwlock_rdlock_full):
Check validity of abstime parameter. Check validity of abstime parameter.

View File

@ -699,6 +699,34 @@ specified or defaulted when @code{pthread_cond_init} was called. Currently,
@code{CLOCK_REALTIME}. @code{CLOCK_REALTIME}.
@end deftypefun @end deftypefun
@comment pthread.h
@comment POSIX-proposed
@deftypefun int pthread_rwlock_clockrdlock (pthread_rwlock_t *@var{rwlock},
clockid_t @var{clockid},
const struct timespec *@var{abstime})
@safety{@prelim{}@mtsafe{}@asunsafe{@asulock{}}@acunsafe{@aculock{}}}
Behaves like @code{pthread_rwlock_timedrdlock} 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}, otherwise @code{EINVAL} is
returned.
@end deftypefun
@comment pthread.h
@comment POSIX-proposed
@deftypefun int pthread_rwlock_clockwrlock (pthread_rwlock_t *@var{rwlock},
clockid_t @var{clockid},
const struct timespec *@var{abstime})
@safety{@prelim{}@mtsafe{}@asunsafe{@asulock{}}@acunsafe{@aculock{}}}
Behaves like @code{pthread_rwlock_timedwrlock} 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}, otherwise @code{EINVAL} is
returned.
@end deftypefun
@c FIXME these are undocumented: @c FIXME these are undocumented:
@c pthread_atfork @c pthread_atfork
@c pthread_attr_destroy @c pthread_attr_destroy

View File

@ -76,7 +76,9 @@ libpthread-routines = nptl-init nptlfreeres vars events version pt-interp \
pthread_mutexattr_gettype pthread_mutexattr_settype \ pthread_mutexattr_gettype pthread_mutexattr_settype \
pthread_rwlock_init pthread_rwlock_destroy \ pthread_rwlock_init pthread_rwlock_destroy \
pthread_rwlock_rdlock pthread_rwlock_timedrdlock \ pthread_rwlock_rdlock pthread_rwlock_timedrdlock \
pthread_rwlock_clockrdlock \
pthread_rwlock_wrlock pthread_rwlock_timedwrlock \ pthread_rwlock_wrlock pthread_rwlock_timedwrlock \
pthread_rwlock_clockwrlock \
pthread_rwlock_tryrdlock pthread_rwlock_trywrlock \ pthread_rwlock_tryrdlock pthread_rwlock_trywrlock \
pthread_rwlock_unlock \ pthread_rwlock_unlock \
pthread_rwlockattr_init pthread_rwlockattr_destroy \ pthread_rwlockattr_init pthread_rwlockattr_destroy \

View File

@ -278,6 +278,7 @@ libpthread {
GLIBC_2.30 { GLIBC_2.30 {
sem_clockwait; pthread_cond_clockwait; sem_clockwait; pthread_cond_clockwait;
pthread_rwlock_clockrdlock; pthread_rwlock_clockwrlock;
} }
GLIBC_PRIVATE { GLIBC_PRIVATE {

View File

@ -0,0 +1,28 @@
/* Implement pthread_rwlock_clockrdlock.
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 "pthread_rwlock_common.c"
/* See pthread_rwlock_common.c. */
int
pthread_rwlock_clockrdlock (pthread_rwlock_t *rwlock, clockid_t clockid,
const struct timespec *abstime)
{
return __pthread_rwlock_rdlock_full (rwlock, clockid, abstime);
}

View File

@ -0,0 +1,28 @@
/* Implement pthread_rwlock_clockwrlock.
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 "pthread_rwlock_common.c"
/* See pthread_rwlock_common.c. */
int
pthread_rwlock_clockwrlock (pthread_rwlock_t *rwlock, clockid_t clockid,
const struct timespec *abstime)
{
return __pthread_rwlock_wrlock_full (rwlock, clockid, abstime);
}

View File

@ -278,17 +278,19 @@ __pthread_rwlock_rdunlock (pthread_rwlock_t *rwlock)
static __always_inline int static __always_inline int
__pthread_rwlock_rdlock_full (pthread_rwlock_t *rwlock, __pthread_rwlock_rdlock_full (pthread_rwlock_t *rwlock,
clockid_t clockid,
const struct timespec *abstime) const struct timespec *abstime)
{ {
unsigned int r; unsigned int r;
/* Make sure any passed in timeout value is valid. Note that the previous /* Make sure any passed in clockid and timeout value are valid. Note that
implementation assumed that this check *must* not be performed if there the previous implementation assumed that this check *must* not be
would in fact be no blocking; however, POSIX only requires that "the performed if there would in fact be no blocking; however, POSIX only
validity of the abstime parameter need not be checked if the lock can be requires that "the validity of the abstime parameter need not be checked
immediately acquired" (i.e., we need not but may check it). */ if the lock can be immediately acquired" (i.e., we need not but may check
if (abstime it). */
&& __glibc_unlikely (abstime->tv_nsec >= 1000000000 if (abstime && __glibc_unlikely (!futex_abstimed_supported_clockid (clockid)
|| abstime->tv_nsec >= 1000000000
|| abstime->tv_nsec < 0)) || abstime->tv_nsec < 0))
return EINVAL; return EINVAL;
@ -329,7 +331,7 @@ __pthread_rwlock_rdlock_full (pthread_rwlock_t *rwlock,
{ {
int private = __pthread_rwlock_get_private (rwlock); int private = __pthread_rwlock_get_private (rwlock);
int err = futex_abstimed_wait (&rwlock->__data.__readers, int err = futex_abstimed_wait (&rwlock->__data.__readers,
r, CLOCK_REALTIME, abstime, private); r, clockid, abstime, private);
/* We ignore EAGAIN and EINTR. On time-outs, we can just /* We ignore EAGAIN and EINTR. On time-outs, we can just
return because we don't need to clean up anything. */ return because we don't need to clean up anything. */
if (err == ETIMEDOUT) if (err == ETIMEDOUT)
@ -457,7 +459,7 @@ __pthread_rwlock_rdlock_full (pthread_rwlock_t *rwlock,
continue; continue;
int err = futex_abstimed_wait (&rwlock->__data.__wrphase_futex, int err = futex_abstimed_wait (&rwlock->__data.__wrphase_futex,
1 | PTHREAD_RWLOCK_FUTEX_USED, 1 | PTHREAD_RWLOCK_FUTEX_USED,
CLOCK_REALTIME, abstime, private); clockid, abstime, private);
if (err == ETIMEDOUT) if (err == ETIMEDOUT)
{ {
/* If we timed out, we need to unregister. If no read phase /* If we timed out, we need to unregister. If no read phase
@ -584,15 +586,17 @@ __pthread_rwlock_wrunlock (pthread_rwlock_t *rwlock)
static __always_inline int static __always_inline int
__pthread_rwlock_wrlock_full (pthread_rwlock_t *rwlock, __pthread_rwlock_wrlock_full (pthread_rwlock_t *rwlock,
clockid_t clockid,
const struct timespec *abstime) const struct timespec *abstime)
{ {
/* Make sure any passed in timeout value is valid. Note that the previous /* Make sure any passed in clockid and timeout value are valid. Note that
implementation assumed that this check *must* not be performed if there the previous implementation assumed that this check *must* not be
would in fact be no blocking; however, POSIX only requires that "the performed if there would in fact be no blocking; however, POSIX only
validity of the abstime parameter need not be checked if the lock can be requires that "the validity of the abstime parameter need not be checked
immediately acquired" (i.e., we need not but may check it). */ if the lock can be immediately acquired" (i.e., we need not but may check
if (abstime it). */
&& __glibc_unlikely (abstime->tv_nsec >= 1000000000 if (abstime && __glibc_unlikely (!futex_abstimed_supported_clockid (clockid)
|| abstime->tv_nsec >= 1000000000
|| abstime->tv_nsec < 0)) || abstime->tv_nsec < 0))
return EINVAL; return EINVAL;
@ -727,7 +731,7 @@ __pthread_rwlock_wrlock_full (pthread_rwlock_t *rwlock,
may_share_futex_used_flag = true; may_share_futex_used_flag = true;
int err = futex_abstimed_wait (&rwlock->__data.__writers_futex, int err = futex_abstimed_wait (&rwlock->__data.__writers_futex,
1 | PTHREAD_RWLOCK_FUTEX_USED, 1 | PTHREAD_RWLOCK_FUTEX_USED,
CLOCK_REALTIME, abstime, private); clockid, abstime, private);
if (err == ETIMEDOUT) if (err == ETIMEDOUT)
{ {
if (prefer_writer) if (prefer_writer)
@ -826,7 +830,7 @@ __pthread_rwlock_wrlock_full (pthread_rwlock_t *rwlock,
continue; continue;
int err = futex_abstimed_wait (&rwlock->__data.__wrphase_futex, int err = futex_abstimed_wait (&rwlock->__data.__wrphase_futex,
PTHREAD_RWLOCK_FUTEX_USED, PTHREAD_RWLOCK_FUTEX_USED,
CLOCK_REALTIME, abstime, private); clockid, abstime, private);
if (err == ETIMEDOUT) if (err == ETIMEDOUT)
{ {
if (rwlock->__data.__flags != PTHREAD_RWLOCK_PREFER_READER_NP) if (rwlock->__data.__flags != PTHREAD_RWLOCK_PREFER_READER_NP)

View File

@ -24,7 +24,7 @@ __pthread_rwlock_rdlock (pthread_rwlock_t *rwlock)
{ {
LIBC_PROBE (rdlock_entry, 1, rwlock); LIBC_PROBE (rdlock_entry, 1, rwlock);
int result = __pthread_rwlock_rdlock_full (rwlock, NULL); int result = __pthread_rwlock_rdlock_full (rwlock, CLOCK_REALTIME, NULL);
LIBC_PROBE (rdlock_acquire_read, 1, rwlock); LIBC_PROBE (rdlock_acquire_read, 1, rwlock);
return result; return result;
} }

View File

@ -23,5 +23,5 @@ int
pthread_rwlock_timedrdlock (pthread_rwlock_t *rwlock, pthread_rwlock_timedrdlock (pthread_rwlock_t *rwlock,
const struct timespec *abstime) const struct timespec *abstime)
{ {
return __pthread_rwlock_rdlock_full (rwlock, abstime); return __pthread_rwlock_rdlock_full (rwlock, CLOCK_REALTIME, abstime);
} }

View File

@ -23,5 +23,5 @@ int
pthread_rwlock_timedwrlock (pthread_rwlock_t *rwlock, pthread_rwlock_timedwrlock (pthread_rwlock_t *rwlock,
const struct timespec *abstime) const struct timespec *abstime)
{ {
return __pthread_rwlock_wrlock_full (rwlock, abstime); return __pthread_rwlock_wrlock_full (rwlock, CLOCK_REALTIME, abstime);
} }

View File

@ -24,7 +24,7 @@ __pthread_rwlock_wrlock (pthread_rwlock_t *rwlock)
{ {
LIBC_PROBE (wrlock_entry, 1, rwlock); LIBC_PROBE (wrlock_entry, 1, rwlock);
int result = __pthread_rwlock_wrlock_full (rwlock, NULL); int result = __pthread_rwlock_wrlock_full (rwlock, CLOCK_REALTIME, NULL);
LIBC_PROBE (wrlock_acquire_write, 1, rwlock); LIBC_PROBE (wrlock_acquire_write, 1, rwlock);
return result; return result;
} }

View File

@ -38,6 +38,14 @@ th (void *arg)
TEST_COMPARE (pthread_mutex_timedlock (&m1, &t), ETIMEDOUT); TEST_COMPARE (pthread_mutex_timedlock (&m1, &t), ETIMEDOUT);
TEST_COMPARE (pthread_rwlock_timedrdlock (&rw1, &t), ETIMEDOUT); TEST_COMPARE (pthread_rwlock_timedrdlock (&rw1, &t), ETIMEDOUT);
TEST_COMPARE (pthread_rwlock_timedwrlock (&rw2, &t), ETIMEDOUT); TEST_COMPARE (pthread_rwlock_timedwrlock (&rw2, &t), ETIMEDOUT);
TEST_COMPARE (pthread_rwlock_clockrdlock (&rw1, CLOCK_REALTIME, &t),
ETIMEDOUT);
TEST_COMPARE (pthread_rwlock_clockwrlock (&rw2, CLOCK_REALTIME, &t),
ETIMEDOUT);
TEST_COMPARE (pthread_rwlock_clockrdlock (&rw1, CLOCK_MONOTONIC, &t),
ETIMEDOUT);
TEST_COMPARE (pthread_rwlock_clockwrlock (&rw2, CLOCK_MONOTONIC, &t),
ETIMEDOUT);
return NULL; return NULL;
} }

View File

@ -64,19 +64,31 @@ do_test (void)
ts.tv_nsec = -1; ts.tv_nsec = -1;
TEST_COMPARE (pthread_rwlock_timedrdlock (&r, &ts), EINVAL); TEST_COMPARE (pthread_rwlock_timedrdlock (&r, &ts), EINVAL);
TEST_COMPARE (pthread_rwlock_clockrdlock (&r, CLOCK_REALTIME, &ts), EINVAL);
TEST_COMPARE (pthread_rwlock_clockrdlock (&r, CLOCK_MONOTONIC, &ts), EINVAL);
TEST_COMPARE (pthread_rwlock_timedwrlock (&r, &ts), EINVAL); TEST_COMPARE (pthread_rwlock_timedwrlock (&r, &ts), EINVAL);
TEST_COMPARE (pthread_rwlock_clockwrlock (&r, CLOCK_REALTIME, &ts), EINVAL);
TEST_COMPARE (pthread_rwlock_clockwrlock (&r, CLOCK_MONOTONIC, &ts), EINVAL);
ts.tv_nsec = 1000000000; ts.tv_nsec = 1000000000;
TEST_COMPARE (pthread_rwlock_timedrdlock (&r, &ts), EINVAL); TEST_COMPARE (pthread_rwlock_timedrdlock (&r, &ts), EINVAL);
TEST_COMPARE (pthread_rwlock_clockrdlock (&r, CLOCK_REALTIME, &ts), EINVAL);
TEST_COMPARE (pthread_rwlock_clockrdlock (&r, CLOCK_MONOTONIC, &ts), EINVAL);
TEST_COMPARE (pthread_rwlock_timedwrlock (&r, &ts), EINVAL); TEST_COMPARE (pthread_rwlock_timedwrlock (&r, &ts), EINVAL);
TEST_COMPARE (pthread_rwlock_clockwrlock (&r, CLOCK_REALTIME, &ts), EINVAL);
TEST_COMPARE (pthread_rwlock_clockwrlock (&r, CLOCK_MONOTONIC, &ts), EINVAL);
ts.tv_nsec = (__typeof (ts.tv_nsec)) 0x100001000LL; ts.tv_nsec = (__typeof (ts.tv_nsec)) 0x100001000LL;
if ((__typeof (ts.tv_nsec)) 0x100001000LL != 0x100001000LL) if ((__typeof (ts.tv_nsec)) 0x100001000LL != 0x100001000LL)
ts.tv_nsec = 2000000000; ts.tv_nsec = 2000000000;
TEST_COMPARE (pthread_rwlock_timedrdlock (&r, &ts), EINVAL); TEST_COMPARE (pthread_rwlock_timedrdlock (&r, &ts), EINVAL);
TEST_COMPARE (pthread_rwlock_clockrdlock (&r, CLOCK_REALTIME, &ts), EINVAL);
TEST_COMPARE (pthread_rwlock_clockrdlock (&r, CLOCK_MONOTONIC, &ts), EINVAL);
TEST_COMPARE (pthread_rwlock_timedwrlock (&r, &ts), EINVAL); TEST_COMPARE (pthread_rwlock_timedwrlock (&r, &ts), EINVAL);
TEST_COMPARE (pthread_rwlock_clockwrlock (&r, CLOCK_REALTIME, &ts), EINVAL);
TEST_COMPARE (pthread_rwlock_clockwrlock (&r, CLOCK_MONOTONIC, &ts), EINVAL);
return 0; return 0;
} }

View File

@ -23,11 +23,17 @@
#include <string.h> #include <string.h>
#include <sys/time.h> #include <sys/time.h>
#include <support/check.h> #include <support/check.h>
#include <support/test-driver.h>
#include <support/timespec.h> #include <support/timespec.h>
#include <support/xthread.h> #include <support/xthread.h>
#include <support/xtime.h> #include <support/xtime.h>
/* A bogus clock value that tells run_test to use pthread_rwlock_timedrdlock
and pthread_rwlock_timedwrlock rather than pthread_rwlock_clockrdlock and
pthread_rwlock_clockwrlock. */
#define CLOCK_USE_TIMEDLOCK (-1)
static int kind[] = static int kind[] =
{ {
PTHREAD_RWLOCK_PREFER_READER_NP, PTHREAD_RWLOCK_PREFER_READER_NP,
@ -35,43 +41,63 @@ static int kind[] =
PTHREAD_RWLOCK_PREFER_WRITER_NP, PTHREAD_RWLOCK_PREFER_WRITER_NP,
}; };
struct thread_args
{
pthread_rwlock_t *rwlock;
clockid_t clockid;
const char *fnname;
};
static void * static void *
tf (void *arg) tf (void *arg)
{ {
pthread_rwlock_t *r = arg; struct thread_args *args = arg;
pthread_rwlock_t *r = args->rwlock;
const clockid_t clockid = args->clockid;
const clockid_t clockid_for_get =
(clockid == CLOCK_USE_TIMEDLOCK) ? CLOCK_REALTIME : clockid;
const char *fnname = args->fnname;
/* Timeout: 0.3 secs. */ /* Timeout: 0.3 secs. */
struct timespec ts_start; struct timespec ts_start;
xclock_gettime (CLOCK_REALTIME, &ts_start); xclock_gettime (clockid_for_get, &ts_start);
struct timespec ts_timeout = timespec_add (ts_start, struct timespec ts_timeout = timespec_add (ts_start,
make_timespec (0, 300000000)); make_timespec (0, 300000000));
puts ("child calling timedrdlock"); verbose_printf ("child calling %srdlock\n", fnname);
if (clockid == CLOCK_USE_TIMEDLOCK)
TEST_COMPARE (pthread_rwlock_timedrdlock (r, &ts_timeout), ETIMEDOUT); TEST_COMPARE (pthread_rwlock_timedrdlock (r, &ts_timeout), ETIMEDOUT);
else
TEST_COMPARE (pthread_rwlock_clockrdlock (r, clockid, &ts_timeout),
ETIMEDOUT);
puts ("1st child timedrdlock done"); verbose_printf ("1st child %srdlock done\n", fnname);
TEST_TIMESPEC_NOW_OR_AFTER (CLOCK_REALTIME, ts_timeout); TEST_TIMESPEC_NOW_OR_AFTER (CLOCK_REALTIME, ts_timeout);
xclock_gettime (CLOCK_REALTIME, &ts_timeout); xclock_gettime (clockid_for_get, &ts_timeout);
ts_timeout.tv_sec += 10; ts_timeout.tv_sec += 10;
/* Note that the following operation makes ts invalid. */ /* Note that the following operation makes ts invalid. */
ts_timeout.tv_nsec += 1000000000; ts_timeout.tv_nsec += 1000000000;
if (clockid == CLOCK_USE_TIMEDLOCK)
TEST_COMPARE (pthread_rwlock_timedrdlock (r, &ts_timeout), EINVAL); TEST_COMPARE (pthread_rwlock_timedrdlock (r, &ts_timeout), EINVAL);
else
TEST_COMPARE (pthread_rwlock_clockrdlock (r, clockid, &ts_timeout), EINVAL);
puts ("2nd child timedrdlock done"); verbose_printf ("2nd child %srdlock done\n", fnname);
return NULL; return NULL;
} }
static int static int
do_test (void) do_test_clock (clockid_t clockid, const char *fnname)
{ {
const clockid_t clockid_for_get =
(clockid == CLOCK_USE_TIMEDLOCK) ? CLOCK_REALTIME : clockid;
size_t cnt; size_t cnt;
for (cnt = 0; cnt < sizeof (kind) / sizeof (kind[0]); ++cnt) for (cnt = 0; cnt < sizeof (kind) / sizeof (kind[0]); ++cnt)
{ {
@ -91,39 +117,46 @@ do_test (void)
FAIL_EXIT1 ("round %Zu: rwlockattr_destroy failed\n", cnt); FAIL_EXIT1 ("round %Zu: rwlockattr_destroy failed\n", cnt);
struct timespec ts; struct timespec ts;
xclock_gettime (CLOCK_REALTIME, &ts); xclock_gettime (clockid_for_get, &ts);
++ts.tv_sec; ++ts.tv_sec;
/* Get a write lock. */ /* Get a write lock. */
int e = pthread_rwlock_timedwrlock (&r, &ts); int e = (clockid == CLOCK_USE_TIMEDLOCK)
? pthread_rwlock_timedwrlock (&r, &ts)
: pthread_rwlock_clockwrlock (&r, clockid, &ts);
if (e != 0) if (e != 0)
FAIL_EXIT1 ("round %Zu: rwlock_timedwrlock failed (%d)\n", cnt, e); FAIL_EXIT1 ("round %Zu: %swrlock failed (%d)\n",
cnt, fnname, e);
puts ("1st timedwrlock done"); verbose_printf ("1st %swrlock done\n", fnname);
xclock_gettime (CLOCK_REALTIME, &ts); xclock_gettime (clockid_for_get, &ts);
++ts.tv_sec; ++ts.tv_sec;
if (clockid == CLOCK_USE_TIMEDLOCK)
TEST_COMPARE (pthread_rwlock_timedrdlock (&r, &ts), EDEADLK); TEST_COMPARE (pthread_rwlock_timedrdlock (&r, &ts), EDEADLK);
else
TEST_COMPARE (pthread_rwlock_clockrdlock (&r, clockid, &ts), EDEADLK);
puts ("1st timedrdlock done"); verbose_printf ("1st %srdlock done\n", fnname);
xclock_gettime (CLOCK_REALTIME, &ts); xclock_gettime (clockid_for_get, &ts);
++ts.tv_sec; ++ts.tv_sec;
if (clockid == CLOCK_USE_TIMEDLOCK)
TEST_COMPARE (pthread_rwlock_timedwrlock (&r, &ts), EDEADLK); TEST_COMPARE (pthread_rwlock_timedwrlock (&r, &ts), EDEADLK);
else
TEST_COMPARE (pthread_rwlock_clockwrlock (&r, clockid, &ts), EDEADLK);
puts ("2nd timedwrlock done"); verbose_printf ("2nd %swrlock done\n", fnname);
pthread_t th; struct thread_args args;
if (pthread_create (&th, NULL, tf, &r) != 0) args.rwlock = &r;
FAIL_EXIT1 ("round %Zu: create failed\n", cnt); args.clockid = clockid;
args.fnname = fnname;
pthread_t th = xpthread_create (NULL, tf, &args);
puts ("started thread"); puts ("started thread");
void *status; (void) xpthread_join (th);
if (pthread_join (th, &status) != 0)
FAIL_EXIT1 ("round %Zu: join failed\n", cnt);
if (status != NULL)
FAIL_EXIT1 ("failure in round %Zu\n", cnt);
puts ("joined thread"); puts ("joined thread");
@ -134,4 +167,12 @@ do_test (void)
return 0; return 0;
} }
static int do_test (void)
{
do_test_clock (CLOCK_USE_TIMEDLOCK, "timed");
do_test_clock (CLOCK_REALTIME, "clock(realtime)");
do_test_clock (CLOCK_MONOTONIC, "clock(monotonic)");
return 0;
}
#include <support/test-driver.c> #include <support/test-driver.c>

View File

@ -28,6 +28,11 @@
#include <support/xtime.h> #include <support/xtime.h>
/* A bogus clock value that tells run_test to use pthread_rwlock_timedrdlock
and pthread_rwlock_timedwrlock rather than pthread_rwlock_clockrdlock and
pthread_rwlock_clockwrlock. */
#define CLOCK_USE_TIMEDLOCK (-1)
static int kind[] = static int kind[] =
{ {
PTHREAD_RWLOCK_PREFER_READER_NP, PTHREAD_RWLOCK_PREFER_READER_NP,
@ -35,40 +40,60 @@ static int kind[] =
PTHREAD_RWLOCK_PREFER_WRITER_NP, PTHREAD_RWLOCK_PREFER_WRITER_NP,
}; };
struct thread_args
{
pthread_rwlock_t *rwlock;
clockid_t clockid;
const char *fnname;
};
static void * static void *
tf (void *arg) tf (void *arg)
{ {
pthread_rwlock_t *r = arg; struct thread_args *args = arg;
pthread_rwlock_t *r = args->rwlock;
const clockid_t clockid = args->clockid;
const clockid_t clockid_for_get =
(clockid == CLOCK_USE_TIMEDLOCK) ? CLOCK_REALTIME : clockid;
const char *fnname = args->fnname;
/* Timeout: 0.3 secs. */ /* Timeout: 0.3 secs. */
struct timespec ts_start; struct timespec ts_start;
xclock_gettime (CLOCK_REALTIME, &ts_start); xclock_gettime (clockid_for_get, &ts_start);
const struct timespec ts_timeout = timespec_add (ts_start, const struct timespec ts_timeout = timespec_add (ts_start,
make_timespec (0, 300000000)); make_timespec (0, 300000000));
if (clockid == CLOCK_USE_TIMEDLOCK)
TEST_COMPARE (pthread_rwlock_timedwrlock (r, &ts_timeout), ETIMEDOUT); TEST_COMPARE (pthread_rwlock_timedwrlock (r, &ts_timeout), ETIMEDOUT);
puts ("child: timedwrlock failed with ETIMEDOUT"); else
TEST_COMPARE (pthread_rwlock_clockwrlock (r, clockid, &ts_timeout),
ETIMEDOUT);
printf ("child: %swrlock failed with ETIMEDOUT", fnname);
TEST_TIMESPEC_NOW_OR_AFTER (CLOCK_REALTIME, ts_timeout); TEST_TIMESPEC_NOW_OR_AFTER (clockid_for_get, ts_timeout);
struct timespec ts_invalid; struct timespec ts_invalid;
xclock_gettime (CLOCK_REALTIME, &ts_invalid); xclock_gettime (clockid_for_get, &ts_invalid);
ts_invalid.tv_sec += 10; ts_invalid.tv_sec += 10;
/* Note that the following operation makes ts invalid. */ /* Note that the following operation makes ts invalid. */
ts_invalid.tv_nsec += 1000000000; ts_invalid.tv_nsec += 1000000000;
if (clockid == CLOCK_USE_TIMEDLOCK)
TEST_COMPARE (pthread_rwlock_timedwrlock (r, &ts_invalid), EINVAL); TEST_COMPARE (pthread_rwlock_timedwrlock (r, &ts_invalid), EINVAL);
else
TEST_COMPARE (pthread_rwlock_clockwrlock (r, clockid, &ts_invalid), EINVAL);
puts ("child: timedwrlock failed with EINVAL"); printf ("child: %swrlock failed with EINVAL", fnname);
return NULL; return NULL;
} }
static int static int
do_test (void) do_test_clock (clockid_t clockid, const char *fnname)
{ {
const clockid_t clockid_for_get =
(clockid == CLOCK_USE_TIMEDLOCK) ? CLOCK_REALTIME : clockid;
size_t cnt; size_t cnt;
for (cnt = 0; cnt < sizeof (kind) / sizeof (kind[0]); ++cnt) for (cnt = 0; cnt < sizeof (kind) / sizeof (kind[0]); ++cnt)
{ {
@ -88,23 +113,27 @@ do_test (void)
FAIL_EXIT1 ("round %Zu: rwlockattr_destroy failed\n", cnt); FAIL_EXIT1 ("round %Zu: rwlockattr_destroy failed\n", cnt);
struct timespec ts; struct timespec ts;
xclock_gettime (CLOCK_REALTIME, &ts); xclock_gettime (clockid_for_get, &ts);
++ts.tv_sec; ++ts.tv_sec;
/* Get a read lock. */ /* Get a read lock. */
if (clockid == CLOCK_USE_TIMEDLOCK) {
if (pthread_rwlock_timedrdlock (&r, &ts) != 0) if (pthread_rwlock_timedrdlock (&r, &ts) != 0)
FAIL_EXIT1 ("round %Zu: rwlock_timedrdlock failed\n", cnt); FAIL_EXIT1 ("round %Zu: rwlock_timedrdlock failed\n", cnt);
} else {
if (pthread_rwlock_clockrdlock (&r, clockid, &ts) != 0)
FAIL_EXIT1 ("round %Zu: rwlock_%srdlock failed\n", cnt, fnname);
}
printf ("%zu: got timedrdlock\n", cnt); printf ("%zu: got %srdlock\n", cnt, fnname);
pthread_t th; struct thread_args args;
if (pthread_create (&th, NULL, tf, &r) != 0) args.rwlock = &r;
FAIL_EXIT1 ("round %Zu: create failed\n", cnt); args.clockid = clockid;
args.fnname = fnname;
void *status; pthread_t th = xpthread_create (NULL, tf, &args);
if (pthread_join (th, &status) != 0) void *status = xpthread_join (th);
FAIL_EXIT1 ("round %Zu: join failed\n", cnt);
if (status != NULL) if (status != NULL)
FAIL_EXIT1 ("failure in round %Zu\n", cnt); FAIL_EXIT1 ("failure in round %Zu\n", cnt);
@ -115,4 +144,14 @@ do_test (void)
return 0; return 0;
} }
static int
do_test (void)
{
do_test_clock (CLOCK_USE_TIMEDLOCK, "timed");
do_test_clock (CLOCK_MONOTONIC, "clock(monotonic)");
do_test_clock (CLOCK_REALTIME, "clock(realtime)");
return 0;
}
#include <support/test-driver.c> #include <support/test-driver.c>

View File

@ -26,6 +26,7 @@
#include <sys/time.h> #include <sys/time.h>
#include <support/check.h> #include <support/check.h>
#include <support/timespec.h> #include <support/timespec.h>
#include <support/xthread.h>
#define NWRITERS 15 #define NWRITERS 15
@ -40,12 +41,30 @@ static const struct timespec delay = { 0, 1000000 };
# define KIND PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP # define KIND PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP
#endif #endif
/* A bogus clock value that tells the tests to use pthread_rwlock_timedrdlock
and pthread_rwlock_timedwrlock rather than pthread_rwlock_clockrdlock and
pthread_rwlock_clockwrlock. */
#define CLOCK_USE_TIMEDLOCK (-1)
static pthread_rwlock_t lock; static pthread_rwlock_t lock;
struct thread_args
{
int nr;
clockid_t clockid;
const char *fnname;
};
static void * static void *
writer_thread (void *nr) writer_thread (void *arg)
{ {
struct thread_args *args = arg;
const int nr = args->nr;
const clockid_t clockid = args->clockid;
const clockid_t clockid_for_get =
(clockid == CLOCK_USE_TIMEDLOCK) ? CLOCK_REALTIME : clockid;
const char *fnname = args->fnname;
struct timespec ts; struct timespec ts;
int n; int n;
@ -54,27 +73,29 @@ writer_thread (void *nr)
int e; int e;
do do
{ {
xclock_gettime (CLOCK_REALTIME, &ts); xclock_gettime (clockid_for_get, &ts);
ts = timespec_add (ts, timeout); ts = timespec_add (ts, timeout);
ts = timespec_add (ts, timeout); ts = timespec_add (ts, timeout);
printf ("writer thread %ld tries again\n", (long int) nr); printf ("writer thread %d tries again\n", nr);
e = pthread_rwlock_timedwrlock (&lock, &ts); e = (clockid == CLOCK_USE_TIMEDLOCK)
? pthread_rwlock_timedwrlock (&lock, &ts)
: pthread_rwlock_clockwrlock (&lock, clockid, &ts);
if (e != 0 && e != ETIMEDOUT) if (e != 0 && e != ETIMEDOUT)
FAIL_EXIT1 ("timedwrlock failed"); FAIL_EXIT1 ("%swrlock failed", fnname);
} }
while (e == ETIMEDOUT); while (e == ETIMEDOUT);
printf ("writer thread %ld succeeded\n", (long int) nr); printf ("writer thread %d succeeded\n", nr);
nanosleep (&delay, NULL); nanosleep (&delay, NULL);
if (pthread_rwlock_unlock (&lock) != 0) if (pthread_rwlock_unlock (&lock) != 0)
FAIL_EXIT1 ("unlock for writer failed"); FAIL_EXIT1 ("unlock for writer failed");
printf ("writer thread %ld released\n", (long int) nr); printf ("writer thread %d released\n", nr);
} }
return NULL; return NULL;
@ -82,8 +103,15 @@ writer_thread (void *nr)
static void * static void *
reader_thread (void *nr) reader_thread (void *arg)
{ {
struct thread_args *args = arg;
const int nr = args->nr;
const clockid_t clockid = args->clockid;
const clockid_t clockid_for_get =
(clockid == CLOCK_USE_TIMEDLOCK) ? CLOCK_REALTIME : clockid;
const char *fnname = args->fnname;
struct timespec ts; struct timespec ts;
int n; int n;
@ -92,26 +120,29 @@ reader_thread (void *nr)
int e; int e;
do do
{ {
xclock_gettime (CLOCK_REALTIME, &ts); xclock_gettime (clockid_for_get, &ts);
ts = timespec_add (ts, timeout); ts = timespec_add (ts, timeout);
printf ("reader thread %ld tries again\n", (long int) nr); printf ("reader thread %d tries again\n", nr);
if (clockid == CLOCK_USE_TIMEDLOCK)
e = pthread_rwlock_timedrdlock (&lock, &ts); e = pthread_rwlock_timedrdlock (&lock, &ts);
else
e = pthread_rwlock_clockrdlock (&lock, clockid, &ts);
if (e != 0 && e != ETIMEDOUT) if (e != 0 && e != ETIMEDOUT)
FAIL_EXIT1 ("timedrdlock failed"); FAIL_EXIT1 ("%srdlock failed", fnname);
} }
while (e == ETIMEDOUT); while (e == ETIMEDOUT);
printf ("reader thread %ld succeeded\n", (long int) nr); printf ("reader thread %d succeeded\n", nr);
nanosleep (&delay, NULL); nanosleep (&delay, NULL);
if (pthread_rwlock_unlock (&lock) != 0) if (pthread_rwlock_unlock (&lock) != 0)
FAIL_EXIT1 ("unlock for reader failed"); FAIL_EXIT1 ("unlock for reader failed");
printf ("reader thread %ld released\n", (long int) nr); printf ("reader thread %d released\n", nr);
} }
return NULL; return NULL;
@ -119,12 +150,11 @@ reader_thread (void *nr)
static int static int
do_test (void) do_test_clock (clockid_t clockid, const char *fnname)
{ {
pthread_t thwr[NWRITERS]; pthread_t thwr[NWRITERS];
pthread_t thrd[NREADERS]; pthread_t thrd[NREADERS];
int n; int n;
void *res;
pthread_rwlockattr_t a; pthread_rwlockattr_t a;
if (pthread_rwlockattr_init (&a) != 0) if (pthread_rwlockattr_init (&a) != 0)
@ -142,23 +172,37 @@ do_test (void)
/* Make sure we see all message, even those on stdout. */ /* Make sure we see all message, even those on stdout. */
setvbuf (stdout, NULL, _IONBF, 0); setvbuf (stdout, NULL, _IONBF, 0);
for (n = 0; n < NWRITERS; ++n) struct thread_args wargs[NWRITERS];
if (pthread_create (&thwr[n], NULL, writer_thread, for (n = 0; n < NWRITERS; ++n) {
(void *) (long int) n) != 0) wargs[n].nr = n;
FAIL_EXIT1 ("writer create failed"); wargs[n].clockid = clockid;
wargs[n].fnname = fnname;
thwr[n] = xpthread_create (NULL, writer_thread, &wargs[n]);
}
for (n = 0; n < NREADERS; ++n) struct thread_args rargs[NREADERS];
if (pthread_create (&thrd[n], NULL, reader_thread, for (n = 0; n < NREADERS; ++n) {
(void *) (long int) n) != 0) rargs[n].nr = n;
FAIL_EXIT1 ("reader create failed"); rargs[n].clockid = clockid;
rargs[n].fnname = fnname;
thrd[n] = xpthread_create (NULL, reader_thread, &rargs[n]);
}
/* Wait for all the threads. */ /* Wait for all the threads. */
for (n = 0; n < NWRITERS; ++n) for (n = 0; n < NWRITERS; ++n)
if (pthread_join (thwr[n], &res) != 0) xpthread_join (thwr[n]);
FAIL_EXIT1 ("writer join failed");
for (n = 0; n < NREADERS; ++n) for (n = 0; n < NREADERS; ++n)
if (pthread_join (thrd[n], &res) != 0) xpthread_join (thrd[n]);
FAIL_EXIT1 ("reader join failed");
return 0;
}
static int
do_test (void)
{
do_test_clock (CLOCK_USE_TIMEDLOCK, "timed");
do_test_clock (CLOCK_REALTIME, "clock(realtime)");
do_test_clock (CLOCK_MONOTONIC, "clock(monotonic)");
return 0; return 0;
} }

View File

@ -909,6 +909,13 @@ extern int pthread_rwlock_timedrdlock (pthread_rwlock_t *__restrict __rwlock,
__abstime) __THROWNL __nonnull ((1, 2)); __abstime) __THROWNL __nonnull ((1, 2));
# endif # endif
# ifdef __USE_GNU
extern int pthread_rwlock_clockrdlock (pthread_rwlock_t *__restrict __rwlock,
clockid_t __clockid,
const struct timespec *__restrict
__abstime) __THROWNL __nonnull ((1, 3));
# endif
/* Acquire write lock for RWLOCK. */ /* Acquire write lock for RWLOCK. */
extern int pthread_rwlock_wrlock (pthread_rwlock_t *__rwlock) extern int pthread_rwlock_wrlock (pthread_rwlock_t *__rwlock)
__THROWNL __nonnull ((1)); __THROWNL __nonnull ((1));
@ -924,6 +931,13 @@ extern int pthread_rwlock_timedwrlock (pthread_rwlock_t *__restrict __rwlock,
__abstime) __THROWNL __nonnull ((1, 2)); __abstime) __THROWNL __nonnull ((1, 2));
# endif # endif
# ifdef __USE_GNU
extern int pthread_rwlock_clockwrlock (pthread_rwlock_t *__restrict __rwlock,
clockid_t __clockid,
const struct timespec *__restrict
__abstime) __THROWNL __nonnull ((1, 3));
# endif
/* Unlock RWLOCK. */ /* Unlock RWLOCK. */
extern int pthread_rwlock_unlock (pthread_rwlock_t *__rwlock) extern int pthread_rwlock_unlock (pthread_rwlock_t *__rwlock)
__THROWNL __nonnull ((1)); __THROWNL __nonnull ((1));

View File

@ -242,4 +242,6 @@ GLIBC_2.28 tss_delete F
GLIBC_2.28 tss_get F GLIBC_2.28 tss_get F
GLIBC_2.28 tss_set F GLIBC_2.28 tss_set F
GLIBC_2.30 pthread_cond_clockwait F GLIBC_2.30 pthread_cond_clockwait F
GLIBC_2.30 pthread_rwlock_clockrdlock F
GLIBC_2.30 pthread_rwlock_clockwrlock F
GLIBC_2.30 sem_clockwait F GLIBC_2.30 sem_clockwait F

View File

@ -255,6 +255,8 @@ GLIBC_2.3.4 pthread_getaffinity_np F
GLIBC_2.3.4 pthread_setaffinity_np F GLIBC_2.3.4 pthread_setaffinity_np F
GLIBC_2.3.4 pthread_setschedprio F GLIBC_2.3.4 pthread_setschedprio F
GLIBC_2.30 pthread_cond_clockwait F GLIBC_2.30 pthread_cond_clockwait F
GLIBC_2.30 pthread_rwlock_clockrdlock F
GLIBC_2.30 pthread_rwlock_clockwrlock F
GLIBC_2.30 sem_clockwait F GLIBC_2.30 sem_clockwait F
GLIBC_2.4 pthread_mutex_consistent_np F GLIBC_2.4 pthread_mutex_consistent_np F
GLIBC_2.4 pthread_mutex_getprioceiling F GLIBC_2.4 pthread_mutex_getprioceiling F

View File

@ -28,6 +28,8 @@ GLIBC_2.28 tss_delete F
GLIBC_2.28 tss_get F GLIBC_2.28 tss_get F
GLIBC_2.28 tss_set F GLIBC_2.28 tss_set F
GLIBC_2.30 pthread_cond_clockwait F GLIBC_2.30 pthread_cond_clockwait F
GLIBC_2.30 pthread_rwlock_clockrdlock F
GLIBC_2.30 pthread_rwlock_clockwrlock F
GLIBC_2.30 sem_clockwait F GLIBC_2.30 sem_clockwait F
GLIBC_2.4 _IO_flockfile F GLIBC_2.4 _IO_flockfile F
GLIBC_2.4 _IO_ftrylockfile F GLIBC_2.4 _IO_ftrylockfile F

View File

@ -234,4 +234,6 @@ GLIBC_2.29 wait F
GLIBC_2.29 waitpid F GLIBC_2.29 waitpid F
GLIBC_2.29 write F GLIBC_2.29 write F
GLIBC_2.30 pthread_cond_clockwait F GLIBC_2.30 pthread_cond_clockwait F
GLIBC_2.30 pthread_rwlock_clockrdlock F
GLIBC_2.30 pthread_rwlock_clockwrlock F
GLIBC_2.30 sem_clockwait F GLIBC_2.30 sem_clockwait F

View File

@ -244,6 +244,8 @@ GLIBC_2.3.4 pthread_getaffinity_np F
GLIBC_2.3.4 pthread_setaffinity_np F GLIBC_2.3.4 pthread_setaffinity_np F
GLIBC_2.3.4 pthread_setschedprio F GLIBC_2.3.4 pthread_setschedprio F
GLIBC_2.30 pthread_cond_clockwait F GLIBC_2.30 pthread_cond_clockwait F
GLIBC_2.30 pthread_rwlock_clockrdlock F
GLIBC_2.30 pthread_rwlock_clockwrlock F
GLIBC_2.30 sem_clockwait F GLIBC_2.30 sem_clockwait F
GLIBC_2.4 pthread_mutex_consistent_np F GLIBC_2.4 pthread_mutex_consistent_np F
GLIBC_2.4 pthread_mutex_getprioceiling F GLIBC_2.4 pthread_mutex_getprioceiling F

View File

@ -253,6 +253,8 @@ GLIBC_2.3.4 pthread_getaffinity_np F
GLIBC_2.3.4 pthread_setaffinity_np F GLIBC_2.3.4 pthread_setaffinity_np F
GLIBC_2.3.4 pthread_setschedprio F GLIBC_2.3.4 pthread_setschedprio F
GLIBC_2.30 pthread_cond_clockwait F GLIBC_2.30 pthread_cond_clockwait F
GLIBC_2.30 pthread_rwlock_clockrdlock F
GLIBC_2.30 pthread_rwlock_clockwrlock F
GLIBC_2.30 sem_clockwait F GLIBC_2.30 sem_clockwait F
GLIBC_2.4 pthread_mutex_consistent_np F GLIBC_2.4 pthread_mutex_consistent_np F
GLIBC_2.4 pthread_mutex_getprioceiling F GLIBC_2.4 pthread_mutex_getprioceiling F

View File

@ -246,6 +246,8 @@ GLIBC_2.3.4 pthread_getaffinity_np F
GLIBC_2.3.4 pthread_setaffinity_np F GLIBC_2.3.4 pthread_setaffinity_np F
GLIBC_2.3.4 pthread_setschedprio F GLIBC_2.3.4 pthread_setschedprio F
GLIBC_2.30 pthread_cond_clockwait F GLIBC_2.30 pthread_cond_clockwait F
GLIBC_2.30 pthread_rwlock_clockrdlock F
GLIBC_2.30 pthread_rwlock_clockwrlock F
GLIBC_2.30 sem_clockwait F GLIBC_2.30 sem_clockwait F
GLIBC_2.4 pthread_mutex_consistent_np F GLIBC_2.4 pthread_mutex_consistent_np F
GLIBC_2.4 pthread_mutex_getprioceiling F GLIBC_2.4 pthread_mutex_getprioceiling F

View File

@ -28,6 +28,8 @@ GLIBC_2.28 tss_delete F
GLIBC_2.28 tss_get F GLIBC_2.28 tss_get F
GLIBC_2.28 tss_set F GLIBC_2.28 tss_set F
GLIBC_2.30 pthread_cond_clockwait F GLIBC_2.30 pthread_cond_clockwait F
GLIBC_2.30 pthread_rwlock_clockrdlock F
GLIBC_2.30 pthread_rwlock_clockwrlock F
GLIBC_2.30 sem_clockwait F GLIBC_2.30 sem_clockwait F
GLIBC_2.4 _IO_flockfile F GLIBC_2.4 _IO_flockfile F
GLIBC_2.4 _IO_ftrylockfile F GLIBC_2.4 _IO_ftrylockfile F

View File

@ -253,6 +253,8 @@ GLIBC_2.3.4 pthread_getaffinity_np F
GLIBC_2.3.4 pthread_setaffinity_np F GLIBC_2.3.4 pthread_setaffinity_np F
GLIBC_2.3.4 pthread_setschedprio F GLIBC_2.3.4 pthread_setschedprio F
GLIBC_2.30 pthread_cond_clockwait F GLIBC_2.30 pthread_cond_clockwait F
GLIBC_2.30 pthread_rwlock_clockrdlock F
GLIBC_2.30 pthread_rwlock_clockwrlock F
GLIBC_2.30 sem_clockwait F GLIBC_2.30 sem_clockwait F
GLIBC_2.4 pthread_mutex_consistent_np F GLIBC_2.4 pthread_mutex_consistent_np F
GLIBC_2.4 pthread_mutex_getprioceiling F GLIBC_2.4 pthread_mutex_getprioceiling F

View File

@ -242,4 +242,6 @@ GLIBC_2.28 tss_delete F
GLIBC_2.28 tss_get F GLIBC_2.28 tss_get F
GLIBC_2.28 tss_set F GLIBC_2.28 tss_set F
GLIBC_2.30 pthread_cond_clockwait F GLIBC_2.30 pthread_cond_clockwait F
GLIBC_2.30 pthread_rwlock_clockrdlock F
GLIBC_2.30 pthread_rwlock_clockwrlock F
GLIBC_2.30 sem_clockwait F GLIBC_2.30 sem_clockwait F

View File

@ -254,6 +254,8 @@ GLIBC_2.3.4 pthread_getaffinity_np F
GLIBC_2.3.4 pthread_setaffinity_np F GLIBC_2.3.4 pthread_setaffinity_np F
GLIBC_2.3.4 pthread_setschedprio F GLIBC_2.3.4 pthread_setschedprio F
GLIBC_2.30 pthread_cond_clockwait F GLIBC_2.30 pthread_cond_clockwait F
GLIBC_2.30 pthread_rwlock_clockrdlock F
GLIBC_2.30 pthread_rwlock_clockwrlock F
GLIBC_2.30 sem_clockwait F GLIBC_2.30 sem_clockwait F
GLIBC_2.4 pthread_mutex_consistent_np F GLIBC_2.4 pthread_mutex_consistent_np F
GLIBC_2.4 pthread_mutex_getprioceiling F GLIBC_2.4 pthread_mutex_getprioceiling F

View File

@ -254,6 +254,8 @@ GLIBC_2.3.4 pthread_getaffinity_np F
GLIBC_2.3.4 pthread_setaffinity_np F GLIBC_2.3.4 pthread_setaffinity_np F
GLIBC_2.3.4 pthread_setschedprio F GLIBC_2.3.4 pthread_setschedprio F
GLIBC_2.30 pthread_cond_clockwait F GLIBC_2.30 pthread_cond_clockwait F
GLIBC_2.30 pthread_rwlock_clockrdlock F
GLIBC_2.30 pthread_rwlock_clockwrlock F
GLIBC_2.30 sem_clockwait F GLIBC_2.30 sem_clockwait F
GLIBC_2.4 pthread_mutex_consistent_np F GLIBC_2.4 pthread_mutex_consistent_np F
GLIBC_2.4 pthread_mutex_getprioceiling F GLIBC_2.4 pthread_mutex_getprioceiling F

View File

@ -242,4 +242,6 @@ GLIBC_2.28 tss_delete F
GLIBC_2.28 tss_get F GLIBC_2.28 tss_get F
GLIBC_2.28 tss_set F GLIBC_2.28 tss_set F
GLIBC_2.30 pthread_cond_clockwait F GLIBC_2.30 pthread_cond_clockwait F
GLIBC_2.30 pthread_rwlock_clockrdlock F
GLIBC_2.30 pthread_rwlock_clockwrlock F
GLIBC_2.30 sem_clockwait F GLIBC_2.30 sem_clockwait F

View File

@ -255,6 +255,8 @@ GLIBC_2.3.4 pthread_setaffinity_np F
GLIBC_2.3.4 pthread_setschedprio F GLIBC_2.3.4 pthread_setschedprio F
GLIBC_2.3.4 siglongjmp F GLIBC_2.3.4 siglongjmp F
GLIBC_2.30 pthread_cond_clockwait F GLIBC_2.30 pthread_cond_clockwait F
GLIBC_2.30 pthread_rwlock_clockrdlock F
GLIBC_2.30 pthread_rwlock_clockwrlock F
GLIBC_2.30 sem_clockwait F GLIBC_2.30 sem_clockwait F
GLIBC_2.4 pthread_mutex_consistent_np F GLIBC_2.4 pthread_mutex_consistent_np F
GLIBC_2.4 pthread_mutex_getprioceiling F GLIBC_2.4 pthread_mutex_getprioceiling F

View File

@ -245,6 +245,8 @@ GLIBC_2.3.4 pthread_setaffinity_np F
GLIBC_2.3.4 pthread_setschedprio F GLIBC_2.3.4 pthread_setschedprio F
GLIBC_2.3.4 siglongjmp F GLIBC_2.3.4 siglongjmp F
GLIBC_2.30 pthread_cond_clockwait F GLIBC_2.30 pthread_cond_clockwait F
GLIBC_2.30 pthread_rwlock_clockrdlock F
GLIBC_2.30 pthread_rwlock_clockwrlock F
GLIBC_2.30 sem_clockwait F GLIBC_2.30 sem_clockwait F
GLIBC_2.4 pthread_mutex_consistent_np F GLIBC_2.4 pthread_mutex_consistent_np F
GLIBC_2.4 pthread_mutex_getprioceiling F GLIBC_2.4 pthread_mutex_getprioceiling F

View File

@ -242,4 +242,6 @@ GLIBC_2.28 tss_delete F
GLIBC_2.28 tss_get F GLIBC_2.28 tss_get F
GLIBC_2.28 tss_set F GLIBC_2.28 tss_set F
GLIBC_2.30 pthread_cond_clockwait F GLIBC_2.30 pthread_cond_clockwait F
GLIBC_2.30 pthread_rwlock_clockrdlock F
GLIBC_2.30 pthread_rwlock_clockwrlock F
GLIBC_2.30 sem_clockwait F GLIBC_2.30 sem_clockwait F

View File

@ -236,4 +236,6 @@ GLIBC_2.28 tss_delete F
GLIBC_2.28 tss_get F GLIBC_2.28 tss_get F
GLIBC_2.28 tss_set F GLIBC_2.28 tss_set F
GLIBC_2.30 pthread_cond_clockwait F GLIBC_2.30 pthread_cond_clockwait F
GLIBC_2.30 pthread_rwlock_clockrdlock F
GLIBC_2.30 pthread_rwlock_clockwrlock F
GLIBC_2.30 sem_clockwait F GLIBC_2.30 sem_clockwait F

View File

@ -255,6 +255,8 @@ GLIBC_2.3.4 pthread_getaffinity_np F
GLIBC_2.3.4 pthread_setaffinity_np F GLIBC_2.3.4 pthread_setaffinity_np F
GLIBC_2.3.4 pthread_setschedprio F GLIBC_2.3.4 pthread_setschedprio F
GLIBC_2.30 pthread_cond_clockwait F GLIBC_2.30 pthread_cond_clockwait F
GLIBC_2.30 pthread_rwlock_clockrdlock F
GLIBC_2.30 pthread_rwlock_clockwrlock F
GLIBC_2.30 sem_clockwait F GLIBC_2.30 sem_clockwait F
GLIBC_2.4 pthread_mutex_consistent_np F GLIBC_2.4 pthread_mutex_consistent_np F
GLIBC_2.4 pthread_mutex_getprioceiling F GLIBC_2.4 pthread_mutex_getprioceiling F

View File

@ -246,6 +246,8 @@ GLIBC_2.3.4 pthread_getaffinity_np F
GLIBC_2.3.4 pthread_setaffinity_np F GLIBC_2.3.4 pthread_setaffinity_np F
GLIBC_2.3.4 pthread_setschedprio F GLIBC_2.3.4 pthread_setschedprio F
GLIBC_2.30 pthread_cond_clockwait F GLIBC_2.30 pthread_cond_clockwait F
GLIBC_2.30 pthread_rwlock_clockrdlock F
GLIBC_2.30 pthread_rwlock_clockwrlock F
GLIBC_2.30 sem_clockwait F GLIBC_2.30 sem_clockwait F
GLIBC_2.4 pthread_mutex_consistent_np F GLIBC_2.4 pthread_mutex_consistent_np F
GLIBC_2.4 pthread_mutex_getprioceiling F GLIBC_2.4 pthread_mutex_getprioceiling F

View File

@ -244,6 +244,8 @@ GLIBC_2.3.4 pthread_getaffinity_np F
GLIBC_2.3.4 pthread_setaffinity_np F GLIBC_2.3.4 pthread_setaffinity_np F
GLIBC_2.3.4 pthread_setschedprio F GLIBC_2.3.4 pthread_setschedprio F
GLIBC_2.30 pthread_cond_clockwait F GLIBC_2.30 pthread_cond_clockwait F
GLIBC_2.30 pthread_rwlock_clockrdlock F
GLIBC_2.30 pthread_rwlock_clockwrlock F
GLIBC_2.30 sem_clockwait F GLIBC_2.30 sem_clockwait F
GLIBC_2.4 pthread_mutex_consistent_np F GLIBC_2.4 pthread_mutex_consistent_np F
GLIBC_2.4 pthread_mutex_getprioceiling F GLIBC_2.4 pthread_mutex_getprioceiling F

View File

@ -255,6 +255,8 @@ GLIBC_2.3.4 pthread_getaffinity_np F
GLIBC_2.3.4 pthread_setaffinity_np F GLIBC_2.3.4 pthread_setaffinity_np F
GLIBC_2.3.4 pthread_setschedprio F GLIBC_2.3.4 pthread_setschedprio F
GLIBC_2.30 pthread_cond_clockwait F GLIBC_2.30 pthread_cond_clockwait F
GLIBC_2.30 pthread_rwlock_clockrdlock F
GLIBC_2.30 pthread_rwlock_clockwrlock F
GLIBC_2.30 sem_clockwait F GLIBC_2.30 sem_clockwait F
GLIBC_2.4 pthread_mutex_consistent_np F GLIBC_2.4 pthread_mutex_consistent_np F
GLIBC_2.4 pthread_mutex_getprioceiling F GLIBC_2.4 pthread_mutex_getprioceiling F

View File

@ -246,6 +246,8 @@ GLIBC_2.3.4 pthread_getaffinity_np F
GLIBC_2.3.4 pthread_setaffinity_np F GLIBC_2.3.4 pthread_setaffinity_np F
GLIBC_2.3.4 pthread_setschedprio F GLIBC_2.3.4 pthread_setschedprio F
GLIBC_2.30 pthread_cond_clockwait F GLIBC_2.30 pthread_cond_clockwait F
GLIBC_2.30 pthread_rwlock_clockrdlock F
GLIBC_2.30 pthread_rwlock_clockwrlock F
GLIBC_2.30 sem_clockwait F GLIBC_2.30 sem_clockwait F
GLIBC_2.4 pthread_mutex_consistent_np F GLIBC_2.4 pthread_mutex_consistent_np F
GLIBC_2.4 pthread_mutex_getprioceiling F GLIBC_2.4 pthread_mutex_getprioceiling F

View File

@ -244,6 +244,8 @@ GLIBC_2.3.4 pthread_getaffinity_np F
GLIBC_2.3.4 pthread_setaffinity_np F GLIBC_2.3.4 pthread_setaffinity_np F
GLIBC_2.3.4 pthread_setschedprio F GLIBC_2.3.4 pthread_setschedprio F
GLIBC_2.30 pthread_cond_clockwait F GLIBC_2.30 pthread_cond_clockwait F
GLIBC_2.30 pthread_rwlock_clockrdlock F
GLIBC_2.30 pthread_rwlock_clockwrlock F
GLIBC_2.30 sem_clockwait F GLIBC_2.30 sem_clockwait F
GLIBC_2.4 pthread_mutex_consistent_np F GLIBC_2.4 pthread_mutex_consistent_np F
GLIBC_2.4 pthread_mutex_getprioceiling F GLIBC_2.4 pthread_mutex_getprioceiling F

View File

@ -242,4 +242,6 @@ GLIBC_2.28 tss_delete F
GLIBC_2.28 tss_get F GLIBC_2.28 tss_get F
GLIBC_2.28 tss_set F GLIBC_2.28 tss_set F
GLIBC_2.30 pthread_cond_clockwait F GLIBC_2.30 pthread_cond_clockwait F
GLIBC_2.30 pthread_rwlock_clockrdlock F
GLIBC_2.30 pthread_rwlock_clockwrlock F
GLIBC_2.30 sem_clockwait F GLIBC_2.30 sem_clockwait F