Compare commits

...
Author SHA1 Message Date
Albert ARIBAUD (3ADEV) 3500dd283b Y2038: add _TIME_BITS support
This makes all previously defined Y2038-proof API types, functions and
implementations the default when _TIME_BITS==64 and __WORDSIZE==32 (so
that 64-bit architectures are unaffected).

Note: it is assumed that the API is consistent, i.e. for each API type
which is enabled here, all API functions which depend on this type are
enabled and mapped to Y2038-proof implementations.
2018-10-24 12:53:27 +02:00
Albert ARIBAUD (3ADEV) f1869e1122 Y2038: add function __pmap_rmtcall64 2018-10-24 12:53:27 +02:00
Albert ARIBAUD (3ADEV) 6b7f0b49b4 Y2038: add function __clntudp_bufcreate64 2018-10-24 12:53:27 +02:00
Albert ARIBAUD (3ADEV) 86df3efa3c Y2038: add function __clntudp_create64 2018-10-24 12:53:27 +02:00
Albert ARIBAUD (3ADEV) 058c76ad4a Y2038: add function select64 2018-10-24 12:53:27 +02:00
Albert ARIBAUD (3ADEV) c4ec41f9cf Y2038: add function pselect64 2018-10-24 12:53:27 +02:00
Albert ARIBAUD (3ADEV) d9a19a3862 Y2038: add struct __timex64 2018-10-24 12:53:27 +02:00
Albert ARIBAUD (3ADEV) 8dc37789c3 Y2038: add function __ntp_gettimex64 2018-10-24 12:53:27 +02:00
Albert ARIBAUD (3ADEV) 3c7cd28109 Y2038: add function __ntp_gettime64 2018-10-24 12:53:27 +02:00
Albert ARIBAUD (3ADEV) f4f353b27f Y2038: add struct __ntp_timeval64 2018-10-24 12:53:27 +02:00
Albert ARIBAUD (3ADEV) 00b105507a Y2038: add function __getrusage64 2018-10-24 12:53:27 +02:00
Albert ARIBAUD (3ADEV) edd2c042ed Y2038: add functions using futexes
This creates 64-bit time versions of the following APIs:
- pthread_rwlock_timedrdlock
- pthread_rwlock_timedwrlock
- pthread_mutex_timedlock
- pthread_cond_timedwait
- sem_timedwait
- aio_suspend

It also creates 64-bit time versions of the following
functions or macros:
- lll_timedlock_elision
- lll_timedlock
- __lll_timedlock_wait
- futex_reltimed_wait_cancelable
- lll_futex_timed_wait
- __pthread_cond_wait_common
- futex_abstimed_wait_cancelable
- lll_futex_timed_wait_bitset
- do_aio_misc_wait
- AIO_MISC_WAIT
- __new_sem_wait_slow
- do_futex_wait
- __pthread_rwlock_wrlock_full
- __pthread_rwlock_rdlock_full
- futex_abstimed_wait
2018-10-24 12:53:27 +02:00
Albert ARIBAUD (3ADEV) ab06a727ab Y2038: add function __setitimer64 2018-10-24 12:53:27 +02:00
Albert ARIBAUD (3ADEV) e5a827554e Y2038: add function __getitimer64 2018-10-24 12:53:27 +02:00
Albert ARIBAUD (3ADEV) f363546f1a Y2038: add struct __itimerval64 2018-10-24 12:53:27 +02:00
Albert ARIBAUD (3ADEV) b49e73a5f5 Y2038: add function __utime64 2018-10-24 12:53:27 +02:00
Albert ARIBAUD (3ADEV) 4a7c14136e Y2038: add function __adjtime64, __adjtimex64 and __ntp_adjtime64 2018-10-24 12:53:27 +02:00
Albert ARIBAUD (3ADEV) d13362f518 Y2038: add function __nanosleep64 2018-10-24 12:53:27 +02:00
Albert ARIBAUD (3ADEV) a79d02ee55 Y2038: add function __sched_rr_get_interval64 2018-10-24 12:53:27 +02:00
Albert ARIBAUD (3ADEV) c367c72d48 Y2038: add function __msgctl64 2018-10-24 12:53:27 +02:00
Albert ARIBAUD (3ADEV) 2db28845c1 Y2038: add function __mq_timedsend_time64 2018-10-24 12:53:27 +02:00
Albert ARIBAUD (3ADEV) 619f791742 Y2038: add function __mq_timedreceiv_time64 2018-10-24 12:53:27 +02:00
Albert ARIBAUD (3ADEV) b065a273b0 Y2038: add function __utimes64 2018-10-24 12:53:27 +02:00
Albert ARIBAUD (3ADEV) b1563168c4 Y2038: add function __stime64
This implementation uses __settimeofday64.
Therefore, on a system where current time-of-day is 32 bits, this
implementation will fail for dates beyond Y2038.
2018-10-24 12:53:27 +02:00
Albert ARIBAUD (3ADEV) 8ba84c8a86 Y2038: add function __time64
This provides a generic Posix implementation based on calling
__gettimeofday64().
2018-10-24 12:53:27 +02:00
Albert ARIBAUD (3ADEV) 2ea80487a7 Y2038: add function __settimeofday64
Implementing a 64-bit settimeofday requires adding a new
file to build under time/ and we cannot name that new file
'settimeofday.c' or it will break the 32-bit settimeofday
file symbol, so we call it 'settimeofday64.c'.
2018-10-24 12:53:27 +02:00
Albert ARIBAUD (3ADEV) 3f87e785be Y2038: add function __gettimeofday64
Implementing a 64-bit settimeofday requires adding a new
file to build under time/ and we cannot name that new file
'settimeofday.c' or it will break the 32-bit settimeofday
symbol, so we call it 'settimeofday64.c'.
2018-10-24 12:53:27 +02:00
Albert ARIBAUD (3ADEV) d01a328977 Y2038: add function __fstatat64_time64 (and __fxstatat_time64)
These implementations just use the existing syscalls and convert from
kernel 32-bit-time struct stat64 to GLIBC Y2038-ready struct __stat64_t64.
2018-10-24 12:53:27 +02:00
Albert ARIBAUD (3ADEV) 17e59e4743 Y2038: add function __lstat64_time64 (and __lxstat64_time64)
These implementations just use the existing syscalls and convert from
kernel 32-bit-time struct stat64 to GLIBC Y2038-ready struct __stat64_t64.
2018-10-24 12:53:27 +02:00
Albert ARIBAUD (3ADEV) 84909c7b83 Y2038: add function __stat64_time64 (and __xstat64_time64)
These implementations just use the existing syscalls and convert from
kernel 32-bit-time struct stat64 to GLIBC Y2038-ready struct __stat64_t64.
2018-10-24 12:53:27 +02:00
Albert ARIBAUD (3ADEV) 088be4c676 Y2038: add function __fstat64_time64 (and __fxstat64_time64)
These implementations just use the existing syscalls and convert from
kernel 32-bit-time struct stat64 to GLIBC Y2038-ready struct __stat64_t64.
2018-10-24 12:53:27 +02:00
Albert ARIBAUD (3ADEV) 301c5f6b41 Y2038: add struct __stat64_t64 2018-10-24 12:53:27 +02:00
Albert ARIBAUD (3ADEV) 2aab10fdfe Y2038: add function __timerfd_settime64
For Linux this uses the 32-bit time syscal, so it converts
syscall input from 64-bit time into 32-bit time and syscall
output from 32-bit time to 64-bit time.
2018-10-24 12:53:27 +02:00
Albert ARIBAUD (3ADEV) c08076eb6a Y2038: add function __timerfd_gettime64
For Linux this uses the 32-bit time syscall so it converts the
syscall output from 32-bit time to 64-bit time.
2018-10-24 12:53:27 +02:00
Albert ARIBAUD (3ADEV) 9ae7229bb9 Y2038: add function __timer_settime64
For Linux this uses a 32-bit syscall, so it converts the syscall
input from 64-bit time into 32-bit time, and the syscall output
from 32-bit time into 64-bit time.
2018-10-24 12:53:27 +02:00
Albert ARIBAUD (3ADEV) a030a9e6b7 Y2038: add function __timer_gettime64
For Linux this uses the 32-bit time syscall, so it
converts the syscall output into 64-bit time.
2018-10-24 12:53:27 +02:00
Albert ARIBAUD (3ADEV) 3958902364 Y2038: add struct __itimerspec64 2018-10-24 12:53:27 +02:00
Albert ARIBAUD (3ADEV) d39ea685b1 Y2038: add function __lutimes64 2018-10-24 12:53:27 +02:00
Albert ARIBAUD (3ADEV) cc5b45f0c6 Y2038: add function __futimes64 2018-10-24 12:53:27 +02:00
Albert ARIBAUD (3ADEV) 8ea072767d Y2038: add struct __timeval64
Also, provide static inline functions and macros for checking
and converting between 32-bit and 64-bit timevals.
2018-10-24 12:53:27 +02:00
Albert ARIBAUD (3ADEV) ac7c4beb24 Y2038: add function __sigtimedwait_time64 2018-10-24 12:53:27 +02:00
Albert ARIBAUD (3ADEV) 50673e789f Y2038: add function __futimens64 2018-10-24 12:53:27 +02:00
Albert ARIBAUD (3ADEV) 440d708a8e Y2038: add function __utimensat_time64 2018-10-24 12:53:27 +02:00
Albert ARIBAUD (3ADEV) e4625075c8 Y2038: add function __timespec_get64 2018-10-24 12:53:27 +02:00
Albert ARIBAUD (3ADEV) c0195aeb05 Y2038: add function __clock_nanosleep64
Linux does not provide a 64-bit-time clock_nanosleep syscall,
so __clock_nanosleep64 is a wrapper calling __clock_nanosleep,
with one conversion before the call and possibly one after.

Note:

There is no point in implementing __clock_nanosleep64 directly
around the 32-bit-time syscall and making __clock_nanosleep a
wrapper around __clock_nanosleep64, because __clock_nanosleep64
would still need one or two conversions, and __clock_nanosleep
would now also need those, adding a cost of 2 to 4 conversions
in the worst case.
2018-10-24 12:53:27 +02:00
Albert ARIBAUD (3ADEV) 4b076e9e31 Y2038: add function __clock_getres_time64
* include/time.h (__clock_getres_time64): Add.
* sysdeps/posix/clock_getres.c (hp_timing_getres): Use
  struct __timespec64.
* sysdeps/posix/clock_getres.c (realtime_getres): Likewise.
* sysdeps/posix/clock_getres.c (__clock_getres_time64): Add.
* sysdeps/posix/clock_getres.c Use SYSDEP_GETRES64.
* sysdeps/posix/clock_getres.c Use SYSDEP_GETRES_CPU64.
* sysdeps/posix/clock_getres.c (__clock_getres):
  Use __clock_getres_time64.
* sysdeps/unix/sysv/linux/clock_getres.c (SYSCALL_GETRES32): Add.
* sysdeps/unix/sysv/linux/clock_getres.c (SYSCALL_GETRES64): Likewise.
* sysdeps/unix/sysv/linux/clock_getres.c (SYSDEP_GETRES64): Likewise.
* sysdeps/unix/sysv/linux/clock_getres.c (SYSDEP_GETRES_CPU64): Likewise.
2018-10-24 12:53:27 +02:00
Albert ARIBAUD (3ADEV) 641e465b84 Y2038: add function __clock_settime64
* include/time.h (__clock_settime64): Add.
* sysdeps/unix/clock_settime.c (__clock_settime64): Add.
* sysdeps/unix/sysv/linux/clock_settime.c (DO_CLOCK_SETTIME_32): Add.
* sysdeps/unix/sysv/linux/clock_settime.c (DO_CLOCK_SETTIME_64): Add.
* sysdeps/unix/sysv/linux/clock_settime.c (SYSDEP_SETTIME64_CPUTIME): Add.
* sysdeps/unix/sysv/linux/clock_settime.c (SYSDEP_SETTIME64): Add.
2018-10-24 12:53:27 +02:00
Albert ARIBAUD (3ADEV) 09cb6964e2 Y2038: add function __clock_gettime64
* include/time.h: Declare __clock_gettime64().
* ntpl/pthread_clock_gettime.c: Add __pthread_clock_gettime64().
* ntpl/pthread_clock_gettime.c: Make __pthread_clock_gettime()
  a wrapper around __pthread_clock_gettime64().
* sysdeps/unix/clock_gettime.c (hp_timing_gettime): Use struct
  __timespec64.
* sysdeps/unix/clock_gettime.c (realtime_gettime): Likewise.
* sysdeps/unix/clock_gettime.c: Add __clock_gettime64().
* sysdeps/unix/clock_gettime.c: Make __clock_gettime() a
  wrapper around __clock_gettime64().
* sysdeps/unix/sysv/linux/clock_gettime.c: Add 64-bit-time syscall
  support.
2018-10-24 12:53:27 +02:00
Albert ARIBAUD (3ADEV) 94811042d7 Y2038: provide kernel support indication
Introduce __ASSUME_KERNEL_Y2038_SUPPORT which means that
the underlying kernel *always* implements 64-bit-time Y2038-proof
syscalls.

If __ASSUME_KERNEL_Y2038_SUPPORT is not defined, glibc must
check dynamically whether the underlying kernel provides these
syscalls or not, and must fallback to 32-bit-time syscalls if
not.

Introduce function __y2038_get_kernel_support(), which returns
true if the underlying kernel supports 64-bit-time syscalls.

Also introduce function __y2038_set_kernel_support(), which
allows an implementation to notify glibc of the absence of
64-bit-time syscalls (ENOSYS) so that they are not needlessly
tried again.

* misc/Makefile: Add module y2038-support.
* misc/Versions: (__y2038_get_kernel_support): Add to GLIBC_PRIVATE.
* misc/Versions: (__y2038_set_kernel_support): Likewise.
* misc/y2038-support.c: New file.
* misc/y2038-support.h: Likewise.
* sysdeps/unix/sysv/linux/kernel-features.h (__ASSUME_KERNEL_Y2038_SUPPORT): Add.
* sysdeps/unix/sysv/linux/y2038-support.c: New file.
* sysdeps/unix/sysv/linux/y2038-support.h: New file.
2018-10-24 12:53:11 +02:00
Albert ARIBAUD (3ADEV) eaf0f523fb Y2038: add struct __timespec64
This type is a glibc-internal type similar to struct timespec
but whose tv_sec field is a _time64_t rather than a time_t,
which makes it Y2038-proof and useable to pass between user
code and Y2038-proof kernel syscalls.

On 64-bit architectures, and on X32, struct __timespec64 is
just an alias of struct timespec, which is already 64-bit.
On other architectures, it must be explicitly defined.

In order to match the Linux kernel struct, the tv_nsec field
of struct __timespec64 is also a signed 64-bit integer. The
kernel ensures that the higher half of tv_nsec is always 0,
which means glibc does not need to do it.

Note: the corresponding glibc public* type will differ from
this private type, as the user source code might depend on the
tv_nsec field being a 32-bit long, not a 64-bit int. To meet
this expectation, the public type will have a 32-bit tv_nsec
field plus 32-bit anonymous padding, ordered according to the
endianness of the architecture.

Tested with make xtests on x86_64 and ARM.

* include/bits/types/struct_timespec64.h:
  Include time/bits/types/struct_timespec64.h
* include/time.h (valid_timeval_to_timespec64): Add.
* include/time.h (valid_timespec_to_timespec64): Likewise.
* include/time.h (valid_timespec64_to_timespec): Likewise.
* include/time.h (valid_timespec64_to_timeval): Likewise.
* include/time.h (IS_VALID_NANOSECONDS): Likewise.
* include/time.h (timespec_to_timespec64): Likewise.
* include/time.h (timespec64_to_timespec): Likewise.
* include/time.h (timespec64_to_timeval): Likewise.
* io/fcntl.h: Include bits/types/struct_timespec64.h.
* io/sys/poll.h: Likewise.
* io/sys/stat.h: Likewise.
* misc/sys/select.h: Likewise.
* posix/sched.h: Likewise.
* posix/netdb.h: Likewise.
* rt/aio.h: Likewise.
* rt/mqueue.h: Likewise.
* signal/signal.h: Likewise.
* sysdeps/nptl/pthread.h: Likewise.
* sysdeps/pthread/semaphore.h: Likewise.
* sysdeps/unix/sysv/linux/hppa/pthread.h: Likewise.
* sysvipc/sys/sem.h: Likewise.
* time/Makefile: Add bits/types/struct_timespec64.h
* time/bits/types/struct_itimerspec.h:
  Include bits/types/struct_timespec64.h
* time/bits/types/struct_itimerspec64.h: Add.
* time/time.h: Include bits/types/struct_timespec64.h
2018-10-24 12:53:03 +02:00
Paul Eggert d6713c0eec Y2038: make __mktime_internal compatible with __time64_t
This implies also making its callers 64-bit-time compatible
(these are mktime/localtime and timegm) and providing wrappers
for 32-bit-time userland to call.

This patch was tested by running 'make check' on branch
master then applying this patch and its two predecessors and
running 'make check' again, and checking that both 'make check'
yield identical results. This was done on x86_64-linux-gnu and
i686-linux-gnu.

* include/time.h (__mktime64): Add prototype.
* include/time.h (__localtime64): Likewise.
* include/time.h (fits_in_time_t): New static function.
* time/mktime.c (__mktime64): New function.
* time/timegm.c (__timegm64): Likewise.
* time/mktime.c (mktime) [__TIMESIZE]: New wrapper function.
* time/timegm.c (timegm) [__TIMESIZE]: Likewise.
2018-10-24 12:52:49 +02:00
Albert ARIBAUD (3ADEV) 2a2c7fa964 Y2038: make __difftime compatible with 64-bit time
Provide a 64-bit-time version of __difftime (but do not assume
__time64_t is a signed int so that Gnulib can reuse the code)
and make the 32-bit version a wrapper of it.

Current difftime expects two time_t arguments and returns a
double. To preserve source-code compatibility, its 64-bit-time
equivalent expects two __time64_t arguments but still returns
a double.

This patch was tested by running 'make check' on branch
master then applying this patch and its two predecessors and
running 'make check' again, and checking that both 'make check'
yield identical results. This was done on x86_64-linux-gnu and
i686-linux-gnu.

This patch was also functionally tested with an ad hoc userland
C program which checks the result of difftime for various pairs
of 32-bit and, for 64-bit builds, of 64-bit time_t values too.
The program was built and run against a glibc with and without
the patch, and the results compared to ensure the patch does
not change the behavior of difftime.

* include/time.h (__difftime64): Add.
* time/difftime.c (subtract): convert to 64-bit time.
* time/difftime.c (__difftime64): Add.
* time/difftime.c (__difftime): Wrap around __difftime64.
2018-10-24 12:50:59 +02:00
Albert ARIBAUD (3ADEV) c2f8573148 Y2038: make __tz_convert compatible with 64-bit-time
Now that __time64_t exists, we can switch internal function
__tz_convert from 32-bit to 64-bit time. This involves switching
some other internal functions and turning some implementations
which use these into wrappers between public 32-bit and internal
64-bit time.

This patch was tested by running 'make check' on branch
master then applying this patch and its two predecessors and
running 'make check' again, and checking that both 'make check'
yield identical results. This was done on x86_64-linux-gnu and
i686-linux-gnu.

	* include/time.h
	(__tz_compute): Replace time_t with __time64_t.
	(__ctime64): Add.
	(__ctime64_r): Likewise.
	(__localtime64): Likewise.
	(__localtime64_r): Likewise.
	(__gmtime64): Likewise.
	(__gmtime64_r): Likewise.
	(__offtime): Replace const time_t* argument with __time64_t.
	(__tz_convert): Likewise.
	* time/ctime.c
	(__ctime64): Add.
	(__ctime): Turn into a wrapper.
	* time/ctime_r.c
	(__ctime64_r): Add.
	(__ctime_r): Turn into a wrapper.
	* time/gmtime.c
	(__gmtime64): Add.
	(__gmtime): Turn into a wrapper.
	(__gmtime64_r): Add.
	(__gmtime_r): Turn into a wrapper.
	* time/localtime.c
	(__localtime64): Add.
	(__localtime): Turn into a wrapper.
	(__localtime64_r): Add.
	(__localtime_r): Turn into a wrapper.
	* time/offtime.c: Replace all time_t occurrences with __time64_t.
	(__offtime): Replace const time_t* argument with __time64_t.
	* time/tzfile.c
	(__tzfile_compute): Adjust __offtime() call arguments.
	* time/tzset.c: Replace all time_t occurrences with __time64_t.
	(__tz_convert): Adjust __tzfile_compute and __tz_compute call arguments.
2018-10-24 12:22:08 +02:00
Albert ARIBAUD (3ADEV) 7e900af37b Y2038: Add 64-bit time for all architectures
glibc support for 64-bit time_t on 32-bit architectures
will involve:

- Using 64-bit times inside glibc, with conversions
  to and from 32-bit times taking place as necessary
  for interfaces using such times.

- Adding 64-bit-time support in the glibc public API.
  This support should be dynamic, i.e. glibc should
  provide both 32-bit and 64-bit implementations and
   let user code choose at compile time whether to use
   the 32-bit or 64-bit interfaces.

This requires a glibc-internal name for a type for times
that are always 64-bit.

Based on __TIMESIZE, a new macro is defined, __TIME64_T_TYPE,
 which is always the right __*_T_TYPE to hold a 64-bit-time.
__TIME64_T_TYPE equals __TIME_T_TYPE if __TIMESIZE equals 64
and equals __SQUAD_T_TYPE otherwise.

__time64_t can then replace uses of internal_time_t.

This patch was tested by running 'make check' on branch
master then applying this patch and its predecessor and
running 'make check' again, and checking that both 'make
check' yield identical results. This was done on
x86_64-linux-gnu and i686-linux-gnu.

	* bits/time64.h: New file.
	* include/time.h: Replace internal_time_t with __time64_t.
	* posix/bits/types (__time64_t): Add.
	* stdlib/Makefile: Add bits/time64.h to includes.
	* time/tzfile.c: Replace internal_time_t with __time64_t.
2018-10-24 11:53:45 +02:00
154 changed files with 6221 additions and 156 deletions
+1
View File
@@ -134,6 +134,7 @@ enum __rusage_who
};
#include <bits/types/struct_timeval.h>
#include <bits/types/struct_timeval64.h>
#include <bits/types/struct_rusage.h>
/* Priority limits. */
+36
View File
@@ -0,0 +1,36 @@
/* bits/time64.h -- underlying types for __time64_t. Generic version.
Copyright (C) 2018 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/>. */
#ifndef _BITS_TYPES_H
# error "Never include <bits/time64.h> directly; use <sys/types.h> instead."
#endif
#ifndef _BITS_TIME64_H
#define _BITS_TIME64_H 1
/* Define __TIME64_T_TYPE so that it is always a 64-bit type. */
#if __TIMESIZE == 64
/* If we already have 64-bit time type then use it. */
# define __TIME64_T_TYPE __TIME_T_TYPE
#else
/* Define a 64-bit time type alongsize the 32-bit one. */
# define __TIME64_T_TYPE __SQUAD_TYPE
#endif
#endif /* bits/time64.h */
+36
View File
@@ -0,0 +1,36 @@
#ifndef __timespec64_defined
#define __timespec64_defined 1
#include <bits/types.h>
#include <bits/timesize.h>
#include <endian.h>
/* The glibc-internal Y2038-proof structure for a time value.
To keep things Posix-ish, we keep the nanoseconds field a 32-bit
signed long, but since the Linux field is a 64-bit signed int, we
pad our tv_nsec with a 32-bit int, which should always be 0.
Note that this is the glibc-internal type; in the public type, the
padding is an anonymous 32-bit bitfield, so that source-code initializers
keep working. */
#if __TIMESIZE==64
# define __timespec64 timespec
#else
#define TIMSPEC64_TV_PAD_DEFINED
# if BYTE_ORDER == BIG_ENDIAN
struct __timespec64
{
__time64_t tv_sec; /* Seconds */
int tv_pad: 32; /* Padding named for checking/setting */
__syscall_slong_t tv_nsec; /* Nanoseconds */
};
# else
struct __timespec64
{
__time64_t tv_sec; /* Seconds */
__syscall_slong_t tv_nsec; /* Nanoseconds */
int tv_pad: 32; /* Padding named for checking/setting */
};
# endif
#endif
#endif
+1
View File
@@ -0,0 +1 @@
#include <time/bits/types/struct_itimerspec64.h>
+1
View File
@@ -0,0 +1 @@
#include <time/bits/types/struct_timeval64.h>
+19
View File
@@ -364,6 +364,25 @@
# define __USE_FILE_OFFSET64 1
#endif
/* we need to know the word size in order to check the time size */
#include <bits/wordsize.h>
#if defined _TIME_BITS
# if _TIME_BITS == 64
# if ! defined(_FILE_OFFSET_BITS) || _FILE_OFFSET_BITS != 64
# error _TIME_BIT==64 is allowed only when _FILE_OFFSET_BITS==64
# elif __WORDSIZE == 32
# define __USE_TIME_BITS64 1
# endif
# elif __TIME_BITS == 32
# if __WORDSIZE > 32
# error __TIME_BITS=32 is not compatible with __WORDSIZE > 32
# endif
# else
# error Invalid _TIME_BITS value (can only be 32 or 64)
# endif
#endif
#if defined _DEFAULT_SOURCE
# define __USE_MISC 1
#endif
+13
View File
@@ -3,6 +3,7 @@
#ifndef _ISOMAC
/* Now define the internal interfaces. */
extern int __pselect (int __nfds, fd_set *__readfds,
fd_set *__writefds, fd_set *__exceptfds,
const struct timespec *__timeout,
@@ -14,5 +15,17 @@ extern int __select (int __nfds, fd_set *__restrict __readfds,
struct timeval *__restrict __timeout);
libc_hidden_proto (__select)
/* 64-bit time version */
extern int __pselect64 (int __nfds, fd_set *__readfds,
fd_set *__writefds, fd_set *__exceptfds,
const struct __timespec64 *__timeout,
const __sigset_t *__sigmask);
extern int __select64 (int __nfds, fd_set *__restrict __readfds,
fd_set *__restrict __writefds,
fd_set *__restrict __exceptfds,
struct __timeval64 *__restrict __timeout);
#endif
#endif
+33
View File
@@ -2,6 +2,28 @@
#include <io/sys/stat.h>
#ifndef _ISOMAC
/* Used for 64-bit time implementations */
struct __stat64_t64
{
__dev_t st_dev; /* Device. */
__ino_t __st_ino; /* 32bit file serial number. */
__mode_t st_mode; /* File mode. */
__nlink_t st_nlink; /* Link count. */
__uid_t st_uid; /* User ID of the file's owner. */
__gid_t st_gid; /* Group ID of the file's group.*/
__dev_t st_rdev; /* Device number, if device. */
__off64_t st_size; /* Size of file, in bytes. */
__blksize_t st_blksize; /* Optimal block size for I/O. */
__blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */
struct __timespec64 st_atim; /* Time of last access. */
struct __timespec64 st_mtim; /* Time of last modification. */
struct __timespec64 st_ctim; /* Time of last status change. */
__ino64_t st_ino; /* File serial number. */
};
/* Now define the internal interfaces. */
extern int __stat (const char *__file, struct stat *__buf);
extern int __fstat (int __fd, struct stat *__buf);
@@ -14,6 +36,17 @@ extern int __mkdir (const char *__path, __mode_t __mode);
libc_hidden_proto (__mkdir)
extern int __mknod (const char *__path,
__mode_t __mode, __dev_t __dev);
extern int __fxstat64_time64 (int __ver, int __fildes,
struct __stat64_t64 *__stat_buf);
extern int __xstat64_time64 (int __ver, const char *__filename,
struct __stat64_t64 *__stat_buf);
extern int __lxstat64_time64 (int __ver, const char *__filename,
struct __stat64_t64 *__stat_buf);
extern int __fxstatat64_time64 (int __ver, int __fildes,
const char *__filename,
struct __stat64_t64 *__stat_buf,
int __flag);
#if IS_IN (libc) || (IS_IN (rtld) && !defined NO_RTLD_HIDDEN)
hidden_proto (__fxstat)
hidden_proto (__fxstat64)
+4
View File
@@ -24,9 +24,13 @@ extern int __gettimeofday (struct timeval *__tv,
struct timezone *__tz);
libc_hidden_proto (__gettimeofday)
libc_hidden_proto (gettimeofday)
extern int __gettimeofday64 (struct __timeval64 *__tv,
struct timezone *__tz);
extern int __settimeofday (const struct timeval *__tv,
const struct timezone *__tz)
attribute_hidden;
extern int __settimeofday64 (const struct __timeval64 *__tv,
const struct timezone *__tz);
extern int __adjtime (const struct timeval *__delta,
struct timeval *__olddelta);
extern int __getitimer (enum __itimer_which __which,
+206 -16
View File
@@ -3,6 +3,9 @@
#ifndef _ISOMAC
# include <bits/types/locale_t.h>
# include <bits/types/struct___timespec64.h>
# include <bits/types/struct___timeval64.h>
# include <stdbool.h>
extern __typeof (strftime_l) __strftime_l;
libc_hidden_proto (__strftime_l)
@@ -16,6 +19,51 @@ libc_hidden_proto (localtime)
libc_hidden_proto (strftime)
libc_hidden_proto (strptime)
#if __TIMESIZE == 64
# define __timegm64 timegm
# define __mktime64 mktime
# define __timelocal64 timelocal
#else
extern __time64_t __timegm64 (struct tm *__tp) __THROW;
extern __time64_t __mktime64 (struct tm *__tp) __THROW;
/* Another name for `__mktime64'. */
extern __time64_t __timelocal64 (struct tm *__tp) __THROW;
libc_hidden_proto (__mktime64)
libc_hidden_proto (__timelocal64)
#endif
/* 64-bit time version of the current struct timex */
struct __timex64
{
unsigned int modes; /* mode selector */
__syscall_slong_t offset; /* time offset (usec) */
__syscall_slong_t freq; /* frequency offset (scaled ppm) */
__syscall_slong_t maxerror; /* maximum error (usec) */
__syscall_slong_t esterror; /* estimated error (usec) */
int status; /* clock command/status */
__syscall_slong_t constant; /* pll time constant */
__syscall_slong_t precision; /* clock precision (usec) (ro) */
__syscall_slong_t tolerance; /* clock frequency tolerance (ppm) (ro) */
struct __timeval64 time; /* (read only, except for ADJ_SETOFFSET) */
__syscall_slong_t tick; /* (modified) usecs between clock ticks */
__syscall_slong_t ppsfreq; /* pps frequency (scaled ppm) (ro) */
__syscall_slong_t jitter; /* pps jitter (us) (ro) */
int shift; /* interval duration (s) (shift) (ro) */
__syscall_slong_t stabil; /* pps stability (scaled ppm) (ro) */
__syscall_slong_t jitcnt; /* jitter limit exceeded (ro) */
__syscall_slong_t calcnt; /* calibration intervals (ro) */
__syscall_slong_t errcnt; /* calibration errors (ro) */
__syscall_slong_t stbcnt; /* stability limit exceeded (ro) */
int tai; /* TAI offset (ro) */
/* ??? */
int :32; int :32; int :32; int :32;
int :32; int :32; int :32; int :32;
int :32; int :32; int :32;
};
extern __typeof (clock_getres) __clock_getres;
extern __typeof (clock_gettime) __clock_gettime;
libc_hidden_proto (__clock_gettime)
@@ -23,13 +71,22 @@ extern __typeof (clock_settime) __clock_settime;
extern __typeof (clock_nanosleep) __clock_nanosleep;
extern __typeof (clock_getcpuclockid) __clock_getcpuclockid;
extern int __clock_gettime64 (clockid_t __clock_id,
struct __timespec64 *__tp) __THROW;
extern int __clock_settime64 (clockid_t __clock_id,
const struct __timespec64 *__tp) __THROW;
extern int __clock_getres_time64 (clockid_t __clock_id,
struct __timespec64 *__res) __THROW;
extern int __clock_nanosleep64 (clockid_t __clock_id, int __flags,
const struct __timespec64 *__req,
struct __timespec64 *__rem);
extern int __utimes64 (const char *file,
const struct __timeval64 tvp[2]);
/* Now define the internal interfaces. */
struct tm;
/* time_t variant for representing time zone data, independent of
time_t. */
typedef __int64_t internal_time_t;
/* Defined in mktime.c. */
extern const unsigned short int __mon_yday[2][13] attribute_hidden;
@@ -43,35 +100,69 @@ extern int __use_tzfile attribute_hidden;
extern void __tzfile_read (const char *file, size_t extra,
char **extrap) attribute_hidden;
extern void __tzfile_compute (internal_time_t timer, int use_localtime,
extern void __tzfile_compute (__time64_t timer, int use_localtime,
long int *leap_correct, int *leap_hit,
struct tm *tp) attribute_hidden;
extern void __tzfile_default (const char *std, const char *dst,
long int stdoff, long int dstoff)
attribute_hidden;
extern void __tzset_parse_tz (const char *tz) attribute_hidden;
extern void __tz_compute (time_t timer, struct tm *tm, int use_localtime)
extern void __tz_compute (__time64_t timer, struct tm *tm, int use_localtime)
__THROW attribute_hidden;
/* Subroutine of `mktime'. Return the `time_t' representation of TP and
normalize TP, given that a `struct tm *' maps to a `time_t' as performed
/* Subroutine of mktime. Return the __time64_t representation of TP and
normalize TP, given that a struct tm * maps to a __time64_t as performed
by FUNC. Record next guess for localtime-gmtime offset in *OFFSET. */
extern time_t __mktime_internal (struct tm *__tp,
struct tm *(*__func) (const time_t *,
struct tm *),
long int *__offset) attribute_hidden;
extern __time64_t __mktime_internal (struct tm *__tp,
struct tm *(*__func) (const __time64_t *,
struct tm *),
long int *__offset) attribute_hidden;
/* nis/nis_print.c needs ctime, so even if ctime is not declared here,
we define __ctime64 as ctime so that nis/nis_print.c can get linked
against a function called ctime. */
#if __TIMESIZE == 64
# define __ctime64 ctime
#endif
#if __TIMESIZE == 64
# define __ctime64_r ctime_r
#endif
#if __TIMESIZE == 64
# define __localtime64 localtime
#else
extern struct tm *__localtime64 (const __time64_t *__timer);
libc_hidden_proto (__localtime64)
#endif
extern struct tm *__localtime_r (const time_t *__timer,
struct tm *__tp) attribute_hidden;
#if __TIMESIZE == 64
# define __localtime64_r __localtime_r
#else
extern struct tm *__localtime64_r (const __time64_t *__timer,
struct tm *__tp) attribute_hidden;
#endif
extern struct tm *__gmtime_r (const time_t *__restrict __timer,
struct tm *__restrict __tp);
libc_hidden_proto (__gmtime_r)
/* Compute the `struct tm' representation of *T,
#if __TIMESIZE == 64
# define __gmtime64 gmtime
# define __gmtime64_r __gmtime_r
#else
extern struct tm *__gmtime64_r (const __time64_t *__restrict __timer,
struct tm *__restrict __tp);
#endif
/* Compute the `struct tm' representation of T,
offset OFFSET seconds east of UTC,
and store year, yday, mon, mday, wday, hour, min, sec into *TP.
Return nonzero if successful. */
extern int __offtime (const time_t *__timer,
extern int __offtime (__time64_t __timer,
long int __offset,
struct tm *__tp) attribute_hidden;
@@ -80,8 +171,8 @@ extern char *__asctime_r (const struct tm *__tp, char *__buf)
extern void __tzset (void) attribute_hidden;
/* Prototype for the internal function to get information based on TZ. */
extern struct tm *__tz_convert (const time_t *timer, int use_localtime,
struct tm *tp) attribute_hidden;
extern struct tm *__tz_convert (__time64_t timer, int use_localtime,
struct tm *tp) attribute_hidden;
extern int __nanosleep (const struct timespec *__requested_time,
struct timespec *__remaining);
@@ -99,6 +190,12 @@ extern char * __strptime_internal (const char *rp, const char *fmt,
struct tm *tm, void *statep,
locale_t locparam) attribute_hidden;
#if __TIMESIZE == 64
# define __difftime64 __difftime
#else
extern double __difftime64 (__time64_t time1, __time64_t time0);
#endif
extern double __difftime (time_t time1, time_t time0);
@@ -106,5 +203,98 @@ extern double __difftime (time_t time1, time_t time0);
actual clock ID. */
#define CLOCK_IDFIELD_SIZE 3
/* Check whether a time64_t value fits in a time_t. */
static inline bool
fits_in_time_t (__time64_t t64)
{
time_t t = t64;
return t == t64;
}
/* Convert a known valid struct timeval into a struct __timespec64. */
static inline void
valid_timeval_to_timespec64 (const struct timeval *tv32,
struct __timespec64 *ts64)
{
ts64->tv_sec = tv32->tv_sec;
ts64->tv_nsec = tv32->tv_usec * 1000;
}
/* Convert a known valid struct timespec into a struct __timespec64. */
static inline void
valid_timespec_to_timespec64 (const struct timespec *ts32,
struct __timespec64 *ts64)
{
ts64->tv_sec = ts32->tv_sec;
ts64->tv_nsec = ts32->tv_nsec;
/* We only need to zero ts64->tv_pad if we pass it to the kernel. */
}
/* Convert a known valid struct __timespec64 into a struct timespec. */
static inline void
valid_timespec64_to_timespec (const struct __timespec64 *ts64,
struct timespec *ts32)
{
ts32->tv_sec = (time_t) ts64->tv_sec;
ts32->tv_nsec = ts64->tv_nsec;
}
/* Convert a known valid struct __timespec64 into a struct timeval. */
static inline void
valid_timespec64_to_timeval (const struct __timespec64 *ts64,
struct timeval *tv32)
{
tv32->tv_sec = (time_t) ts64->tv_sec;
tv32->tv_usec = ts64->tv_nsec / 1000;
}
/* Check if a value lies with the valid nanoseconds range. */
#define IS_VALID_NANOSECONDS(ns) (ns >= 0 && ns <= 999999999)
/* Check and convert a struct timespec into a struct __timespec64. */
static inline bool
timespec_to_timespec64 (const struct timespec *ts32,
struct __timespec64 *ts64)
{
/* Check that ts32 holds a valid count of nanoseconds. */
if (! IS_VALID_NANOSECONDS (ts32->tv_nsec))
return false;
/* All ts32 fields can fit in ts64, so copy them. */
valid_timespec_to_timespec64 (ts32, ts64);
/* We only need to zero ts64->tv_pad if we pass it to the kernel. */
return true;
}
/* Check and convert a struct __timespec64 into a struct timespec. */
static inline bool
timespec64_to_timespec (const struct __timespec64 *ts64,
struct timespec *ts32)
{
/* Check that tv_nsec holds a valid count of nanoseconds. */
if (! IS_VALID_NANOSECONDS (ts64->tv_nsec))
return false;
/* Check that tv_sec can fit in a __time_t. */
if (! fits_in_time_t (ts64->tv_sec))
return false;
/* All ts64 fields can fit in ts32, so copy them. */
valid_timespec64_to_timespec (ts64, ts32);
return true;
}
/* Check and convert a struct __timespec64 into a struct timeval. */
static inline bool
timespec64_to_timeval (const struct __timespec64 *ts64,
struct timeval *tv32)
{
/* Check that tv_nsec holds a valid count of nanoseconds. */
if (! IS_VALID_NANOSECONDS (ts64->tv_nsec))
return false;
/* Check that tv_sec can fit in a __time_t. */
if (! fits_in_time_t (ts64->tv_sec))
return false;
/* All ts64 fields can fit in tv32, so copy them. */
valid_timespec64_to_timeval (ts64, tv32);
return true;
}
#endif
#endif
+7
View File
@@ -6,4 +6,11 @@
libc_hidden_proto (utime)
#endif
/* Structure describing file times, 64-bit time version. */
struct __utimbuf64
{
__time64_t actime; /* Access time. */
__time64_t modtime; /* Modification time. */
};
#endif /* utime.h */
+1 -1
View File
@@ -28,7 +28,7 @@ headers := sys/stat.h bits/stat.h sys/statfs.h bits/statfs.h sys/vfs.h \
bits/statx.h utime.h ftw.h fts.h sys/sendfile.h
routines := \
utime \
utime utime64 \
mkfifo mkfifoat \
stat fstat lstat stat64 fstat64 lstat64 fstatat fstatat64 \
xstat fxstat lxstat xstat64 fxstat64 lxstat64 statx \
+7
View File
@@ -132,6 +132,13 @@ libc {
fcntl64;
statx;
}
GLIBC_2.29 {
__fxstat64_time64;
__xstat64_time64;
__lxstat64_time64;
__fxstatat64_time64;
__utime64;
}
GLIBC_PRIVATE {
__libc_fcntl64;
__fcntl_nocancel;
+7
View File
@@ -50,3 +50,10 @@ fstat64 (int fd, struct stat64 *buf)
{
return __fxstat64 (_STAT_VER, fd, buf);
}
int
attribute_hidden
__fstat64_time64 (int fd, struct __stat64_t64 *buf)
{
return __fxstat64_time64 (_STAT_VER, fd, buf);
}
+7
View File
@@ -50,3 +50,10 @@ fstatat64 (int fd, const char *file, struct stat64 *buf, int flag)
{
return __fxstatat64 (_STAT_VER, fd, file, buf, flag);
}
int
attribute_hidden
__fstatat64_time64 (int fd, const char *file, struct __stat64_t64 *buf, int flag)
{
return __fxstatat64_time64 (_STAT_VER, fd, file, buf, flag);
}
+8
View File
@@ -32,3 +32,11 @@ futimens (int fd, const struct timespec tsp[2])
return -1;
}
stub_warning (futimens)
int
__futimens64 (int fd, const struct __timespec64 tsp[2])
{
__set_errno (ENOSYS);
return -1;
}
stub_warning (__futimens64)
+7
View File
@@ -50,3 +50,10 @@ lstat64 (const char *file, struct stat64 *buf)
{
return __lxstat64 (_STAT_VER, file, buf);
}
int
attribute_hidden
__lstat64_time64 (const char *file, struct __stat64_t64 *buf)
{
return __lxstat64_time64 (_STAT_VER, file, buf);
}
+7
View File
@@ -50,3 +50,10 @@ stat64 (const char *file, struct stat64 *buf)
{
return __xstat64 (_STAT_VER, file, buf);
}
int
attribute_hidden
__stat64_time64 (const char *file, struct __stat64_t64 *buf)
{
return __xstat64_time64 (_STAT_VER, file, buf);
}
+69 -6
View File
@@ -210,14 +210,27 @@ extern int stat (const char *__restrict __file,
extern int fstat (int __fd, struct stat *__buf) __THROW __nonnull ((2));
#else
# ifdef __REDIRECT_NTH
# ifdef __USE_TIME_BITS64
extern int __REDIRECT_NTH (stat, (const char *__restrict __file,
struct stat *__restrict __buf), __stat64_time64)
__nonnull ((1, 2));
extern int __REDIRECT_NTH (fstat, (int __fd, struct stat *__buf), __fstat64_time64)
__nonnull ((2));
# else
extern int __REDIRECT_NTH (stat, (const char *__restrict __file,
struct stat *__restrict __buf), stat64)
__nonnull ((1, 2));
extern int __REDIRECT_NTH (fstat, (int __fd, struct stat *__buf), fstat64)
__nonnull ((2));
# endif
# else
# define stat stat64
# define fstat fstat64
# ifdef __USE_TIME_BITS64
# define stat stat64_time64
# define fstat fstat64_time64
# else
# define stat stat64
# define fstat fstat64
# endif
# endif
#endif
#ifdef __USE_LARGEFILE64
@@ -260,12 +273,23 @@ extern int lstat (const char *__restrict __file,
struct stat *__restrict __buf) __THROW __nonnull ((1, 2));
# else
# ifdef __REDIRECT_NTH
# ifdef __USE_TIME_BITS64
extern int __REDIRECT_NTH (lstat,
(const char *__restrict __file,
struct stat *__restrict __buf), __lstat64_time64)
__nonnull ((1, 2));
# else
extern int __REDIRECT_NTH (lstat,
(const char *__restrict __file,
struct stat *__restrict __buf), lstat64)
__nonnull ((1, 2));
# endif
# else
# define lstat lstat64
# ifdef __USE_TIME_BITS64
# define lstat __lstat64_time64
# else
# define lstat lstat64
# endif
# endif
# endif
# ifdef __USE_LARGEFILE64
@@ -357,6 +381,15 @@ extern int mkfifoat (int __fd, const char *__path, __mode_t __mode)
#ifdef __USE_ATFILE
/* Set file access and modification times relative to directory file
descriptor. */
#ifdef __USE_TIME_BITS64
# if defined(__REDIRECT)
extern int __REDIRECT (utimensat, (int __fd, const char *__path,
const struct timespec __times[2], int __flags),
__utimensat64) __THROW __nonnull((2));
# else
# define utimensat __utimensat64
# endif
#endif
extern int utimensat (int __fd, const char *__path,
const struct timespec __times[2],
int __flags)
@@ -365,6 +398,14 @@ extern int utimensat (int __fd, const char *__path,
#ifdef __USE_XOPEN2K8
/* Set file access and modification times of the file associated with FD. */
#ifdef __USE_TIME_BITS64
# if defined(__REDIRECT)
extern int __REDIRECT (futimens, (int __fd, const struct timespec __times[2]),
__futimens64) __THROW;
# else
# define futimens __futimens64
# endif
#endif
extern int futimens (int __fd, const struct timespec __times[2]) __THROW;
#endif
@@ -403,6 +444,21 @@ extern int __fxstatat (int __ver, int __fildes, const char *__filename,
__THROW __nonnull ((3, 4));
#else
# ifdef __REDIRECT_NTH
# ifdef __USE_TIME_BITS64
extern int __REDIRECT_NTH (__fxstat, (int __ver, int __fildes,
struct stat *__stat_buf), __fxstat64_time64)
__nonnull ((3));
extern int __REDIRECT_NTH (__xstat, (int __ver, const char *__filename,
struct stat *__stat_buf), __xstat64_time64)
__nonnull ((2, 3));
extern int __REDIRECT_NTH (__lxstat, (int __ver, const char *__filename,
struct stat *__stat_buf), __lxstat64_time64)
__nonnull ((2, 3));
extern int __REDIRECT_NTH (__fxstatat, (int __ver, int __fildes,
const char *__filename,
struct stat *__stat_buf, int __flag),
__fxstatat64_time64) __nonnull ((3, 4));
# else
extern int __REDIRECT_NTH (__fxstat, (int __ver, int __fildes,
struct stat *__stat_buf), __fxstat64)
__nonnull ((3));
@@ -416,11 +472,18 @@ extern int __REDIRECT_NTH (__fxstatat, (int __ver, int __fildes,
const char *__filename,
struct stat *__stat_buf, int __flag),
__fxstatat64) __nonnull ((3, 4));
# endif
# else
# define __fxstat __fxstat64
# define __xstat __xstat64
# define __lxstat __lxstat64
# ifdef __USE_TIME_BITS64
# define __fxstat __fxstat64_time64
# define __xstat __xstat64_time64
# define __lxstat __lxstat64_time64
# else
# define __fxstat __fxstat64
# define __xstat __xstat64
# define __lxstat __lxstat64
# endif
# endif
#endif
+16
View File
@@ -38,3 +38,19 @@ utime (const char *file, const struct utimbuf *times)
libc_hidden_def (utime)
stub_warning (utime)
/* 64-bit time version */
int
__utime64 (const char *file, const struct __utimbuf64 *times)
{
if (file == NULL)
{
__set_errno (EINVAL);
return -1;
}
__set_errno (ENOSYS);
return -1;
}
stub_warning (__utime64)
+13 -3
View File
@@ -27,20 +27,30 @@
__BEGIN_DECLS
#include <bits/types.h>
#include <bits/types/time_t.h>
#if defined __USE_XOPEN || defined __USE_XOPEN2K
# include <bits/types/time_t.h>
#endif
/* Structure describing file times. */
/* Structure describing file times, 32- or 64-bit time. */
struct utimbuf
{
__time_t actime; /* Access time. */
__time_t modtime; /* Modification time. */
time_t actime; /* Access time. */
time_t modtime; /* Modification time. */
};
/* Set the access and modification times of FILE to those given in
*FILE_TIMES. If FILE_TIMES is NULL, set them to the current time. */
#ifdef __USE_TIME_BITS64
# if defined(__REDIRECT)
extern int __REDIRECT (utime, (const char *__file,
const struct utimbuf *__file_times),
__utime64) __THROW __nonnull ((1));
# else
# define utime __utime64
# endif
#endif
extern int utime (const char *__file,
const struct utimbuf *__file_times)
__THROW __nonnull ((1));
+9
View File
@@ -30,3 +30,12 @@ utimensat (int fd, const char *file, const struct timespec tsp[2],
return -1;
}
stub_warning (utimensat)
int
__utimensat_time64 (int fd, const char *file, const struct __timespec64 tsp[2],
int flags)
{
__set_errno (ENOSYS);
return -1;
}
stub_warning (__utimensat_time64)
+28
View File
@@ -165,6 +165,34 @@ This macro was introduced as part of the Large File Support extension
(LFS).
@end defvr
@defvr Macro _TIME_BITS
This macro determines the bit size of @code{time_t} (and therefore the
bit size of all @code{time_t} derived types and the prototypes of all
related functions). If @code{_TIME_BITS} is undefined, the bit size of
time_t equals the bit size of the architecture.
If @code{_TIME_BITS} is undefined, or if @code{_TIME_BITS} is defined
to the value @code{32} and @code{__WORDSIZE} is defined to the value
@code{32}, or or if @code{_TIME_BITS} is defined to the value @code{64}
and @code{__WORDSIZE} is defined to the value @code{64}, nothing changes.
If @code{_TIME_BITS} is defined to the value @code{64} and if
@code{__WORDSIZE} is defined to the value @code{32}, then the @w{64 bit}
time API and implementation are used even though the architecture word
size is @code{32}. Also, if the kernel provides @w{64 bit} time support,
it is used; otherwise, the @w{32 bit} kernel time support is used (with
no provision to address kernel Y2038 shortcomings).
If @code{_TIME_BITS} is defined to the value @code{32} and if
@code{__WORDSIZE} is defined to the value @code{64}, then a compile-time
error is emitted.
If @code{_TIME_BITS} is defined to a value different from both @code{32}
and @code{64}, then a compile-time error is emitted.
This macro was introduced as part of the Y2038 support.
@end defvr
@defvr Macro _ISOC99_SOURCE
@standards{GNU, (none)}
If this macro is defined, features from ISO C99 are included. Since
+1 -1
View File
@@ -71,7 +71,7 @@ routines := brk sbrk sstk ioctl \
fgetxattr flistxattr fremovexattr fsetxattr getxattr \
listxattr lgetxattr llistxattr lremovexattr lsetxattr \
removexattr setxattr getauxval ifunc-impl-list makedev \
allocate_once
allocate_once y2038-support utimes64
generated += tst-error1.mtrace tst-error1-mem.out \
tst-allocate_once.mtrace tst-allocate_once-mem.out
+4
View File
@@ -158,6 +158,8 @@ libc {
GLIBC_2.26 {
preadv2; preadv64v2; pwritev2; pwritev64v2;
}
GLIBC_2.29 {
}
GLIBC_PRIVATE {
__madvise;
__mktemp;
@@ -166,5 +168,7 @@ libc {
__mmap; __munmap; __mprotect;
__sched_get_priority_min; __sched_get_priority_max;
__libc_allocate_once_slow;
__y2038_get_kernel_support;
__y2038_set_kernel_support;
}
}
+9
View File
@@ -30,3 +30,12 @@ __futimes (int fd, const struct timeval tvp[2])
weak_alias (__futimes, futimes)
stub_warning (futimes)
int
__futimes64 (int fd, const struct __timeval64 tvp[2])
{
__set_errno (ENOSYS);
return -1;
}
stub_warning (__futimes64)
+8
View File
@@ -31,3 +31,11 @@ __lutimes (const char *file, const struct timeval tvp[2])
weak_alias (__lutimes, lutimes)
stub_warning (lutimes)
int
__lutimes64 (const char *file, const struct __timeval64 tvp[2])
{
__set_errno (ENOSYS);
return -1;
}
stub_warning (__lutimes64)
+26
View File
@@ -35,6 +35,7 @@
/* Get definition of timer specification structures. */
#include <bits/types/time_t.h>
#include <bits/types/struct_timeval.h>
#include <bits/types/struct_timeval64.h>
#ifdef __USE_XOPEN2K
# include <bits/types/struct_timespec.h>
#endif
@@ -98,6 +99,18 @@ __BEGIN_DECLS
This function is a cancellation point and therefore not marked with
__THROW. */
#ifdef __USE_TIME_BITS64
# if defined(__REDIRECT)
extern int __REDIRECT (select, (int __nfds,
fd_set *__restrict __readfds,
fd_set *__restrict __writefds,
fd_set *__restrict __exceptfds,
struct timeval *__restrict __timeout),
__select64);
# else
# define select __select64
# endif
#endif
extern int select (int __nfds, fd_set *__restrict __readfds,
fd_set *__restrict __writefds,
fd_set *__restrict __exceptfds,
@@ -110,6 +123,19 @@ extern int select (int __nfds, fd_set *__restrict __readfds,
This function is a cancellation point and therefore not marked with
__THROW. */
#ifdef __USE_TIME_BITS64
# if defined(__REDIRECT)
extern int __REDIRECT (pselect, (int __nfds,
fd_set *__restrict __readfds,
fd_set *__restrict __writefds,
fd_set *__restrict __exceptfds,
const struct timespec *__restrict __timeout,
const __sigset_t *__restrict __sigmask),
__pselect64);
# else
# define pselect __pselect64
# endif
#endif
extern int pselect (int __nfds, fd_set *__restrict __readfds,
fd_set *__restrict __writefds,
fd_set *__restrict __exceptfds,
+15
View File
@@ -38,3 +38,18 @@ __utimes (const char *file, const struct timeval tvp[2])
weak_alias (__utimes, utimes)
stub_warning (utimes)
int
__utimes64 (const char *file, const struct __timeval64 tvp[2])
{
if (file == NULL)
{
__set_errno (EINVAL);
return -1;
}
__set_errno (ENOSYS);
return -1;
}
stub_warning (__utimes64)
+40
View File
@@ -0,0 +1,40 @@
/* y2038 general kernel support indication.
Copyright (C) 2018 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 <stdbool.h>
#ifndef __ASSUME_KERNEL_Y2038_SUPPORT
/* By default glibc assumes the underlying kernel does not support Y2038. */
bool
__default_y2038_get_kernel_support (void)
{
return false;
}
weak_alias (__default_y2038_get_kernel_support, __y2038_get_kernel_support)
/* By default glibc just ignores Y2038 support indication setting. */
void
__default_y2038_set_kernel_support (bool support __attribute__ ((unused)))
{
/* Do nothing. */
}
weak_alias (__default_y2038_set_kernel_support, __y2038_set_kernel_support)
#endif
+33
View File
@@ -0,0 +1,33 @@
/* y2038 general kernel support indication.
Copyright (C) 2018 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 <stdbool.h>
/* If we do not assume that the kernel provides 64-bit-time syscalls,
* then we need a dynamic way to remember whether it does or not. */
#ifndef __ASSUME_KERNEL_Y2038_SUPPORT
/* Dynamically check whether actual kernel supports Y2038 or not. */
extern bool __y2038_get_kernel_support (void);
/* Dynamically set whether actual kernel supports Y2038 or not. */
extern void __y2038_set_kernel_support (bool support);
#endif
+9
View File
@@ -269,6 +269,7 @@ libpthread {
GLIBC_2.22 {
}
<<<<<<< HEAD
# C11 thread symbols.
GLIBC_2.28 {
thrd_create; thrd_detach; thrd_exit; thrd_join;
@@ -277,6 +278,14 @@ libpthread {
cnd_timedwait; cnd_wait; tss_create; tss_delete; tss_get; tss_set;
}
GLIBC_2.29 {
__pthread_rwlock_rdlock64;
__pthread_rwlock_wrlock64;
__pthread_mutex_timedlock64;
__sem_timedwait64;
__pthread_cond_timedwait64;
}
GLIBC_PRIVATE {
__pthread_initialize_minimal;
__pthread_clock_gettime; __pthread_clock_settime;
+37
View File
@@ -57,3 +57,40 @@ __lll_timedlock_wait (int *futex, const struct timespec *abstime, int private)
return 0;
}
/* 64-bit time version */
int
__lll_timedlock_wait64 (int *futex, const struct __timespec64 *abstime, int private)
{
/* Reject invalid timeouts. */
if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)
return EINVAL;
/* Try locking. */
while (atomic_exchange_acq (futex, 2) != 0)
{
struct timeval tv;
/* Get the current time. */
(void) __gettimeofday (&tv, NULL);
/* Compute relative timeout. */
struct timespec rt;
rt.tv_sec = abstime->tv_sec - tv.tv_sec;
rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000;
if (rt.tv_nsec < 0)
{
rt.tv_nsec += 1000000000;
--rt.tv_sec;
}
if (rt.tv_sec < 0)
return ETIMEDOUT;
/* If *futex == 2, wait until woken or timeout. */
lll_futex_timed_wait (futex, 2, &rt, private);
}
return 0;
}
+35 -2
View File
@@ -18,13 +18,14 @@
#include <errno.h>
#include <stdlib.h>
#include <time.h>
#include <bits/types/struct_timespec64.h>
#include "pthreadP.h"
#if HP_TIMING_AVAIL
int
__pthread_clock_gettime (clockid_t clock_id, hp_timing_t freq,
struct timespec *tp)
__pthread_clock_gettime64 (clockid_t clock_id, hp_timing_t freq,
struct __timespec64 *tp)
{
hp_timing_t tsc;
@@ -64,4 +65,36 @@ __pthread_clock_gettime (clockid_t clock_id, hp_timing_t freq,
return 0;
}
int
__pthread_clock_gettime (clockid_t clock_id, hp_timing_t freq,
struct timespec *tp)
{
struct __timespec64 ts64;
int res;
if (tp == NULL)
{
__set_errno(EINVAL);
res = -1;
}
else
{
int res = __pthread_clock_gettime64 (clock_id, freq, &ts64);
if (res == 0)
{
if (fits_in_time_t (ts64.tv_time))
{
tp->tv_sec = ts64.tv_sec;
tp->tv_nsec = ts64.tv_nsec;
}
else
{
set_errno(EOVERFLOW);
res = -1;
}
}
}
return res;
}
#endif
+285
View File
@@ -647,6 +647,280 @@ __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex,
return (err != 0) ? err : result;
}
/* 64-bit time variant */
static __always_inline int
__pthread_cond_wait_common64 (pthread_cond_t *cond, pthread_mutex_t *mutex,
const struct __timespec64 *abstime)
{
const int maxspin = 0;
int err;
int result = 0;
LIBC_PROBE (cond_wait, 2, cond, mutex);
/* Acquire a position (SEQ) in the waiter sequence (WSEQ). We use an
atomic operation because signals and broadcasts may update the group
switch without acquiring the mutex. We do not need release MO here
because we do not need to establish any happens-before relation with
signalers (see __pthread_cond_signal); modification order alone
establishes a total order of waiters/signals. We do need acquire MO
to synchronize with group reinitialization in
__condvar_quiesce_and_switch_g1. */
uint64_t wseq = __condvar_fetch_add_wseq_acquire (cond, 2);
/* Find our group's index. We always go into what was G2 when we acquired
our position. */
unsigned int g = wseq & 1;
uint64_t seq = wseq >> 1;
/* Increase the waiter reference count. Relaxed MO is sufficient because
we only need to synchronize when decrementing the reference count. */
unsigned int flags = atomic_fetch_add_relaxed (&cond->__data.__wrefs, 8);
int private = __condvar_get_private (flags);
/* Now that we are registered as a waiter, we can release the mutex.
Waiting on the condvar must be atomic with releasing the mutex, so if
the mutex is used to establish a happens-before relation with any
signaler, the waiter must be visible to the latter; thus, we release the
mutex after registering as waiter.
If releasing the mutex fails, we just cancel our registration as a
waiter and confirm that we have woken up. */
err = __pthread_mutex_unlock_usercnt (mutex, 0);
if (__glibc_unlikely (err != 0))
{
__condvar_cancel_waiting (cond, seq, g, private);
__condvar_confirm_wakeup (cond, private);
return err;
}
/* Now wait until a signal is available in our group or it is closed.
Acquire MO so that if we observe a value of zero written after group
switching in __condvar_quiesce_and_switch_g1, we synchronize with that
store and will see the prior update of __g1_start done while switching
groups too. */
unsigned int signals = atomic_load_acquire (cond->__data.__g_signals + g);
do
{
while (1)
{
/* Spin-wait first.
Note that spinning first without checking whether a timeout
passed might lead to what looks like a spurious wake-up even
though we should return ETIMEDOUT (e.g., if the caller provides
an absolute timeout that is clearly in the past). However,
(1) spurious wake-ups are allowed, (2) it seems unlikely that a
user will (ab)use pthread_cond_wait as a check for whether a
point in time is in the past, and (3) spinning first without
having to compare against the current time seems to be the right
choice from a performance perspective for most use cases. */
unsigned int spin = maxspin;
while (signals == 0 && spin > 0)
{
/* Check that we are not spinning on a group that's already
closed. */
if (seq < (__condvar_load_g1_start_relaxed (cond) >> 1))
goto done;
/* TODO Back off. */
/* Reload signals. See above for MO. */
signals = atomic_load_acquire (cond->__data.__g_signals + g);
spin--;
}
/* If our group will be closed as indicated by the flag on signals,
don't bother grabbing a signal. */
if (signals & 1)
goto done;
/* If there is an available signal, don't block. */
if (signals != 0)
break;
/* No signals available after spinning, so prepare to block.
We first acquire a group reference and use acquire MO for that so
that we synchronize with the dummy read-modify-write in
__condvar_quiesce_and_switch_g1 if we read from that. In turn,
in this case this will make us see the closed flag on __g_signals
that designates a concurrent attempt to reuse the group's slot.
We use acquire MO for the __g_signals check to make the
__g1_start check work (see spinning above).
Note that the group reference acquisition will not mask the
release MO when decrementing the reference count because we use
an atomic read-modify-write operation and thus extend the release
sequence. */
atomic_fetch_add_acquire (cond->__data.__g_refs + g, 2);
if (((atomic_load_acquire (cond->__data.__g_signals + g) & 1) != 0)
|| (seq < (__condvar_load_g1_start_relaxed (cond) >> 1)))
{
/* Our group is closed. Wake up any signalers that might be
waiting. */
__condvar_dec_grefs (cond, g, private);
goto done;
}
// Now block.
struct _pthread_cleanup_buffer buffer;
struct _condvar_cleanup_buffer cbuffer;
cbuffer.wseq = wseq;
cbuffer.cond = cond;
cbuffer.mutex = mutex;
cbuffer.private = private;
__pthread_cleanup_push (&buffer, __condvar_cleanup_waiting, &cbuffer);
if (abstime == NULL)
{
/* Block without a timeout. */
err = futex_wait_cancelable (
cond->__data.__g_signals + g, 0, private);
}
else
{
/* Block, but with a timeout.
Work around the fact that the kernel rejects negative timeout
values despite them being valid. */
if (__glibc_unlikely (abstime->tv_sec < 0))
err = ETIMEDOUT;
else if ((flags & __PTHREAD_COND_CLOCK_MONOTONIC_MASK) != 0)
{
/* CLOCK_MONOTONIC is requested. */
struct timespec rt;
struct __timespec64 rt64;
if (__clock_gettime (CLOCK_MONOTONIC, &rt) != 0)
__libc_fatal ("clock_gettime does not support "
"CLOCK_MONOTONIC");
/* Convert the absolute timeout value to a relative
timeout. */
rt64.tv_sec = abstime->tv_sec - rt.tv_sec;
rt64.tv_nsec = abstime->tv_nsec - rt.tv_nsec;
if (rt64.tv_nsec < 0)
{
rt64.tv_nsec += 1000000000;
--rt64.tv_sec;
}
/* Did we already time out? */
if (__glibc_unlikely (rt64.tv_sec < 0))
err = ETIMEDOUT;
else
err = futex_reltimed_wait_cancelable64
(cond->__data.__g_signals + g, 0, &rt64, private);
}
else
{
/* Use CLOCK_REALTIME. */
err = futex_abstimed_wait_cancelable64
(cond->__data.__g_signals + g, 0, abstime, private);
}
}
__pthread_cleanup_pop (&buffer, 0);
if (__glibc_unlikely (err == ETIMEDOUT))
{
__condvar_dec_grefs (cond, g, private);
/* If we timed out, we effectively cancel waiting. Note that
we have decremented __g_refs before cancellation, so that a
deadlock between waiting for quiescence of our group in
__condvar_quiesce_and_switch_g1 and us trying to acquire
the lock during cancellation is not possible. */
__condvar_cancel_waiting (cond, seq, g, private);
result = ETIMEDOUT;
goto done;
}
else
__condvar_dec_grefs (cond, g, private);
/* Reload signals. See above for MO. */
signals = atomic_load_acquire (cond->__data.__g_signals + g);
}
}
/* Try to grab a signal. Use acquire MO so that we see an up-to-date value
of __g1_start below (see spinning above for a similar case). In
particular, if we steal from a more recent group, we will also see a
more recent __g1_start below. */
while (!atomic_compare_exchange_weak_acquire (cond->__data.__g_signals + g,
&signals, signals - 2));
/* We consumed a signal but we could have consumed from a more recent group
that aliased with ours due to being in the same group slot. If this
might be the case our group must be closed as visible through
__g1_start. */
uint64_t g1_start = __condvar_load_g1_start_relaxed (cond);
if (seq < (g1_start >> 1))
{
/* We potentially stole a signal from a more recent group but we do not
know which group we really consumed from.
We do not care about groups older than current G1 because they are
closed; we could have stolen from these, but then we just add a
spurious wake-up for the current groups.
We will never steal a signal from current G2 that was really intended
for G2 because G2 never receives signals (until it becomes G1). We
could have stolen a signal from G2 that was conservatively added by a
previous waiter that also thought it stole a signal -- but given that
that signal was added unnecessarily, it's not a problem if we steal
it.
Thus, the remaining case is that we could have stolen from the current
G1, where "current" means the __g1_start value we observed. However,
if the current G1 does not have the same slot index as we do, we did
not steal from it and do not need to undo that. This is the reason
for putting a bit with G2's index into__g1_start as well. */
if (((g1_start & 1) ^ 1) == g)
{
/* We have to conservatively undo our potential mistake of stealing
a signal. We can stop trying to do that when the current G1
changes because other spinning waiters will notice this too and
__condvar_quiesce_and_switch_g1 has checked that there are no
futex waiters anymore before switching G1.
Relaxed MO is fine for the __g1_start load because we need to
merely be able to observe this fact and not have to observe
something else as well.
??? Would it help to spin for a little while to see whether the
current G1 gets closed? This might be worthwhile if the group is
small or close to being closed. */
unsigned int s = atomic_load_relaxed (cond->__data.__g_signals + g);
while (__condvar_load_g1_start_relaxed (cond) == g1_start)
{
/* Try to add a signal. We don't need to acquire the lock
because at worst we can cause a spurious wake-up. If the
group is in the process of being closed (LSB is true), this
has an effect similar to us adding a signal. */
if (((s & 1) != 0)
|| atomic_compare_exchange_weak_relaxed
(cond->__data.__g_signals + g, &s, s + 2))
{
/* If we added a signal, we also need to add a wake-up on
the futex. We also need to do that if we skipped adding
a signal because the group is being closed because
while __condvar_quiesce_and_switch_g1 could have closed
the group, it might stil be waiting for futex waiters to
leave (and one of those waiters might be the one we stole
the signal from, which cause it to block using the
futex). */
futex_wake (cond->__data.__g_signals + g, 1, private);
break;
}
/* TODO Back off. */
}
}
}
done:
/* Confirm that we have been woken. We do that before acquiring the mutex
to allow for execution of pthread_cond_destroy while having acquired the
mutex. */
__condvar_confirm_wakeup (cond, private);
/* Woken up; now re-acquire the mutex. If this doesn't fail, return RESULT,
which is set to ETIMEDOUT if a timeout occured, or zero otherwise. */
err = __pthread_mutex_cond_lock (mutex);
/* XXX Abort on errors that are disallowed by POSIX? */
return (err != 0) ? err : result;
}
/* See __pthread_cond_wait_common. */
int
@@ -667,6 +941,17 @@ __pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex,
return __pthread_cond_wait_common (cond, mutex, abstime);
}
int
__pthread_cond_timedwait64 (pthread_cond_t *cond, pthread_mutex_t *mutex,
const struct __timespec64 *abstime)
{
/* Check parameter validity. This should also tell the compiler that
it can assume that abstime is not NULL. */
if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)
return EINVAL;
return __pthread_cond_wait_common64 (cond, mutex, abstime);
}
versioned_symbol (libpthread, __pthread_cond_wait, pthread_cond_wait,
GLIBC_2_3_2);
versioned_symbol (libpthread, __pthread_cond_timedwait, pthread_cond_timedwait,
+637
View File
@@ -25,6 +25,7 @@
#include <atomic.h>
#include <lowlevellock.h>
#include <not-cancel.h>
#include <y2038-support.h>
#include <stap-probe.h>
@@ -32,6 +33,10 @@
#define lll_timedlock_elision(a,dummy,b,c) lll_timedlock(a, b, c)
#endif
#ifndef lll_timedlock_elision64
#define lll_timedlock_elision64(a,dummy,b,c) lll_timedlock64(a, b, c)
#endif
#ifndef lll_trylock_elision
#define lll_trylock_elision(a,t) lll_trylock(a)
#endif
@@ -649,3 +654,635 @@ __pthread_mutex_timedlock (pthread_mutex_t *mutex,
return result;
}
weak_alias (__pthread_mutex_timedlock, pthread_mutex_timedlock)
/* 64-bit time version */
int
__pthread_mutex_timedlock64 (pthread_mutex_t *mutex,
const struct __timespec64 *abstime)
{
/* Only compile this function if kernel provides clock_gettime64 */
#ifdef __NR_clock_gettime64
int oldval;
pid_t id = THREAD_GETMEM (THREAD_SELF, tid);
int result = 0;
#endif
struct timespec abstime32;
LIBC_PROBE (mutex_timedlock_entry, 2, mutex, abstime);
/* Only compile this function if kernel provides clock_gettime64 */
#ifdef __NR_clock_gettime64
if (__y2038_get_kernel_support())
{
/* We must not check ABSTIME here. If the thread does not block
abstime must not be checked for a valid value. */
switch (__builtin_expect (PTHREAD_MUTEX_TYPE_ELISION (mutex),
PTHREAD_MUTEX_TIMED_NP))
{
/* Recursive mutex. */
case PTHREAD_MUTEX_RECURSIVE_NP|PTHREAD_MUTEX_ELISION_NP:
case PTHREAD_MUTEX_RECURSIVE_NP:
/* Check whether we already hold the mutex. */
if (mutex->__data.__owner == id)
{
/* Just bump the counter. */
if (__glibc_unlikely (mutex->__data.__count + 1 == 0))
/* Overflow of the counter. */
return EAGAIN;
++mutex->__data.__count;
goto out;
}
/* We have to get the mutex. */
result = lll_timedlock64 (mutex->__data.__lock, abstime,
PTHREAD_MUTEX_PSHARED (mutex));
if (result != 0)
goto out;
/* Only locked once so far. */
mutex->__data.__count = 1;
break;
/* Error checking mutex. */
case PTHREAD_MUTEX_ERRORCHECK_NP:
/* Check whether we already hold the mutex. */
if (__glibc_unlikely (mutex->__data.__owner == id))
return EDEADLK;
/* Don't do lock elision on an error checking mutex. */
goto simple;
case PTHREAD_MUTEX_TIMED_NP:
FORCE_ELISION (mutex, goto elision);
simple:
/* Normal mutex. */
result = lll_timedlock64 (mutex->__data.__lock, abstime,
PTHREAD_MUTEX_PSHARED (mutex));
break;
case PTHREAD_MUTEX_TIMED_ELISION_NP:
elision: __attribute__((unused))
/* Don't record ownership */
return lll_timedlock_elision64 (mutex->__data.__lock,
mutex->__data.__spins,
abstime,
PTHREAD_MUTEX_PSHARED (mutex));
case PTHREAD_MUTEX_ADAPTIVE_NP:
if (! __is_smp)
goto simple;
if (lll_trylock (mutex->__data.__lock) != 0)
{
int cnt = 0;
int max_cnt = MIN (MAX_ADAPTIVE_COUNT,
mutex->__data.__spins * 2 + 10);
do
{
if (cnt++ >= max_cnt)
{
result = lll_timedlock64 (mutex->__data.__lock, abstime,
PTHREAD_MUTEX_PSHARED (mutex));
break;
}
atomic_spin_nop ();
}
while (lll_trylock (mutex->__data.__lock) != 0);
mutex->__data.__spins += (cnt - mutex->__data.__spins) / 8;
}
break;
case PTHREAD_MUTEX_ROBUST_RECURSIVE_NP:
case PTHREAD_MUTEX_ROBUST_ERRORCHECK_NP:
case PTHREAD_MUTEX_ROBUST_NORMAL_NP:
case PTHREAD_MUTEX_ROBUST_ADAPTIVE_NP:
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
&mutex->__data.__list.__next);
/* We need to set op_pending before starting the operation. Also
see comments at ENQUEUE_MUTEX. */
__asm ("" ::: "memory");
oldval = mutex->__data.__lock;
/* This is set to FUTEX_WAITERS iff we might have shared the
FUTEX_WAITERS flag with other threads, and therefore need to keep it
set to avoid lost wake-ups. We have the same requirement in the
simple mutex algorithm. */
unsigned int assume_other_futex_waiters = 0;
while (1)
{
/* Try to acquire the lock through a CAS from 0 (not acquired) to
our TID | assume_other_futex_waiters. */
if (__glibc_likely (oldval == 0))
{
oldval
= atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
id | assume_other_futex_waiters, 0);
if (__glibc_likely (oldval == 0))
break;
}
if ((oldval & FUTEX_OWNER_DIED) != 0)
{
/* The previous owner died. Try locking the mutex. */
int newval = id | (oldval & FUTEX_WAITERS)
| assume_other_futex_waiters;
newval
= atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
newval, oldval);
if (newval != oldval)
{
oldval = newval;
continue;
}
/* We got the mutex. */
mutex->__data.__count = 1;
/* But it is inconsistent unless marked otherwise. */
mutex->__data.__owner = PTHREAD_MUTEX_INCONSISTENT;
/* We must not enqueue the mutex before we have acquired it.
Also see comments at ENQUEUE_MUTEX. */
__asm ("" ::: "memory");
ENQUEUE_MUTEX (mutex);
/* We need to clear op_pending after we enqueue the mutex. */
__asm ("" ::: "memory");
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
/* Note that we deliberately exit here. If we fall
through to the end of the function __nusers would be
incremented which is not correct because the old
owner has to be discounted. */
return EOWNERDEAD;
}
/* Check whether we already hold the mutex. */
if (__glibc_unlikely ((oldval & FUTEX_TID_MASK) == id))
{
int kind = PTHREAD_MUTEX_TYPE (mutex);
if (kind == PTHREAD_MUTEX_ROBUST_ERRORCHECK_NP)
{
/* We do not need to ensure ordering wrt another memory
access. Also see comments at ENQUEUE_MUTEX. */
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
NULL);
return EDEADLK;
}
if (kind == PTHREAD_MUTEX_ROBUST_RECURSIVE_NP)
{
/* We do not need to ensure ordering wrt another memory
access. */
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
NULL);
/* Just bump the counter. */
if (__glibc_unlikely (mutex->__data.__count + 1 == 0))
/* Overflow of the counter. */
return EAGAIN;
++mutex->__data.__count;
LIBC_PROBE (mutex_timedlock_acquired, 1, mutex);
return 0;
}
}
/* We are about to block; check whether the timeout is invalid. */
if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)
return EINVAL;
/* Work around the fact that the kernel rejects negative timeout
values despite them being valid. */
if (__glibc_unlikely (abstime->tv_sec < 0))
return ETIMEDOUT;
#if (!defined __ASSUME_FUTEX_CLOCK_REALTIME \
|| !defined lll_futex_timed_wait_bitset)
struct timeval tv;
struct timespec rt;
/* Get the current time. */
(void) __gettimeofday (&tv, NULL);
/* Compute relative timeout. */
rt.tv_sec = abstime->tv_sec - tv.tv_sec;
rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000;
if (rt.tv_nsec < 0)
{
rt.tv_nsec += 1000000000;
--rt.tv_sec;
}
/* Already timed out? */
if (rt.tv_sec < 0)
return ETIMEDOUT;
#endif
/* We cannot acquire the mutex nor has its owner died. Thus, try
to block using futexes. Set FUTEX_WAITERS if necessary so that
other threads are aware that there are potentially threads
blocked on the futex. Restart if oldval changed in the
meantime. */
if ((oldval & FUTEX_WAITERS) == 0)
{
if (atomic_compare_and_exchange_bool_acq (&mutex->__data.__lock,
oldval | FUTEX_WAITERS,
oldval)
!= 0)
{
oldval = mutex->__data.__lock;
continue;
}
oldval |= FUTEX_WAITERS;
}
/* It is now possible that we share the FUTEX_WAITERS flag with
another thread; therefore, update assume_other_futex_waiters so
that we do not forget about this when handling other cases
above and thus do not cause lost wake-ups. */
assume_other_futex_waiters |= FUTEX_WAITERS;
/* Block using the futex. */
#if (!defined __ASSUME_FUTEX_CLOCK_REALTIME \
|| !defined lll_futex_timed_wait_bitset)
lll_futex_timed wait_64 (&mutex->__data.__lock, oldval,
&rt, PTHREAD_ROBUST_MUTEX_PSHARED (mutex));
#else
int err = lll_futex_timed_wait_bitset64 (&mutex->__data.__lock,
oldval, abstime, FUTEX_CLOCK_REALTIME,
PTHREAD_ROBUST_MUTEX_PSHARED (mutex));
/* The futex call timed out. */
if (err == -ETIMEDOUT)
return -err;
#endif
/* Reload current lock value. */
oldval = mutex->__data.__lock;
}
/* We have acquired the mutex; check if it is still consistent. */
if (__builtin_expect (mutex->__data.__owner
== PTHREAD_MUTEX_NOTRECOVERABLE, 0))
{
/* This mutex is now not recoverable. */
mutex->__data.__count = 0;
int private = PTHREAD_ROBUST_MUTEX_PSHARED (mutex);
lll_unlock (mutex->__data.__lock, private);
/* FIXME This violates the mutex destruction requirements. See
__pthread_mutex_unlock_full. */
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
return ENOTRECOVERABLE;
}
mutex->__data.__count = 1;
/* We must not enqueue the mutex before we have acquired it.
Also see comments at ENQUEUE_MUTEX. */
__asm ("" ::: "memory");
ENQUEUE_MUTEX (mutex);
/* We need to clear op_pending after we enqueue the mutex. */
__asm ("" ::: "memory");
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
break;
/* The PI support requires the Linux futex system call. If that's not
available, pthread_mutex_init should never have allowed the type to
be set. So it will get the default case for an invalid type. */
#ifdef __NR_futex
case PTHREAD_MUTEX_PI_RECURSIVE_NP:
case PTHREAD_MUTEX_PI_ERRORCHECK_NP:
case PTHREAD_MUTEX_PI_NORMAL_NP:
case PTHREAD_MUTEX_PI_ADAPTIVE_NP:
case PTHREAD_MUTEX_PI_ROBUST_RECURSIVE_NP:
case PTHREAD_MUTEX_PI_ROBUST_ERRORCHECK_NP:
case PTHREAD_MUTEX_PI_ROBUST_NORMAL_NP:
case PTHREAD_MUTEX_PI_ROBUST_ADAPTIVE_NP:
{
int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP;
int robust = mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP;
if (robust)
{
/* Note: robust PI futexes are signaled by setting bit 0. */
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
(void *) (((uintptr_t) &mutex->__data.__list.__next)
| 1));
/* We need to set op_pending before starting the operation. Also
see comments at ENQUEUE_MUTEX. */
__asm ("" ::: "memory");
}
oldval = mutex->__data.__lock;
/* Check whether we already hold the mutex. */
if (__glibc_unlikely ((oldval & FUTEX_TID_MASK) == id))
{
if (kind == PTHREAD_MUTEX_ERRORCHECK_NP)
{
/* We do not need to ensure ordering wrt another memory
access. */
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
return EDEADLK;
}
if (kind == PTHREAD_MUTEX_RECURSIVE_NP)
{
/* We do not need to ensure ordering wrt another memory
access. */
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
/* Just bump the counter. */
if (__glibc_unlikely (mutex->__data.__count + 1 == 0))
/* Overflow of the counter. */
return EAGAIN;
++mutex->__data.__count;
LIBC_PROBE (mutex_timedlock_acquired, 1, mutex);
return 0;
}
}
oldval = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
id, 0);
if (oldval != 0)
{
/* The mutex is locked. The kernel will now take care of
everything. The timeout value must be a relative value.
Convert it. */
int private = (robust
? PTHREAD_ROBUST_MUTEX_PSHARED (mutex)
: PTHREAD_MUTEX_PSHARED (mutex));
INTERNAL_SYSCALL_DECL (__err);
int e;
if (abstime->tv_sec > INT_MAX)
{
e = EOVERFLOW;
}
else
{
struct timespec ts;
ts.tv_sec = abstime->tv_sec;
ts.tv_nsec = abstime->tv_nsec;
e = INTERNAL_SYSCALL (futex, __err, 4, &mutex->__data.__lock,
__lll_private_flag (FUTEX_LOCK_PI,
private), 1,
&ts);
}
if (INTERNAL_SYSCALL_ERROR_P (e, __err))
{
if (INTERNAL_SYSCALL_ERRNO (e, __err) == ETIMEDOUT)
return ETIMEDOUT;
if (INTERNAL_SYSCALL_ERRNO (e, __err) == ESRCH
|| INTERNAL_SYSCALL_ERRNO (e, __err) == EDEADLK)
{
assert (INTERNAL_SYSCALL_ERRNO (e, __err) != EDEADLK
|| (kind != PTHREAD_MUTEX_ERRORCHECK_NP
&& kind != PTHREAD_MUTEX_RECURSIVE_NP));
/* ESRCH can happen only for non-robust PI mutexes where
the owner of the lock died. */
assert (INTERNAL_SYSCALL_ERRNO (e, __err) != ESRCH
|| !robust);
/* Delay the thread until the timeout is reached.
Then return ETIMEDOUT. */
struct timespec reltime;
struct __timespec64 now;
INTERNAL_SYSCALL (clock_gettime64, __err, 2, CLOCK_REALTIME,
&now);
reltime.tv_sec = abstime->tv_sec - now.tv_sec;
reltime.tv_nsec = abstime->tv_nsec - now.tv_nsec;
if (reltime.tv_nsec < 0)
{
reltime.tv_nsec += 1000000000;
--reltime.tv_sec;
}
if (reltime.tv_sec >= 0)
while (__nanosleep_nocancel (&reltime, &reltime) != 0)
continue;
return ETIMEDOUT;
}
return INTERNAL_SYSCALL_ERRNO (e, __err);
}
oldval = mutex->__data.__lock;
assert (robust || (oldval & FUTEX_OWNER_DIED) == 0);
}
if (__glibc_unlikely (oldval & FUTEX_OWNER_DIED))
{
atomic_and (&mutex->__data.__lock, ~FUTEX_OWNER_DIED);
/* We got the mutex. */
mutex->__data.__count = 1;
/* But it is inconsistent unless marked otherwise. */
mutex->__data.__owner = PTHREAD_MUTEX_INCONSISTENT;
/* We must not enqueue the mutex before we have acquired it.
Also see comments at ENQUEUE_MUTEX. */
__asm ("" ::: "memory");
ENQUEUE_MUTEX_PI (mutex);
/* We need to clear op_pending after we enqueue the mutex. */
__asm ("" ::: "memory");
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
/* Note that we deliberately exit here. If we fall
through to the end of the function __nusers would be
incremented which is not correct because the old owner
has to be discounted. */
return EOWNERDEAD;
}
if (robust
&& __builtin_expect (mutex->__data.__owner
== PTHREAD_MUTEX_NOTRECOVERABLE, 0))
{
/* This mutex is now not recoverable. */
mutex->__data.__count = 0;
INTERNAL_SYSCALL_DECL (__err);
INTERNAL_SYSCALL (futex, __err, 4, &mutex->__data.__lock,
__lll_private_flag (FUTEX_UNLOCK_PI,
PTHREAD_ROBUST_MUTEX_PSHARED (mutex)),
0, 0);
/* To the kernel, this will be visible after the kernel has
acquired the mutex in the syscall. */
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
return ENOTRECOVERABLE;
}
mutex->__data.__count = 1;
if (robust)
{
/* We must not enqueue the mutex before we have acquired it.
Also see comments at ENQUEUE_MUTEX. */
__asm ("" ::: "memory");
ENQUEUE_MUTEX_PI (mutex);
/* We need to clear op_pending after we enqueue the mutex. */
__asm ("" ::: "memory");
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
}
}
break;
#endif /* __NR_futex. */
case PTHREAD_MUTEX_PP_RECURSIVE_NP:
case PTHREAD_MUTEX_PP_ERRORCHECK_NP:
case PTHREAD_MUTEX_PP_NORMAL_NP:
case PTHREAD_MUTEX_PP_ADAPTIVE_NP:
{
int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP;
oldval = mutex->__data.__lock;
/* Check whether we already hold the mutex. */
if (mutex->__data.__owner == id)
{
if (kind == PTHREAD_MUTEX_ERRORCHECK_NP)
return EDEADLK;
if (kind == PTHREAD_MUTEX_RECURSIVE_NP)
{
/* Just bump the counter. */
if (__glibc_unlikely (mutex->__data.__count + 1 == 0))
/* Overflow of the counter. */
return EAGAIN;
++mutex->__data.__count;
LIBC_PROBE (mutex_timedlock_acquired, 1, mutex);
return 0;
}
}
int oldprio = -1, ceilval;
do
{
int ceiling = (oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK)
>> PTHREAD_MUTEX_PRIO_CEILING_SHIFT;
if (__pthread_current_priority () > ceiling)
{
result = EINVAL;
failpp:
if (oldprio != -1)
__pthread_tpp_change_priority (oldprio, -1);
return result;
}
result = __pthread_tpp_change_priority (oldprio, ceiling);
if (result)
return result;
ceilval = ceiling << PTHREAD_MUTEX_PRIO_CEILING_SHIFT;
oldprio = ceiling;
oldval
= atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
ceilval | 1, ceilval);
if (oldval == ceilval)
break;
do
{
oldval
= atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
ceilval | 2,
ceilval | 1);
if ((oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK) != ceilval)
break;
if (oldval != ceilval)
{
/* Reject invalid timeouts. */
if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)
{
result = EINVAL;
goto failpp;
}
struct timeval tv;
struct timespec rt;
/* Get the current time. */
(void) __gettimeofday (&tv, NULL);
/* Compute relative timeout. */
rt.tv_sec = abstime->tv_sec - tv.tv_sec;
rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000;
if (rt.tv_nsec < 0)
{
rt.tv_nsec += 1000000000;
--rt.tv_sec;
}
/* Already timed out? */
if (rt.tv_sec < 0)
{
result = ETIMEDOUT;
goto failpp;
}
lll_futex_timed_wait (&mutex->__data.__lock,
ceilval | 2, &rt,
PTHREAD_MUTEX_PSHARED (mutex));
}
}
while (atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
ceilval | 2, ceilval)
!= ceilval);
}
while ((oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK) != ceilval);
assert (mutex->__data.__owner == 0);
mutex->__data.__count = 1;
}
break;
default:
/* Correct code cannot set any other type. */
return EINVAL;
}
if (result == 0)
{
/* Record the ownership. */
mutex->__data.__owner = id;
++mutex->__data.__nusers;
LIBC_PROBE (mutex_timedlock_acquired, 1, mutex);
}
out:
return result;
}
#endif
if (abstime->tv_sec > INT_MAX || abstime->tv_sec < INT_MIN)
{
return EOVERFLOW;
}
abstime32.tv_sec = (time_t) (abstime->tv_sec);
abstime32.tv_nsec = abstime->tv_nsec;
return __pthread_mutex_timedlock (mutex, &abstime32);
}
+591
View File
@@ -507,6 +507,240 @@ __pthread_rwlock_rdlock_full (pthread_rwlock_t *rwlock,
return 0;
}
/* 64-bit time version */
static __always_inline int
__pthread_rwlock_rdlock_full64 (pthread_rwlock_t *rwlock,
const struct __timespec64 *abstime)
{
unsigned int r;
/* Make sure we are not holding the rwlock as a writer. This is a deadlock
situation we recognize and report. */
if (__glibc_unlikely (atomic_load_relaxed (&rwlock->__data.__cur_writer)
== THREAD_GETMEM (THREAD_SELF, tid)))
return EDEADLK;
/* If we prefer writers, recursive rdlock is disallowed, we are in a read
phase, and there are other readers present, we try to wait without
extending the read phase. We will be unblocked by either one of the
other active readers, or if the writer gives up WRLOCKED (e.g., on
timeout).
If there are no other readers, we simply race with any existing primary
writer; it would have been a race anyway, and changing the odds slightly
will likely not make a big difference. */
if (rwlock->__data.__flags == PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP)
{
r = atomic_load_relaxed (&rwlock->__data.__readers);
while (((r & PTHREAD_RWLOCK_WRPHASE) == 0)
&& ((r & PTHREAD_RWLOCK_WRLOCKED) != 0)
&& ((r >> PTHREAD_RWLOCK_READER_SHIFT) > 0))
{
/* TODO Spin first. */
/* Try setting the flag signaling that we are waiting without having
incremented the number of readers. Relaxed MO is fine because
this is just about waiting for a state change in __readers. */
if (atomic_compare_exchange_weak_relaxed
(&rwlock->__data.__readers, &r, r | PTHREAD_RWLOCK_RWAITING))
{
/* Wait for as long as the flag is set. An ABA situation is
harmless because the flag is just about the state of
__readers, and all threads set the flag under the same
conditions. */
while ((atomic_load_relaxed (&rwlock->__data.__readers)
& PTHREAD_RWLOCK_RWAITING) != 0)
{
int private = __pthread_rwlock_get_private (rwlock);
int err = futex_abstimed_wait64 (&rwlock->__data.__readers,
r, abstime, private);
/* We ignore EAGAIN and EINTR. On time-outs, we can just
return because we don't need to clean up anything. */
if (err == ETIMEDOUT)
return err;
}
/* It makes sense to not break out of the outer loop here
because we might be in the same situation again. */
}
else
{
/* TODO Back-off. */
}
}
}
/* Register as a reader, using an add-and-fetch so that R can be used as
expected value for future operations. Acquire MO so we synchronize with
prior writers as well as the last reader of the previous read phase (see
below). */
r = atomic_fetch_add_acquire (&rwlock->__data.__readers,
(1 << PTHREAD_RWLOCK_READER_SHIFT)) + (1 << PTHREAD_RWLOCK_READER_SHIFT);
/* Check whether there is an overflow in the number of readers. We assume
that the total number of threads is less than half the maximum number
of readers that we have bits for in __readers (i.e., with 32-bit int and
PTHREAD_RWLOCK_READER_SHIFT of 3, we assume there are less than
1 << (32-3-1) concurrent threads).
If there is an overflow, we use a CAS to try to decrement the number of
readers if there still is an overflow situation. If so, we return
EAGAIN; if not, we are not a thread causing an overflow situation, and so
we just continue. Using a fetch-add instead of the CAS isn't possible
because other readers might release the lock concurrently, which could
make us the last reader and thus responsible for handing ownership over
to writers (which requires a CAS too to make the decrement and ownership
transfer indivisible). */
while (__glibc_unlikely (r >= PTHREAD_RWLOCK_READER_OVERFLOW))
{
/* Relaxed MO is okay because we just want to undo our registration and
cannot have changed the rwlock state substantially if the CAS
succeeds. */
if (atomic_compare_exchange_weak_relaxed (&rwlock->__data.__readers, &r,
r - (1 << PTHREAD_RWLOCK_READER_SHIFT)))
return EAGAIN;
}
/* We have registered as a reader, so if we are in a read phase, we have
acquired a read lock. This is also the reader--reader fast-path.
Even if there is a primary writer, we just return. If writers are to
be preferred and we are the only active reader, we could try to enter a
write phase to let the writer proceed. This would be okay because we
cannot have acquired the lock previously as a reader (which could result
in deadlock if we would wait for the primary writer to run). However,
this seems to be a corner case and handling it specially not be worth the
complexity. */
if (__glibc_likely ((r & PTHREAD_RWLOCK_WRPHASE) == 0))
return 0;
/* If there is no primary writer but we are in a write phase, we can try
to install a read phase ourself. */
while (((r & PTHREAD_RWLOCK_WRPHASE) != 0)
&& ((r & PTHREAD_RWLOCK_WRLOCKED) == 0))
{
/* Try to enter a read phase: If the CAS below succeeds, we have
ownership; if it fails, we will simply retry and reassess the
situation.
Acquire MO so we synchronize with prior writers. */
if (atomic_compare_exchange_weak_acquire (&rwlock->__data.__readers, &r,
r ^ PTHREAD_RWLOCK_WRPHASE))
{
/* We started the read phase, so we are also responsible for
updating the write-phase futex. Relaxed MO is sufficient.
Note that there can be no other reader that we have to wake
because all other readers will see the read phase started by us
(or they will try to start it themselves); if a writer started
the read phase, we cannot have started it. Furthermore, we
cannot discard a PTHREAD_RWLOCK_FUTEX_USED flag because we will
overwrite the value set by the most recent writer (or the readers
before it in case of explicit hand-over) and we know that there
are no waiting readers. */
atomic_store_relaxed (&rwlock->__data.__wrphase_futex, 0);
return 0;
}
else
{
/* TODO Back off before retrying. Also see above. */
}
}
if ((r & PTHREAD_RWLOCK_WRPHASE) != 0)
{
/* We are in a write phase, and there must be a primary writer because
of the previous loop. Block until the primary writer gives up the
write phase. This case requires explicit hand-over using
__wrphase_futex.
However, __wrphase_futex might not have been set to 1 yet (either
because explicit hand-over to the writer is still ongoing, or because
the writer has started the write phase but does not yet have updated
__wrphase_futex). The least recent value of __wrphase_futex we can
read from here is the modification of the last read phase (because
we synchronize with the last reader in this read phase through
__readers; see the use of acquire MO on the fetch_add above).
Therefore, if we observe a value of 0 for __wrphase_futex, we need
to subsequently check that __readers now indicates a read phase; we
need to use acquire MO for this so that if we observe a read phase,
we will also see the modification of __wrphase_futex by the previous
writer. We then need to load __wrphase_futex again and continue to
wait if it is not 0, so that we do not skip explicit hand-over.
Relaxed MO is sufficient for the load from __wrphase_futex because
we just use it as an indicator for when we can proceed; we use
__readers and the acquire MO accesses to it to eventually read from
the proper stores to __wrphase_futex. */
unsigned int wpf;
bool ready = false;
for (;;)
{
while (((wpf = atomic_load_relaxed (&rwlock->__data.__wrphase_futex))
| PTHREAD_RWLOCK_FUTEX_USED) == (1 | PTHREAD_RWLOCK_FUTEX_USED))
{
int private = __pthread_rwlock_get_private (rwlock);
if (((wpf & PTHREAD_RWLOCK_FUTEX_USED) == 0)
&& !atomic_compare_exchange_weak_relaxed
(&rwlock->__data.__wrphase_futex,
&wpf, wpf | PTHREAD_RWLOCK_FUTEX_USED))
continue;
int err = futex_abstimed_wait64 (&rwlock->__data.__wrphase_futex,
1 | PTHREAD_RWLOCK_FUTEX_USED, abstime, private);
if (err == ETIMEDOUT)
{
/* If we timed out, we need to unregister. If no read phase
has been installed while we waited, we can just decrement
the number of readers. Otherwise, we just acquire the
lock, which is allowed because we give no precise timing
guarantees, and because the timeout is only required to
be in effect if we would have had to wait for other
threads (e.g., if futex_wait would time-out immediately
because the given absolute time is in the past). */
r = atomic_load_relaxed (&rwlock->__data.__readers);
while ((r & PTHREAD_RWLOCK_WRPHASE) != 0)
{
/* We don't need to make anything else visible to
others besides unregistering, so relaxed MO is
sufficient. */
if (atomic_compare_exchange_weak_relaxed
(&rwlock->__data.__readers, &r,
r - (1 << PTHREAD_RWLOCK_READER_SHIFT)))
return ETIMEDOUT;
/* TODO Back-off. */
}
/* Use the acquire MO fence to mirror the steps taken in the
non-timeout case. Note that the read can happen both
in the atomic_load above as well as in the failure case
of the CAS operation. */
atomic_thread_fence_acquire ();
/* We still need to wait for explicit hand-over, but we must
not use futex_wait anymore because we would just time out
in this case and thus make the spin-waiting we need
unnecessarily expensive. */
while ((atomic_load_relaxed (&rwlock->__data.__wrphase_futex)
| PTHREAD_RWLOCK_FUTEX_USED)
== (1 | PTHREAD_RWLOCK_FUTEX_USED))
{
/* TODO Back-off? */
}
ready = true;
break;
}
/* If we got interrupted (EINTR) or the futex word does not have the
expected value (EAGAIN), retry. */
}
if (ready)
/* See below. */
break;
/* We need acquire MO here so that we synchronize with the lock
release of the writer, and so that we observe a recent value of
__wrphase_futex (see below). */
if ((atomic_load_acquire (&rwlock->__data.__readers)
& PTHREAD_RWLOCK_WRPHASE) == 0)
/* We are in a read phase now, so the least recent modification of
__wrphase_futex we can read from is the store by the writer
with value 1. Thus, only now we can assume that if we observe
a value of 0, explicit hand-over is finished. Retry the loop
above one more time. */
ready = true;
}
}
return 0;
}
static __always_inline void
__pthread_rwlock_wrunlock (pthread_rwlock_t *rwlock)
@@ -924,3 +1158,360 @@ __pthread_rwlock_wrlock_full (pthread_rwlock_t *rwlock,
THREAD_GETMEM (THREAD_SELF, tid));
return 0;
}
/* 64-bit time version */
static __always_inline int
__pthread_rwlock_wrlock_full64 (pthread_rwlock_t *rwlock,
const struct __timespec64 *abstime)
{
/* Make sure we are not holding the rwlock as a writer. This is a deadlock
situation we recognize and report. */
if (__glibc_unlikely (atomic_load_relaxed (&rwlock->__data.__cur_writer)
== THREAD_GETMEM (THREAD_SELF, tid)))
return EDEADLK;
/* First we try to acquire the role of primary writer by setting WRLOCKED;
if it was set before, there already is a primary writer. Acquire MO so
that we synchronize with previous primary writers.
We do not try to change to a write phase right away using a fetch_or
because we would have to reset it again and wake readers if there are
readers present (some readers could try to acquire the lock more than
once, so setting a write phase in the middle of this could cause
deadlock). Changing to a write phase eagerly would only speed up the
transition from a read phase to a write phase in the uncontended case,
but it would slow down the contended case if readers are preferred (which
is the default).
We could try to CAS from a state with no readers to a write phase, but
this could be less scalable if readers arrive and leave frequently. */
bool may_share_futex_used_flag = false;
unsigned int r = atomic_fetch_or_acquire (&rwlock->__data.__readers,
PTHREAD_RWLOCK_WRLOCKED);
if (__glibc_unlikely ((r & PTHREAD_RWLOCK_WRLOCKED) != 0))
{
/* There is another primary writer. */
bool prefer_writer =
(rwlock->__data.__flags != PTHREAD_RWLOCK_PREFER_READER_NP);
if (prefer_writer)
{
/* We register as a waiting writer, so that we can make use of
writer--writer hand-over. Relaxed MO is fine because we just
want to register. We assume that the maximum number of threads
is less than the capacity in __writers. */
atomic_fetch_add_relaxed (&rwlock->__data.__writers, 1);
}
for (;;)
{
/* TODO Spin until WRLOCKED is 0 before trying the CAS below.
But pay attention to not delay trying writer--writer hand-over
for too long (which we must try eventually anyway). */
if ((r & PTHREAD_RWLOCK_WRLOCKED) == 0)
{
/* Try to become the primary writer or retry. Acquire MO as in
the fetch_or above. */
if (atomic_compare_exchange_weak_acquire
(&rwlock->__data.__readers, &r,
r | PTHREAD_RWLOCK_WRLOCKED))
{
if (prefer_writer)
{
/* Unregister as a waiting writer. Note that because we
acquired WRLOCKED, WRHANDOVER will not be set.
Acquire MO on the CAS above ensures that
unregistering happens after the previous writer;
this sorts the accesses to __writers by all
primary writers in a useful way (e.g., any other
primary writer acquiring after us or getting it from
us through WRHANDOVER will see both our changes to
__writers).
??? Perhaps this is not strictly necessary for
reasons we do not yet know of. */
atomic_fetch_add_relaxed (&rwlock->__data.__writers,
-1);
}
break;
}
/* Retry if the CAS fails (r will have been updated). */
continue;
}
/* If writer--writer hand-over is available, try to become the
primary writer this way by grabbing the WRHANDOVER token. If we
succeed, we own WRLOCKED. */
if (prefer_writer)
{
unsigned int w = atomic_load_relaxed
(&rwlock->__data.__writers);
if ((w & PTHREAD_RWLOCK_WRHANDOVER) != 0)
{
/* Acquire MO is required here so that we synchronize with
the writer that handed over WRLOCKED. We also need this
for the reload of __readers below because our view of
__readers must be at least as recent as the view of the
writer that handed over WRLOCKED; we must avoid an ABA
through WRHANDOVER, which could, for example, lead to us
assuming we are still in a write phase when in fact we
are not. */
if (atomic_compare_exchange_weak_acquire
(&rwlock->__data.__writers,
&w, (w - PTHREAD_RWLOCK_WRHANDOVER - 1)))
{
/* Reload so our view is consistent with the view of
the previous owner of WRLOCKED. See above. */
r = atomic_load_relaxed (&rwlock->__data.__readers);
break;
}
/* We do not need to reload __readers here. We should try
to perform writer--writer hand-over if possible; if it
is not possible anymore, we will reload __readers
elsewhere in this loop. */
continue;
}
}
/* We did not acquire WRLOCKED nor were able to use writer--writer
hand-over, so we block on __writers_futex. */
int private = __pthread_rwlock_get_private (rwlock);
unsigned int wf = atomic_load_relaxed
(&rwlock->__data.__writers_futex);
if (((wf & ~(unsigned int) PTHREAD_RWLOCK_FUTEX_USED) != 1)
|| ((wf != (1 | PTHREAD_RWLOCK_FUTEX_USED))
&& !atomic_compare_exchange_weak_relaxed
(&rwlock->__data.__writers_futex, &wf,
1 | PTHREAD_RWLOCK_FUTEX_USED)))
{
/* If we cannot block on __writers_futex because there is no
primary writer, or we cannot set PTHREAD_RWLOCK_FUTEX_USED,
we retry. We must reload __readers here in case we cannot
block on __writers_futex so that we can become the primary
writer and are not stuck in a loop that just continuously
fails to block on __writers_futex. */
r = atomic_load_relaxed (&rwlock->__data.__readers);
continue;
}
/* We set the flag that signals that the futex is used, or we could
have set it if we had been faster than other waiters. As a
result, we may share the flag with an unknown number of other
writers. Therefore, we must keep this flag set when we acquire
the lock. We do not need to do this when we do not reach this
point here because then we are not part of the group that may
share the flag, and another writer will wake one of the writers
in this group. */
may_share_futex_used_flag = true;
int err = futex_abstimed_wait64 (&rwlock->__data.__writers_futex,
1 | PTHREAD_RWLOCK_FUTEX_USED, abstime, private);
if (err == ETIMEDOUT)
{
if (prefer_writer)
{
/* We need to unregister as a waiting writer. If we are the
last writer and writer--writer hand-over is available,
we must make use of it because nobody else will reset
WRLOCKED otherwise. (If we use it, we simply pretend
that this happened before the timeout; see
pthread_rwlock_rdlock_full for the full reasoning.)
Also see the similar code above. */
unsigned int w = atomic_load_relaxed
(&rwlock->__data.__writers);
while (!atomic_compare_exchange_weak_acquire
(&rwlock->__data.__writers, &w,
(w == PTHREAD_RWLOCK_WRHANDOVER + 1 ? 0 : w - 1)))
{
/* TODO Back-off. */
}
if (w == PTHREAD_RWLOCK_WRHANDOVER + 1)
{
/* We must continue as primary writer. See above. */
r = atomic_load_relaxed (&rwlock->__data.__readers);
break;
}
}
/* We cleaned up and cannot have stolen another waiting writer's
futex wake-up, so just return. */
return ETIMEDOUT;
}
/* If we got interrupted (EINTR) or the futex word does not have the
expected value (EAGAIN), retry after reloading __readers. */
r = atomic_load_relaxed (&rwlock->__data.__readers);
}
/* Our snapshot of __readers is up-to-date at this point because we
either set WRLOCKED using a CAS or were handed over WRLOCKED from
another writer whose snapshot of __readers we inherit. */
}
/* If we are in a read phase and there are no readers, try to start a write
phase. */
while (((r & PTHREAD_RWLOCK_WRPHASE) == 0)
&& ((r >> PTHREAD_RWLOCK_READER_SHIFT) == 0))
{
/* Acquire MO so that we synchronize with prior writers and do
not interfere with their updates to __writers_futex, as well
as regarding prior readers and their updates to __wrphase_futex,
respectively. */
if (atomic_compare_exchange_weak_acquire (&rwlock->__data.__readers,
&r, r | PTHREAD_RWLOCK_WRPHASE))
{
/* We have started a write phase, so need to enable readers to wait.
See the similar case in__pthread_rwlock_rdlock_full. */
atomic_store_relaxed (&rwlock->__data.__wrphase_futex, 1);
/* Make sure we fall through to the end of the function. */
r |= PTHREAD_RWLOCK_WRPHASE;
break;
}
/* TODO Back-off. */
}
/* We are the primary writer; enable blocking on __writers_futex. Relaxed
MO is sufficient for futex words; acquire MO on the previous
modifications of __readers ensures that this store happens after the
store of value 0 by the previous primary writer. */
atomic_store_relaxed (&rwlock->__data.__writers_futex,
1 | (may_share_futex_used_flag ? PTHREAD_RWLOCK_FUTEX_USED : 0));
if (__glibc_unlikely ((r & PTHREAD_RWLOCK_WRPHASE) == 0))
{
/* We are not in a read phase and there are readers (because of the
previous loop). Thus, we have to wait for explicit hand-over from
one of these readers.
We basically do the same steps as for the similar case in
__pthread_rwlock_rdlock_full, except that we additionally might try
to directly hand over to another writer and need to wake up
other writers or waiting readers (i.e., PTHREAD_RWLOCK_RWAITING). */
unsigned int wpf;
bool ready = false;
for (;;)
{
while (((wpf = atomic_load_relaxed (&rwlock->__data.__wrphase_futex))
| PTHREAD_RWLOCK_FUTEX_USED) == PTHREAD_RWLOCK_FUTEX_USED)
{
int private = __pthread_rwlock_get_private (rwlock);
if (((wpf & PTHREAD_RWLOCK_FUTEX_USED) == 0)
&& !atomic_compare_exchange_weak_relaxed
(&rwlock->__data.__wrphase_futex, &wpf,
PTHREAD_RWLOCK_FUTEX_USED))
continue;
int err = futex_abstimed_wait64 (&rwlock->__data.__wrphase_futex,
PTHREAD_RWLOCK_FUTEX_USED, abstime, private);
if (err == ETIMEDOUT)
{
if (rwlock->__data.__flags
!= PTHREAD_RWLOCK_PREFER_READER_NP)
{
/* We try writer--writer hand-over. */
unsigned int w = atomic_load_relaxed
(&rwlock->__data.__writers);
if (w != 0)
{
/* We are about to hand over WRLOCKED, so we must
release __writers_futex too; otherwise, we'd have
a pending store, which could at least prevent
other threads from waiting using the futex
because it could interleave with the stores
by subsequent writers. In turn, this means that
we have to clean up when we do not hand over
WRLOCKED.
Release MO so that another writer that gets
WRLOCKED from us can take over our view of
__readers. */
unsigned int wf = atomic_exchange_relaxed
(&rwlock->__data.__writers_futex, 0);
while (w != 0)
{
if (atomic_compare_exchange_weak_release
(&rwlock->__data.__writers, &w,
w | PTHREAD_RWLOCK_WRHANDOVER))
{
/* Wake other writers. */
if ((wf & PTHREAD_RWLOCK_FUTEX_USED) != 0)
futex_wake
(&rwlock->__data.__writers_futex, 1,
private);
return ETIMEDOUT;
}
/* TODO Back-off. */
}
/* We still own WRLOCKED and someone else might set
a write phase concurrently, so enable waiting
again. Make sure we don't loose the flag that
signals whether there are threads waiting on
this futex. */
atomic_store_relaxed
(&rwlock->__data.__writers_futex, wf);
}
}
/* If we timed out and we are not in a write phase, we can
just stop being a primary writer. Otherwise, we just
acquire the lock. */
r = atomic_load_relaxed (&rwlock->__data.__readers);
if ((r & PTHREAD_RWLOCK_WRPHASE) == 0)
{
/* We are about to release WRLOCKED, so we must release
__writers_futex too; see the handling of
writer--writer hand-over above. */
unsigned int wf = atomic_exchange_relaxed
(&rwlock->__data.__writers_futex, 0);
while ((r & PTHREAD_RWLOCK_WRPHASE) == 0)
{
/* While we don't need to make anything from a
caller's critical section visible to other
threads, we need to ensure that our changes to
__writers_futex are properly ordered.
Therefore, use release MO to synchronize with
subsequent primary writers. Also wake up any
waiting readers as they are waiting because of
us. */
if (atomic_compare_exchange_weak_release
(&rwlock->__data.__readers, &r,
(r ^ PTHREAD_RWLOCK_WRLOCKED)
& ~(unsigned int) PTHREAD_RWLOCK_RWAITING))
{
/* Wake other writers. */
if ((wf & PTHREAD_RWLOCK_FUTEX_USED) != 0)
futex_wake (&rwlock->__data.__writers_futex,
1, private);
/* Wake waiting readers. */
if ((r & PTHREAD_RWLOCK_RWAITING) != 0)
futex_wake (&rwlock->__data.__readers,
INT_MAX, private);
return ETIMEDOUT;
}
}
/* We still own WRLOCKED and someone else might set a
write phase concurrently, so enable waiting again.
Make sure we don't loose the flag that signals
whether there are threads waiting on this futex. */
atomic_store_relaxed (&rwlock->__data.__writers_futex,
wf);
}
/* Use the acquire MO fence to mirror the steps taken in the
non-timeout case. Note that the read can happen both
in the atomic_load above as well as in the failure case
of the CAS operation. */
atomic_thread_fence_acquire ();
/* We still need to wait for explicit hand-over, but we must
not use futex_wait anymore. */
while ((atomic_load_relaxed
(&rwlock->__data.__wrphase_futex)
| PTHREAD_RWLOCK_FUTEX_USED)
== PTHREAD_RWLOCK_FUTEX_USED)
{
/* TODO Back-off. */
}
ready = true;
break;
}
/* If we got interrupted (EINTR) or the futex word does not have
the expected value (EAGAIN), retry. */
}
/* See pthread_rwlock_rdlock_full. */
if (ready)
break;
if ((atomic_load_acquire (&rwlock->__data.__readers)
& PTHREAD_RWLOCK_WRPHASE) != 0)
ready = true;
}
}
atomic_store_relaxed (&rwlock->__data.__cur_writer,
THREAD_GETMEM (THREAD_SELF, tid));
return 0;
}
+19
View File
@@ -35,3 +35,22 @@ pthread_rwlock_timedrdlock (pthread_rwlock_t *rwlock,
return __pthread_rwlock_rdlock_full (rwlock, abstime);
}
/* 64-bit time version */
int
__pthread_rwlock_timedrdlock64 (pthread_rwlock_t *rwlock,
const struct __timespec64 *abstime)
{
/* Make sure the passed in timeout value is valid. Note that the previous
implementation assumed that this check *must* not be performed if there
would in fact be no blocking; however, POSIX only requires that "the
validity of the abstime parameter need not be checked if the lock can be
immediately acquired" (i.e., we need not but may check it). */
/* ??? Just move this to __pthread_rwlock_rdlock_full? */
if (__glibc_unlikely (abstime->tv_nsec >= 1000000000
|| abstime->tv_nsec < 0))
return EINVAL;
return __pthread_rwlock_rdlock_full64 (rwlock, abstime);
}
+19
View File
@@ -35,3 +35,22 @@ pthread_rwlock_timedwrlock (pthread_rwlock_t *rwlock,
return __pthread_rwlock_wrlock_full (rwlock, abstime);
}
/* 64-bit time version */
int
__pthread_rwlock_timedwrlock64 (pthread_rwlock_t *rwlock,
const struct __timespec64 *abstime)
{
/* Make sure the passed in timeout value is valid. Note that the previous
implementation assumed that this check *must* not be performed if there
would in fact be no blocking; however, POSIX only requires that "the
validity of the abstime parameter need not be checked if the lock can be
immediately acquired" (i.e., we need not but may check it). */
/* ??? Just move this to __pthread_rwlock_wrlock_full? */
if (__glibc_unlikely (abstime->tv_nsec >= 1000000000
|| abstime->tv_nsec < 0))
return EINVAL;
return __pthread_rwlock_wrlock_full64 (rwlock, abstime);
}
+18
View File
@@ -38,3 +38,21 @@ sem_timedwait (sem_t *sem, const struct timespec *abstime)
else
return __new_sem_wait_slow((struct new_sem *) sem, abstime);
}
int
__sem_timedwait64 (sem_t *sem, const struct __timespec64 *abstime)
{
if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)
{
__set_errno (EINVAL);
return -1;
}
/* Check sem_wait.c for a more detailed explanation why it is required. */
__pthread_testcancel ();
if (__new_sem_wait_fast ((struct new_sem *) sem, 0) == 0)
return 0;
else
return __new_sem_wait_slow64 ((struct new_sem *) sem, abstime);
}
+24
View File
@@ -43,6 +43,30 @@ __new_sem_wait (sem_t *sem)
}
versioned_symbol (libpthread, __new_sem_wait, sem_wait, GLIBC_2_1);
/* 64-bit time version */
int
__new_sem_wait64 (sem_t *sem)
{
/* We need to check whether we need to act upon a cancellation request here
because POSIX specifies that cancellation points "shall occur" in
sem_wait and sem_timedwait, which also means that they need to check
this regardless whether they block or not (unlike "may occur"
functions). See the POSIX Rationale for this requirement: Section
"Thread Cancellation Overview" [1] and austin group issue #1076 [2]
for thoughs on why this may be a suboptimal design.
[1] http://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xsh_chap02.html
[2] http://austingroupbugs.net/view.php?id=1076 for thoughts on why this
*/
__pthread_testcancel ();
if (__new_sem_wait_fast ((struct new_sem *) sem, 0) == 0)
return 0;
else
return __new_sem_wait_slow64 ((struct new_sem *) sem, NULL);
}
#if SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_1)
int
attribute_compat_text_section
+172
View File
@@ -119,6 +119,24 @@ do_futex_wait (struct new_sem *sem, const struct timespec *abstime)
return err;
}
static int
__attribute__ ((noinline))
do_futex_wait64 (struct new_sem *sem, const struct __timespec64 *abstime)
{
int err;
#if __HAVE_64B_ATOMICS
err = futex_abstimed_wait_cancelable64 (
(unsigned int *) &sem->data + SEM_VALUE_OFFSET, 0, abstime,
sem->private);
#else
err = futex_abstimed_wait_cancelable64 (&sem->value, SEM_NWAITERS_MASK,
abstime, sem->private);
#endif
return err;
}
/* Fast path: Try to grab a token without blocking. */
static int
__new_sem_wait_fast (struct new_sem *sem, int definitive_result)
@@ -310,6 +328,160 @@ error:
return err;
}
/* 64-bit time version */
static int
__attribute__ ((noinline))
__new_sem_wait_slow64 (struct new_sem *sem, const struct __timespec64 *abstime)
{
int err = 0;
#if __HAVE_64B_ATOMICS
/* Add a waiter. Relaxed MO is sufficient because we can rely on the
ordering provided by the RMW operations we use. */
uint64_t d = atomic_fetch_add_relaxed (&sem->data,
(uint64_t) 1 << SEM_NWAITERS_SHIFT);
pthread_cleanup_push (__sem_wait_cleanup, sem);
/* Wait for a token to be available. Retry until we can grab one. */
for (;;)
{
/* If there is no token available, sleep until there is. */
if ((d & SEM_VALUE_MASK) == 0)
{
err = do_futex_wait64 (sem, 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.
If we timed out, forward this to the caller.
EINTR is returned if we are interrupted by a signal; we
forward this to the caller. (See futex_wait and related
documentation. Before Linux 2.6.22, EINTR was also returned on
spurious wake-ups; we only support more recent Linux versions,
so do not need to consider this here.) */
if (err == ETIMEDOUT || err == EINTR)
{
__set_errno (err);
err = -1;
/* Stop being registered as a waiter. */
atomic_fetch_add_relaxed (&sem->data,
-((uint64_t) 1 << SEM_NWAITERS_SHIFT));
break;
}
/* Relaxed MO is sufficient; see below. */
d = atomic_load_relaxed (&sem->data);
}
else
{
/* Try to grab both a token and stop being a waiter. We need
acquire MO so this synchronizes with all token providers (i.e.,
the RMW operation we read from or all those before it in
modification order; also see sem_post). On the failure path,
relaxed MO is sufficient because we only eventually need the
up-to-date value; the futex_wait or the CAS perform the real
work. */
if (atomic_compare_exchange_weak_acquire (&sem->data,
&d, d - 1 - ((uint64_t) 1 << SEM_NWAITERS_SHIFT)))
{
err = 0;
break;
}
}
}
pthread_cleanup_pop (0);
#else
/* The main difference to the 64b-atomics implementation is that we need to
access value and nwaiters in separate steps, and that the nwaiters bit
in the value can temporarily not be set even if nwaiters is nonzero.
We work around incorrectly unsetting the nwaiters bit by letting sem_wait
set the bit again and waking the number of waiters that could grab a
token. There are two additional properties we need to ensure:
(1) We make sure that whenever unsetting the bit, we see the increment of
nwaiters by the other thread that set the bit. IOW, we will notice if
we make a mistake.
(2) When setting the nwaiters bit, we make sure that we see the unsetting
of the bit by another waiter that happened before us. This avoids having
to blindly set the bit whenever we need to block on it. We set/unset
the bit while having incremented nwaiters (i.e., are a registered
waiter), and the problematic case only happens when one waiter indeed
followed another (i.e., nwaiters was never larger than 1); thus, this
works similarly as with a critical section using nwaiters (see the MOs
and related comments below).
An alternative approach would be to unset the bit after decrementing
nwaiters; however, that would result in needing Dekker-like
synchronization and thus full memory barriers. We also would not be able
to prevent misspeculation, so this alternative scheme does not seem
beneficial. */
unsigned int v;
/* Add a waiter. We need acquire MO so this synchronizes with the release
MO we use when decrementing nwaiters below; it ensures that if another
waiter unset the bit before us, we see that and set it again. Also see
property (2) above. */
atomic_fetch_add_acquire (&sem->nwaiters, 1);
pthread_cleanup_push (__sem_wait_cleanup, sem);
/* Wait for a token to be available. Retry until we can grab one. */
/* We do not need any ordering wrt. to this load's reads-from, so relaxed
MO is sufficient. The acquire MO above ensures that in the problematic
case, we do see the unsetting of the bit by another waiter. */
v = atomic_load_relaxed (&sem->value);
do
{
do
{
/* We are about to block, so make sure that the nwaiters bit is
set. We need release MO on the CAS to ensure that when another
waiter unsets the nwaiters bit, it will also observe that we
incremented nwaiters in the meantime (also see the unsetting of
the bit below). Relaxed MO on CAS failure is sufficient (see
above). */
do
{
if ((v & SEM_NWAITERS_MASK) != 0)
break;
}
while (!atomic_compare_exchange_weak_release (&sem->value,
&v, v | SEM_NWAITERS_MASK));
/* If there is no token, wait. */
if ((v >> SEM_VALUE_SHIFT) == 0)
{
/* See __HAVE_64B_ATOMICS variant. */
err = do_futex_wait64 (sem, abstime);
if (err == ETIMEDOUT || err == EINTR)
{
__set_errno (err);
err = -1;
goto error;
}
err = 0;
/* We blocked, so there might be a token now. Relaxed MO is
sufficient (see above). */
v = atomic_load_relaxed (&sem->value);
}
}
/* If there is no token, we must not try to grab one. */
while ((v >> SEM_VALUE_SHIFT) == 0);
}
/* Try to grab a token. We need acquire MO so this synchronizes with
all token providers (i.e., the RMW operation we read from or all those
before it in modification order; also see sem_post). */
while (!atomic_compare_exchange_weak_acquire (&sem->value,
&v, v - (1 << SEM_VALUE_SHIFT)));
error:
pthread_cleanup_pop (0);
__sem_wait_32_finish (sem);
#endif
return err;
}
/* Stop being a registered waiter (non-64b-atomics code only). */
#if !__HAVE_64B_ATOMICS
static void
+2 -1
View File
@@ -62,7 +62,8 @@ routines := \
spawnattr_getsigmask spawnattr_getschedpolicy spawnattr_getschedparam \
spawnattr_setsigmask spawnattr_setschedpolicy spawnattr_setschedparam \
posix_madvise \
get_child_max sched_cpucount sched_cpualloc sched_cpufree
get_child_max sched_cpucount sched_cpualloc sched_cpufree \
sched_rr_gi64 nanosleep64
aux := init-posix environ
tests := test-errno tstgetopt testfnm runtests runptests \
+4
View File
@@ -137,6 +137,10 @@ libc {
GLIBC_2.27 {
glob; glob64;
}
GLIBC_2.29 {
__sched_rr_get_interval_time64;
__nanosleep64;
}
GLIBC_PRIVATE {
__libc_fork; __libc_pread; __libc_pwrite;
__nanosleep_nocancel; __pause_nocancel;
+8
View File
@@ -25,6 +25,7 @@
#include <features.h>
#include <bits/wordsize.h>
#include <bits/timesize.h>
/* Convenience types. */
typedef unsigned char __u_char;
@@ -138,6 +139,7 @@ __extension__ typedef unsigned long long int __uintmax_t;
# error
#endif
#include <bits/typesizes.h> /* Defines __*_T_TYPE macros. */
#include <bits/time64.h> /* Defines __TIME*_T_TYPE macros. */
__STD_TYPE __DEV_T_TYPE __dev_t; /* Type of device numbers. */
@@ -211,6 +213,12 @@ __STD_TYPE __U32_TYPE __socklen_t;
It is not currently necessary for this to be machine-specific. */
typedef int __sig_atomic_t;
#if __TIMESIZE == 64
# define __time64_t __time_t
#else
__STD_TYPE __TIME64_T_TYPE __time64_t; /* Seconds since the Epoch. */
#endif
#undef __STD_TYPE
#endif /* bits/types.h */
+56
View File
@@ -0,0 +1,56 @@
/* Pause execution for a number of nanoseconds
Copyright (C) 2018 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 <time.h>
/* Pause execution for a number of nanoseconds. */
int
__nanosleep64 (const struct __timespec64 *requested_time,
struct __timespec64 *remaining)
{
struct timespec treq32, *treqp32 = NULL;
struct timespec trem32, *tremp32 = NULL;
if (requested_time)
{
if (requested_time->tv_sec > INT_MAX)
{
__set_errno(EOVERFLOW);
return -1;
}
treq32.tv_sec = requested_time->tv_sec;
treq32.tv_nsec = requested_time->tv_nsec;
treqp32 = & treq32;
}
if (remaining)
tremp32 = &trem32;
int result = __nanosleep(treqp32, tremp32);
if (result == 1 && errno == EINTR && remaining)
{
remaining->tv_sec = trem32.tv_sec;
remaining->tv_nsec = trem32.tv_nsec;
remaining->tv_pad = 0;
}
return result;
}
+9
View File
@@ -74,6 +74,15 @@ extern int sched_get_priority_max (int __algorithm) __THROW;
extern int sched_get_priority_min (int __algorithm) __THROW;
/* Get the SCHED_RR interval for the named process. */
#ifdef __USE_TIME_BITS64
# if defined(__REDIRECT)
extern int __REDIRECT (sched_rr_get_interval,
(__pid_t __pid, struct timespec *__t),
__sched_rr_get_interval_time64) __THROW;
# else
# define sched_rr_get_interval __sched_rr_get_interval_time64
# endif
#endif
extern int sched_rr_get_interval (__pid_t __pid, struct timespec *__t) __THROW;
+55
View File
@@ -0,0 +1,55 @@
/* Get the SCHED_RR interval for the named process.
Copyright (C) 2018 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 <sched.h>
#include <sys/types.h>
#include <y2038-support.h>
int
__sched_rr_get_interval_time64 (pid_t pid, struct __timespec64 *t)
{
struct timespec ts32;
int result;
if (t == NULL)
{
__set_errno(EINVAL);
return -1;
}
#ifdef __NR_sched_rr_get_interval_time64
if (__y2038_linux_support > 0)
{
result = INLINE_SYSCALL(sched_rr_get_interval_time64, 2, pid, t);
if (result == 0 || errno != ENOSYS)
return result;
__y2038_linux_support = -1;
}
#endif
result = __sched_rr_get_interval(pid, &ts32);
if (result == 0)
{
t->tv_sec = ts32.tv_sec;
t->tv_nsec = ts32.tv_nsec;
t->tv_pad = 0;
}
return result;
}
+1 -1
View File
@@ -23,7 +23,7 @@ headers := sys/resource.h bits/resource.h sys/vlimit.h sys/vtimes.h \
ulimit.h bits/types/struct_rusage.h
routines := getrlimit setrlimit getrlimit64 setrlimit64 getrusage ulimit \
vlimit vtimes getpriority setpriority nice
vlimit vtimes getpriority setpriority nice getrusage64
tests = tst-getrlimit bug-ulimit1
+3
View File
@@ -22,6 +22,9 @@ libc {
# s*
setrlimit64;
}
GLIBC_2.29 {
__getrusage64;
}
GLIBC_PRIVATE {
__getrlimit;
}
+1
View File
@@ -21,6 +21,7 @@
#include <bits/types.h>
#include <bits/types/struct_timeval.h>
#include <bits/types/struct_timeval64.h>
/* Structure which says how much of each resource has been used. If
the system does not keep track of a particular value, the struct
+181
View File
@@ -0,0 +1,181 @@
/* Return resource usage for the current process.
Copyright (C) 2018 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 <sys/resource.h>
#include <include/time.h>
#include <sysdep.h>
#include <sys/syscall.h>
#include <errno.h>
/* Structure which says how much of each resource has been used. */
/* 64-bit time version */
/* The purpose of all the unions is to have the kernel-compatible layout
while keeping the API type as 'long int', and among machines where
__syscall_slong_t is not 'long int', this only does the right thing
for little-endian ones, like x32. */
struct __rusage64
{
/* Total amount of user time used. */
struct __timeval64 ru_utime;
/* Total amount of system time used. */
struct __timeval64 ru_stime;
/* Maximum resident set size (in kilobytes). */
__extension__ union
{
long int ru_maxrss;
__syscall_slong_t __ru_maxrss_word;
};
/* Amount of sharing of text segment memory
with other processes (kilobyte-seconds). */
/* Maximum resident set size (in kilobytes). */
__extension__ union
{
long int ru_ixrss;
__syscall_slong_t __ru_ixrss_word;
};
/* Amount of data segment memory used (kilobyte-seconds). */
__extension__ union
{
long int ru_idrss;
__syscall_slong_t __ru_idrss_word;
};
/* Amount of stack memory used (kilobyte-seconds). */
__extension__ union
{
long int ru_isrss;
__syscall_slong_t __ru_isrss_word;
};
/* Number of soft page faults (i.e. those serviced by reclaiming
a page from the list of pages awaiting reallocation. */
__extension__ union
{
long int ru_minflt;
__syscall_slong_t __ru_minflt_word;
};
/* Number of hard page faults (i.e. those that required I/O). */
__extension__ union
{
long int ru_majflt;
__syscall_slong_t __ru_majflt_word;
};
/* Number of times a process was swapped out of physical memory. */
__extension__ union
{
long int ru_nswap;
__syscall_slong_t __ru_nswap_word;
};
/* Number of input operations via the file system. Note: This
and `ru_oublock' do not include operations with the cache. */
__extension__ union
{
long int ru_inblock;
__syscall_slong_t __ru_inblock_word;
};
/* Number of output operations via the file system. */
__extension__ union
{
long int ru_oublock;
__syscall_slong_t __ru_oublock_word;
};
/* Number of IPC messages sent. */
__extension__ union
{
long int ru_msgsnd;
__syscall_slong_t __ru_msgsnd_word;
};
/* Number of IPC messages received. */
__extension__ union
{
long int ru_msgrcv;
__syscall_slong_t __ru_msgrcv_word;
};
/* Number of signals delivered. */
__extension__ union
{
long int ru_nsignals;
__syscall_slong_t __ru_nsignals_word;
};
/* Number of voluntary context switches, i.e. because the process
gave up the process before it had to (usually to wait for some
resource to be available). */
__extension__ union
{
long int ru_nvcsw;
__syscall_slong_t __ru_nvcsw_word;
};
/* Number of involuntary context switches, i.e. a higher priority process
became runnable or the current process used up its time slice. */
__extension__ union
{
long int ru_nivcsw;
__syscall_slong_t __ru_nivcsw_word;
};
};
int __getrusage64 (__rusage_who_t __who, struct __rusage64 *__usage)
{
int result;
struct rusage usage32;
result = INLINE_SYSCALL(getrusage, 2, __who, &usage32);
/* Copy fields from 32-bit into 64-bit rusage structure */
/* Total amount of user time used. */
__usage->ru_utime.tv_sec = usage32.ru_utime.tv_sec;
__usage->ru_utime.tv_usec = usage32.ru_utime.tv_usec;
/* Total amount of system time used. */
__usage->ru_stime.tv_sec = usage32.ru_stime.tv_sec;
__usage->ru_stime.tv_usec = usage32.ru_stime.tv_usec;
/* Maximum resident set size (in kilobytes). */
__usage->ru_maxrss = usage32.ru_maxrss;
/* Amount of sharing of text segment memory
with other processes (kilobyte-seconds). */
/* Maximum resident set size (in kilobytes). */
__usage->ru_ixrss = usage32.ru_ixrss;
/* Amount of data segment memory used (kilobyte-seconds). */
__usage->ru_idrss = usage32.ru_idrss;
/* Amount of stack memory used (kilobyte-seconds). */
__usage->ru_isrss = usage32.ru_isrss;
/* Number of soft page faults (i.e. those serviced by reclaiming
a page from the list of pages awaiting reallocation. */
__usage->ru_minflt = usage32.ru_minflt;
/* Number of hard page faults (i.e. those that required I/O). */
__usage->ru_majflt = usage32.ru_majflt;
/* Number of times a process was swapped out of physical memory. */
__usage->ru_nswap = usage32.ru_nswap;
/* Number of input operations via the file system. Note: This
and `ru_oublock' do not include operations with the cache. */
__usage->ru_inblock = usage32.ru_inblock;
/* Number of output operations via the file system. */
__usage->ru_oublock = usage32.ru_oublock;
/* Number of IPC messages sent. */
__usage->ru_msgsnd = usage32.ru_msgsnd;
/* Number of IPC messages received. */
__usage->ru_msgrcv = usage32.ru_msgrcv;
/* Number of signals delivered. */
__usage->ru_nsignals = usage32.ru_nsignals;
/* Number of voluntary context switches, i.e. because the process
gave up the process before it had to (usually to wait for some
resource to be available). */
__usage->ru_nvcsw = usage32.ru_nvcsw;
/* Number of involuntary context switches, i.e. a higher priority process
became runnable or the current process used up its time slice. */
__usage->ru_nivcsw = usage32.ru_nivcsw;
return result;
}
+9
View File
@@ -84,6 +84,15 @@ extern int setrlimit64 (__rlimit_resource_t __resource,
/* Return resource usage information on process indicated by WHO
and put it in *USAGE. Returns 0 for success, -1 for failure. */
#ifdef __USE_TIME_BITS64
# if defined(__REDIRECT)
extern int __REDIRECT (getrusage, (__rusage_who_t __who,
struct rusage *__usage),
__getrusage64) __THROW;
# else
# define getrusage __getrusage64
# endif
#endif
extern int getrusage (__rusage_who_t __who, struct rusage *__usage) __THROW;
/* Return the highest priority of any process specified by WHICH and WHO
+4 -2
View File
@@ -32,11 +32,13 @@ clock-routines := get_clockfreq clock_getcpuclockid \
clock_getres clock_gettime clock_settime \
clock_nanosleep
timer-routines := timer_create timer_delete timer_getoverr \
timer_gettime timer_settime
timer_gettime timer_settime \
timerfd_gettime64 timerfd_settime64
shm-routines := shm_open shm_unlink
mq-routines := mq_open mq_close mq_unlink mq_getattr mq_setattr \
mq_notify mq_send mq_receive mq_timedsend \
mq_timedreceive
mq_timedreceive \
mq_timedreceiv_time64 mq_timedsend_time64
routines = $(clock-routines)
+9
View File
@@ -37,4 +37,13 @@ librt {
GLIBC_2.7 {
__mq_open_2;
}
GLIBC_2.29 {
__timer_gettime64;
__timer_settime64;
__timerfd_gettime64;
__timerfd_settime64;
__mq_timedreceive64;
__mq_timedsend_time64;
__aio_suspend64;
}
}
+54
View File
@@ -0,0 +1,54 @@
/* Receive the oldest from highest priority messages in message queue
MQDES, stop waiting if ABS_TIMEOUT expires.
Copyright (C) 2018 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 <mqueue.h>
#include <y2038-support.h>
/* 64-bit time version */
ssize_t
__mq_timedreceiv_time64 (mqd_t mqdes, char *__restrict msg_ptr, size_t msg_len,
unsigned int *__restrict msg_prio,
const struct __timespec64 *__restrict abs_timeout)
{
struct timespec ts32, *tsp32 = NULL;
#ifdef __NR_timedreceiv_time64
int result;
if (__y2038_get_kernel_support () > 0)
{
result = INLINE_SYSCALL (mq_timedreceiv_time64, 5, mqdes, msg_ptr, msg_len,
msg_prio, abs_timeout);
if (result == 0 || errno != ENOSYS)
return result;
__y2038_set_kernel_support (-1);
}
#endif
if (abs_timeout)
{
ts32.tv_sec = abs_timeout->tv_sec;
ts32.tv_nsec = abs_timeout->tv_nsec;
tsp32 = &ts32;
}
return mq_timedreceive(mqdes, msg_ptr, msg_len, msg_prio, tsp32);
}
+52
View File
@@ -0,0 +1,52 @@
/* Add message pointed by MSG_PTR to message queue MQDES, stop blocking
on full message queue if ABS_TIMEOUT expires.
Copyright (C) 2018 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 <mqueue.h>
#include <y2038-support.h>
/* 64-bit time version */
int
__mq_timedsend_time64 (mqd_t mqdes, const char *msg_ptr, size_t msg_len,
unsigned int msg_prio, const struct __timespec64 *abs_timeout)
{
struct timespec ts32, *tsp32 = NULL;
#ifdef __NR_mq_timedsend_time64
int result;
if (__y2038_get_kernel_support () > 0)
{
result = INLINE_SYSCALL (mq_timedsend_time64, 5, mqdes, msg_ptr,
msg_len, msg_prio, abs_timeout);
if (result == 0 || errno != ENOSYS)
return result;
__y2038_set_kernel_support (-1);
}
#endif
if (abs_timeout)
{
ts32.tv_sec = abs_timeout->tv_sec;
ts32.tv_nsec = abs_timeout->tv_nsec;
tsp32 = &ts32;
}
return mq_timedsend(mqdes, msg_ptr, msg_len, msg_prio, tsp32);
}
+22
View File
@@ -73,6 +73,17 @@ extern int mq_send (mqd_t __mqdes, const char *__msg_ptr, size_t __msg_len,
#ifdef __USE_XOPEN2K
/* Receive the oldest from highest priority messages in message queue
MQDES, stop waiting if ABS_TIMEOUT expires. */
# ifdef __USE_TIME_BITS64
# if defined(__REDIRECT)
extern ssize_t __REDIRECT (mq_timedreceive, (mqd_t __mqdes,
char *__restrict __msg_ptr, size_t __msg_len,
unsigned int *__restrict __msg_prio,
const struct timespec *__restrict __abs_timeout),
__mq_timedreceive64) __nonnull((2, 5));
# else
# define mq_timedreceive __mq_timedreceive64
# endif
# endif
extern ssize_t mq_timedreceive (mqd_t __mqdes, char *__restrict __msg_ptr,
size_t __msg_len,
unsigned int *__restrict __msg_prio,
@@ -81,6 +92,17 @@ extern ssize_t mq_timedreceive (mqd_t __mqdes, char *__restrict __msg_ptr,
/* Add message pointed by MSG_PTR to message queue MQDES, stop blocking
on full message queue if ABS_TIMEOUT expires. */
# ifdef __USE_TIME_BITS64
# if defined(__REDIRECT)
extern int __REDIRECT (mq_timedsend, (mqd_t __mqdes,
const char *__msg_ptr, size_t __msg_len,
unsigned int __msg_prio,
const struct timespec *__abs_timeout),
__mq_timedsend64) __nonnull((2, 5));
# else
# define mq_timedsend __mq_timedsend64
# endif
# endif
extern int mq_timedsend (mqd_t __mqdes, const char *__msg_ptr,
size_t __msg_len, unsigned int __msg_prio,
const struct timespec *__abs_timeout)
+29
View File
@@ -0,0 +1,29 @@
/* Get current value of timer TIMERID and store it in VALUE.
Copyright (C) 2018 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 <time.h>
int
__timerfd_gettime64 (int fd, struct itimerspec *value)
{
__set_errno (ENOSYS);
return -1;
}
stub_warning (__timerfd_gettime64)
+30
View File
@@ -0,0 +1,30 @@
/* Set timer TIMERID to VALUE, returning old value in OVALUE.
Copyright (C) 2018 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 <time.h>
int
__timerfd_settime64 (int fd, int flags, const struct itimerspec *value,
struct itimerspec *ovalue)
{
__set_errno (ENOSYS);
return -1;
}
stub_warning (__timerfd_settime64)
+10
View File
@@ -266,6 +266,16 @@ extern int sigwaitinfo (const sigset_t *__restrict __set,
This function is a cancellation point and therefore not marked with
__THROW. */
#ifdef __USE_TIME_BITS64
# if defined(__REDIRECT)
extern int __REDIRECT (sigtimedwait, (const sigset_t *__restrict __set,
siginfo_t *__restrict __info,
const struct timespec *__restrict __timeout),
__sigtimedwait64) __nonnull ((1));
# else
# define sigtimedwait __sigtimedwait64
# endif
#endif
extern int sigtimedwait (const sigset_t *__restrict __set,
siginfo_t *__restrict __info,
const struct timespec *__restrict __timeout)
+10
View File
@@ -30,3 +30,13 @@ libc_hidden_def (__sigtimedwait)
weak_alias (__sigtimedwait, sigtimedwait)
stub_warning (sigtimedwait)
int
__sigtimedwait_time64 (const sigset_t *set, siginfo_t *info,
const struct __timespec64 *timeout)
{
__set_errno (ENOSYS);
return -1;
}
stub_warning (__sigtimedwait_time64)
+1 -1
View File
@@ -29,7 +29,7 @@ headers := stdlib.h bits/stdlib.h bits/stdlib-ldbl.h bits/stdlib-float.h \
ucontext.h sys/ucontext.h bits/indirect-return.h \
alloca.h fmtmsg.h \
bits/stdlib-bsearch.h sys/random.h bits/stdint-intn.h \
bits/stdint-uintn.h
bits/stdint-uintn.h bits/time64.h \
routines := \
atof atoi atol atoll \
+37
View File
@@ -644,3 +644,40 @@ clntudp_destroy (CLIENT *cl)
mem_free ((caddr_t) cu, (sizeof (*cu) + cu->cu_sendsz + cu->cu_recvsz));
mem_free ((caddr_t) cl, sizeof (CLIENT));
}
/* 64-bit time versions */
CLIENT *
__clntudp_create64 (struct sockaddr_in *raddr, u_long program, u_long version,
struct __timeval64 wait, int *sockp)
{
struct timeval wait32;
if (wait.tv_sec > INT32_MAX || wait.tv_sec < INT32_MIN)
{
return NULL;
}
wait32.tv_sec = wait.tv_sec;
wait32.tv_usec = wait.tv_usec;
return clntudp_create (raddr, program, version, wait32, sockp);
}
CLIENT *
__clntudp_bufcreate64 (struct sockaddr_in *raddr, u_long program, u_long version,
struct __timeval64 wait, int *sockp, u_int sendsz,
u_int recvsz)
{
struct timeval wait32;
if (wait.tv_sec > INT_MAX)
{
return NULL;
}
wait32.tv_sec = wait.tv_sec;
wait32.tv_usec = wait.tv_usec;
return clntudp_bufcreate (raddr, program, version, wait32, sockp, sendsz, recvsz);
}
+23
View File
@@ -390,3 +390,26 @@ done_broad:
return stat;
}
libc_hidden_nolink_sunrpc (clnt_broadcast, GLIBC_2_0)
/* 64-bit-time version */
/* The 64-bit-time version of pmap_rmtcall.
* Only handles 64-bit-time timeouts smaller than 2^^31 seconds.
*/
enum clnt_stat
__pmap_rmtcall64 (struct sockaddr_in *addr, u_long prog, u_long vers,
u_long proc, xdrproc_t xdrargs, caddr_t argsp,
xdrproc_t xdrres, caddr_t resp,
struct __timeval64 tout, u_long *port_ptr)
{
struct timeval tout32;
if (tout.tv_sec > INT_MAX)
{
return RPC_SYSTEMERROR;
}
tout32.tv_sec = tout.tv_sec;
tout32.tv_usec = tout.tv_usec;
return pmap_rmtcall (addr, prog, vers, proc, xdrargs, argsp, xdrres,
resp, tout32, port_ptr);
}
+24
View File
@@ -329,9 +329,33 @@ extern CLIENT *clnttcp_create (struct sockaddr_in *__raddr, u_long __prog,
* u_int sendsz;
* u_int recvsz;
*/
#ifdef __USE_TIME_BITS64
# if defined(__REDIRECT)
extern CLIENT * __REDIRECT (clntudp_create,(struct sockaddr_in *__raddr,
u_long __program,
u_long __version,
struct timeval __wait_resend,
int *__sockp),
__clntudp_create64) __THROW;
# else
# define clntudp_create __clntudp_create64
# endif
#endif
extern CLIENT *clntudp_create (struct sockaddr_in *__raddr, u_long __program,
u_long __version, struct timeval __wait_resend,
int *__sockp) __THROW;
#ifdef __USE_TIME_BITS64
# if defined(__REDIRECT)
extern CLIENT * __REDIRECT (clntudp_bufcreate,(struct sockaddr_in *__raddr,
u_long __program, u_long __version,
struct __timeval64 __wait_resend,
int *__sockp, u_int __sendsz,
u_int __recvsz),
__clntudp_bufcreate64) __THROW;
# else
# define clntudp_bufcreate __clntudp_bufcreate64
# endif
#endif
extern CLIENT *clntudp_bufcreate (struct sockaddr_in *__raddr,
u_long __program, u_long __version,
struct timeval __wait_resend, int *__sockp,
+15
View File
@@ -71,6 +71,21 @@ extern bool_t pmap_set (const u_long __program, const u_long __vers,
extern bool_t pmap_unset (const u_long __program, const u_long __vers)
__THROW;
extern struct pmaplist *pmap_getmaps (struct sockaddr_in *__address) __THROW;
#ifdef __USE_TIME_BITS64
# if defined(__REDIRECT)
extern enum clnt_stat __REDIRECT (pmap_rmtcall, (struct sockaddr_in *__addr,
const u_long __prog,
const u_long __vers,
const u_long __proc,
xdrproc_t __xdrargs,
caddr_t __argsp, xdrproc_t __xdrres,
caddr_t __resp, struct timeval __tout,
u_long *__port_ptr),
__pmap_rmtcall64) __THROW;
# else
# define pmap_rmtcall __pmap_rmtcall64
# endif
#endif
extern enum clnt_stat pmap_rmtcall (struct sockaddr_in *__addr,
const u_long __prog,
const u_long __vers,
+39
View File
@@ -71,4 +71,43 @@
} \
} while (0)
#define AIO_MISC_WAIT_T64(result, futex, timeout, cancel) \
do { \
volatile unsigned int *futexaddr = &futex; \
unsigned int oldval = futex; \
\
if (oldval != 0) \
{ \
pthread_mutex_unlock (&__aio_requests_mutex); \
\
int oldtype; \
if (cancel) \
oldtype = LIBC_CANCEL_ASYNC (); \
\
int status; \
do \
{ \
status = futex_reltimed_wait64 ((unsigned int *) futexaddr, \
oldval, timeout, FUTEX_PRIVATE);\
if (status != EAGAIN) \
break; \
\
oldval = *futexaddr; \
} \
while (oldval != 0); \
\
if (cancel) \
LIBC_CANCEL_RESET (oldtype); \
\
if (status == EINTR) \
result = EINTR; \
else if (status == ETIMEDOUT) \
result = EAGAIN; \
else \
assert (status == 0 || status == EAGAIN); \
\
pthread_mutex_lock (&__aio_requests_mutex); \
} \
} while (0)
#include_next <aio_misc.h>
+17
View File
@@ -122,6 +122,10 @@ extern void __lll_lock_wait (int *futex, int private) attribute_hidden;
extern int __lll_timedlock_wait (int *futex, const struct timespec *,
int private) attribute_hidden;
extern int __lll_timedlock_wait64 (int *futex,
const struct __timespec64 *,
int private) attribute_hidden;
/* As __lll_lock, but with a timeout. If the timeout occurs then return
ETIMEDOUT. If ABSTIME is invalid, return EINVAL. */
@@ -138,6 +142,19 @@ extern int __lll_timedlock_wait (int *futex, const struct timespec *,
#define lll_timedlock(futex, abstime, private) \
__lll_timedlock (&(futex), abstime, private)
#define __lll_timedlock64(futex, abstime, private) \
({ \
int *__futex = (futex); \
int __val = 0; \
\
if (__glibc_unlikely \
(atomic_compare_and_exchange_bool_acq (__futex, 1, 0))) \
__val = __lll_timedlock_wait64 (__futex, abstime, private); \
__val; \
})
#define lll_timedlock64(futex, abstime, private) \
__lll_timedlock64 (&(futex), abstime, private)
/* This is an expression rather than a statement even though its value is
void, so that it can be used in a comma expression or as an expression
+45
View File
@@ -765,6 +765,17 @@ extern int pthread_mutex_lock (pthread_mutex_t *__mutex)
#ifdef __USE_XOPEN2K
/* Wait until lock becomes available, or specified time passes. */
#ifdef __USE_TIME_BITS64
# if defined(__REDIRECT)
extern int __REDIRECT (pthread_mutex_timedlock,
(pthread_mutex_t *__restrict __mutex,
const struct timespec *__restrict __abstime),
__pthread_mutex_timedlock64)
__THROWNL __nonnull ((1, 2));
# else
# define pthread_mutex_timedlock __pthread_mutex_timedlock64
# endif
#endif
extern int pthread_mutex_timedlock (pthread_mutex_t *__restrict __mutex,
const struct timespec *__restrict
__abstime) __THROWNL __nonnull ((1, 2));
@@ -904,6 +915,17 @@ extern int pthread_rwlock_tryrdlock (pthread_rwlock_t *__rwlock)
# ifdef __USE_XOPEN2K
/* Try to acquire read lock for RWLOCK or return after specfied time. */
#ifdef __USE_TIME_BITS64
# if defined(__REDIRECT)
extern int __REDIRECT (pthread_rwlock_timedrdlock,
(pthread_rwlock_t *__restrict __rwlock,
const struct timespec *__restrict __abstime),
__pthread_rwlock_timedrdlock64)
__THROWNL __nonnull ((1, 2));
# else
# define pthread_rwlock_timedrdlock __pthread_rwlock_timedrdlock64
# endif
#endif
extern int pthread_rwlock_timedrdlock (pthread_rwlock_t *__restrict __rwlock,
const struct timespec *__restrict
__abstime) __THROWNL __nonnull ((1, 2));
@@ -919,6 +941,17 @@ extern int pthread_rwlock_trywrlock (pthread_rwlock_t *__rwlock)
# ifdef __USE_XOPEN2K
/* Try to acquire write lock for RWLOCK or return after specfied time. */
#ifdef __USE_TIME_BITS64
# if defined(__REDIRECT)
extern int __REDIRECT (pthread_rwlock_timedwrlock,
(pthread_rwlock_t *__restrict __rwlock,
const struct timespec *__restrict __abstime),
__pthread_rwlock_timedwrlock64)
__THROWNL __nonnull ((1, 2));
# else
# define pthread_rwlock_timedwrlock __pthread_rwlock_timedwrlock64
# endif
#endif
extern int pthread_rwlock_timedwrlock (pthread_rwlock_t *__restrict __rwlock,
const struct timespec *__restrict
__abstime) __THROWNL __nonnull ((1, 2));
@@ -998,6 +1031,18 @@ extern int pthread_cond_wait (pthread_cond_t *__restrict __cond,
This function is a cancellation point and therefore not marked with
__THROW. */
#ifdef __USE_TIME_BITS64
# if defined(__REDIRECT)
extern int __REDIRECT (pthread_cond_timedwait,
(pthread_cond_t *__restrict __cond,
pthread_mutex_t *__restrict __mutex,
const struct timespec *__restrict __abstime),
__pthread_cond_timedwait64)
__nonnull ((1, 2, 3));
# else
# define pthread_cond_timedwait __pthread_cond_timedwait64
# endif
#endif
extern int pthread_cond_timedwait (pthread_cond_t *__restrict __cond,
pthread_mutex_t *__restrict __mutex,
const struct timespec *__restrict __abstime)
+22 -9
View File
@@ -23,12 +23,11 @@
#include <sys/param.h>
#include <libc-internal.h>
#if HP_TIMING_AVAIL
static long int nsec; /* Clock frequency of the processor. */
static int
hp_timing_getres (struct timespec *res)
hp_timing_getres (struct __timespec64 *res)
{
if (__glibc_unlikely (nsec == 0))
{
@@ -56,7 +55,7 @@ hp_timing_getres (struct timespec *res)
#endif
static inline int
realtime_getres (struct timespec *res)
realtime_getres (struct __timespec64 *res)
{
long int clk_tck = __sysconf (_SC_CLK_TCK);
@@ -73,17 +72,16 @@ realtime_getres (struct timespec *res)
return -1;
}
/* Get resolution of clock. */
int
__clock_getres (clockid_t clock_id, struct timespec *res)
__clock_getres_time64 (clockid_t clock_id, struct __timespec64 *res)
{
int retval = -1;
switch (clock_id)
{
#ifdef SYSDEP_GETRES
SYSDEP_GETRES;
#ifdef SYSDEP_GETRES64
SYSDEP_GETRES64;
#endif
#ifndef HANDLED_REALTIME
@@ -93,8 +91,8 @@ __clock_getres (clockid_t clock_id, struct timespec *res)
#endif /* handled REALTIME */
default:
#ifdef SYSDEP_GETRES_CPU
SYSDEP_GETRES_CPU;
#ifdef SYSDEP_GETRES_CPU64
SYSDEP_GETRES_CPU64;
#endif
#if HP_TIMING_AVAIL
if ((clock_id & ((1 << CLOCK_IDFIELD_SIZE) - 1))
@@ -115,4 +113,19 @@ __clock_getres (clockid_t clock_id, struct timespec *res)
return retval;
}
int
__clock_getres (clockid_t clock_id, struct timespec *res)
{
struct __timespec64 ts64;
int retval = __clock_getres_time64 (clock_id, &ts64);
if (retval == 0)
{
// We assume we never run with a CPU clock period greater than
// 2**31 seconds and therefore we do not check the seconds field
res->tv_sec = ts64.tv_sec;
res->tv_nsec = ts64.tv_nsec;
}
return retval;
}
weak_alias (__clock_getres, clock_getres)
+43
View File
@@ -0,0 +1,43 @@
/* Get the 64-bit current time
*
Copyright (C) 1991-2018 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 <stddef.h> /* For NULL. */
#include <time.h>
#include <sys/time.h>
/* Return the current time as a `time_t' and also put it in *T if T is
not NULL. Time is represented as seconds from Jan 1 00:00:00 1970. */
__time64_t
__time64 (__time64_t *t)
{
struct __timeval64 tv;
__time64_t result;
if (__gettimeofday64 (&tv, (struct timezone *) NULL))
result = (__time64_t) -1;
else
result = tv.tv_sec;
if (t != NULL)
*t = result;
return result;
}
+46
View File
@@ -0,0 +1,46 @@
/* Copyright (C) 1991-2018 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 <sysdep.h>
#include <errno.h>
#include <utime.h>
#include <time.h>
#include <sys/types.h>
#include <sys/time.h>
/* Set the access and modification times of FILE to those given in TIMES.
If TIMES is NULL, set them to the current time. */
int
__utime64 (const char *file, const struct __utimbuf64 *times)
{
struct __timeval64 timevals[2];
struct __timeval64 *tvp;
if (times != NULL)
{
timevals[0].tv_sec = (time_t) times->actime;
timevals[0].tv_usec = 0L;
timevals[1].tv_sec = (time_t) times->modtime;
timevals[1].tv_usec = 0L;
tvp = timevals;
}
else
tvp = NULL;
return __utimes64 (file, tvp);
}
+164
View File
@@ -251,3 +251,167 @@ aio_suspend (const struct aiocb *const list[], int nent,
}
weak_alias (aio_suspend, aio_suspend64)
#ifdef DONT_NEED_AIO_MISC_COND
static int
__attribute__ ((noinline))
do_aio_misc_wait64 (unsigned int *cntr,
const struct __timespec64 *timeout)
{
int result = 0;
AIO_MISC_WAIT_T64 (result, *cntr, timeout, 1);
return result;
}
#endif
int
__aio_suspend64 (const struct aiocb *const list[], int nent,
const struct __timespec64 *timeout)
{
if (__glibc_unlikely (nent < 0))
{
__set_errno (EINVAL);
return -1;
}
struct waitlist waitlist[nent];
struct requestlist *requestlist[nent];
#ifndef DONT_NEED_AIO_MISC_COND
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
#endif
int cnt;
bool any = false;
int result = 0;
unsigned int cntr = 1;
/* Request the mutex. */
pthread_mutex_lock (&__aio_requests_mutex);
/* There is not yet a finished request. Signal the request that
we are working for it. */
for (cnt = 0; cnt < nent; ++cnt)
if (list[cnt] != NULL)
{
if (list[cnt]->__error_code == EINPROGRESS)
{
requestlist[cnt] = __aio_find_req ((aiocb_union *) list[cnt]);
if (requestlist[cnt] != NULL)
{
#ifndef DONT_NEED_AIO_MISC_COND
waitlist[cnt].cond = &cond;
#endif
waitlist[cnt].result = NULL;
waitlist[cnt].next = requestlist[cnt]->waiting;
waitlist[cnt].counterp = &cntr;
waitlist[cnt].sigevp = NULL;
#ifdef BROKEN_THREAD_SIGNALS
waitlist[cnt].caller_pid = 0; /* Not needed. */
#endif
requestlist[cnt]->waiting = &waitlist[cnt];
any = true;
}
else
/* We will never suspend. */
break;
}
else
/* We will never suspend. */
break;
}
/* Only if none of the entries is NULL or finished to be wait. */
if (cnt == nent && any)
{
struct clparam clparam =
{
.list = list,
.waitlist = waitlist,
.requestlist = requestlist,
#ifndef DONT_NEED_AIO_MISC_COND
.cond = &cond,
#endif
.nent = nent
};
pthread_cleanup_push (cleanup, &clparam);
#ifdef DONT_NEED_AIO_MISC_COND
result = do_aio_misc_wait64 (&cntr, timeout);
#else
if (timeout == NULL)
result = pthread_cond_wait (&cond, &__aio_requests_mutex);
else
{
/* We have to convert the relative timeout value into an
absolute time value with pthread_cond_timedwait expects. */
struct timeval now;
struct timespec abstime;
__gettimeofday (&now, NULL);
abstime.tv_nsec = timeout->tv_nsec + now.tv_usec * 1000;
abstime.tv_sec = timeout->tv_sec + now.tv_sec;
if (abstime.tv_nsec >= 1000000000)
{
abstime.tv_nsec -= 1000000000;
abstime.tv_sec += 1;
}
result = __pthread_cond_timedwait64 (&cond,
&__aio_requests_mutex,
&abstime);
}
#endif
pthread_cleanup_pop (0);
}
/* Now remove the entry in the waiting list for all requests
which didn't terminate. */
while (cnt-- > 0)
if (list[cnt] != NULL && list[cnt]->__error_code == EINPROGRESS)
{
struct waitlist **listp;
assert (requestlist[cnt] != NULL);
/* There is the chance that we cannot find our entry anymore. This
could happen if the request terminated and restarted again. */
listp = &requestlist[cnt]->waiting;
while (*listp != NULL && *listp != &waitlist[cnt])
listp = &(*listp)->next;
if (*listp != NULL)
*listp = (*listp)->next;
}
#ifndef DONT_NEED_AIO_MISC_COND
/* Release the conditional variable. */
if (__glibc_unlikely (pthread_cond_destroy (&cond) != 0))
/* This must never happen. */
abort ();
#endif
if (result != 0)
{
#ifndef DONT_NEED_AIO_MISC_COND
/* An error occurred. Possibly it's ETIMEDOUT. We have to translate
the timeout error report of `pthread_cond_timedwait' to the
form expected from `aio_suspend'. */
if (result == ETIMEDOUT)
__set_errno (EAGAIN);
else
#endif
__set_errno (result);
result = -1;
}
/* Release the mutex. */
pthread_mutex_unlock (&__aio_requests_mutex);
return result;
}
+10
View File
@@ -57,6 +57,16 @@ extern int sem_wait (sem_t *__sem);
This function is a cancellation point and therefore not marked with
__THROW. */
#ifdef __USE_TIME_BITS64
# if defined(__REDIRECT)
extern struct tm * __REDIRECT (sem_timedwait,
(sem_t *__restrict __sem,
const struct timespec *__restrict __abstime),
__sem_timedwait64);
# else
# define sem_timedwait __sem_timedwait64
# endif
#endif
extern int sem_timedwait (sem_t *__restrict __sem,
const struct timespec *__restrict __abstime);
#endif
+40 -9
View File
@@ -32,12 +32,12 @@ static hp_timing_t freq;
/* This function is defined in the thread library. */
extern int __pthread_clock_gettime (clockid_t clock_id, hp_timing_t freq,
struct timespec *tp)
extern int __pthread_clock_gettime64 (clockid_t clock_id, hp_timing_t freq,
struct __timespec64 *tp)
__attribute__ ((__weak__));
static int
hp_timing_gettime (clockid_t clock_id, struct timespec *tp)
hp_timing_gettime (clockid_t clock_id, struct __timespec64 *tp)
{
hp_timing_t tsc;
@@ -55,7 +55,7 @@ hp_timing_gettime (clockid_t clock_id, struct timespec *tp)
if (clock_id != CLOCK_PROCESS_CPUTIME_ID
&& __pthread_clock_gettime != NULL)
return __pthread_clock_gettime (clock_id, freq, tp);
return __pthread_clock_gettime64 (clock_id, freq, tp);
/* Get the current counter. */
HP_TIMING_NOW (tsc);
@@ -76,20 +76,20 @@ hp_timing_gettime (clockid_t clock_id, struct timespec *tp)
static inline int
realtime_gettime (struct timespec *tp)
realtime_gettime (struct __timespec64 *tp)
{
struct timeval tv;
int retval = __gettimeofday (&tv, NULL);
if (retval == 0)
/* Convert into `timespec'. */
TIMEVAL_TO_TIMESPEC (&tv, tp);
valid_timeval_to_timespec64 (&tv, tp);
return retval;
}
/* Get current value of CLOCK and store it in TP. */
int
__clock_gettime (clockid_t clock_id, struct timespec *tp)
__clock_gettime64 (clockid_t clock_id, struct __timespec64 *tp)
{
int retval = -1;
@@ -103,9 +103,9 @@ __clock_gettime (clockid_t clock_id, struct timespec *tp)
case CLOCK_REALTIME:
{
struct timeval tv;
retval = __gettimeofday (&tv, NULL);
retval = __gettimeofday (&tv32, NULL);
if (retval == 0)
TIMEVAL_TO_TIMESPEC (&tv, tp);
valid_timeval_to_timespec64 (&tv32, tp);
}
break;
#endif
@@ -132,5 +132,36 @@ __clock_gettime (clockid_t clock_id, struct timespec *tp)
return retval;
}
int
__clock_gettime (clockid_t clock_id, struct timespec *tp)
{
struct __timespec64 ts64;
int res;
if (tp == NULL)
{
__set_errno(EINVAL);
res = -1;
}
else
{
res = __clock_gettime64 (clock_id, &ts64);
if (res == 0)
{
if (fits_in_time_t (ts64.tv_sec))
{
tp->tv_sec = ts64.tv_sec;
tp->tv_nsec = ts64.tv_nsec;
}
else
{
__set_errno(EOVERFLOW);
res = -1;
}
}
}
return res;
}
weak_alias (__clock_gettime, clock_gettime)
libc_hidden_def (__clock_gettime)
+59 -1
View File
@@ -68,8 +68,66 @@ hp_timing_settime (clockid_t clock_id, const struct timespec *tp)
}
#endif
/* Set CLOCK to value TP. */
int
__clock_settime64 (clockid_t clock_id, const struct __timespec64 *tp)
{
#ifndef HANDLED_REALTIME
struct timeval tv32;
#endif
int retval = -1;
/* Make sure the time cvalue is OK. */
if (! IS_VALID_NANOSECONDS(tp->tv_nsec))
{
__set_errno (EINVAL);
return -1;
}
switch (clock_id)
{
#define HANDLE_REALTIME64 \
if (timespec64_to_timeval (tp, &tv32)) \
{ \
retval = __settimeofday (&tv32, NULL); \
else \
{ \
__set_errno (EOVERFLOW); \
retval = -1; \
}
#ifdef SYSDEP_SETTIME64
SYSDEP_SETTIME64;
#endif
#ifndef HANDLED_REALTIME
case CLOCK_REALTIME:
HANDLE_REALTIME64;
break;
#endif
default:
#ifdef SYSDEP_SETTIME64_CPU
SYSDEP_SETTIME64_CPU;
#endif
#ifndef HANDLED_CPUTIME
# if HP_TIMING_AVAIL
if (CPUCLOCK_WHICH (clock_id) == CLOCK_PROCESS_CPUTIME_ID
|| CPUCLOCK_WHICH (clock_id) == CLOCK_THREAD_CPUTIME_ID)
retval = hp_timing_settime (clock_id, tp);
else
# endif
{
__set_errno (EINVAL);
retval = -1;
}
#endif
break;
}
return retval;
}
int
__clock_settime (clockid_t clock_id, const struct timespec *tp)
{
+47
View File
@@ -0,0 +1,47 @@
/* Set the system clock on a unix system
Copyright (C) 2018 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 <stddef.h> /* For NULL. */
#include <sys/time.h>
#include <time.h>
/* Set the system clock to *WHEN. */
int
__stime64 (const __time64_t *when)
{
struct __timeval64 tv;
if (when == NULL)
{
__set_errno (EINVAL);
return -1;
}
if (*when > INT_MAX)
{
__set_errno (EOVERFLOW);
return -1;
}
tv.tv_sec = *when;
tv.tv_usec = 0;
return __settimeofday64 (&tv, (struct timezone *) 0);
}
+2
View File
@@ -170,6 +170,8 @@ libc {
memfd_create;
mlock2;
pkey_alloc; pkey_free; pkey_set; pkey_get; pkey_mprotect;
__ntp_gettime64;
__ntp_gettimex64;
}
GLIBC_PRIVATE {
# functions used in other libraries
+1
View File
@@ -19,6 +19,7 @@
#include <limits.h>
#include <sys/time.h>
#include <sys/timex.h>
#include <include/time.h>
#define MAX_SEC (INT_MAX / 1000000L - 2)
#define MIN_SEC (INT_MIN / 1000000L + 2)
+164
View File
@@ -0,0 +1,164 @@
/* Copyright (C) 1995-2018 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 <limits.h>
#include <sys/time.h>
#include <sys/timex.h>
#include <include/time.h>
#define MAX_SEC (INT_MAX / 1000000L - 2)
#define MIN_SEC (INT_MIN / 1000000L + 2)
#ifndef MOD_OFFSET
#define modes mode
#endif
#ifndef TIMEVAL
#define TIMEVAL timeval
#endif
#ifndef TIMEX
#define TIMEX timex
#endif
#ifndef ADJTIME
#define ADJTIME __adjtime
#endif
#ifndef ADJTIMEX
#define NO_LOCAL_ADJTIME
#define ADJTIMEX(x) __adjtimex (x)
#endif
#ifndef LINKAGE
#define LINKAGE
#endif
int __adjtime64 (const struct __timeval64 *itv,
struct __timeval64 *otv)
{
struct TIMEX tntx;
if (itv)
{
struct TIMEVAL tmp;
/* We will do some check here. */
tmp.tv_sec = itv->tv_sec + itv->tv_usec / 1000000L;
tmp.tv_usec = itv->tv_usec % 1000000L;
if (tmp.tv_sec > MAX_SEC || tmp.tv_sec < MIN_SEC)
return INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL);
tntx.offset = tmp.tv_usec + tmp.tv_sec * 1000000L;
tntx.modes = ADJ_OFFSET_SINGLESHOT;
}
else
tntx.modes = ADJ_OFFSET_SS_READ;
if (__glibc_unlikely (ADJTIMEX (&tntx) < 0))
return -1;
if (otv)
{
if (tntx.offset < 0)
{
otv->tv_usec = -(-tntx.offset % 1000000);
otv->tv_sec = -(-tntx.offset / 1000000);
}
else
{
otv->tv_usec = tntx.offset % 1000000;
otv->tv_sec = tntx.offset / 1000000;
}
}
return 0;
}
int
__adjtimex64(struct __timex64 *tx)
{
struct timex tx32;
if (tx == NULL)
{
__set_errno (EFAULT);
return -1;
}
if ((tx->modes & ADJ_SETOFFSET) != 0 && tx->time.tv_sec > INT_MAX)
{
__set_errno (EOVERFLOW);
return -1;
}
/* Implement with existing 32-bit time syscall */
/* Just copy everything */
tx32.modes = tx->modes;
tx32.offset = tx->offset;
tx32.freq = tx->freq;
tx32.maxerror = tx->maxerror;
tx32.esterror = tx->esterror;
tx32.status = tx->status;
tx32.constant = tx->constant;
tx32.precision = tx->precision;
tx32.tolerance = tx->tolerance;
tx32.time.tv_sec = tx->time.tv_sec;
tx32.time.tv_usec = tx->time.tv_usec;
tx32.tick = tx->tick;
tx32.ppsfreq = tx->ppsfreq;
tx32.jitter = tx->jitter;
tx32.shift = tx->shift;
tx32.stabil = tx->stabil;
tx32.jitcnt = tx->jitcnt;
tx32.calcnt = tx->calcnt;
tx32.errcnt = tx->errcnt;
tx32.stbcnt = tx->stbcnt;
tx32.tai = tx->tai;
/* WARNING -- anonymous fields after TAI are not copied. */
int result = ADJTIMEX(&tx32);
if (result == 0)
{
/* Just copy back everything */
tx->modes = tx32.modes;
tx->offset = tx32.offset;
tx->freq = tx32.freq;
tx->maxerror = tx32.maxerror;
tx->esterror = tx32.esterror;
tx->status = tx32.status;
tx->constant = tx32.constant;
tx->precision = tx32.precision;
tx->tolerance = tx32.tolerance;
tx->time.tv_sec = tx32.time.tv_sec;
tx->time.tv_usec = tx32.time.tv_usec;
tx->tick = tx32.tick;
tx->ppsfreq = tx32.ppsfreq;
tx->jitter = tx32.jitter;
tx->shift = tx32.shift;
tx->stabil = tx32.stabil;
tx->jitcnt = tx32.jitcnt;
tx->calcnt = tx32.calcnt;
tx->errcnt = tx32.errcnt;
tx->stbcnt = tx32.stbcnt;
}
return result;
}
weak_alias (__adjtimex64, __ntp_adjtime64);
@@ -176,6 +176,7 @@ enum __rusage_who
};
#include <bits/types/struct_timeval.h>
#include <bits/types/struct_timeval64.h>
#include <bits/types/struct_rusage.h>
/* Priority limits. */
@@ -27,6 +27,9 @@ GLIBC_2.28 tss_create F
GLIBC_2.28 tss_delete F
GLIBC_2.28 tss_get F
GLIBC_2.28 tss_set F
GLIBC_2.29 __pthread_cond_timedwait64 F
GLIBC_2.29 __pthread_mutex_timedlock64 F
GLIBC_2.29 __sem_timedwait64 F
GLIBC_2.4 _IO_flockfile F
GLIBC_2.4 _IO_ftrylockfile F
GLIBC_2.4 _IO_funlockfile F
@@ -1,3 +1,10 @@
GLIBC_2.29 __aio_suspend64 F
GLIBC_2.29 __mq_timedreceive64 F
GLIBC_2.29 __mq_timedsend_time64 F
GLIBC_2.29 __timer_gettime64 F
GLIBC_2.29 __timer_settime64 F
GLIBC_2.29 __timerfd_gettime64 F
GLIBC_2.29 __timerfd_settime64 F
GLIBC_2.4 aio_cancel F
GLIBC_2.4 aio_cancel64 F
GLIBC_2.4 aio_error F
+17
View File
@@ -46,6 +46,22 @@ typedef __syscall_ulong_t msglen_t;
/* Structure of record for one message inside the kernel.
The type `struct msg' is opaque. */
#ifdef __USE_TIME_BITS64
struct msqid_ds
{
struct ipc_perm msg_perm; /* structure describing operation permission */
__time64_t msg_stime; /* time of last msgsnd command */
__time64_t msg_rtime; /* time of last msgrcv command */
__time64_t msg_ctime; /* time of last change */
unsigned long int __msg_cbytes; /* current number of bytes on queue */
msgqnum_t msg_qnum; /* number of messages currently on queue */
msglen_t msg_qbytes; /* max number of bytes allowed on queue */
__pid_t msg_lspid; /* pid of last msgsnd() */
__pid_t msg_lrpid; /* pid of last msgrcv() */
unsigned long int __glibc_reserved4;
unsigned long int __glibc_reserved5;
};
#else
struct msqid_ds
{
struct ipc_perm msg_perm; /* structure describing operation permission */
@@ -60,6 +76,7 @@ struct msqid_ds
__syscall_ulong_t __glibc_reserved4;
__syscall_ulong_t __glibc_reserved5;
};
#endif
#ifdef __USE_MISC
+1
View File
@@ -176,6 +176,7 @@ enum __rusage_who
};
#include <bits/types/struct_timeval.h>
#include <bits/types/struct_timeval64.h>
#include <bits/types/struct_rusage.h>
/* Priority limits. */
+3 -3
View File
@@ -119,11 +119,11 @@ struct stat64
struct timespec st_mtim; /* Time of last modification. */
struct timespec st_ctim; /* Time of last status change. */
# else
__time_t st_atime; /* Time of last access. */
time_t st_atime; /* Time of last access. */
unsigned long int st_atimensec; /* Nscecs of last access. */
__time_t st_mtime; /* Time of last modification. */
time_t st_mtime; /* Time of last modification. */
unsigned long int st_mtimensec; /* Nsecs of last modification. */
__time_t st_ctime; /* Time of last status change. */
time_t st_ctime; /* Time of last status change. */
unsigned long int st_ctimensec; /* Nsecs of last status change. */
# endif
__ino64_t st_ino; /* File serial number. */
+1
View File
@@ -20,6 +20,7 @@
#include <bits/types.h>
#include <bits/types/struct_timeval.h>
#include <bits/types/struct_timeval64.h>
/* These definitions from linux/timex.h as of 3.18. */
+61
View File
@@ -19,6 +19,7 @@
#include <sysdep.h>
#include <errno.h>
#include <time.h>
#include <y2038-support.h>
#include "kernel-posix-cpu-timers.h"
#ifdef HAVE_CLOCK_GETRES_VSYSCALL
@@ -48,4 +49,64 @@
#define SYSDEP_GETRES_CPU SYSCALL_GETRES
#define SYSDEP_GETRES_CPUTIME /* Default catches them too. */
/* The 64-bit version */
// Call the 32-bit syscall and convert to 64-bit time
#define SYSCALL_GETRES32 \
retval = INLINE_VSYSCALL (clock_getres, 2, clock_id, &ts32); \
if (retval==0) \
{ \
timespec_to_timespec64(&ts32, res); \
res->tv_pad = 0; \
}
#ifdef __NR_clock_getres_time64
/* We are building with a 64-bit-time getres syscall */
#define SYSCALL_GETRES64 \
if (__y2038_linux_support > 0) \
{ \
retval = INLINE_SYSCALL (clock_getres_time64, 2, clock_id, res); \
if (retval == -1 && errno == ENOSYS) \
{ \
__y2038_linux_support = -1; \
SYSCALL_GETRES32; \
} \
} \
else \
{ \
SYSCALL_GETRES32; \
} \
break
#else
/* We are building without a 64-bit-time getres syscall */
#define SYSCALL_GETRES64 \
SYSCALL_GETRES32; \
break
#endif
/* The REALTIME and MONOTONIC clock are definitely supported in the
kernel. */
#define SYSDEP_GETRES64 \
SYSDEP_GETRES_CPUTIME64 \
case CLOCK_REALTIME: \
case CLOCK_MONOTONIC: \
case CLOCK_MONOTONIC_RAW: \
case CLOCK_REALTIME_COARSE: \
case CLOCK_MONOTONIC_COARSE: \
SYSCALL_GETRES64
/* We handled the REALTIME clock here. */
#define HANDLED_REALTIME64 1
#define HANDLED_CPUTIME64 1
#define SYSDEP_GETRES_CPU64 SYSCALL_GETRES64
#define SYSDEP_GETRES_CPUTIME64 \
struct timespec ts32;
#include <sysdeps/posix/clock_getres.c>
+40 -3
View File
@@ -25,6 +25,41 @@
# define HAVE_VSYSCALL
#endif
#include <sysdep-vdso.h>
#include <y2038-support.h>
# define DO_CLOCK_GETTIME_32 \
retval = INLINE_VSYSCALL (clock_gettime, 2, clock_id, &ts32); \
if (retval == 0) \
{ \
valid_timespec_to_timespec64 (&ts32, tp); \
}
#ifdef __NR_clock_gettime64
/* We are building with a 64-bit-time clock_gettime syscall */
# define DO_CLOCK_GETTIME_64 \
if (__y2038_linux_support > 0) \
{ \
retval = INLINE_SYSCALL (clock_gettime64, 2, clock_id, tp); \
if (retval == -1 && errno == ENOSYS) \
{ \
__y2038_linux_support = -1; \
DO_CLOCK_GETTIME_32; \
} \
} \
else \
{ \
DO_CLOCK_GETTIME_32; \
}
#else
/* We are building without a 64-bit-time clock_gettime syscall */
# define DO_CLOCK_GETTIME_64 DO_CLOCK_GETTIME_32
#endif
/* The REALTIME and MONOTONIC clock are definitely supported in the
kernel. */
@@ -32,7 +67,7 @@
SYSDEP_GETTIME_CPUTIME; \
case CLOCK_REALTIME: \
case CLOCK_MONOTONIC: \
retval = INLINE_VSYSCALL (clock_gettime, 2, clock_id, tp); \
DO_CLOCK_GETTIME_64; \
break
/* We handled the REALTIME clock here. */
@@ -40,8 +75,10 @@
#define HANDLED_CPUTIME 1
#define SYSDEP_GETTIME_CPU(clock_id, tp) \
retval = INLINE_VSYSCALL (clock_gettime, 2, clock_id, tp); \
DO_CLOCK_GETTIME_64; \
break
#define SYSDEP_GETTIME_CPUTIME /* Default catches them too. */
#define SYSDEP_GETTIME_CPUTIME \
struct timespec ts32
#include <sysdeps/unix/clock_gettime.c>
+48 -1
View File
@@ -21,7 +21,6 @@
#include <sysdep-cancel.h>
#include "kernel-posix-cpu-timers.h"
/* We can simply use the syscall. The CPU clocks are not supported
with this function. */
int
@@ -52,3 +51,51 @@ __clock_nanosleep (clockid_t clock_id, int flags, const struct timespec *req,
? INTERNAL_SYSCALL_ERRNO (r, err) : 0);
}
weak_alias (__clock_nanosleep, clock_nanosleep)
/* 64-bit time version */
/* We don't have a 64-bit-time syscall yet, so just convert arguments
* between 64-bit and 32-bit time, and use the 32-bit implementation.
*
* We could do the reverse and make the 32-bit time implementation a
* wrapper around the 64-bit-time implementation, but then 32-bit-time
* uses would incur four conversions instead of zero right now.
*/
int
__clock_nanosleep64 (clockid_t clock_id, int flags,
const struct __timespec64 *req,
struct __timespec64 *rem)
{
int res;
struct timespec req32, rem32, *rem32p = NULL;
if (req == NULL)
{
__set_errno (EFAULT);
return -1;
}
if (req->tv_sec > INT32_MAX || req->tv_sec < INT32_MIN)
{
__set_errno (EOVERFLOW);
return -1;
}
/* For now, use the 32-bit-time implementation above */
req32.tv_sec = req->tv_sec;
req32.tv_nsec = req->tv_nsec;
if (rem != NULL)
rem32p = &rem32;
res = __clock_nanosleep (clock_id, flags, &req32, rem32p);
if (res == 0 && rem != NULL)
{
rem->tv_sec = rem32.tv_sec;
rem->tv_nsec = rem32.tv_nsec;
}
return res;
}
+58
View File
@@ -18,6 +18,7 @@
#include <errno.h>
#include <sysdep.h>
#include <time.h>
#include <y2038-support.h>
#include "kernel-posix-cpu-timers.h"
@@ -35,4 +36,61 @@
#define SYSDEP_SETTIME_CPU \
retval = INLINE_SYSCALL (clock_settime, 2, clock_id, tp)
/* 64-bit time version */
# define DO_CLOCK_SETTIME_32 \
if (! fits_in_time_t(tp->tv_sec)) \
{ \
__set_errno (EOVERFLOW); \
retval = -1; \
} \
else \
{ \
valid_timespec64_to_timespec(tp, &ts32); \
retval = INLINE_SYSCALL (clock_settime, 2, clock_id, &ts32); \
}
#ifdef __NR_clock_settime64
/* We are building with a 64-bit-time clock_gettime syscall */
# define DO_CLOCK_SETTIME_64 \
if (__y2038_linux_support > 0) \
{ \
ts64.tv_sec = tp->tv_sec; \
ts64.tv_nsec = tp->tv_nsec; \
ts64.tv_pad = 0; \
retval = INLINE_SYSCALL (clock_settime64, 2, clock_id, &ts64); \
if (retval == 1 && errno==ENOSYS) \
{ \
__y2038_linux_support = -1; \
DO_CLOCK_SETTIME_32; \
} \
} \
else \
{ \
DO_CLOCK_SETTIME_32; \
}
# define SYSDEP_SETTIME64_CPUTIME \
struct __timespec64 ts64; \
struct timespec ts32
#else
/* We are building without a 64-bit-time clock_gettime syscall */
# define DO_CLOCK_SETTIME_64 DO_CLOCK_SETTIME_32
# define SYSDEP_SETTIME64_CPUTIME \
struct timespec ts32
#endif
#define SYSDEP_SETTIME64 \
SYSDEP_SETTIME64_CPUTIME; \
case CLOCK_REALTIME: \
DO_CLOCK_SETTIME_64; \
break
#include <sysdeps/unix/clock_settime.c>
+123
View File
@@ -131,6 +131,32 @@ futex_reltimed_wait (unsigned int *futex_word, unsigned int expected,
}
}
/* 64-bit time version */
static __always_inline int
futex_reltimed_wait64 (unsigned int *futex_word, unsigned int expected,
const struct __timespec64 *reltime, int private)
{
int err = lll_futex_timed_wait64 (futex_word, expected, reltime,
private);
switch (err)
{
case 0:
case -EAGAIN:
case -EINTR:
case -ETIMEDOUT:
return -err;
case -EFAULT: /* Must have been caused by a glibc or application bug. */
case -EINVAL: /* Either due to wrong alignment or due to the timeout not
being normalized. Must have been caused by a glibc or
application bug. */
case -ENOSYS: /* Must have been caused by a glibc bug. */
/* No other errors are documented at this time. */
default:
futex_fatal_error ();
}
}
/* See sysdeps/nptl/futex-internal.h for details. */
static __always_inline int
futex_reltimed_wait_cancelable (unsigned int *futex_word,
@@ -160,6 +186,37 @@ futex_reltimed_wait_cancelable (unsigned int *futex_word,
}
}
/* 64-bit time version */
static __always_inline int
futex_reltimed_wait_cancelable64 (unsigned int *futex_word,
unsigned int expected,
const struct __timespec64 *reltime,
int private)
{
int oldtype;
oldtype = __pthread_enable_asynccancel ();
int err = lll_futex_timed_wait64 (futex_word, expected, reltime, private);
__pthread_disable_asynccancel (oldtype);
switch (err)
{
case 0:
case -EAGAIN:
case -EINTR:
case -ETIMEDOUT:
return -err;
case -EFAULT: /* Must have been caused by a glibc or application bug. */
case -EINVAL: /* Either due to wrong alignment or due to the timeout not
being normalized. Must have been caused by a glibc or
application bug. */
case -ENOSYS: /* Must have been caused by a glibc bug. */
/* No other errors are documented at this time. */
default:
futex_fatal_error ();
}
}
/* See sysdeps/nptl/futex-internal.h for details. */
static __always_inline int
futex_abstimed_wait (unsigned int *futex_word, unsigned int expected,
@@ -190,6 +247,36 @@ futex_abstimed_wait (unsigned int *futex_word, unsigned int expected,
}
}
/* 64-bit time version */
static __always_inline int
futex_abstimed_wait64 (unsigned int *futex_word, unsigned int expected,
const struct __timespec64 *abstime, int private)
{
/* Work around the fact that the kernel rejects negative timeout values
despite them being valid. */
if (__glibc_unlikely ((abstime != NULL) && (abstime->tv_sec < 0)))
return ETIMEDOUT;
int err = lll_futex_timed_wait_bitset64 (futex_word, expected, abstime,
FUTEX_CLOCK_REALTIME, private);
switch (err)
{
case 0:
case -EAGAIN:
case -EINTR:
case -ETIMEDOUT:
return -err;
case -EFAULT: /* Must have been caused by a glibc or application bug. */
case -EINVAL: /* Either due to wrong alignment or due to the timeout not
being normalized. Must have been caused by a glibc or
application bug. */
case -ENOSYS: /* Must have been caused by a glibc bug. */
/* No other errors are documented at this time. */
default:
futex_fatal_error ();
}
}
/* See sysdeps/nptl/futex-internal.h for details. */
static __always_inline int
futex_abstimed_wait_cancelable (unsigned int *futex_word,
@@ -224,6 +311,42 @@ futex_abstimed_wait_cancelable (unsigned int *futex_word,
}
}
/* 64-bit time version */
static __always_inline int
futex_abstimed_wait_cancelable64 (unsigned int *futex_word,
unsigned int expected,
const struct __timespec64 *abstime,
int private)
{
/* Work around the fact that the kernel rejects negative timeout values
despite them being valid. */
if (__glibc_unlikely ((abstime != NULL) && (abstime->tv_sec < 0)))
return ETIMEDOUT;
int oldtype;
oldtype = __pthread_enable_asynccancel ();
int err = lll_futex_timed_wait_bitset64 (futex_word, expected, abstime,
FUTEX_CLOCK_REALTIME, private);
__pthread_disable_asynccancel (oldtype);
switch (err)
{
case 0:
case -EAGAIN:
case -EINTR:
case -ETIMEDOUT:
return -err;
case -EFAULT: /* Must have been caused by a glibc or application bug. */
case -EINVAL: /* Either due to wrong alignment or due to the timeout not
being normalized. Must have been caused by a glibc or
application bug. */
case -ENOSYS: /* Must have been caused by a glibc bug. */
/* No other errors are documented at this time. */
default:
futex_fatal_error ();
}
}
/* See sysdeps/nptl/futex-internal.h for details. */
static __always_inline void
futex_wake (unsigned int *futex_word, int processes_to_wake, int private)
+48 -1
View File
@@ -21,7 +21,7 @@
#include <string.h>
#include <time.h>
#include <sysdep.h>
#include <y2038-support.h>
/* Change the access time of the file associated with FD to TSP[0] and
the modification time of FILE to TSP[1].
@@ -36,3 +36,50 @@ futimens (int fd, const struct timespec tsp[2])
/* Avoid implicit array coercion in syscall macros. */
return INLINE_SYSCALL (utimensat, 4, fd, NULL, &tsp[0], 0);
}
/* 64-bit time version */
int
__futimens64 (int fd, const struct __timespec64 tsp[2])
{
struct timespec ts32[2];
/* Only try and use this syscall if defined by kernel */
#ifdef __NR_utimesat_time64
struct __timespec64 ts64[2];
int res;
#endif
if (fd < 0)
return INLINE_SYSCALL_ERROR_RETURN_VALUE (EBADF);
/* Only try and use this syscall if defined by kernel */
#ifdef __NR_utimesat_time64
if (__y2038_linux_support > 0)
{
ts64[0].tv_sec = tsp[0].tv_sec;
ts64[0].tv_nsec = tsp[0].tv_nsec;
ts64[0].tv_pad = 0;
ts64[1].tv_sec = tsp[1].tv_sec;
ts64[1].tv_nsec = tsp[1].tv_nsec;
ts64[1].tv_pad = 0;
res = INLINE_SYSCALL (utimensat_time64, 4, fd, NULL, &ts64[0], 0);
if (res == 0 || errno != ENOSYS)
return res;
__y2038_linux_support = -1;
}
#endif
if (! timespec64_to_timespec(&tsp[0], &ts32[0]))
{
__set_errno(EOVERFLOW);
return -1;
}
if (! timespec64_to_timespec(&tsp[1], &ts32[1]))
{
__set_errno(EOVERFLOW);
return -1;
}
return INLINE_SYSCALL (utimensat, 4, fd, NULL, &ts32[0], 0);
}
+59
View File
@@ -24,6 +24,7 @@
#include <sys/time.h>
#include <_itoa.h>
#include <fcntl.h>
#include <y2038-support.h>
/* Change the access time of the file associated with FD to TVP[0] and
@@ -49,3 +50,61 @@ __futimes (int fd, const struct timeval tvp[2])
return INLINE_SYSCALL (utimensat, 4, fd, NULL, tvp ? &ts : NULL, 0);
}
weak_alias (__futimes, futimes)
/* 64-bit time version */
int
__futimes64 (int fd, const struct __timeval64 tvp[2])
{
struct timespec ts32[2], *ts32p = NULL;
/* Only try and use this syscall if defined by kernel */
#ifdef __NR_utimensat_time64
/* The utimensat system call expects timespec not timeval. */
struct __timespec64 ts64[2], *ts64p = NULL;
int result;
#endif
/* Only try and use this syscall if defined by kernel */
#ifdef __NR_utimensat_time64
if (__y2038_linux_support > 0)
{
if (tvp != NULL)
{
if (tvp[0].tv_usec < 0 || tvp[0].tv_usec >= 1000000
|| tvp[1].tv_usec < 0 || tvp[1].tv_usec >= 1000000)
return INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL);
ts64[0].tv_sec = tvp[0].tv_sec;
ts64[0].tv_nsec = tvp[0].tv_usec * 1000;
ts64[0].tv_pad = 0;
ts64[1].tv_sec = tvp[1].tv_sec;
ts64[1].tv_nsec = tvp[1].tv_usec * 1000;
ts64[1].tv_pad = 0;
ts64p = ts64;
}
result = INLINE_SYSCALL (utimensat_time64, 4, fd, NULL, ts64p, 0);
if (result == 0 || errno != ENOSYS)
return result;
__y2038_linux_support = -1;
}
#endif
if (tvp != NULL)
{
if (tvp[0].tv_usec < 0 || tvp[0].tv_usec >= 1000000
|| tvp[1].tv_usec < 0 || tvp[1].tv_usec >= 1000000)
return INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL);
if (tvp[0].tv_sec > INT_MAX || tvp[1].tv_sec > INT_MAX)
return INLINE_SYSCALL_ERROR_RETURN_VALUE (EOVERFLOW);
ts32[0].tv_sec = tvp[0].tv_sec;
ts32[0].tv_nsec = tvp[0].tv_usec * 1000;
ts32[1].tv_sec = tvp[1].tv_sec;
ts32[1].tv_nsec = tvp[1].tv_usec * 1000;
ts32p = ts32;
}
return INLINE_SYSCALL (utimensat, 4, fd, NULL, ts32p, 0);
}
+40
View File
@@ -51,3 +51,43 @@ hidden_ver (___fxstat64, __fxstat64)
strong_alias (___fxstat64, __fxstat64)
hidden_def (__fxstat64)
#endif
/* 64-bit time version */
int
__fxstat64_time64 (int vers, int fd, struct __stat64_t64 *buf)
{
int result;
struct stat64 st64;
result = INLINE_SYSCALL (fstat64, 2, fd, &st64);
#if defined _HAVE_STAT64___ST_INO && !__ASSUME_ST_INO_64_BIT
if (__builtin_expect (!result, 1) && st64.__st_ino != (__ino_t) st64.st_ino)
st64.st_ino = st64.__st_ino;
#endif
if (!result)
{
buf->st_dev = st64.st_dev;
#if defined _HAVE_STAT64___ST_INO
buf->__st_ino = st64.__st_ino;
#endif
buf->st_mode = st64.st_mode;
buf->st_nlink = st64.st_nlink;
buf->st_uid = st64.st_uid;
buf->st_gid = st64.st_gid;
buf->st_rdev = st64.st_rdev;
buf->st_size = st64.st_size;
buf->st_blksize = st64.st_blksize;
buf->st_blocks = st64.st_blocks;
buf->st_atim.tv_sec = st64.st_atim.tv_sec;
buf->st_atim.tv_nsec = st64.st_atim.tv_nsec;
buf->st_mtim.tv_sec = st64.st_mtim.tv_sec;
buf->st_mtim.tv_nsec = st64.st_mtim.tv_nsec;
buf->st_ctim.tv_sec = st64.st_ctim.tv_sec;
buf->st_ctim.tv_nsec = st64.st_ctim.tv_nsec;
buf->st_ino = st64.st_ino;
}
return result;
}
+45
View File
@@ -45,3 +45,48 @@ __fxstatat64 (int vers, int fd, const char *file, struct stat64 *st, int flag)
err));
}
libc_hidden_def (__fxstatat64)
/* 64-bit time version */
int
__fxstatat64_time64 (int vers, int fd, const char *file, struct __stat64_t64 *buf, int flag)
{
if (__glibc_unlikely (vers != _STAT_VER_LINUX))
return INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL);
int result;
struct stat64 st64;
INTERNAL_SYSCALL_DECL (err);
result = INTERNAL_SYSCALL (fstatat64, err, 4, fd, file, &st64, flag);
if (!__builtin_expect (INTERNAL_SYSCALL_ERROR_P (result, err), 1))
{
buf->st_dev = st64.st_dev;
#if defined _HAVE_STAT64___ST_INO
buf->__st_ino = st64.__st_ino;
#endif
buf->st_mode = st64.st_mode;
buf->st_nlink = st64.st_nlink;
buf->st_uid = st64.st_uid;
buf->st_gid = st64.st_gid;
buf->st_rdev = st64.st_rdev;
buf->st_size = st64.st_size;
buf->st_blksize = st64.st_blksize;
buf->st_blocks = st64.st_blocks;
buf->st_atim.tv_sec = st64.st_atim.tv_sec;
buf->st_atim.tv_nsec = st64.st_atim.tv_nsec;
buf->st_mtim.tv_sec = st64.st_mtim.tv_sec;
buf->st_mtim.tv_nsec = st64.st_mtim.tv_nsec;
buf->st_ctim.tv_sec = st64.st_ctim.tv_sec;
buf->st_ctim.tv_nsec = st64.st_ctim.tv_nsec;
buf->st_ino = st64.st_ino;
return 0;
}
else
return INLINE_SYSCALL_ERROR_RETURN_VALUE (INTERNAL_SYSCALL_ERRNO (result,
err));
}
+52
View File
@@ -0,0 +1,52 @@
/* Copyright (C) 2015-2018 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 <sys/time.h>
#undef __gettimeofday
#ifdef HAVE_GETTIMEOFDAY_VSYSCALL
# define HAVE_VSYSCALL
#include <sysdep-vdso.h>
#endif
/* Get the current time of day and timezone information,
putting it into *tv and *tz. If tz is null, *tz is not filled.
Returns 0 on success, -1 on errors. */
int
__gettimeofday64 (struct __timeval64 *tv, struct timezone *tz)
{
struct timeval tv32;
int result;
#ifdef __vdso_gettimeofday
result = INLINE_VSYSCALL (gettimeofday, 2, &tv32, tz);
#else
result = INLINE_SYSCALL (gettimeofday, 2, &tv32, tz);
#endif
if (result == 0)
{
tv->tv_sec = tv32.tv_sec;
tv->tv_usec = tv32.tv_usec;
}
return result;
}
+14
View File
@@ -154,3 +154,17 @@
*/
#define __ASSUME_CLONE_DEFAULT 1
/* Support for Y2038-proof times.
If defined, the underlying kernel always provides a set of syscalls
(__NR_* names and numbers) which can handle times beyond Y2038.
If undefined, whether the underlying kernel provides this set or not
must be checked dynamically.
Definition is commented out until Y2038 syscalls are merged in the
kernel.
*/
/* #define __ASSUME_KERNEL_Y2038_SUPPORT 1 */
@@ -82,6 +82,16 @@
__lll_private_flag (FUTEX_WAIT, private), \
val, timeout)
#define lll_futex_timed_wait64(futexp, val, timeout, private) \
({ \
struct timespec ts; \
ts.tv_sec = timeout->tv_sec; \
ts.tv_nsec = timeout->tv_nsec; \
lll_futex_syscall (4, futexp, \
__lll_private_flag (FUTEX_WAIT, private), \
val, &ts); \
})
#define lll_futex_timed_wait_bitset(futexp, val, timeout, clockbit, private) \
lll_futex_syscall (6, futexp, \
__lll_private_flag (FUTEX_WAIT_BITSET | (clockbit), \
@@ -89,6 +99,18 @@
val, timeout, NULL /* Unused. */, \
FUTEX_BITSET_MATCH_ANY)
#define lll_futex_timed_wait_bitset64(futexp, val, timeout, clockbit, private) \
({ \
struct timespec ts; \
ts.tv_sec = timeout->tv_sec; \
ts.tv_nsec = timeout->tv_nsec; \
lll_futex_syscall (6, futexp, \
__lll_private_flag (FUTEX_WAIT_BITSET | (clockbit), \
private), \
val, &ts, NULL /* Unused. */, \
FUTEX_BITSET_MATCH_ANY); \
})
#define lll_futex_wake(futexp, nr, private) \
lll_futex_syscall (4, futexp, \
__lll_private_flag (FUTEX_WAKE, private), nr, 0)

Some files were not shown because too many files have changed in this diff Show More