This is the mail archive of the
glibc-cvs@sourceware.org
mailing list for the glibc project.
GNU C Library master sources branch aaribaud/y2038 created. glibc-2.28.9000-194-g30271f7
- From: aaribaud at sourceware dot org
- To: glibc-cvs at sourceware dot org
- Date: 19 Sep 2018 07:25:28 -0000
- Subject: GNU C Library master sources branch aaribaud/y2038 created. glibc-2.28.9000-194-g30271f7
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU C Library master sources".
The branch, aaribaud/y2038 has been created
at 30271f7b8b5931e9ae3b30fbccc73182552b1bf3 (commit)
- Log -----------------------------------------------------------------
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=30271f7b8b5931e9ae3b30fbccc73182552b1bf3
commit 30271f7b8b5931e9ae3b30fbccc73182552b1bf3
Author: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
Date: Wed Sep 6 10:00:42 2017 +0200
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.
diff --git a/include/features.h b/include/features.h
index 5bed0a4..47eb58b 100644
--- a/include/features.h
+++ b/include/features.h
@@ -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
diff --git a/io/sys/stat.h b/io/sys/stat.h
index a1092f5..93ba4be 100644
--- a/io/sys/stat.h
+++ b/io/sys/stat.h
@@ -211,14 +211,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
@@ -261,12 +274,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
@@ -358,6 +382,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)
@@ -366,6 +399,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
@@ -404,6 +445,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));
@@ -417,11 +473,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
diff --git a/io/utime.h b/io/utime.h
index 8409ba4..0068e2f 100644
--- a/io/utime.h
+++ b/io/utime.h
@@ -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));
diff --git a/manual/creature.texi b/manual/creature.texi
index 8876b2a..10b7111 100644
--- a/manual/creature.texi
+++ b/manual/creature.texi
@@ -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
diff --git a/misc/sys/select.h b/misc/sys/select.h
index 060e7f4..d289175 100644
--- a/misc/sys/select.h
+++ b/misc/sys/select.h
@@ -100,6 +100,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,
@@ -112,6 +124,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,
diff --git a/posix/sched.h b/posix/sched.h
index 732c12b..3ed9713 100644
--- a/posix/sched.h
+++ b/posix/sched.h
@@ -75,6 +75,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;
diff --git a/resource/sys/resource.h b/resource/sys/resource.h
index 881db39..5363adf 100644
--- a/resource/sys/resource.h
+++ b/resource/sys/resource.h
@@ -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
diff --git a/rt/mqueue.h b/rt/mqueue.h
index 39e2a24..051c730 100644
--- a/rt/mqueue.h
+++ b/rt/mqueue.h
@@ -74,6 +74,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,
@@ -82,6 +93,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)
diff --git a/signal/signal.h b/signal/signal.h
index caa2915..9596184 100644
--- a/signal/signal.h
+++ b/signal/signal.h
@@ -267,6 +267,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)
diff --git a/sysdeps/nptl/pthread.h b/sysdeps/nptl/pthread.h
index 41b915e..59b4abe 100644
--- a/sysdeps/nptl/pthread.h
+++ b/sysdeps/nptl/pthread.h
@@ -766,6 +766,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));
@@ -905,6 +916,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));
@@ -920,6 +942,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));
@@ -999,6 +1032,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)
diff --git a/sysdeps/pthread/semaphore.h b/sysdeps/pthread/semaphore.h
index 312433f..b286c06 100644
--- a/sysdeps/pthread/semaphore.h
+++ b/sysdeps/pthread/semaphore.h
@@ -58,6 +58,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
diff --git a/sysdeps/unix/sysv/linux/bits/msq.h b/sysdeps/unix/sysv/linux/bits/msq.h
index 3195210..c3a12c0 100644
--- a/sysdeps/unix/sysv/linux/bits/msq.h
+++ b/sysdeps/unix/sysv/linux/bits/msq.h
@@ -35,6 +35,22 @@ typedef unsigned long int 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 */
@@ -52,6 +68,7 @@ struct msqid_ds
unsigned long int __glibc_reserved4;
unsigned long int __glibc_reserved5;
};
+#endif
#ifdef __USE_MISC
diff --git a/sysdeps/unix/sysv/linux/bits/stat.h b/sysdeps/unix/sysv/linux/bits/stat.h
index 48ef82d..fde673e 100644
--- a/sysdeps/unix/sysv/linux/bits/stat.h
+++ b/sysdeps/unix/sysv/linux/bits/stat.h
@@ -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. */
diff --git a/sysdeps/unix/sysv/linux/sys/timerfd.h b/sysdeps/unix/sysv/linux/sys/timerfd.h
index 37490cf..58d632e 100644
--- a/sysdeps/unix/sysv/linux/sys/timerfd.h
+++ b/sysdeps/unix/sysv/linux/sys/timerfd.h
@@ -44,11 +44,30 @@ extern int timerfd_create (__clockid_t __clock_id, int __flags) __THROW;
/* Set next expiration time of interval timer source UFD to UTMR. If
FLAGS has the TFD_TIMER_ABSTIME flag set the timeout value is
absolute. Optionally return the old expiration time in OTMR. */
+#ifdef __USE_TIME_BITS64
+# if defined(__REDIRECT)
+extern int __REDIRECT (timerfd_settime, (int __ufd, int __flags,
+ const struct itimerspec *__utmr,
+ struct itimerspec *__otmr),__timerfd_settime64)
+ __THROW;
+# else
+# define timerfd_settime __timerfd_settime64
+# endif
+#endif
extern int timerfd_settime (int __ufd, int __flags,
const struct itimerspec *__utmr,
struct itimerspec *__otmr) __THROW;
/* Return the next expiration time of UFD. */
+#ifdef __USE_TIME_BITS64
+# if defined(__REDIRECT)
+extern int __REDIRECT (timerfd_gettime, (int __ufd,
+ struct itimerspec *__otmr),__timerfd_gettime64)
+ __THROW;
+# else
+# define timerfd_gettime __timerfd_gettime64
+# endif
+#endif
extern int timerfd_gettime (int __ufd, struct itimerspec *__otmr) __THROW;
__END_DECLS
diff --git a/sysdeps/unix/sysv/linux/sys/timex.h b/sysdeps/unix/sysv/linux/sys/timex.h
index fd45929..d4ddb33 100644
--- a/sysdeps/unix/sysv/linux/sys/timex.h
+++ b/sysdeps/unix/sysv/linux/sys/timex.h
@@ -68,15 +68,43 @@ struct __ntptimeval64
__BEGIN_DECLS
extern int __adjtimex (struct timex *__ntx) __THROW;
+
+#ifdef __USE_TIME_BITS64
+# if defined(__REDIRECT)
+extern time_t __REDIRECT (adjtimex, (struct timex *__ntx),
+ __adjtimex64) __THROW;
+# else
+# define adjtimex __adjtimex64
+# endif
+#endif
extern int adjtimex (struct timex *__ntx) __THROW;
-#ifdef __REDIRECT_NTH
+#if __WORDSIZE > 32 || ! defined(__USE_TIME_BITS64)
+# ifdef __REDIRECT_NTH
extern int __REDIRECT_NTH (ntp_gettime, (struct ntptimeval *__ntv),
ntp_gettimex);
-#else
+# else
extern int ntp_gettimex (struct ntptimeval *__ntv) __THROW;
+# define ntp_gettime ntp_gettimex
+# endif
+#else
+# if defined(__REDIRECT)
+extern time_t __REDIRECT (ntp_gettimex, (struct ntptimeval *__ntv),
+ __ntp_gettimex64) __THROW;
+# else
+# define ntp_gettimex __ntp_gettimex64
+# endif
# define ntp_gettime ntp_gettimex
#endif
+
+#ifdef __USE_TIME_BITS64
+# if defined(__REDIRECT)
+extern int __REDIRECT (ntp_adjtime, (struct timex *__tntx),
+ __ntp_adjtime64) __THROW;
+# else
+# define ntp_adjtime __ntp_adjtime64
+# endif
+#endif
extern int ntp_adjtime (struct timex *__tntx) __THROW;
__END_DECLS
diff --git a/sysvipc/sys/msg.h b/sysvipc/sys/msg.h
index 1635839..92ea7ac 100644
--- a/sysvipc/sys/msg.h
+++ b/sysvipc/sys/msg.h
@@ -58,6 +58,15 @@ struct msgbuf
__BEGIN_DECLS
/* Message queue control operation. */
+#ifdef __USE_TIME_BITS64
+# if defined(__REDIRECT)
+extern int __REDIRECT (msgctl, (int __msqid, int __cmd,
+ struct msqid_ds *__buf),
+ __msgctl64) __THROW;
+# else
+# define msgctl __msgctl64
+# endif
+#endif
extern int msgctl (int __msqid, int __cmd, struct msqid_ds *__buf) __THROW;
/* Get messages queue. */
diff --git a/time/bits/types/struct_itimerspec.h b/time/bits/types/struct_itimerspec.h
index d36295a..1e4ab51 100644
--- a/time/bits/types/struct_itimerspec.h
+++ b/time/bits/types/struct_itimerspec.h
@@ -5,11 +5,17 @@
#include <bits/types/struct_timespec.h>
#include <bits/types/struct_timespec64.h>
+/* Use the original definition for 64-bit arches
+ or when 64-bit-time by default has *not* been requested */
+#if __WORDSIZE > 32 || ! defined(__USE_TIME_BITS64)
/* POSIX.1b structure for timer start values and intervals. */
struct itimerspec
{
struct timespec it_interval;
struct timespec it_value;
};
+#else
+# define itimerspec __itimerspec64
+#endif
#endif
diff --git a/time/bits/types/struct_timespec.h b/time/bits/types/struct_timespec.h
index 5b77c52..f93557f 100644
--- a/time/bits/types/struct_timespec.h
+++ b/time/bits/types/struct_timespec.h
@@ -4,6 +4,9 @@
#include <bits/types.h>
+/* Use the original definition for 64-bit arches
+ or when 64-bit-time by default has *not* been requested */
+#if __WORDSIZE > 32 || ! defined(__USE_TIME_BITS64)
/* POSIX.1b structure for a time value. This is like a `struct timeval' but
has nanoseconds instead of microseconds. */
struct timespec
@@ -11,5 +14,9 @@ struct timespec
__time_t tv_sec; /* Seconds. */
__syscall_slong_t tv_nsec; /* Nanoseconds. */
};
+#else
+/* Use the 64-bit-time timespec by default */
+#define timespec __timespec64
+# endif
#endif
diff --git a/time/bits/types/struct_timeval.h b/time/bits/types/struct_timeval.h
index 70394ce..e710b37 100644
--- a/time/bits/types/struct_timeval.h
+++ b/time/bits/types/struct_timeval.h
@@ -3,6 +3,9 @@
#include <bits/types.h>
+/* Use the original definition for 64-bit arches
+ or when 64-bit-time by default has *not* been requested */
+# if __WORDSIZE > 32 || ! defined(__USE_TIME_BITS64)
/* A time value that is accurate to the nearest
microsecond but also has a range of years. */
struct timeval
@@ -10,4 +13,9 @@ struct timeval
__time_t tv_sec; /* Seconds. */
__suseconds_t tv_usec; /* Microseconds. */
};
+# else
+/* Use the 64-bit-time timespec by default */
+# define timeval __timeval64
+# endif
+
#endif
diff --git a/time/bits/types/time_t.h b/time/bits/types/time_t.h
index ab8287c..84d67f6 100644
--- a/time/bits/types/time_t.h
+++ b/time/bits/types/time_t.h
@@ -4,6 +4,10 @@
#include <bits/types.h>
/* Returned by `time'. */
+#ifdef __USE_TIME_BITS64
+typedef __time64_t time_t;
+#else
typedef __time_t time_t;
+#endif
#endif
diff --git a/time/sys/time.h b/time/sys/time.h
index b7fe339..01ac9b6 100644
--- a/time/sys/time.h
+++ b/time/sys/time.h
@@ -66,12 +66,31 @@ typedef void *__restrict __timezone_ptr_t;
Returns 0 on success, -1 on errors.
NOTE: This form of timezone information is obsolete.
Use the functions and variables declared in <time.h> instead. */
+#ifdef __USE_TIME_BITS64
+# if defined(__REDIRECT)
+extern int __REDIRECT (gettimeofday, (struct timeval *__restrict __tv,
+ __timezone_ptr_t __tz),
+ __gettimeofday64) __THROW __nonnull((1));
+# else
+# define gettimeofday __gettimeofday64
+# endif
+#endif
extern int gettimeofday (struct timeval *__restrict __tv,
__timezone_ptr_t __tz) __THROW __nonnull ((1));
#ifdef __USE_MISC
/* Set the current time of day and timezone information.
This call is restricted to the super-user. */
+#ifdef __USE_TIME_BITS64
+# if defined(__REDIRECT)
+extern int __REDIRECT (settimeofday,
+ (const struct timeval *__tv,
+ const struct timezone *__tz),
+ __settimeofday64) __THROW;
+# else
+# define settimeofday __settimeofday64
+# endif
+# endif
extern int settimeofday (const struct timeval *__tv,
const struct timezone *__tz)
__THROW;
@@ -80,6 +99,16 @@ extern int settimeofday (const struct timeval *__tv,
If OLDDELTA is not NULL, it is filled in with the amount
of time adjustment remaining to be done from the last `adjtime' call.
This call is restricted to the super-user. */
+#ifdef __USE_TIME_BITS64
+# if defined(__REDIRECT)
+extern int __REDIRECT (adjtime,
+ (const struct timeval *__delta,
+ struct timeval *__olddelta),
+ __adjtime64) __THROW;
+# else
+# define adjtime __adjtime64
+# endif
+# endif
extern int adjtime (const struct timeval *__delta,
struct timeval *__olddelta) __THROW;
#endif
@@ -130,12 +159,31 @@ typedef int __itimer_which_t;
/* Set *VALUE to the current setting of timer WHICH.
Return 0 on success, -1 on errors. */
+#ifdef __USE_TIME_BITS64
+# if defined(__REDIRECT)
+extern int __REDIRECT (getitimer, (__itimer_which_t __which,
+ struct itimerval *__value), __getitimer64)
+ __THROW;
+# else
+# define getitimer __getitimer64
+# endif
+#endif
extern int getitimer (__itimer_which_t __which,
struct itimerval *__value) __THROW;
/* Set the timer WHICH to *NEW. If OLD is not NULL,
set *OLD to the old value of timer WHICH.
Returns 0 on success, -1 on errors. */
+#ifdef __USE_TIME_BITS64
+# if defined(__REDIRECT)
+extern int __REDIRECT (setitimer, (__itimer_which_t __which,
+ const struct itimerval *__restrict __new,
+ struct itimerval *__restrict __old), __setitimer64)
+ __THROW;
+# else
+# define setitimer __setitimer64
+# endif
+#endif
extern int setitimer (__itimer_which_t __which,
const struct itimerval *__restrict __new,
struct itimerval *__restrict __old) __THROW;
@@ -143,15 +191,41 @@ extern int setitimer (__itimer_which_t __which,
/* Change the access time of FILE to TVP[0] and the modification time of
FILE to TVP[1]. If TVP is a null pointer, use the current time instead.
Returns 0 on success, -1 on errors. */
+#ifdef __USE_TIME_BITS64
+# if defined(__REDIRECT)
+extern int __REDIRECT (utimes, (const char *__file,
+ const struct timeval __tvp[2]), __utimes64)
+ __THROW __nonnull ((1));
+# else
+# define utimes __utimes64
+# endif
+#endif
extern int utimes (const char *__file, const struct timeval __tvp[2])
__THROW __nonnull ((1));
#ifdef __USE_MISC
/* Same as `utimes', but does not follow symbolic links. */
+#ifdef __USE_TIME_BITS64
+# if defined(__REDIRECT)
+extern int __REDIRECT (lutimes, (const char *__file,
+ const struct timeval __tvp[2]), __lutimes64)
+ __THROW __nonnull ((1));
+# else
+# define lutimes __lutimes64
+# endif
+#endif
extern int lutimes (const char *__file, const struct timeval __tvp[2])
__THROW __nonnull ((1));
/* Same as `utimes', but takes an open file descriptor instead of a name. */
+#ifdef __USE_TIME_BITS64
+# if defined(__REDIRECT)
+extern int __REDIRECT (futimes, (int __fd, const struct timeval __tvp[2]),
+ __futimes64) __THROW;
+# else
+# define futimes __futimes64
+# endif
+#endif
extern int futimes (int __fd, const struct timeval __tvp[2]) __THROW;
#endif
diff --git a/time/time.h b/time/time.h
index dcc275a..9471c6e 100644
--- a/time/time.h
+++ b/time/time.h
@@ -74,16 +74,38 @@ __BEGIN_DECLS
extern clock_t clock (void) __THROW;
/* Return the current time and put it in *TIMER if TIMER is not NULL. */
+#ifdef __USE_TIME_BITS64
+# if defined(__REDIRECT)
+extern time_t __REDIRECT (time, (time_t * __timer),
+ __time64) __THROW;
+# else
+# define time __time64
+# endif
+#endif
extern time_t time (time_t *__timer) __THROW;
/* Return the difference between TIME1 and TIME0. */
+#ifdef __USE_TIME_BITS64
+# if defined(__REDIRECT)
+extern double __REDIRECT (difftime, (time_t __time1, time_t __time0),
+ __difftime64) __THROW;
+# else
+# define difftime __difftime64
+# endif
+#endif
extern double difftime (time_t __time1, time_t __time0)
__THROW __attribute__ ((__const__));
/* Return the `time_t' representation of TP and normalize TP. */
+#ifdef __USE_TIME_BITS64
+# if defined(__REDIRECT)
+extern time_t __REDIRECT (mktime, (struct tm *__tp), __mktime64) __THROW;
+# else
+# define mktime __mktime64
+# endif
+#endif
extern time_t mktime (struct tm *__tp) __THROW;
-
/* Format TP into S according to FORMAT.
Write no more than MAXSIZE characters and return the number
of characters written, or 0 if it would exceed MAXSIZE. */
@@ -118,20 +140,52 @@ extern char *strptime_l (const char *__restrict __s,
/* Return the `struct tm' representation of *TIMER
in Universal Coordinated Time (aka Greenwich Mean Time). */
+#ifdef __USE_TIME_BITS64
+# if defined(__REDIRECT)
+extern struct tm * __REDIRECT (gmtime, (const time_t *__timer),
+ __gmtime64) __THROW;
+# else
+# define gmtime __gmtime64
+# endif
+#endif
extern struct tm *gmtime (const time_t *__timer) __THROW;
/* Return the `struct tm' representation
of *TIMER in the local timezone. */
+#ifdef __USE_TIME_BITS64
+# if defined(__REDIRECT)
+extern struct tm * __REDIRECT (localtime, (const time_t *__timer),
+ __localtime64) __THROW;
+# else
+# define localtime __localtime64
+# endif
+#endif
extern struct tm *localtime (const time_t *__timer) __THROW;
#ifdef __USE_POSIX
/* Return the `struct tm' representation of *TIMER in UTC,
using *TP to store the result. */
+#ifdef __USE_TIME_BITS64
+# if defined(__REDIRECT)
+extern struct tm * __REDIRECT (gmtime_r, (const time_t *__restrict
+ __timer, struct tm *__restrict __tp), __gmtime64_r) __THROW;
+# else
+# define gmtime_r __gmtime64_r
+# endif
+#endif
extern struct tm *gmtime_r (const time_t *__restrict __timer,
struct tm *__restrict __tp) __THROW;
/* Return the `struct tm' representation of *TIMER in local time,
using *TP to store the result. */
+#ifdef __USE_TIME_BITS64
+# if defined(__REDIRECT)
+extern struct tm * __REDIRECT (localtime_r, (const time_t *__restrict
+ __timer, struct tm *__restrict __tp), __localtime64_r) __THROW;
+# else
+# define localtime_r __localtime64_r
+# endif
+#endif
extern struct tm *localtime_r (const time_t *__restrict __timer,
struct tm *__restrict __tp) __THROW;
#endif /* POSIX */
@@ -141,6 +195,14 @@ extern struct tm *localtime_r (const time_t *__restrict __timer,
extern char *asctime (const struct tm *__tp) __THROW;
/* Equivalent to `asctime (localtime (timer))'. */
+#ifdef __USE_TIME_BITS64
+# if defined(__REDIRECT)
+extern char * __REDIRECT (ctime, (const time_t *__timer),
+ __ctime64) __THROW;
+# else
+# define ctime __ctime64
+# endif
+#endif
extern char *ctime (const time_t *__timer) __THROW;
#ifdef __USE_POSIX
@@ -152,6 +214,14 @@ extern char *asctime_r (const struct tm *__restrict __tp,
char *__restrict __buf) __THROW;
/* Equivalent to `asctime_r (localtime_r (timer, *TMP*), buf)'. */
+#ifdef __USE_TIME_BITS64
+# if defined(__REDIRECT)
+extern char * __REDIRECT (ctime_r, (const time_t *__restrict __timer,
+ char *__restrict __buf), __ctime64_r) __THROW;
+# else
+# define ctime_r __ctime64_r
+# endif
+#endif
extern char *ctime_r (const time_t *__restrict __timer,
char *__restrict __buf) __THROW;
#endif /* POSIX */
@@ -180,6 +250,14 @@ extern long int timezone;
#ifdef __USE_MISC
/* Set the system time to *WHEN.
This call is restricted to the superuser. */
+#ifdef __USE_TIME_BITS64
+# if defined(__REDIRECT)
+extern int __REDIRECT (stime, (const time_t *__when), __stime64)
+ __THROW;
+# else
+# define stime __stime64
+# endif
+#endif
extern int stime (const time_t *__when) __THROW;
#endif
@@ -195,9 +273,23 @@ extern int stime (const time_t *__when) __THROW;
localtime package. These are included only for compatibility. */
/* Like `mktime', but for TP represents Universal Time, not local time. */
+#ifdef __USE_TIME_BITS64
+# if defined(__REDIRECT)
+extern time_t __REDIRECT (timegm, (struct tm *__tp), __timegm64) __THROW;
+# else
+# define timegm __timegm64
+# endif
+#endif
extern time_t timegm (struct tm *__tp) __THROW;
/* Another name for `mktime'. */
+#ifdef __USE_TIME_BITS64
+# if defined(__REDIRECT)
+extern time_t __REDIRECT (timelocal, (struct tm *__tp), __timelocal64) __THROW;
+# else
+# define timelocal __timelocal64
+# endif
+#endif
extern time_t timelocal (struct tm *__tp) __THROW;
/* Return the number of days in YEAR. */
@@ -210,17 +302,49 @@ extern int dysize (int __year) __THROW __attribute__ ((__const__));
This function is a cancellation point and therefore not marked with
__THROW. */
+#ifdef __USE_TIME_BITS64
+# if defined(__REDIRECT)
+extern int __REDIRECT (nanosleep, (const struct timespec *__requested_time,
+ struct timespec *__remaining), __nanosleep64);
+# else
+# define nanosleep __nanosleep64
+# endif
+#endif
extern int nanosleep (const struct timespec *__requested_time,
struct timespec *__remaining);
/* Get resolution of clock CLOCK_ID. */
+#ifdef __USE_TIME_BITS64
+# if defined(__REDIRECT)
+extern int __REDIRECT (clock_getres, (clockid_t __clock_id, struct
+ timespec *__res), __clock_getres64) __THROW;
+# else
+# define clock_getres __clock_getres64
+# endif
+#endif
extern int clock_getres (clockid_t __clock_id, struct timespec *__res) __THROW;
/* Get current value of clock CLOCK_ID and store it in TP. */
+#ifdef __USE_TIME_BITS64
+# if defined(__REDIRECT)
+extern int __REDIRECT (clock_gettime, (clockid_t __clock_id, struct
+ timespec *__tp), __clock_gettime64) __THROW;
+# else
+# define clock_gettime __clock_gettime64
+# endif
+#endif
extern int clock_gettime (clockid_t __clock_id, struct timespec *__tp) __THROW;
/* Set clock CLOCK_ID to value TP. */
+#ifdef __USE_TIME_BITS64
+# if defined(__REDIRECT)
+extern int __REDIRECT (clock_settime, (clockid_t __clock_id, const struct
+ timespec *__tp), __clock_settime64) __THROW;
+# else
+# define clock_settime __clock_settime64
+# endif
+#endif
extern int clock_settime (clockid_t __clock_id, const struct timespec *__tp)
__THROW;
@@ -229,6 +353,15 @@ extern int clock_settime (clockid_t __clock_id, const struct timespec *__tp)
This function is a cancellation point and therefore not marked with
__THROW. */
+#ifdef __USE_TIME_BITS64
+# if defined(__REDIRECT)
+extern int __REDIRECT (clock_nanosleep, (clockid_t __clock_id, int __flags,
+ const struct timespec *__req, struct timespec *__rem),
+ __clock_nanosleep64) __THROW;
+# else
+# define clock_nanosleep __clock_nanosleep64
+# endif
+#endif
extern int clock_nanosleep (clockid_t __clock_id, int __flags,
const struct timespec *__req,
struct timespec *__rem);
@@ -247,11 +380,29 @@ extern int timer_create (clockid_t __clock_id,
extern int timer_delete (timer_t __timerid) __THROW;
/* Set timer TIMERID to VALUE, returning old value in OVALUE. */
+#ifdef __USE_TIME_BITS64
+# if defined(__REDIRECT)
+extern int __REDIRECT (timer_settime, (timer_t __timerid, int __flags,
+ const struct itimerspec *__restrict __value,
+ struct itimerspec *__restrict __ovalue),
+ __timer_settime64) __THROW;
+# else
+# define timer_settime __timer_settime64
+# endif
+#endif
extern int timer_settime (timer_t __timerid, int __flags,
const struct itimerspec *__restrict __value,
struct itimerspec *__restrict __ovalue) __THROW;
/* Get current value of timer TIMERID and store it in VALUE. */
+#ifdef __USE_TIME_BITS64
+# if defined(__REDIRECT)
+extern int __REDIRECT (timer_gettime, (timer_t __timerid, struct
+ itimerspec *__value), __timer_gettime64) __THROW __nonnull ((1));
+# else
+# define timer_gettime __timer_gettime64
+# endif
+#endif
extern int timer_gettime (timer_t __timerid, struct itimerspec *__value)
__THROW;
@@ -262,6 +413,14 @@ extern int timer_getoverrun (timer_t __timerid) __THROW;
#ifdef __USE_ISOC11
/* Set TS to calendar time based in time base BASE. */
+#ifdef __USE_TIME_BITS64
+# if defined(__REDIRECT)
+extern int __REDIRECT (timespec_get, (struct timespec *__ts, int __base),
+ __timespec_get64) __THROW __nonnull ((1));
+# else
+# define timespec_get __timespec_get64
+# endif
+#endif
extern int timespec_get (struct timespec *__ts, int __base)
__THROW __nonnull ((1));
#endif
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=86179f7bd8418456b9717c7c4c64fb8da48bda02
commit 86179f7bd8418456b9717c7c4c64fb8da48bda02
Author: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
Date: Thu Apr 12 20:50:21 2018 +0200
Y2038: add function __pmap_rmtcall64
diff --git a/sunrpc/pmap_rmt.c b/sunrpc/pmap_rmt.c
index 6b142e5..501da4f 100644
--- a/sunrpc/pmap_rmt.c
+++ b/sunrpc/pmap_rmt.c
@@ -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);
+}
diff --git a/sunrpc/rpc/pmap_clnt.h b/sunrpc/rpc/pmap_clnt.h
index 1cc94b8..b436ebb 100644
--- a/sunrpc/rpc/pmap_clnt.h
+++ b/sunrpc/rpc/pmap_clnt.h
@@ -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,
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=5b6c5e98902b82a2f326e7749e7a6b745d5406fa
commit 5b6c5e98902b82a2f326e7749e7a6b745d5406fa
Author: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
Date: Thu Apr 12 20:49:49 2018 +0200
Y2038: add function __clntudp_bufcreate64
diff --git a/sunrpc/clnt_udp.c b/sunrpc/clnt_udp.c
index 27a3244..0892ae3 100644
--- a/sunrpc/clnt_udp.c
+++ b/sunrpc/clnt_udp.c
@@ -663,3 +663,21 @@ __clntudp_create64 (struct sockaddr_in *raddr, u_long program, u_long version,
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);
+}
diff --git a/sunrpc/rpc/clnt.h b/sunrpc/rpc/clnt.h
index b24b5cc..a6dff89 100644
--- a/sunrpc/rpc/clnt.h
+++ b/sunrpc/rpc/clnt.h
@@ -344,6 +344,18 @@ extern CLIENT * __REDIRECT (clntudp_create,(struct sockaddr_in *__raddr,
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,
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=f2bddd332e41b35bbb4c07f2dff38f18dacee823
commit f2bddd332e41b35bbb4c07f2dff38f18dacee823
Author: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
Date: Thu Apr 12 20:46:27 2018 +0200
Y2038: add function __clntudp_create64
diff --git a/sunrpc/clnt_udp.c b/sunrpc/clnt_udp.c
index c2436e3..27a3244 100644
--- a/sunrpc/clnt_udp.c
+++ b/sunrpc/clnt_udp.c
@@ -644,3 +644,22 @@ 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);
+}
diff --git a/sunrpc/rpc/clnt.h b/sunrpc/rpc/clnt.h
index f4d4a94..b24b5cc 100644
--- a/sunrpc/rpc/clnt.h
+++ b/sunrpc/rpc/clnt.h
@@ -329,6 +329,18 @@ 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;
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=83892df6525ef10847ace62823359757481eb3bd
commit 83892df6525ef10847ace62823359757481eb3bd
Author: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
Date: Fri Sep 8 19:49:07 2017 +0200
Y2038: add function select64
diff --git a/include/sys/select.h b/include/sys/select.h
index ba013a3..9c58a15 100644
--- a/include/sys/select.h
+++ b/include/sys/select.h
@@ -22,5 +22,10 @@ extern int __pselect64 (int __nfds, fd_set *__readfds,
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
diff --git a/sysdeps/unix/sysv/linux/select.c b/sysdeps/unix/sysv/linux/select.c
index e4124a1..ba17746 100644
--- a/sysdeps/unix/sysv/linux/select.c
+++ b/sysdeps/unix/sysv/linux/select.c
@@ -21,6 +21,7 @@
#include <sys/select.h>
#include <errno.h>
#include <sysdep-cancel.h>
+#include <y2038-support.h>
/* Check the first NFDS descriptors each in READFDS (if not NULL) for read
readiness, in WRITEFDS (if not NULL) for write readiness, and in EXCEPTFDS
@@ -69,3 +70,73 @@ libc_hidden_def (__select)
weak_alias (__select, select)
weak_alias (__select, __libc_select)
+
+/* 64-bit time version */
+
+int
+__select64 (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+ struct __timeval64 *timeout)
+{
+#ifdef __NR_select
+ struct timeval tval32, *timeout32 = NULL;
+#else
+ int result;
+ struct timespec ts32, *tsp32 = NULL;
+#endif
+
+#ifdef __NR_pselect6_time64
+ int res;
+ if (__y2038_linux_support > 0)
+ {
+ res = SYSCALL_CANCEL (pselect6_time64, nfds, readfds, writefds,
+ exceptfds, timeout, NULL);
+ if (res == 0 || errno != ENOSYS)
+ return res;
+ __y2038_linux_support = -1;
+ }
+#endif
+
+#ifdef __NR_select
+ if (timeout != NULL)
+ {
+ if (timeout->tv_sec > INT_MAX)
+ {
+ errno = EOVERFLOW;
+ return -1;
+ }
+ tval32.tv_sec = timeout->tv_sec;
+ tval32.tv_usec = timeout->tv_usec;
+ timeout32 = &tval32;
+ }
+
+ return SYSCALL_CANCEL (select, nfds, readfds, writefds, exceptfds,
+ timeout32);
+#else
+ if (timeout)
+ {
+ if (timeout->tv_sec > INT_MAX)
+ {
+ errno = EOVERFLOW;
+ return -1;
+ }
+ ts32.tv_sec = timeout->tv_sec;
+ ts32.tv_nsec = timeout->tv_usec * 1000;
+ tsp32 = &ts32;
+ }
+
+ result = SYSCALL_CANCEL (pselect6, nfds, readfds, writefds, exceptfds, tsp32,
+ NULL);
+
+ if (timeout)
+ {
+ /* Linux by default will update the timeout after a pselect6 syscall
+ (though the pselect() glibc call suppresses this behavior).
+ Since select() on Linux has the same behavior as the pselect6
+ syscall, we update the timeout here. */
+ timeout->tv_sec = ts32.tv_sec;
+ timeout->tv_usec = ts32.tv_nsec / 1000;
+ }
+
+ return result;
+#endif
+}
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=dd95cae9dacbff3d7ea4ac8dff59faa1e2a63b7a
commit dd95cae9dacbff3d7ea4ac8dff59faa1e2a63b7a
Author: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
Date: Fri Sep 8 00:42:16 2017 +0200
Y2038: add function pselect64
diff --git a/include/sys/select.h b/include/sys/select.h
index 07bb49b..ba013a3 100644
--- a/include/sys/select.h
+++ b/include/sys/select.h
@@ -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,12 @@ 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);
+
#endif
#endif
diff --git a/sysdeps/unix/sysv/linux/pselect.c b/sysdeps/unix/sysv/linux/pselect.c
index 2b052e7..8a77036 100644
--- a/sysdeps/unix/sysv/linux/pselect.c
+++ b/sysdeps/unix/sysv/linux/pselect.c
@@ -22,6 +22,7 @@
#include <sys/poll.h>
#include <kernel-features.h>
#include <sysdep-cancel.h>
+#include <y2038-support.h>
#ifdef __NR_pselect6
@@ -79,6 +80,71 @@ __pselect (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
}
weak_alias (__pselect, pselect)
+/* 64-bit time version */
+
+int
+__pselect64 (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+ const struct __timespec64 *timeout, const sigset_t *sigmask)
+{
+ struct timespec tval32, *timeout32 = NULL;
+
+ /* Note: the system call expects 7 values but on most architectures
+ we can only pass in 6 directly. If there is an architecture with
+ support for more parameters a new version of this file needs to
+ be created. */
+ struct
+ {
+ __syscall_ulong_t ss;
+ __syscall_ulong_t ss_len;
+ } data;
+
+ data.ss = (__syscall_ulong_t) (uintptr_t) sigmask;
+ data.ss_len = _NSIG / 8;
+
+ int result;
+
+#ifdef __NR_pselect6_time64
+ if (__y2038_linux_support > 0)
+ {
+ result = SYSCALL_CANCEL (pselect6_time64, nfds, readfds, writefds,
+ exceptfds, timeout, &data);
+ if (result == 0 || errno != ENOSYS)
+ return result;
+ __y2038_linux_support = -1;
+ }
+#endif
+
+ /* The Linux kernel can in some situations update the timeout value.
+ We do not want that so use a local variable. */
+ if (timeout != NULL)
+ {
+ if (timeout->tv_sec > INT_MAX)
+ {
+ errno = EOVERFLOW;
+ return -1;
+ }
+ tval32.tv_sec = timeout->tv_sec;
+ tval32.tv_nsec = timeout->tv_nsec;
+ timeout32 = &tval32;
+ }
+
+#ifndef CALL_PSELECT6
+# define CALL_PSELECT6(nfds, readfds, writefds, exceptfds, timeout, data) \
+ SYSCALL_CANCEL (pselect6, nfds, readfds, writefds, exceptfds, timeout32, data)
+#endif
+
+ result = CALL_PSELECT6 (nfds, readfds, writefds, exceptfds, timeout32,
+ &data);
+
+# ifndef __ASSUME_PSELECT
+ if (result == -1 && errno == ENOSYS)
+ result = __generic_pselect (nfds, readfds, writefds, exceptfds, timeout32,
+ sigmask);
+# endif
+
+ return result;
+}
+
# ifndef __ASSUME_PSELECT
# define __pselect static __generic_pselect
# endif
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=ff0379ba9ea047e281418253eeb335b0dbfc0e9f
commit ff0379ba9ea047e281418253eeb335b0dbfc0e9f
Author: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
Date: Fri Sep 8 00:42:15 2017 +0200
Y2038: add struct __timex64
diff --git a/include/time.h b/include/time.h
index b4d40c7..42ccf2b 100644
--- a/include/time.h
+++ b/include/time.h
@@ -3,6 +3,7 @@
#ifndef _ISOMAC
# include <bits/types/locale_t.h>
+# include <bits/types/struct_timeval64.h>
# include <stdbool.h>
extern __typeof (strftime_l) __strftime_l;
@@ -17,6 +18,37 @@ libc_hidden_proto (localtime)
libc_hidden_proto (strftime)
libc_hidden_proto (strptime)
+/* 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)
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=c6929803700f1cb54091d8dc1e496bdce59d9155
commit c6929803700f1cb54091d8dc1e496bdce59d9155
Author: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
Date: Fri Sep 8 00:42:14 2017 +0200
Y2038: add function __ntp_gettimex64
diff --git a/sysdeps/unix/sysv/linux/Versions b/sysdeps/unix/sysv/linux/Versions
index 07a36e8..955d158 100644
--- a/sysdeps/unix/sysv/linux/Versions
+++ b/sysdeps/unix/sysv/linux/Versions
@@ -171,6 +171,7 @@ libc {
mlock2;
pkey_alloc; pkey_free; pkey_set; pkey_get; pkey_mprotect;
__ntp_gettime64;
+ __ntp_gettimex64;
}
GLIBC_PRIVATE {
# functions used in other libraries
diff --git a/sysdeps/unix/sysv/linux/ntp_gettimex.c b/sysdeps/unix/sysv/linux/ntp_gettimex.c
index e491549..abd1c7e 100644
--- a/sysdeps/unix/sysv/linux/ntp_gettimex.c
+++ b/sysdeps/unix/sysv/linux/ntp_gettimex.c
@@ -16,6 +16,7 @@
<http://www.gnu.org/licenses/>. */
#include <sys/timex.h>
+#include <include/time.h>
#ifndef MOD_OFFSET
# define modes mode
@@ -40,3 +41,26 @@ ntp_gettimex (struct ntptimeval *ntv)
ntv->__glibc_reserved4 = 0;
return result;
}
+
+/* The 64-bit-time version */
+
+int
+__ntp_gettimex64 (struct __ntptimeval64 *ntv)
+{
+ struct timex tntx;
+ int result;
+
+ tntx.modes = 0;
+ result = __adjtimex (&tntx);
+ ntv->time.tv_sec = tntx.time.tv_sec;
+ ntv->time.tv_usec = tntx.time.tv_usec;
+ ntv->maxerror = tntx.maxerror;
+ ntv->maxerror = tntx.maxerror;
+ ntv->esterror = tntx.esterror;
+ ntv->tai = tntx.tai;
+ ntv->__glibc_reserved1 = 0;
+ ntv->__glibc_reserved2 = 0;
+ ntv->__glibc_reserved3 = 0;
+ ntv->__glibc_reserved4 = 0;
+ return result;
+}
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=f98889682bead5ca95f9ea0f338c2ab1c074ca02
commit f98889682bead5ca95f9ea0f338c2ab1c074ca02
Author: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
Date: Fri Sep 8 00:42:13 2017 +0200
Y2038: add function __ntp_gettime64
diff --git a/sysdeps/unix/sysv/linux/Versions b/sysdeps/unix/sysv/linux/Versions
index 336c13b..07a36e8 100644
--- a/sysdeps/unix/sysv/linux/Versions
+++ b/sysdeps/unix/sysv/linux/Versions
@@ -170,6 +170,7 @@ libc {
memfd_create;
mlock2;
pkey_alloc; pkey_free; pkey_set; pkey_get; pkey_mprotect;
+ __ntp_gettime64;
}
GLIBC_PRIVATE {
# functions used in other libraries
diff --git a/sysdeps/unix/sysv/linux/ntp_gettime.c b/sysdeps/unix/sysv/linux/ntp_gettime.c
index 18650da..f025263 100644
--- a/sysdeps/unix/sysv/linux/ntp_gettime.c
+++ b/sysdeps/unix/sysv/linux/ntp_gettime.c
@@ -18,6 +18,7 @@
#define ntp_gettime ntp_gettime_redirect
#include <sys/timex.h>
+#include <include/time.h>
#undef ntp_gettime
@@ -39,3 +40,20 @@ ntp_gettime (struct ntptimeval *ntv)
ntv->esterror = tntx.esterror;
return result;
}
+
+/* The 64-bit-time version */
+
+int
+__ntp_gettime64 (struct __ntptimeval64 *ntv)
+{
+ struct timex tntx;
+ int result;
+
+ tntx.modes = 0;
+ result = __adjtimex (&tntx);
+ ntv->time.tv_sec = tntx.time.tv_sec;
+ ntv->time.tv_usec = tntx.time.tv_usec;
+ ntv->maxerror = tntx.maxerror;
+ ntv->esterror = tntx.esterror;
+ return result;
+}
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=14a93c3a2a4fea70bed4e4f66cf5f027eaf96c3f
commit 14a93c3a2a4fea70bed4e4f66cf5f027eaf96c3f
Author: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
Date: Fri Sep 8 00:42:12 2017 +0200
Y2038: add struct __ntp_timeval64
diff --git a/sysdeps/unix/sysv/linux/sys/timex.h b/sysdeps/unix/sysv/linux/sys/timex.h
index 0d652c8..fd45929 100644
--- a/sysdeps/unix/sysv/linux/sys/timex.h
+++ b/sysdeps/unix/sysv/linux/sys/timex.h
@@ -40,6 +40,19 @@ struct ntptimeval
long int __glibc_reserved4;
};
+struct __ntptimeval64
+{
+ struct __timeval64 time; /* current time (ro) */
+ long int maxerror; /* maximum error (us) (ro) */
+ long int esterror; /* estimated error (us) (ro) */
+ long int tai; /* TAI offset (ro) */
+
+ long int __glibc_reserved1;
+ long int __glibc_reserved2;
+ long int __glibc_reserved3;
+ long int __glibc_reserved4;
+};
+
/* Clock states (time_state) */
#define TIME_OK 0 /* clock synchronized, no leap second */
#define TIME_INS 1 /* insert leap second */
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=6644b95f14ebd9690f43534b67ffd1dc8ad9f082
commit 6644b95f14ebd9690f43534b67ffd1dc8ad9f082
Author: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
Date: Fri Sep 8 00:42:11 2017 +0200
Y2038: add function __getrusage64
diff --git a/resource/Makefile b/resource/Makefile
index bf66294..c482e82 100644
--- a/resource/Makefile
+++ b/resource/Makefile
@@ -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
diff --git a/resource/Versions b/resource/Versions
index d6c2cce..a45e684 100644
--- a/resource/Versions
+++ b/resource/Versions
@@ -22,6 +22,9 @@ libc {
# s*
setrlimit64;
}
+ GLIBC_2.29 {
+ __getrusage64;
+ }
GLIBC_PRIVATE {
__getrlimit;
}
diff --git a/resource/getrusage64.c b/resource/getrusage64.c
new file mode 100644
index 0000000..f7edb97
--- /dev/null
+++ b/resource/getrusage64.c
@@ -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;
+}
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=f493afa2f026d60cc276fd284b7f5adfded3acbd
commit f493afa2f026d60cc276fd284b7f5adfded3acbd
Author: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
Date: Fri Sep 8 00:42:10 2017 +0200
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
diff --git a/nptl/Versions b/nptl/Versions
index e7f691d..a205706 100644
--- a/nptl/Versions
+++ b/nptl/Versions
@@ -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;
diff --git a/nptl/lll_timedlock_wait.c b/nptl/lll_timedlock_wait.c
index 91bf963..6d3aecb 100644
--- a/nptl/lll_timedlock_wait.c
+++ b/nptl/lll_timedlock_wait.c
@@ -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;
+}
diff --git a/nptl/pthread_cond_wait.c b/nptl/pthread_cond_wait.c
index ebf07ca..072375c 100644
--- a/nptl/pthread_cond_wait.c
+++ b/nptl/pthread_cond_wait.c
@@ -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,
diff --git a/nptl/pthread_mutex_timedlock.c b/nptl/pthread_mutex_timedlock.c
index 28237b0..9d9dfdf 100644
--- a/nptl/pthread_mutex_timedlock.c
+++ b/nptl/pthread_mutex_timedlock.c
@@ -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
@@ -638,3 +643,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);
+}
diff --git a/nptl/pthread_rwlock_common.c b/nptl/pthread_rwlock_common.c
index a290d08..f34750e 100644
--- a/nptl/pthread_rwlock_common.c
+++ b/nptl/pthread_rwlock_common.c
@@ -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;
+}
diff --git a/nptl/pthread_rwlock_timedrdlock.c b/nptl/pthread_rwlock_timedrdlock.c
index 383e41e..90e8eaa 100644
--- a/nptl/pthread_rwlock_timedrdlock.c
+++ b/nptl/pthread_rwlock_timedrdlock.c
@@ -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);
+}
diff --git a/nptl/pthread_rwlock_timedwrlock.c b/nptl/pthread_rwlock_timedwrlock.c
index 7a3d2ec..d4b32aa 100644
--- a/nptl/pthread_rwlock_timedwrlock.c
+++ b/nptl/pthread_rwlock_timedwrlock.c
@@ -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);
+}
diff --git a/nptl/sem_timedwait.c b/nptl/sem_timedwait.c
index 8886ea2..8a6bfba 100644
--- a/nptl/sem_timedwait.c
+++ b/nptl/sem_timedwait.c
@@ -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);
+}
diff --git a/nptl/sem_wait.c b/nptl/sem_wait.c
index e7d9106..f59f7f4 100644
--- a/nptl/sem_wait.c
+++ b/nptl/sem_wait.c
@@ -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
diff --git a/nptl/sem_waitcommon.c b/nptl/sem_waitcommon.c
index 30984be..c75c74b 100644
--- a/nptl/sem_waitcommon.c
+++ b/nptl/sem_waitcommon.c
@@ -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
diff --git a/rt/Versions b/rt/Versions
index 4844d6b..e57de23 100644
--- a/rt/Versions
+++ b/rt/Versions
@@ -44,5 +44,6 @@ librt {
__timerfd_settime64;
__mq_timedreceive64;
__mq_timedsend_time64;
+ __aio_suspend64;
}
}
diff --git a/sysdeps/nptl/aio_misc.h b/sysdeps/nptl/aio_misc.h
index 206d8e1..24c2852 100644
--- a/sysdeps/nptl/aio_misc.h
+++ b/sysdeps/nptl/aio_misc.h
@@ -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>
diff --git a/sysdeps/nptl/lowlevellock.h b/sysdeps/nptl/lowlevellock.h
index bfbda99..7784ce7 100644
--- a/sysdeps/nptl/lowlevellock.h
+++ b/sysdeps/nptl/lowlevellock.h
@@ -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
diff --git a/sysdeps/pthread/aio_suspend.c b/sysdeps/pthread/aio_suspend.c
index 010cbf8..a14263d 100644
--- a/sysdeps/pthread/aio_suspend.c
+++ b/sysdeps/pthread/aio_suspend.c
@@ -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;
+}
diff --git a/sysdeps/unix/sysv/linux/arm/libpthread.abilist b/sysdeps/unix/sysv/linux/arm/libpthread.abilist
index af82a4c..e1a2ade 100644
--- a/sysdeps/unix/sysv/linux/arm/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/arm/libpthread.abilist
@@ -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
diff --git a/sysdeps/unix/sysv/linux/arm/librt.abilist b/sysdeps/unix/sysv/linux/arm/librt.abilist
index 58e5f4b..88b61f3 100644
--- a/sysdeps/unix/sysv/linux/arm/librt.abilist
+++ b/sysdeps/unix/sysv/linux/arm/librt.abilist
@@ -1,3 +1,4 @@
+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
diff --git a/sysdeps/unix/sysv/linux/futex-internal.h b/sysdeps/unix/sysv/linux/futex-internal.h
index 96a07b0..484c8be 100644
--- a/sysdeps/unix/sysv/linux/futex-internal.h
+++ b/sysdeps/unix/sysv/linux/futex-internal.h
@@ -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)
diff --git a/sysdeps/unix/sysv/linux/lowlevellock-futex.h b/sysdeps/unix/sysv/linux/lowlevellock-futex.h
index fc834ed..02fc2a5 100644
--- a/sysdeps/unix/sysv/linux/lowlevellock-futex.h
+++ b/sysdeps/unix/sysv/linux/lowlevellock-futex.h
@@ -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)
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/libpthread.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/libpthread.abilist
index 09e8447..228d45c 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/libpthread.abilist
@@ -227,6 +227,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.3.2 pthread_cond_broadcast F
GLIBC_2.3.2 pthread_cond_destroy F
GLIBC_2.3.2 pthread_cond_init F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/librt.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/librt.abilist
index 7027d8a..d384de8 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/librt.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/librt.abilist
@@ -27,6 +27,7 @@ GLIBC_2.2 timer_delete F
GLIBC_2.2 timer_getoverrun F
GLIBC_2.2 timer_gettime F
GLIBC_2.2 timer_settime F
+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
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=41932d5a08ce1ef30fb71876534a1e7457133628
commit 41932d5a08ce1ef30fb71876534a1e7457133628
Author: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
Date: Fri Sep 8 00:42:09 2017 +0200
Y2038: add function __setitimer64
diff --git a/time/Makefile b/time/Makefile
index 01ee071..2bc2b80 100644
--- a/time/Makefile
+++ b/time/Makefile
@@ -37,7 +37,7 @@ routines := offtime asctime clock ctime ctime_r difftime \
gettimeofday settimeofday adjtime tzset \
gettimeofday64 settimeofday64 \
tzfile getitimer setitimer \
- getitimer64 \
+ getitimer64 setitimer64 \
stime dysize timegm ftime \
getdate strptime strptime_l \
strftime wcsftime strftime_l wcsftime_l \
diff --git a/time/Versions b/time/Versions
index 155180e..e7368ac 100644
--- a/time/Versions
+++ b/time/Versions
@@ -88,5 +88,6 @@ libc {
__adjtime64;
__adjtimex64;
__getitimer64;
+ __setitimer64;
}
}
diff --git a/time/setitimer64.c b/time/setitimer64.c
new file mode 100644
index 0000000..13133ad
--- /dev/null
+++ b/time/setitimer64.c
@@ -0,0 +1,64 @@
+/* Set an interval timer
+
+ 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 <stddef.h>
+#include <errno.h>
+#include <sys/time.h>
+
+/* Set the timer WHICH to *NEW. If OLD is not NULL,
+ set *OLD to the old value of timer WHICH.
+ Returns 0 on success, -1 on errors. */
+int
+__setitimer64 (enum __itimer_which which,
+ const struct __itimerval64 *new,
+ struct __itimerval64 *old)
+{
+ struct itimerval new32, *new32p = NULL;
+ struct itimerval old32, *old32p = NULL;
+
+ if (new != NULL)
+ {
+ if (new->it_interval.tv_sec > INT_MAX ||
+ new->it_value.tv_sec > INT_MAX)
+ {
+ __set_errno (EOVERFLOW);
+ return -1;
+ }
+ new32.it_interval.tv_sec = new->it_interval.tv_sec;
+ new32.it_interval.tv_usec = new->it_interval.tv_usec;
+ new32.it_value.tv_sec = new->it_value.tv_sec;
+ new32.it_value.tv_usec = new->it_value.tv_usec;
+ new32p = &new32;
+ }
+
+ if (old != NULL)
+ old32p = &old32;
+
+ int result = __setitimer(which, new32p, old32p);
+
+ if (old)
+ {
+ old->it_interval.tv_sec = old32.it_interval.tv_sec;
+ old->it_interval.tv_usec = old32.it_interval.tv_usec;
+ old->it_value.tv_sec = old32.it_value.tv_sec;
+ old->it_value.tv_usec = old32.it_value.tv_usec;
+ }
+
+ return result;
+}
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=41678ce2ce9896958f3e2bd04b00288d7e5c0581
commit 41678ce2ce9896958f3e2bd04b00288d7e5c0581
Author: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
Date: Fri Sep 8 00:42:08 2017 +0200
Y2038: add function __getitimer64
diff --git a/time/Makefile b/time/Makefile
index a38f640..01ee071 100644
--- a/time/Makefile
+++ b/time/Makefile
@@ -37,6 +37,7 @@ routines := offtime asctime clock ctime ctime_r difftime \
gettimeofday settimeofday adjtime tzset \
gettimeofday64 settimeofday64 \
tzfile getitimer setitimer \
+ getitimer64 \
stime dysize timegm ftime \
getdate strptime strptime_l \
strftime wcsftime strftime_l wcsftime_l \
diff --git a/time/Versions b/time/Versions
index a965b69..155180e 100644
--- a/time/Versions
+++ b/time/Versions
@@ -87,5 +87,6 @@ libc {
__utimes64;
__adjtime64;
__adjtimex64;
+ __getitimer64;
}
}
diff --git a/time/getitimer64.c b/time/getitimer64.c
new file mode 100644
index 0000000..68bcaef
--- /dev/null
+++ b/time/getitimer64.c
@@ -0,0 +1,46 @@
+/* Get the current value of an interval timer
+
+ 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 <stddef.h>
+#include <errno.h>
+#include <sys/time.h>
+
+/* Set *VALUE to the current setting of timer WHICH.
+ Return 0 on success, -1 on errors. */
+int
+__getitimer64 (enum __itimer_which which,
+ struct __itimerval64 *value)
+{
+ struct itimerval value32, *value32p= NULL;
+
+ if (value != NULL)
+ value32p = &value32;
+
+ int result = __getitimer(which, value32p);
+
+ if (result == 0 && value != NULL)
+ {
+ value->it_interval.tv_sec = value32.it_interval.tv_sec;
+ value->it_interval.tv_usec = value32.it_interval.tv_usec;
+ value->it_value.tv_sec = value32.it_value.tv_sec;
+ value->it_value.tv_usec = value32.it_value.tv_usec;
+ }
+
+ return result;
+}
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=16bbec25d517bdf175a1285880c73bcf773454cd
commit 16bbec25d517bdf175a1285880c73bcf773454cd
Author: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
Date: Fri Sep 8 00:42:07 2017 +0200
Y2038: add struct __itimerval64
diff --git a/time/sys/time.h b/time/sys/time.h
index 4e6255e..b7fe339 100644
--- a/time/sys/time.h
+++ b/time/sys/time.h
@@ -110,6 +110,16 @@ struct itimerval
struct timeval it_value;
};
+/* 64-BIT-TIME Type of the second argument to `getitimer' and
+ the second and third arguments `setitimer'. */
+struct __itimerval64
+ {
+ /* Value to put into `it_value' when the timer expires. */
+ struct __timeval64 it_interval;
+ /* Time to the next timer expiration. */
+ struct __timeval64 it_value;
+ };
+
#if defined __USE_GNU && !defined __cplusplus
/* Use the nicer parameter type only in GNU mode and not for C++ since the
strict C++ rules prevent the automatic promotion. */
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=e3c698880c051fc25dfa785099f31c5cf5158f63
commit e3c698880c051fc25dfa785099f31c5cf5158f63
Author: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
Date: Fri Sep 8 00:42:06 2017 +0200
Y2038: add function __utime64
diff --git a/include/utime.h b/include/utime.h
index 5049251..eb907f7 100644
--- a/include/utime.h
+++ b/include/utime.h
@@ -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 */
diff --git a/io/Makefile b/io/Makefile
index ec5c6d7..34075a8 100644
--- a/io/Makefile
+++ b/io/Makefile
@@ -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 \
diff --git a/io/Versions b/io/Versions
index 90956fe..58dca72 100644
--- a/io/Versions
+++ b/io/Versions
@@ -137,6 +137,7 @@ libc {
__xstat64_time64;
__lxstat64_time64;
__fxstatat64_time64;
+ __utime64;
}
GLIBC_PRIVATE {
__libc_fcntl64;
diff --git a/io/utime.c b/io/utime.c
index 3f3c03c..b33296b 100644
--- a/io/utime.c
+++ b/io/utime.c
@@ -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)
diff --git a/io/utime.c b/sysdeps/posix/utime64.c
similarity index 63%
copy from io/utime.c
copy to sysdeps/posix/utime64.c
index 3f3c03c..1f043da 100644
--- a/io/utime.c
+++ b/sysdeps/posix/utime64.c
@@ -1,5 +1,4 @@
-/* utime -- change access and modification times of file. Stub version.
- Copyright (C) 1991-2018 Free Software Foundation, Inc.
+/* 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
@@ -16,25 +15,32 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
+#include <sysdep.h>
#include <errno.h>
-#include <stddef.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
-utime (const char *file, const struct utimbuf *times)
+__utime64 (const char *file, const struct __utimbuf64 *times)
{
- if (file == NULL)
+ struct __timeval64 timevals[2];
+ struct __timeval64 *tvp;
+
+ if (times != NULL)
{
- __set_errno (EINVAL);
- return -1;
+ 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;
- __set_errno (ENOSYS);
- return -1;
+ return __utimes64 (file, tvp);
}
-libc_hidden_def (utime)
-
-stub_warning (utime)
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=d6f08bb680506cfa9767857edff93a32dcfb0fbe
commit d6f08bb680506cfa9767857edff93a32dcfb0fbe
Author: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
Date: Fri Sep 8 00:42:05 2017 +0200
Y2038: add function __adjtime64, __adjtimex64 and __ntp_adjtime64
diff --git a/sysdeps/unix/sysv/linux/adjtime.c b/sysdeps/unix/sysv/linux/adjtime.c
index 6edecb7..4238abd 100644
--- a/sysdeps/unix/sysv/linux/adjtime.c
+++ b/sysdeps/unix/sysv/linux/adjtime.c
@@ -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)
diff --git a/sysdeps/unix/sysv/linux/adjtime64.c b/sysdeps/unix/sysv/linux/adjtime64.c
new file mode 100644
index 0000000..c305717
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/adjtime64.c
@@ -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);
diff --git a/time/Versions b/time/Versions
index c28dab6..a965b69 100644
--- a/time/Versions
+++ b/time/Versions
@@ -85,5 +85,7 @@ libc {
__time64;
__stime64;
__utimes64;
+ __adjtime64;
+ __adjtimex64;
}
}
diff --git a/time/adjtime.c b/time/adjtime.c
index 4a972d6..800715c 100644
--- a/time/adjtime.c
+++ b/time/adjtime.c
@@ -31,3 +31,13 @@ __adjtime (const struct timeval *delta, struct timeval *olddelta)
stub_warning (adjtime)
weak_alias (__adjtime, adjtime)
+
+/* 64-bit time version */
+
+int
+__adjtime64 (const struct __timeval64 *delta, struct __timeval64 *olddelta)
+{
+ __set_errno (ENOSYS);
+ return -1;
+}
+stub_warning (__adjtime64)
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=29fd064f881a877400b7ec2357e9a52e423d3680
commit 29fd064f881a877400b7ec2357e9a52e423d3680
Author: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
Date: Fri Sep 8 00:42:04 2017 +0200
Y2038: add function __nanosleep64
diff --git a/posix/Makefile b/posix/Makefile
index a66d6db..f40096c 100644
--- a/posix/Makefile
+++ b/posix/Makefile
@@ -63,7 +63,7 @@ routines := \
spawnattr_setsigmask spawnattr_setschedpolicy spawnattr_setschedparam \
posix_madvise \
get_child_max sched_cpucount sched_cpualloc sched_cpufree \
- sched_rr_gi64
+ sched_rr_gi64 nanosleep64
aux := init-posix environ
tests := test-errno tstgetopt testfnm runtests runptests \
diff --git a/posix/Versions b/posix/Versions
index deb1be1..56b8f6f 100644
--- a/posix/Versions
+++ b/posix/Versions
@@ -139,6 +139,7 @@ libc {
}
GLIBC_2.29 {
__sched_rr_get_interval_time64;
+ __nanosleep64;
}
GLIBC_PRIVATE {
__libc_fork; __libc_pread; __libc_pwrite;
diff --git a/posix/nanosleep64.c b/posix/nanosleep64.c
new file mode 100644
index 0000000..ae4805d
--- /dev/null
+++ b/posix/nanosleep64.c
@@ -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;
+}
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=b832fdd497a4967e4ce9fa6b246f03c8fa4a1592
commit b832fdd497a4967e4ce9fa6b246f03c8fa4a1592
Author: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
Date: Fri Sep 8 00:42:03 2017 +0200
Y2038: add function __sched_rr_get_interval64
diff --git a/posix/Makefile b/posix/Makefile
index 8316212..a66d6db 100644
--- a/posix/Makefile
+++ b/posix/Makefile
@@ -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
aux := init-posix environ
tests := test-errno tstgetopt testfnm runtests runptests \
diff --git a/posix/Versions b/posix/Versions
index cad4c23..deb1be1 100644
--- a/posix/Versions
+++ b/posix/Versions
@@ -137,6 +137,9 @@ libc {
GLIBC_2.27 {
glob; glob64;
}
+ GLIBC_2.29 {
+ __sched_rr_get_interval_time64;
+ }
GLIBC_PRIVATE {
__libc_fork; __libc_pread; __libc_pwrite;
__nanosleep_nocancel; __pause_nocancel;
diff --git a/posix/sched_rr_gi64.c b/posix/sched_rr_gi64.c
new file mode 100644
index 0000000..35dc938
--- /dev/null
+++ b/posix/sched_rr_gi64.c
@@ -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;
+}
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=1ad95656381e14150d7048ed87a9e1c444270d24
commit 1ad95656381e14150d7048ed87a9e1c444270d24
Author: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
Date: Fri Sep 8 00:42:02 2017 +0200
Y2038: add function __msgctl64
diff --git a/sysdeps/unix/sysv/linux/msgctl.c b/sysdeps/unix/sysv/linux/msgctl.c
index 7280cba..f785804 100644
--- a/sysdeps/unix/sysv/linux/msgctl.c
+++ b/sysdeps/unix/sysv/linux/msgctl.c
@@ -69,3 +69,60 @@ __old_msgctl (int msqid, int cmd, struct __old_msqid_ds *buf)
}
compat_symbol (libc, __old_msgctl, msgctl, GLIBC_2_0);
#endif
+
+/* 64-bit time version */
+
+struct __msqid_ds64
+{
+ 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;
+};
+
+int
+__msgctl64 (int msqid, int cmd, struct __msqid_ds64 *buf)
+{
+ int result;
+ struct msqid_ds buf32, *pbuf32 = NULL;
+
+ if (cmd == IPC_SET && buf != NULL)
+ {
+ buf32.msg_qbytes = buf->msg_qbytes;
+ buf32.msg_perm.uid = buf->msg_perm.uid;
+ buf32.msg_perm.gid = buf->msg_perm.gid;
+ buf32.msg_perm.mode = buf->msg_perm.mode;
+ }
+
+ if (cmd == IPC_SET || cmd == IPC_STAT)
+ pbuf32 = &buf32;
+
+#ifdef __ASSUME_DIRECT_SYSVIPC_SYSCALLS
+ result = INLINE_SYSCALL_CALL (msgctl, msqid, cmd | __IPC_64, pbuf32);
+#else
+ result = INLINE_SYSCALL_CALL (ipc, IPCOP_msgctl, msqid, cmd | __IPC_64,
+ 0, pbuf32);
+#endif
+
+ if (cmd == IPC_STAT && result == 0 && buf != NULL)
+ {
+ buf->msg_perm = buf32.msg_perm;
+ buf->msg_stime = buf32.msg_stime;
+ buf->msg_rtime = buf32.msg_rtime;
+ buf->msg_ctime = buf32.msg_ctime;
+ buf->__msg_cbytes = buf32.__msg_cbytes;
+ buf->msg_qnum = buf32.msg_qnum;
+ buf->msg_qbytes = buf32.msg_qbytes;
+ buf->msg_lspid = buf32.msg_lspid;
+ buf->msg_lrpid = buf32.msg_lrpid;
+ }
+
+ return result;
+}
diff --git a/sysvipc/Versions b/sysvipc/Versions
index 4c797e2..0e7f297 100644
--- a/sysvipc/Versions
+++ b/sysvipc/Versions
@@ -13,6 +13,9 @@ libc {
# Non-standard function.
semtimedop;
}
+ GLIBC_2.28 {
+ __msgctl64;
+ }
GLIBC_PRIVATE {
# Cancellation point entries.
__libc_msgrcv; __libc_msgsnd;
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=10cacc3e26cbb6f3640ddd56208153dc3ff39690
commit 10cacc3e26cbb6f3640ddd56208153dc3ff39690
Author: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
Date: Fri Sep 8 00:42:01 2017 +0200
Y2038: add function __mq_timedsend_time64
diff --git a/rt/Makefile b/rt/Makefile
index 928f90e..f6011f4 100644
--- a/rt/Makefile
+++ b/rt/Makefile
@@ -38,7 +38,7 @@ 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_timedreceiv_time64
+ mq_timedreceiv_time64 mq_timedsend_time64
routines = $(clock-routines)
diff --git a/rt/Versions b/rt/Versions
index 25202cf..4844d6b 100644
--- a/rt/Versions
+++ b/rt/Versions
@@ -43,5 +43,6 @@ librt {
__timerfd_gettime64;
__timerfd_settime64;
__mq_timedreceive64;
+ __mq_timedsend_time64;
}
}
diff --git a/rt/mq_timedsend_time64.c b/rt/mq_timedsend_time64.c
new file mode 100644
index 0000000..7459d94
--- /dev/null
+++ b/rt/mq_timedsend_time64.c
@@ -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);
+}
diff --git a/sysdeps/unix/sysv/linux/arm/librt.abilist b/sysdeps/unix/sysv/linux/arm/librt.abilist
index a056a93..58e5f4b 100644
--- a/sysdeps/unix/sysv/linux/arm/librt.abilist
+++ b/sysdeps/unix/sysv/linux/arm/librt.abilist
@@ -1,4 +1,5 @@
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
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/librt.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/librt.abilist
index 8142325..7027d8a 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/librt.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/librt.abilist
@@ -28,6 +28,7 @@ GLIBC_2.2 timer_getoverrun F
GLIBC_2.2 timer_gettime F
GLIBC_2.2 timer_settime 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
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=53e6ac7500dbc03a47d1002bebc15d22a6283dce
commit 53e6ac7500dbc03a47d1002bebc15d22a6283dce
Author: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
Date: Fri Sep 8 00:42:00 2017 +0200
Y2038: add function __mq_timedreceiv_time64
diff --git a/rt/Makefile b/rt/Makefile
index 994891e..928f90e 100644
--- a/rt/Makefile
+++ b/rt/Makefile
@@ -37,7 +37,8 @@ timer-routines := timer_create timer_delete timer_getoverr \
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
routines = $(clock-routines)
diff --git a/rt/Versions b/rt/Versions
index 8f757ed..25202cf 100644
--- a/rt/Versions
+++ b/rt/Versions
@@ -42,5 +42,6 @@ librt {
__timer_settime64;
__timerfd_gettime64;
__timerfd_settime64;
+ __mq_timedreceive64;
}
}
diff --git a/rt/mq_timedreceiv_time64.c b/rt/mq_timedreceiv_time64.c
new file mode 100644
index 0000000..6d94efe
--- /dev/null
+++ b/rt/mq_timedreceiv_time64.c
@@ -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);
+}
diff --git a/sysdeps/unix/sysv/linux/arm/librt.abilist b/sysdeps/unix/sysv/linux/arm/librt.abilist
index 344fa5b..a056a93 100644
--- a/sysdeps/unix/sysv/linux/arm/librt.abilist
+++ b/sysdeps/unix/sysv/linux/arm/librt.abilist
@@ -1,3 +1,4 @@
+GLIBC_2.29 __mq_timedreceive64 F
GLIBC_2.29 __timer_gettime64 F
GLIBC_2.29 __timer_settime64 F
GLIBC_2.29 __timerfd_gettime64 F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/librt.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/librt.abilist
index f34ae35..8142325 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/librt.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/librt.abilist
@@ -27,6 +27,7 @@ GLIBC_2.2 timer_delete F
GLIBC_2.2 timer_getoverrun F
GLIBC_2.2 timer_gettime F
GLIBC_2.2 timer_settime F
+GLIBC_2.29 __mq_timedreceive64 F
GLIBC_2.29 __timer_gettime64 F
GLIBC_2.29 __timer_settime64 F
GLIBC_2.29 __timerfd_gettime64 F
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=4e61dcf37bba2c3b231e6e617800788a2b654712
commit 4e61dcf37bba2c3b231e6e617800788a2b654712
Author: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
Date: Fri Sep 8 00:41:57 2017 +0200
Y2038: add function __utimes64
diff --git a/include/time.h b/include/time.h
index 875f368..b4d40c7 100644
--- a/include/time.h
+++ b/include/time.h
@@ -34,6 +34,9 @@ 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;
diff --git a/misc/Makefile b/misc/Makefile
index dd64bf2..4bca299 100644
--- a/misc/Makefile
+++ b/misc/Makefile
@@ -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 y2038-support
+ allocate_once y2038-support utimes64
generated += tst-error1.mtrace tst-error1-mem.out \
tst-allocate_once.mtrace tst-allocate_once-mem.out
diff --git a/misc/utimes.c b/misc/utimes.c
index 0ae6946..cdb43f6 100644
--- a/misc/utimes.c
+++ b/misc/utimes.c
@@ -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)
diff --git a/misc/utimes.c b/sysdeps/unix/sysv/linux/utimes64.c
similarity index 52%
copy from misc/utimes.c
copy to sysdeps/unix/sysv/linux/utimes64.c
index 0ae6946..b17f997 100644
--- a/misc/utimes.c
+++ b/sysdeps/unix/sysv/linux/utimes64.c
@@ -1,5 +1,4 @@
-/* utimes -- Change access and modification times of file. Stub version.
- Copyright (C) 1991-2018 Free Software Foundation, Inc.
+/* 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
@@ -16,25 +15,34 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
-#include <sys/time.h>
#include <errno.h>
#include <stddef.h>
+#include <utime.h>
+#include <sys/time.h>
+#include <sysdep.h>
+#include <fcntl.h>
+
+/* 64-bit-time variant */
-/* Change the access time of FILE to TVP[0] and
- the modification time of FILE to TVP[1]. */
int
-__utimes (const char *file, const struct timeval tvp[2])
+__utimes64 (const char *file, const struct __timeval64 tvp[2])
{
- if (file == NULL)
+ struct timespec ts32[2], *tsp32 = NULL;
+
+ if (tvp != NULL)
{
- __set_errno (EINVAL);
- return -1;
+ if (tvp[0].tv_sec > INT_MAX || tvp[1].tv_sec > INT_MAX)
+ {
+ __set_errno(EOVERFLOW);
+ return -1;
+ }
+ 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;
+ tsp32 = ts32;
}
- __set_errno (ENOSYS);
- return -1;
+ /* use utimensat rather than utimes which not all arches can use */
+ return INLINE_SYSCALL (utimensat, 4, AT_FDCWD, file, tsp32, 0);
}
-
-weak_alias (__utimes, utimes)
-
-stub_warning (utimes)
diff --git a/time/Versions b/time/Versions
index e8b63d2..c28dab6 100644
--- a/time/Versions
+++ b/time/Versions
@@ -84,5 +84,6 @@ libc {
__settimeofday64;
__time64;
__stime64;
+ __utimes64;
}
}
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=c51cb1ab07d861652e0f7383ef27f1d60896ece9
commit c51cb1ab07d861652e0f7383ef27f1d60896ece9
Author: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
Date: Fri Sep 8 00:41:56 2017 +0200
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.
diff --git a/time/stime.c b/sysdeps/unix/stime64.c
similarity index 69%
copy from time/stime.c
copy to sysdeps/unix/stime64.c
index 0378e23..2506227 100644
--- a/time/stime.c
+++ b/sysdeps/unix/stime64.c
@@ -1,4 +1,6 @@
-/* Copyright (C) 1992-2018 Free Software Foundation, Inc.
+/* 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
@@ -16,22 +18,30 @@
<http://www.gnu.org/licenses/>. */
#include <errno.h>
+#include <stddef.h> /* For NULL. */
+#include <sys/time.h>
#include <time.h>
-#include <stddef.h>
/* Set the system clock to *WHEN. */
int
-stime (const time_t *when)
+__stime64 (const __time64_t *when)
{
+ struct __timeval64 tv;
+
if (when == NULL)
{
__set_errno (EINVAL);
return -1;
}
- __set_errno (ENOSYS);
- return -1;
-}
+ if (*when > INT_MAX)
+ {
+ __set_errno (EOVERFLOW);
+ return -1;
+ }
-stub_warning (stime)
+ tv.tv_sec = *when;
+ tv.tv_usec = 0;
+ return __settimeofday64 (&tv, (struct timezone *) 0);
+}
diff --git a/time/Makefile b/time/Makefile
index 497123e..a38f640 100644
--- a/time/Makefile
+++ b/time/Makefile
@@ -33,7 +33,7 @@ headers := time.h sys/time.h sys/timeb.h bits/time.h \
routines := offtime asctime clock ctime ctime_r difftime \
gmtime localtime mktime time \
- time64 \
+ time64 stime64 \
gettimeofday settimeofday adjtime tzset \
gettimeofday64 settimeofday64 \
tzfile getitimer setitimer \
diff --git a/time/Versions b/time/Versions
index b5e070f..e8b63d2 100644
--- a/time/Versions
+++ b/time/Versions
@@ -83,5 +83,6 @@ libc {
__gettimeofday64;
__settimeofday64;
__time64;
+ __stime64;
}
}
diff --git a/time/stime.c b/time/stime.c
index 0378e23..5d22aaa 100644
--- a/time/stime.c
+++ b/time/stime.c
@@ -35,3 +35,20 @@ stime (const time_t *when)
}
stub_warning (stime)
+
+/* 64-bit time version */
+
+int
+__stime64 (const __time64_t *when)
+{
+ if (when == NULL)
+ {
+ __set_errno (EINVAL);
+ return -1;
+ }
+
+ __set_errno (ENOSYS);
+ return -1;
+}
+
+stub_warning (__stime64)
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=342a738b2fa2b0edf2a91d7ab81f6668f5324f99
commit 342a738b2fa2b0edf2a91d7ab81f6668f5324f99
Author: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
Date: Fri Sep 8 00:41:55 2017 +0200
Y2038: add function __time64
This provides a generic Posix implementation based on calling
__gettimeofday64().
diff --git a/time/time.c b/sysdeps/posix/time64.c
similarity index 57%
copy from time/time.c
copy to sysdeps/posix/time64.c
index 4996d26..4a58228 100644
--- a/time/time.c
+++ b/sysdeps/posix/time64.c
@@ -1,4 +1,6 @@
-/* Copyright (C) 1991-2018 Free Software Foundation, Inc.
+/* 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
@@ -15,19 +17,27 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
-#include <errno.h>
+#include <stddef.h> /* For NULL. */
#include <time.h>
+#include <sys/time.h>
-/* Return the time now, and store it in *TIMER if not NULL. */
-time_t
-time (time_t *timer)
+
+/* 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)
{
- __set_errno (ENOSYS);
+ struct __timeval64 tv;
+ __time64_t result;
- if (timer != NULL)
- *timer = (time_t) -1;
- return (time_t) -1;
-}
-libc_hidden_def (time)
+ if (__gettimeofday64 (&tv, (struct timezone *) NULL))
+ result = (__time64_t) -1;
+ else
+ result = tv.tv_sec;
-stub_warning (time)
+ if (t != NULL)
+ *t = result;
+
+ return result;
+}
diff --git a/time/Makefile b/time/Makefile
index 1efe9ac..497123e 100644
--- a/time/Makefile
+++ b/time/Makefile
@@ -33,6 +33,7 @@ headers := time.h sys/time.h sys/timeb.h bits/time.h \
routines := offtime asctime clock ctime ctime_r difftime \
gmtime localtime mktime time \
+ time64 \
gettimeofday settimeofday adjtime tzset \
gettimeofday64 settimeofday64 \
tzfile getitimer setitimer \
diff --git a/time/Versions b/time/Versions
index 1b178e4..b5e070f 100644
--- a/time/Versions
+++ b/time/Versions
@@ -82,5 +82,6 @@ libc {
__lutimes64;
__gettimeofday64;
__settimeofday64;
+ __time64;
}
}
diff --git a/time/time.c b/time/time.c
index 4996d26..9703c72 100644
--- a/time/time.c
+++ b/time/time.c
@@ -31,3 +31,16 @@ time (time_t *timer)
libc_hidden_def (time)
stub_warning (time)
+
+/* 64-bit time version */
+
+__time64_t
+__time64 (__time64_ *timer)
+{
+ __set_errno (ENOSYS);
+
+ if (timer != NULL)
+ *timer = (__time64_t) -1;
+ return (__time64_t) -1;
+}
+libc_hidden_def (__time64)
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=bc05361ef3943a1156e6651fbf9f5987b450a6af
commit bc05361ef3943a1156e6651fbf9f5987b450a6af
Author: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
Date: Fri Sep 8 00:41:59 2017 +0200
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'.
diff --git a/include/sys/time.h b/include/sys/time.h
index ed73a44..792fe84 100644
--- a/include/sys/time.h
+++ b/include/sys/time.h
@@ -29,6 +29,8 @@ extern int __gettimeofday64 (struct __timeval64 *__tv,
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,
diff --git a/time/settimeofday.c b/sysdeps/unix/sysv/linux/settimeofday64.c
similarity index 68%
copy from time/settimeofday.c
copy to sysdeps/unix/sysv/linux/settimeofday64.c
index 01bf4b0..1a9fa23 100644
--- a/time/settimeofday.c
+++ b/sysdeps/unix/sysv/linux/settimeofday64.c
@@ -1,4 +1,6 @@
-/* Copyright (C) 1991-2018 Free Software Foundation, Inc.
+/* Set the current time of day and timezone information.
+
+ 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
@@ -15,17 +17,23 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
+#include <sysdep.h>
#include <errno.h>
#include <sys/time.h>
-/* Set the current time of day and timezone information.
- This call is restricted to the super-user. */
-int
-__settimeofday (const struct timeval *tv, const struct timezone *tz)
+int __settimeofday64(const struct __timeval64 *tv,
+ const struct timezone *tz)
{
- __set_errno (ENOSYS);
- return -1;
-}
-stub_warning (settimeofday)
+ struct timeval tv32;
-weak_alias (__settimeofday, settimeofday)
+ if (tv && tv->tv_sec > INT_MAX)
+ {
+ __set_errno(EOVERFLOW);
+ return -1;
+ }
+
+ tv32.tv_sec = tv->tv_sec;
+ tv32.tv_usec = tv->tv_usec;
+
+ return __settimeofday(&tv32, tz);
+}
diff --git a/time/Makefile b/time/Makefile
index dd09d09..1efe9ac 100644
--- a/time/Makefile
+++ b/time/Makefile
@@ -34,7 +34,7 @@ headers := time.h sys/time.h sys/timeb.h bits/time.h \
routines := offtime asctime clock ctime ctime_r difftime \
gmtime localtime mktime time \
gettimeofday settimeofday adjtime tzset \
- gettimeofday64 \
+ gettimeofday64 settimeofday64 \
tzfile getitimer setitimer \
stime dysize timegm ftime \
getdate strptime strptime_l \
diff --git a/time/Versions b/time/Versions
index f1b4cbf..1b178e4 100644
--- a/time/Versions
+++ b/time/Versions
@@ -81,5 +81,6 @@ libc {
__futimes64;
__lutimes64;
__gettimeofday64;
+ __settimeofday64;
}
}
diff --git a/time/settimeofday.c b/time/settimeofday.c
index 01bf4b0..000ed21 100644
--- a/time/settimeofday.c
+++ b/time/settimeofday.c
@@ -29,3 +29,11 @@ __settimeofday (const struct timeval *tv, const struct timezone *tz)
stub_warning (settimeofday)
weak_alias (__settimeofday, settimeofday)
+
+int
+__settimeofday64 (const struct timeval *tv, const struct timezone *tz)
+{
+ __set_errno (ENOSYS);
+ return -1;
+}
+stub_warning (__settimeofday64)
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=4bee22b41e9b0bac1855676b97484d5554dccb99
commit 4bee22b41e9b0bac1855676b97484d5554dccb99
Author: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
Date: Fri Sep 8 00:41:58 2017 +0200
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'.
diff --git a/include/sys/time.h b/include/sys/time.h
index 98f6b6b..ed73a44 100644
--- a/include/sys/time.h
+++ b/include/sys/time.h
@@ -24,6 +24,8 @@ 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;
diff --git a/sysdeps/unix/sysv/linux/gettimeofday64.c b/sysdeps/unix/sysv/linux/gettimeofday64.c
new file mode 100644
index 0000000..e1538a9
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/gettimeofday64.c
@@ -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;
+}
diff --git a/time/Makefile b/time/Makefile
index 2d60110..dd09d09 100644
--- a/time/Makefile
+++ b/time/Makefile
@@ -34,6 +34,7 @@ headers := time.h sys/time.h sys/timeb.h bits/time.h \
routines := offtime asctime clock ctime ctime_r difftime \
gmtime localtime mktime time \
gettimeofday settimeofday adjtime tzset \
+ gettimeofday64 \
tzfile getitimer setitimer \
stime dysize timegm ftime \
getdate strptime strptime_l \
diff --git a/time/Versions b/time/Versions
index f22ce38..f1b4cbf 100644
--- a/time/Versions
+++ b/time/Versions
@@ -80,5 +80,6 @@ libc {
__sigtimedwait_time64;
__futimes64;
__lutimes64;
+ __gettimeofday64;
}
}
diff --git a/time/gettimeofday.c b/time/gettimeofday.c
index d1ab9ac..e4a67c6 100644
--- a/time/gettimeofday.c
+++ b/time/gettimeofday.c
@@ -16,7 +16,6 @@
<http://www.gnu.org/licenses/>. */
#include <errno.h>
-#include <sys/time.h>
/* Get the current time of day and timezone information,
putting it into *TV and *TZ. If TZ is NULL, *TZ is not filled.
@@ -32,3 +31,13 @@ weak_alias (__gettimeofday, gettimeofday)
libc_hidden_weak (gettimeofday)
stub_warning (gettimeofday)
+
+/* 64-bit time version */
+
+int
+__gettimeofday64 (struct timeval *tv, struct timezone *tz)
+{
+ __set_errno (ENOSYS);
+ return -1;
+}
+stub_warning (__gettimeofday64)
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=9c7f38faf67efde6ddb0f4ddd2453a7be6b6832b
commit 9c7f38faf67efde6ddb0f4ddd2453a7be6b6832b
Author: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
Date: Fri Sep 8 00:41:54 2017 +0200
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.
diff --git a/include/sys/stat.h b/include/sys/stat.h
index 72aca27..d267dd0 100644
--- a/include/sys/stat.h
+++ b/include/sys/stat.h
@@ -42,6 +42,10 @@ 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)
diff --git a/io/Versions b/io/Versions
index 46f9d4c..90956fe 100644
--- a/io/Versions
+++ b/io/Versions
@@ -136,6 +136,7 @@ libc {
__fxstat64_time64;
__xstat64_time64;
__lxstat64_time64;
+ __fxstatat64_time64;
}
GLIBC_PRIVATE {
__libc_fcntl64;
diff --git a/io/fstatat64.c b/io/fstatat64.c
index f4f46a9..b7efd89 100644
--- a/io/fstatat64.c
+++ b/io/fstatat64.c
@@ -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);
+}
diff --git a/sysdeps/unix/sysv/linux/fxstatat64.c b/sysdeps/unix/sysv/linux/fxstatat64.c
index baa9a60..2c04e66 100644
--- a/sysdeps/unix/sysv/linux/fxstatat64.c
+++ b/sysdeps/unix/sysv/linux/fxstatat64.c
@@ -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));
+}
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=2b58e311d54c688e320746d4a3d510fc0aa0ee21
commit 2b58e311d54c688e320746d4a3d510fc0aa0ee21
Author: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
Date: Fri Sep 8 00:41:53 2017 +0200
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.
diff --git a/include/sys/stat.h b/include/sys/stat.h
index 186df0c..72aca27 100644
--- a/include/sys/stat.h
+++ b/include/sys/stat.h
@@ -40,6 +40,8 @@ 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);
#if IS_IN (libc) || (IS_IN (rtld) && !defined NO_RTLD_HIDDEN)
hidden_proto (__fxstat)
diff --git a/io/Versions b/io/Versions
index 821e375..46f9d4c 100644
--- a/io/Versions
+++ b/io/Versions
@@ -135,6 +135,7 @@ libc {
GLIBC_2.29 {
__fxstat64_time64;
__xstat64_time64;
+ __lxstat64_time64;
}
GLIBC_PRIVATE {
__libc_fcntl64;
diff --git a/io/lstat64.c b/io/lstat64.c
index c3eb7a7..96ce999 100644
--- a/io/lstat64.c
+++ b/io/lstat64.c
@@ -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);
+}
diff --git a/sysdeps/unix/sysv/linux/lxstat64.c b/sysdeps/unix/sysv/linux/lxstat64.c
index d05fa14..0c55407 100644
--- a/sysdeps/unix/sysv/linux/lxstat64.c
+++ b/sysdeps/unix/sysv/linux/lxstat64.c
@@ -50,3 +50,44 @@ hidden_ver (___lxstat64, __lxstat64)
strong_alias (___lxstat64, __lxstat64);
hidden_def (__lxstat64)
#endif
+
+/* 64-bit time version */
+
+int
+__lxstat64_time64 (int vers, const char *name, struct __stat64_t64 *buf)
+{
+ int result;
+ struct stat64 st64;
+
+ result = INLINE_SYSCALL (lstat64, 2, name, &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;
+}
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=77fb4b34d42e8761634bb9557472b6bb63521269
commit 77fb4b34d42e8761634bb9557472b6bb63521269
Author: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
Date: Fri Sep 8 00:41:52 2017 +0200
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.
diff --git a/include/sys/stat.h b/include/sys/stat.h
index c00f7b4..186df0c 100644
--- a/include/sys/stat.h
+++ b/include/sys/stat.h
@@ -38,6 +38,8 @@ 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);
#if IS_IN (libc) || (IS_IN (rtld) && !defined NO_RTLD_HIDDEN)
hidden_proto (__fxstat)
diff --git a/io/Versions b/io/Versions
index 0d8f63c..821e375 100644
--- a/io/Versions
+++ b/io/Versions
@@ -134,6 +134,7 @@ libc {
}
GLIBC_2.29 {
__fxstat64_time64;
+ __xstat64_time64;
}
GLIBC_PRIVATE {
__libc_fcntl64;
diff --git a/io/stat64.c b/io/stat64.c
index 5020551..4ed632f 100644
--- a/io/stat64.c
+++ b/io/stat64.c
@@ -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);
+}
diff --git a/sysdeps/unix/sysv/linux/xstat64.c b/sysdeps/unix/sysv/linux/xstat64.c
index afc9ba2..e0341c1 100644
--- a/sysdeps/unix/sysv/linux/xstat64.c
+++ b/sysdeps/unix/sysv/linux/xstat64.c
@@ -52,3 +52,44 @@ hidden_ver (___xstat64, __xstat64)
strong_alias (___xstat64, __xstat64)
hidden_def (__xstat64)
#endif
+
+/* 64-bit time version */
+
+int
+__xstat64_time64 (int vers, const char *name, struct __stat64_t64 *buf)
+{
+ int result;
+ struct stat64 st64;
+
+ result = INLINE_SYSCALL (stat64, 2, name, &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;
+}
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=80247ab05235567e17ff981c97f120b2cd22950a
commit 80247ab05235567e17ff981c97f120b2cd22950a
Author: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
Date: Fri Sep 8 00:41:51 2017 +0200
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.
diff --git a/include/sys/stat.h b/include/sys/stat.h
index 0f2a662..c00f7b4 100644
--- a/include/sys/stat.h
+++ b/include/sys/stat.h
@@ -36,6 +36,9 @@ 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);
+
#if IS_IN (libc) || (IS_IN (rtld) && !defined NO_RTLD_HIDDEN)
hidden_proto (__fxstat)
hidden_proto (__fxstat64)
diff --git a/io/Versions b/io/Versions
index f7e5dbe..0d8f63c 100644
--- a/io/Versions
+++ b/io/Versions
@@ -132,6 +132,9 @@ libc {
fcntl64;
statx;
}
+ GLIBC_2.29 {
+ __fxstat64_time64;
+ }
GLIBC_PRIVATE {
__libc_fcntl64;
__fcntl_nocancel;
diff --git a/io/fstat64.c b/io/fstat64.c
index 0f4de02..56b1b3f 100644
--- a/io/fstat64.c
+++ b/io/fstat64.c
@@ -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);
+}
diff --git a/sysdeps/unix/sysv/linux/fxstat64.c b/sysdeps/unix/sysv/linux/fxstat64.c
index 0d05389..8c376cc 100644
--- a/sysdeps/unix/sysv/linux/fxstat64.c
+++ b/sysdeps/unix/sysv/linux/fxstat64.c
@@ -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;
+}
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=3e1b0beed2557b4a26caf26b2a8fe6c719c520d5
commit 3e1b0beed2557b4a26caf26b2a8fe6c719c520d5
Author: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
Date: Fri Sep 8 00:41:50 2017 +0200
Y2038: add struct __stat64_t64
diff --git a/include/sys/stat.h b/include/sys/stat.h
index b82d452..0f2a662 100644
--- a/include/sys/stat.h
+++ b/include/sys/stat.h
@@ -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);
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=0163cee615041e89797d7c04a7c33a5256bf4324
commit 0163cee615041e89797d7c04a7c33a5256bf4324
Author: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
Date: Fri Sep 8 00:41:49 2017 +0200
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.
diff --git a/rt/Makefile b/rt/Makefile
index c0aad5d..994891e 100644
--- a/rt/Makefile
+++ b/rt/Makefile
@@ -33,7 +33,7 @@ clock-routines := get_clockfreq clock_getcpuclockid \
clock_nanosleep
timer-routines := timer_create timer_delete timer_getoverr \
timer_gettime timer_settime \
- timerfd_gettime64
+ 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 \
diff --git a/rt/Versions b/rt/Versions
index 7cee855..8f757ed 100644
--- a/rt/Versions
+++ b/rt/Versions
@@ -41,5 +41,6 @@ librt {
__timer_gettime64;
__timer_settime64;
__timerfd_gettime64;
+ __timerfd_settime64;
}
}
diff --git a/rt/timerfd_settime64.c b/rt/timerfd_settime64.c
new file mode 100644
index 0000000..39ce88b
--- /dev/null
+++ b/rt/timerfd_settime64.c
@@ -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)
diff --git a/sysdeps/unix/sysv/linux/arm/librt.abilist b/sysdeps/unix/sysv/linux/arm/librt.abilist
index bcfdc22..344fa5b 100644
--- a/sysdeps/unix/sysv/linux/arm/librt.abilist
+++ b/sysdeps/unix/sysv/linux/arm/librt.abilist
@@ -1,6 +1,7 @@
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
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/librt.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/librt.abilist
index eabb760..f34ae35 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/librt.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/librt.abilist
@@ -30,6 +30,7 @@ GLIBC_2.2 timer_settime 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.3.4 mq_close F
GLIBC_2.3.4 mq_getattr F
GLIBC_2.3.4 mq_notify F
diff --git a/sysdeps/unix/sysv/linux/timerfd_settime64.c b/sysdeps/unix/sysv/linux/timerfd_settime64.c
new file mode 100644
index 0000000..fc31f5a
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/timerfd_settime64.c
@@ -0,0 +1,72 @@
+/* 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; see the file COPYING.LIB. If
+ not, see <http://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sysdep.h>
+#include <y2038-support.h>
+#include "kernel-posix-timers.h"
+
+int
+__timerfd_settime64 (int fd, int flags, const struct __itimerspec64 *value,
+ struct __itimerspec64 *ovalue)
+{
+ int res;
+ struct itimerspec value32;
+ struct itimerspec ovalue32;
+
+ if (value == NULL)
+ return EFAULT;
+
+#ifdef __NR_timerfd_settime64
+ if (__y2038_get_kernel_support () > 0)
+ {
+ res = INLINE_SYSCALL (timerfd_settime64, 3, fd, value, ovalue);
+ if (res == 0 || errno != ENOSYS)
+ return res;
+ __y2038_set_kernel_support (-1);
+ }
+#endif
+
+ if (value->it_value.tv_sec > INT_MAX
+ || value->it_interval.tv_sec > INT_MAX)
+ {
+ __set_errno(EOVERFLOW);
+ return -1;
+ }
+
+ value32.it_value.tv_sec = value->it_value.tv_sec;
+ value32.it_value.tv_nsec = value->it_value.tv_nsec;
+ value32.it_interval.tv_sec = value->it_interval.tv_sec;
+ value32.it_interval.tv_nsec = value->it_interval.tv_nsec;
+
+ res = INLINE_SYSCALL (timerfd_settime, 4, fd, flags,
+ &value32, &ovalue32);
+
+ if (res == 0 && ovalue != NULL)
+ {
+ ovalue->it_value.tv_sec = ovalue32.it_value.tv_sec;
+ ovalue->it_value.tv_nsec = ovalue32.it_value.tv_nsec;
+ ovalue->it_interval.tv_sec = ovalue32.it_interval.tv_sec;
+ ovalue->it_interval.tv_nsec = ovalue32.it_interval.tv_nsec;
+ }
+
+ return res;
+}
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=223a3bd4eb34acd7e2fb1e9415849a1bd4404084
commit 223a3bd4eb34acd7e2fb1e9415849a1bd4404084
Author: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
Date: Fri Sep 8 00:41:48 2017 +0200
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.
diff --git a/rt/Makefile b/rt/Makefile
index 6d6b896..c0aad5d 100644
--- a/rt/Makefile
+++ b/rt/Makefile
@@ -32,7 +32,8 @@ 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
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 \
diff --git a/rt/Versions b/rt/Versions
index c8703cb..7cee855 100644
--- a/rt/Versions
+++ b/rt/Versions
@@ -40,5 +40,6 @@ librt {
GLIBC_2.29 {
__timer_gettime64;
__timer_settime64;
+ __timerfd_gettime64;
}
}
diff --git a/rt/timerfd_gettime64.c b/rt/timerfd_gettime64.c
new file mode 100644
index 0000000..72d0b68
--- /dev/null
+++ b/rt/timerfd_gettime64.c
@@ -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)
diff --git a/sysdeps/unix/sysv/linux/arm/librt.abilist b/sysdeps/unix/sysv/linux/arm/librt.abilist
index b92173e..bcfdc22 100644
--- a/sysdeps/unix/sysv/linux/arm/librt.abilist
+++ b/sysdeps/unix/sysv/linux/arm/librt.abilist
@@ -1,5 +1,6 @@
GLIBC_2.29 __timer_gettime64 F
GLIBC_2.29 __timer_settime64 F
+GLIBC_2.29 __timerfd_gettime64 F
GLIBC_2.4 aio_cancel F
GLIBC_2.4 aio_cancel64 F
GLIBC_2.4 aio_error F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/librt.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/librt.abilist
index e7774ee..eabb760 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/librt.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/librt.abilist
@@ -29,6 +29,7 @@ GLIBC_2.2 timer_gettime F
GLIBC_2.2 timer_settime F
GLIBC_2.29 __timer_gettime64 F
GLIBC_2.29 __timer_settime64 F
+GLIBC_2.29 __timerfd_gettime64 F
GLIBC_2.3.4 mq_close F
GLIBC_2.3.4 mq_getattr F
GLIBC_2.3.4 mq_notify F
diff --git a/sysdeps/unix/sysv/linux/timerfd_gettime64.c b/sysdeps/unix/sysv/linux/timerfd_gettime64.c
new file mode 100644
index 0000000..51be6c7
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/timerfd_gettime64.c
@@ -0,0 +1,54 @@
+/* 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; see the file COPYING.LIB. If
+ not, see <http://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sysdep.h>
+#include <y2038-support.h>
+#include "kernel-posix-timers.h"
+
+int
+__timerfd_gettime64 (int fd, struct __itimerspec64 *value)
+{
+ int res;
+ struct itimerspec value32;
+
+#ifdef __NR_timerfd_gettime64
+ if (__y2038_get_kernel_support () > 0)
+ {
+ res = INLINE_SYSCALL (timerfd_gettime64, 2, fd, value);
+ if (res == 0 || errno != ENOSYS)
+ return res;
+ __y2038_set_kernel_support (-1);
+ }
+#endif
+
+ res = INLINE_SYSCALL (timerfd_gettime, 2, fd, &value32);
+
+ if (res == 0)
+ {
+ value->it_value.tv_sec = value32.it_value.tv_sec;
+ value->it_value.tv_nsec = value32.it_value.tv_nsec;
+ value->it_interval.tv_sec = value32.it_interval.tv_sec;
+ value->it_interval.tv_nsec = value32.it_interval.tv_nsec;
+ }
+
+ return res;
+}
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=59cfa92672eda4b424e70df380ad6750ed6c79ad
commit 59cfa92672eda4b424e70df380ad6750ed6c79ad
Author: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
Date: Fri Sep 8 00:41:47 2017 +0200
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.
diff --git a/rt/Versions b/rt/Versions
index e55faa0..c8703cb 100644
--- a/rt/Versions
+++ b/rt/Versions
@@ -39,5 +39,6 @@ librt {
}
GLIBC_2.29 {
__timer_gettime64;
+ __timer_settime64;
}
}
diff --git a/sysdeps/unix/sysv/linux/arm/librt.abilist b/sysdeps/unix/sysv/linux/arm/librt.abilist
index e18f5ee..b92173e 100644
--- a/sysdeps/unix/sysv/linux/arm/librt.abilist
+++ b/sysdeps/unix/sysv/linux/arm/librt.abilist
@@ -1,4 +1,5 @@
GLIBC_2.29 __timer_gettime64 F
+GLIBC_2.29 __timer_settime64 F
GLIBC_2.4 aio_cancel F
GLIBC_2.4 aio_cancel64 F
GLIBC_2.4 aio_error F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/librt.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/librt.abilist
index cb6ba72..e7774ee 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/librt.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/librt.abilist
@@ -28,6 +28,7 @@ GLIBC_2.2 timer_getoverrun F
GLIBC_2.2 timer_gettime F
GLIBC_2.2 timer_settime F
GLIBC_2.29 __timer_gettime64 F
+GLIBC_2.29 __timer_settime64 F
GLIBC_2.3.4 mq_close F
GLIBC_2.3.4 mq_getattr F
GLIBC_2.3.4 mq_notify F
diff --git a/sysdeps/unix/sysv/linux/timer_settime.c b/sysdeps/unix/sysv/linux/timer_settime.c
index 7c938bd..bc876a9 100644
--- a/sysdeps/unix/sysv/linux/timer_settime.c
+++ b/sysdeps/unix/sysv/linux/timer_settime.c
@@ -20,6 +20,7 @@
#include <stdlib.h>
#include <time.h>
#include <sysdep.h>
+#include <y2038-support.h>
#include "kernel-posix-timers.h"
@@ -41,3 +42,52 @@ timer_settime (timer_t timerid, int flags, const struct itimerspec *value,
return res;
}
+
+/* 64-bit time version */
+
+int
+__timer_settime64 (timer_t timerid, int flags, const struct itimerspec *value,
+ struct itimerspec *ovalue)
+{
+ int res;
+ struct timer *kt = (struct timer *) timerid;
+ struct itimerspec value32, ovalue32;
+
+ if (value == NULL)
+ {
+ __set_errno(EFAULT);
+ return -1;
+ }
+
+#ifdef __NR_timer_settime64
+ if (__y2038_get_kernel_support () > 0)
+ {
+ res = INLINE_SYSCALL (timer_settime, 3, kt->ktimerid, value, ovalue);
+ if (res == 0 || errno != ENOSYS)
+ return res;
+ __y2038_set_kernel_support (-1);
+ }
+#endif
+
+ if (value->it_value.tv_sec > INT_MAX
+ || value->it_interval.tv_sec > INT_MAX)
+ return EOVERFLOW;
+
+ value32.it_value.tv_sec = value->it_value.tv_sec;
+ value32.it_value.tv_nsec = value->it_value.tv_nsec;
+ value32.it_interval.tv_sec = value->it_interval.tv_sec;
+ value32.it_interval.tv_nsec = value->it_interval.tv_nsec;
+
+ res = INLINE_SYSCALL (timer_settime, 4, kt->ktimerid, flags,
+ &value32, &ovalue32);
+
+ if (res == 0 && ovalue != NULL)
+ {
+ ovalue->it_value.tv_sec = ovalue32.it_value.tv_sec;
+ ovalue->it_value.tv_nsec = ovalue32.it_value.tv_nsec;
+ ovalue->it_interval.tv_sec = ovalue32.it_interval.tv_sec;
+ ovalue->it_interval.tv_nsec = ovalue32.it_interval.tv_nsec;
+ }
+
+ return res;
+}
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=5f62b6fcedd7b2ec976a4c357a019c71ee36a8ce
commit 5f62b6fcedd7b2ec976a4c357a019c71ee36a8ce
Author: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
Date: Fri Sep 8 00:41:46 2017 +0200
Y2038: add function __timer_gettime64
For Linux this uses the 32-bit time syscall, so it
converts the syscall output into 64-bit time.
diff --git a/rt/Versions b/rt/Versions
index 91e3fd2..e55faa0 100644
--- a/rt/Versions
+++ b/rt/Versions
@@ -37,4 +37,7 @@ librt {
GLIBC_2.7 {
__mq_open_2;
}
+ GLIBC_2.29 {
+ __timer_gettime64;
+ }
}
diff --git a/sysdeps/unix/sysv/linux/arm/librt.abilist b/sysdeps/unix/sysv/linux/arm/librt.abilist
index cfbbd27..e18f5ee 100644
--- a/sysdeps/unix/sysv/linux/arm/librt.abilist
+++ b/sysdeps/unix/sysv/linux/arm/librt.abilist
@@ -1,3 +1,4 @@
+GLIBC_2.29 __timer_gettime64 F
GLIBC_2.4 aio_cancel F
GLIBC_2.4 aio_cancel64 F
GLIBC_2.4 aio_error F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/librt.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/librt.abilist
index 595f1b7..cb6ba72 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/librt.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/librt.abilist
@@ -27,6 +27,7 @@ GLIBC_2.2 timer_delete F
GLIBC_2.2 timer_getoverrun F
GLIBC_2.2 timer_gettime F
GLIBC_2.2 timer_settime F
+GLIBC_2.29 __timer_gettime64 F
GLIBC_2.3.4 mq_close F
GLIBC_2.3.4 mq_getattr F
GLIBC_2.3.4 mq_notify F
diff --git a/sysdeps/unix/sysv/linux/timer_gettime.c b/sysdeps/unix/sysv/linux/timer_gettime.c
index 10a19d9..85806f4 100644
--- a/sysdeps/unix/sysv/linux/timer_gettime.c
+++ b/sysdeps/unix/sysv/linux/timer_gettime.c
@@ -20,6 +20,7 @@
#include <stdlib.h>
#include <time.h>
#include <sysdep.h>
+#include <y2038-support.h>
#include "kernel-posix-timers.h"
@@ -39,3 +40,35 @@ timer_gettime (timer_t timerid, struct itimerspec *value)
return res;
}
+
+/* 64-bit time version */
+
+int
+__timer_gettime64 (timer_t timerid, struct __itimerspec64 *value)
+{
+ struct itimerspec value32;
+ struct timer *kt = (struct timer *) timerid;
+ int res;
+
+#ifdef __NR_timer_gettime64
+ if (__y2038_get_kernel_support () > 0)
+ {
+ res = INLINE_SYSCALL (timer_gettime, 2, kt->ktimerid, value);
+ if (res == 0 || errno != ENOSYS)
+ return res;
+ __y2038_set_kernel_support (-1);
+ }
+#endif
+
+ res = INLINE_SYSCALL (timer_gettime, 2, kt->ktimerid, &value32);
+
+ if (res == 0)
+ {
+ value->it_value.tv_sec = value32.it_value.tv_sec;
+ value->it_value.tv_nsec = value32.it_value.tv_nsec;
+ value->it_interval.tv_sec = value32.it_interval.tv_sec;
+ value->it_interval.tv_nsec = value32.it_interval.tv_nsec;
+ }
+
+ return res;
+}
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=cc757c8616cd93fdc268d87f70c5e3f7088cae4b
commit cc757c8616cd93fdc268d87f70c5e3f7088cae4b
Author: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
Date: Fri Sep 8 00:41:45 2017 +0200
Y2038: add struct __itimerspec64
diff --git a/include/bits/types/struct_itimerspec64.h b/include/bits/types/struct_itimerspec64.h
new file mode 100644
index 0000000..cc503f7
--- /dev/null
+++ b/include/bits/types/struct_itimerspec64.h
@@ -0,0 +1 @@
+#include <time/bits/types/struct_itimerspec64.h>
diff --git a/sysdeps/unix/sysv/linux/sys/timerfd.h b/sysdeps/unix/sysv/linux/sys/timerfd.h
index 4d75e15..37490cf 100644
--- a/sysdeps/unix/sysv/linux/sys/timerfd.h
+++ b/sysdeps/unix/sysv/linux/sys/timerfd.h
@@ -20,6 +20,7 @@
#include <time.h>
#include <bits/types/struct_itimerspec.h>
+#include <bits/types/struct_itimerspec64.h>
/* Get the platform-dependent flags. */
#include <bits/timerfd.h>
diff --git a/time/Makefile b/time/Makefile
index 5e76bc0..2d60110 100644
--- a/time/Makefile
+++ b/time/Makefile
@@ -28,7 +28,8 @@ headers := time.h sys/time.h sys/timeb.h bits/time.h \
bits/types/struct_timespec.h bits/types/struct_timeval.h \
bits/types/struct_tm.h bits/types/timer_t.h \
bits/types/time_t.h bits/types/struct_timespec64.h \
- bits/types/struct_timeval64.h
+ bits/types/struct_timeval64.h \
+ bits/types/struct_itimerspec64.h
routines := offtime asctime clock ctime ctime_r difftime \
gmtime localtime mktime time \
diff --git a/time/bits/types/struct_itimerspec64.h b/time/bits/types/struct_itimerspec64.h
new file mode 100644
index 0000000..039af1c
--- /dev/null
+++ b/time/bits/types/struct_itimerspec64.h
@@ -0,0 +1,15 @@
+#ifndef __itimerspec64_defined
+#define __itimerspec64_defined 1
+
+#include <bits/types.h>
+#include <bits/types/struct_timespec.h>
+#include <bits/types/struct_timespec64.h>
+
+/* POSIX.1b structure for timer start values and intervals. */
+struct __itimerspec64
+{
+ struct __timespec64 it_interval;
+ struct __timespec64 it_value;
+};
+
+#endif
diff --git a/time/time.h b/time/time.h
index c9282e2..dcc275a 100644
--- a/time/time.h
+++ b/time/time.h
@@ -47,6 +47,7 @@
# include <bits/types/clockid_t.h>
# include <bits/types/timer_t.h>
# include <bits/types/struct_itimerspec.h>
+# include <bits/types/struct_itimerspec64.h>
struct sigevent;
#endif
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=b3c501fa4333f91ba563229d45bbc013f8860f6f
commit b3c501fa4333f91ba563229d45bbc013f8860f6f
Author: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
Date: Fri Sep 8 00:41:44 2017 +0200
Y2038: add function __lutimes64
diff --git a/misc/lutimes.c b/misc/lutimes.c
index b241c14..e436899 100644
--- a/misc/lutimes.c
+++ b/misc/lutimes.c
@@ -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)
diff --git a/sysdeps/unix/sysv/linux/lutimes.c b/sysdeps/unix/sysv/linux/lutimes.c
index 4f2f9ec..e76b9dd 100644
--- a/sysdeps/unix/sysv/linux/lutimes.c
+++ b/sysdeps/unix/sysv/linux/lutimes.c
@@ -22,6 +22,7 @@
#include <time.h>
#include <sys/time.h>
#include <sysdep.h>
+#include <y2038-support.h>
int
@@ -42,3 +43,60 @@ lutimes (const char *file, const struct timeval tvp[2])
return INLINE_SYSCALL (utimensat, 4, AT_FDCWD, file, tvp ? ts : NULL,
AT_SYMLINK_NOFOLLOW);
}
+
+/* 64-bit time version */
+
+int
+__lutimes64 (const char *file, 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 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, AT_FDCWD, file, ts64p,
+ AT_SYMLINK_NOFOLLOW);
+ 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);
+
+ 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, AT_FDCWD, file, ts32p,
+ AT_SYMLINK_NOFOLLOW);
+}
diff --git a/time/Versions b/time/Versions
index 0a55284..f22ce38 100644
--- a/time/Versions
+++ b/time/Versions
@@ -79,5 +79,6 @@ libc {
__futimens64;
__sigtimedwait_time64;
__futimes64;
+ __lutimes64;
}
}
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=ce4546c21b80664daf00fa6ad4b8ca5f5127c550
commit ce4546c21b80664daf00fa6ad4b8ca5f5127c550
Author: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
Date: Fri Sep 8 00:41:43 2017 +0200
Y2038: add function __futimes64
diff --git a/misc/futimes.c b/misc/futimes.c
index 3ffa40b..c8756a0 100644
--- a/misc/futimes.c
+++ b/misc/futimes.c
@@ -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)
diff --git a/sysdeps/unix/sysv/linux/futimes.c b/sysdeps/unix/sysv/linux/futimes.c
index 9e6267c..c3d7678 100644
--- a/sysdeps/unix/sysv/linux/futimes.c
+++ b/sysdeps/unix/sysv/linux/futimes.c
@@ -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);
+}
diff --git a/time/Versions b/time/Versions
index 8e5f021..0a55284 100644
--- a/time/Versions
+++ b/time/Versions
@@ -78,5 +78,6 @@ libc {
__utimensat_time64;
__futimens64;
__sigtimedwait_time64;
+ __futimes64;
}
}
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=88b52239061ac893e012826b4529766d900ff2e7
commit 88b52239061ac893e012826b4529766d900ff2e7
Author: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
Date: Fri Sep 8 00:41:42 2017 +0200
Y2038: add struct __timeval64
Also, provide static inline functions and macros for checking
and converting between 32-bit and 64-bit timevals.
diff --git a/bits/resource.h b/bits/resource.h
index 7693d20..c0b00be 100644
--- a/bits/resource.h
+++ b/bits/resource.h
@@ -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. */
diff --git a/include/bits/types/struct_timeval64.h b/include/bits/types/struct_timeval64.h
new file mode 100644
index 0000000..fe2ffe6
--- /dev/null
+++ b/include/bits/types/struct_timeval64.h
@@ -0,0 +1 @@
+#include <time/bits/types/struct_timeval64.h>
diff --git a/misc/sys/select.h b/misc/sys/select.h
index 1285dc4..060e7f4 100644
--- a/misc/sys/select.h
+++ b/misc/sys/select.h
@@ -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>
# include <bits/types/struct_timespec64.h>
diff --git a/resource/bits/types/struct_rusage.h b/resource/bits/types/struct_rusage.h
index 5dc0916..bb2ecb2 100644
--- a/resource/bits/types/struct_rusage.h
+++ b/resource/bits/types/struct_rusage.h
@@ -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. */
diff --git a/sysdeps/unix/sysv/linux/alpha/bits/resource.h b/sysdeps/unix/sysv/linux/alpha/bits/resource.h
index dddcb0f..b602f56 100644
--- a/sysdeps/unix/sysv/linux/alpha/bits/resource.h
+++ b/sysdeps/unix/sysv/linux/alpha/bits/resource.h
@@ -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. */
diff --git a/sysdeps/unix/sysv/linux/bits/resource.h b/sysdeps/unix/sysv/linux/bits/resource.h
index fafbadf..1f42d0d 100644
--- a/sysdeps/unix/sysv/linux/bits/resource.h
+++ b/sysdeps/unix/sysv/linux/bits/resource.h
@@ -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. */
diff --git a/sysdeps/unix/sysv/linux/bits/timex.h b/sysdeps/unix/sysv/linux/bits/timex.h
index 1dbcc0b..d3c16ec 100644
--- a/sysdeps/unix/sysv/linux/bits/timex.h
+++ b/sysdeps/unix/sysv/linux/bits/timex.h
@@ -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. */
diff --git a/sysdeps/unix/sysv/linux/mips/bits/resource.h b/sysdeps/unix/sysv/linux/mips/bits/resource.h
index 89d8788..ba46c0b 100644
--- a/sysdeps/unix/sysv/linux/mips/bits/resource.h
+++ b/sysdeps/unix/sysv/linux/mips/bits/resource.h
@@ -184,6 +184,7 @@ enum __rusage_who
};
#include <bits/types/struct_timeval.h>
+#include <bits/types/struct_timeval64.h>
#include <bits/types/struct_rusage.h>
/* Priority limits. */
diff --git a/sysdeps/unix/sysv/linux/sparc/bits/resource.h b/sysdeps/unix/sysv/linux/sparc/bits/resource.h
index ee5c26e..1c88169 100644
--- a/sysdeps/unix/sysv/linux/sparc/bits/resource.h
+++ b/sysdeps/unix/sysv/linux/sparc/bits/resource.h
@@ -192,6 +192,7 @@ enum __rusage_who
};
#include <bits/types/struct_timeval.h>
+#include <bits/types/struct_timeval64.h>
#include <bits/types/struct_rusage.h>
/* Priority limits. */
diff --git a/time/Makefile b/time/Makefile
index 61b8904..5e76bc0 100644
--- a/time/Makefile
+++ b/time/Makefile
@@ -27,7 +27,8 @@ headers := time.h sys/time.h sys/timeb.h bits/time.h \
bits/types/struct_itimerspec.h \
bits/types/struct_timespec.h bits/types/struct_timeval.h \
bits/types/struct_tm.h bits/types/timer_t.h \
- bits/types/time_t.h bits/types/struct_timespec64.h
+ bits/types/time_t.h bits/types/struct_timespec64.h \
+ bits/types/struct_timeval64.h
routines := offtime asctime clock ctime ctime_r difftime \
gmtime localtime mktime time \
diff --git a/time/bits/types/struct_timeval64.h b/time/bits/types/struct_timeval64.h
new file mode 100644
index 0000000..e4966ea
--- /dev/null
+++ b/time/bits/types/struct_timeval64.h
@@ -0,0 +1,13 @@
+#ifndef __timeval64_defined
+#define __timeval64_defined 1
+
+#include <bits/types.h>
+
+/* A time value that is accurate to the nearest
+ microsecond but also has a range of years. */
+struct __timeval64
+{
+ __time64_t tv_sec; /* Seconds */
+ __int64_t tv_usec; /* Microseconds */
+};
+#endif
diff --git a/time/sys/time.h b/time/sys/time.h
index 4166a5b..4e6255e 100644
--- a/time/sys/time.h
+++ b/time/sys/time.h
@@ -23,6 +23,7 @@
#include <bits/types.h>
#include <bits/types/time_t.h>
#include <bits/types/struct_timeval.h>
+#include <bits/types/struct_timeval64.h>
#ifndef __suseconds_t_defined
typedef __suseconds_t suseconds_t;
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=d47516a63714137a1f5cb3ed457db42a75d6f059
commit d47516a63714137a1f5cb3ed457db42a75d6f059
Author: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
Date: Fri Sep 8 00:41:41 2017 +0200
Y2038: add function __sigtimedwait_time64
diff --git a/signal/sigtimedwait.c b/signal/sigtimedwait.c
index 308b9b9..e187883 100644
--- a/signal/sigtimedwait.c
+++ b/signal/sigtimedwait.c
@@ -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)
diff --git a/sysdeps/unix/sysv/linux/sigtimedwait.c b/sysdeps/unix/sysv/linux/sigtimedwait.c
index b4de885..6cfe8f0 100644
--- a/sysdeps/unix/sysv/linux/sigtimedwait.c
+++ b/sysdeps/unix/sysv/linux/sigtimedwait.c
@@ -18,7 +18,11 @@
#include <errno.h>
#include <signal.h>
#include <string.h>
+//#include <stdint.h>
+
+//#include <nptl/pthreadP.h>
#include <sysdep-cancel.h>
+#include <y2038-support.h>
int
__sigtimedwait (const sigset_t *set, siginfo_t *info,
@@ -39,3 +43,80 @@ __sigtimedwait (const sigset_t *set, siginfo_t *info,
}
libc_hidden_def (__sigtimedwait)
weak_alias (__sigtimedwait, sigtimedwait)
+
+/* 64-bit time version */
+
+int
+__sigtimedwait_time64 (const sigset_t *set, siginfo_t *info,
+ const struct __timespec64 *timeout)
+{
+ int result;
+ struct timespec ts32;
+#ifdef __NR_rt_sigtimedwait_time64
+ struct __timespec64 ts64;
+#endif
+
+#ifdef SIGCANCEL
+ sigset_t tmpset;
+ if (set != NULL
+ && (__builtin_expect (__sigismember (set, SIGCANCEL), 0)
+# ifdef SIGSETXID
+ || __builtin_expect (__sigismember (set, SIGSETXID), 0)
+# endif
+ ))
+ {
+ /* Create a temporary mask without the bit for SIGCANCEL set. */
+ // We are not copying more than we have to.
+ memcpy (&tmpset, set, _NSIG / 8);
+ __sigdelset (&tmpset, SIGCANCEL);
+# ifdef SIGSETXID
+ __sigdelset (&tmpset, SIGSETXID);
+# endif
+ set = &tmpset;
+ }
+#endif
+
+ /* XXX The size argument hopefully will have to be changed to the
+ real size of the user-level sigset_t. */
+#ifdef __NR_rt_sigtimedwait_time64
+ if (__y2038_linux_support > 0)
+ {
+ if (timeout)
+ {
+ ts64.tv_sec = timeout->tv_sec;
+ ts64.tv_nsec = timeout->tv_nsec;
+ ts64.tv_pad = 0;
+ result = SYSCALL_CANCEL (rt_sigtimedwait_time64, set, info, &ts64, _NSIG / 8);
+ if (result == -1 && errno==ENOSYS)
+ {
+ __y2038_linux_support = -1;
+ }
+ }
+ else
+ result = SYSCALL_CANCEL (rt_sigtimedwait, set, info, NULL, _NSIG / 8);
+ }
+ else
+#endif
+ {
+ if (timeout)
+ {
+ if (! timespec64_to_timespec(timeout, &ts32))
+ {
+ errno = EOVERFLOW;
+ return -1;
+ }
+ result = SYSCALL_CANCEL (rt_sigtimedwait, set, info, &ts32, _NSIG / 8);
+ }
+ else
+ result = SYSCALL_CANCEL (rt_sigtimedwait, set, info, NULL, _NSIG / 8);
+ }
+
+ /* The kernel generates a SI_TKILL code in si_code in case tkill is
+ used. tkill is transparently used in raise(). Since having
+ SI_TKILL as a code is useful in general we fold the results
+ here. */
+ if (result != -1 && info != NULL && info->si_code == SI_TKILL)
+ info->si_code = SI_USER;
+
+ return result;
+}
diff --git a/time/Versions b/time/Versions
index 5614729..8e5f021 100644
--- a/time/Versions
+++ b/time/Versions
@@ -77,5 +77,6 @@ libc {
__timespec_get64;
__utimensat_time64;
__futimens64;
+ __sigtimedwait_time64;
}
}
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=e2266f244913860df9d91a5de6bd5b7baacc9f7e
commit e2266f244913860df9d91a5de6bd5b7baacc9f7e
Author: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
Date: Fri Sep 8 00:41:39 2017 +0200
Y2038: add function __futimens64
diff --git a/io/futimens.c b/io/futimens.c
index fb170ff..2e9648a 100644
--- a/io/futimens.c
+++ b/io/futimens.c
@@ -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)
diff --git a/sysdeps/unix/sysv/linux/futimens.c b/sysdeps/unix/sysv/linux/futimens.c
index bc7fe54..5de651d 100644
--- a/sysdeps/unix/sysv/linux/futimens.c
+++ b/sysdeps/unix/sysv/linux/futimens.c
@@ -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);
+}
diff --git a/time/Versions b/time/Versions
index c5f6336..5614729 100644
--- a/time/Versions
+++ b/time/Versions
@@ -76,5 +76,6 @@ libc {
__clock_nanosleep64;
__timespec_get64;
__utimensat_time64;
+ __futimens64;
}
}
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=37cac0c3ae59f2dd46ed790d2534fedc2de574d9
commit 37cac0c3ae59f2dd46ed790d2534fedc2de574d9
Author: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
Date: Fri Sep 8 00:41:40 2017 +0200
Y2038: add function __utimensat_time64
diff --git a/io/utimensat.c b/io/utimensat.c
index 6b67a52..c535930 100644
--- a/io/utimensat.c
+++ b/io/utimensat.c
@@ -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)
diff --git a/sysdeps/unix/sysv/linux/utimensat.c b/sysdeps/unix/sysv/linux/utimensat.c
index 108d3bc..a0d1f5d 100644
--- a/sysdeps/unix/sysv/linux/utimensat.c
+++ b/sysdeps/unix/sysv/linux/utimensat.c
@@ -19,6 +19,7 @@
#include <errno.h>
#include <sys/stat.h>
#include <sysdep.h>
+#include <y2038-support.h>
/* Change the access time of FILE to TSP[0] and
@@ -34,3 +35,60 @@ utimensat (int fd, const char *file, const struct timespec tsp[2],
/* Avoid implicit array coercion in syscall macros. */
return INLINE_SYSCALL (utimensat, 4, fd, file, &tsp[0], flags);
}
+
+/* 64-bit time version */
+
+int
+__utimensat_time64 (int fd, const char *file, const struct __timespec64 tsp[2],
+ int flags)
+{
+ struct timespec ts32[2], *ts32p = NULL;
+/* Only try and use this syscall if defined by kernel */
+#ifdef __NR_utimensat_time64
+ struct __timespec64 ts64[2], *ts64p = NULL;
+ int res;
+#endif
+
+ if (file == NULL)
+ return INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL);
+
+/* Only try and use this syscall if defined by kernel */
+#ifdef __NR_utimensat_time64
+ if (__y2038_linux_support > 0)
+ {
+ if (tsp)
+ {
+ 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;
+ ts64p = ts64;
+ }
+
+ res = INLINE_SYSCALL (utimensat_time64, 4, fd, file, ts64p, flags);
+ if (res == 0 || errno != ENOSYS)
+ return res;
+ __y2038_linux_support = -1;
+ }
+#endif
+
+ if (tsp)
+ {
+ 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;
+ }
+ ts32p = ts32;
+ }
+
+ return INLINE_SYSCALL (utimensat, 4, fd, file, ts32p, flags);
+}
diff --git a/time/Versions b/time/Versions
index 1e4d81b..c5f6336 100644
--- a/time/Versions
+++ b/time/Versions
@@ -75,5 +75,6 @@ libc {
__clock_getres_time64;
__clock_nanosleep64;
__timespec_get64;
+ __utimensat_time64;
}
}
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=5162fdf671b157e76a5000c731d14a6827b7648d
commit 5162fdf671b157e76a5000c731d14a6827b7648d
Author: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
Date: Fri Sep 8 00:41:38 2017 +0200
Y2038: add function __timespec_get64
diff --git a/sysdeps/unix/sysv/linux/timespec_get.c b/sysdeps/unix/sysv/linux/timespec_get.c
index b14a302..4cc534a 100644
--- a/sysdeps/unix/sysv/linux/timespec_get.c
+++ b/sysdeps/unix/sysv/linux/timespec_get.c
@@ -44,3 +44,24 @@ timespec_get (struct timespec *ts, int base)
return base;
}
+
+/* 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 two conversions instead of zero right now.
+ */
+int
+__timespec_get64 (struct __timespec64 *ts, int base)
+{
+ struct timespec ts32;
+ int res = timespec_get (&ts32, base);
+ if (res != base)
+ {
+ timespec_to_timespec64(&ts32, ts);
+ }
+ return res;
+}
diff --git a/time/Versions b/time/Versions
index 5dfe984..1e4d81b 100644
--- a/time/Versions
+++ b/time/Versions
@@ -74,5 +74,6 @@ libc {
__clock_settime64;
__clock_getres_time64;
__clock_nanosleep64;
+ __timespec_get64;
}
}
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=1b3c14926f9d80aeb36d1d37ed4064497a79699c
commit 1b3c14926f9d80aeb36d1d37ed4064497a79699c
Author: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
Date: Fri Sep 8 00:41:37 2017 +0200
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.
diff --git a/include/time.h b/include/time.h
index d5bddeb..875f368 100644
--- a/include/time.h
+++ b/include/time.h
@@ -30,6 +30,9 @@ 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);
/* Now define the internal interfaces. */
struct tm;
diff --git a/sysdeps/unix/sysv/linux/clock_nanosleep.c b/sysdeps/unix/sysv/linux/clock_nanosleep.c
index 93d5d6e..6878da9 100644
--- a/sysdeps/unix/sysv/linux/clock_nanosleep.c
+++ b/sysdeps/unix/sysv/linux/clock_nanosleep.c
@@ -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;
+}
diff --git a/time/Versions b/time/Versions
index 52feca6..5dfe984 100644
--- a/time/Versions
+++ b/time/Versions
@@ -73,5 +73,6 @@ libc {
__clock_gettime64;
__clock_settime64;
__clock_getres_time64;
+ __clock_nanosleep64;
}
}
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=133c3ec5746730b7ad7dffd154bc7fa6deb2f9c1
commit 133c3ec5746730b7ad7dffd154bc7fa6deb2f9c1
Author: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
Date: Fri Sep 8 00:41:36 2017 +0200
Y2038: add function __clock_getres_time64
The Unix implementation uses 32-bit calls and converts to
64-bit time.
The Linux implementation uses the 64-bit time syscall if
available, otherwise it falls back to 32-bit syscall and
conversion.
This implementation depends on the clock_getres_time64
syscall being provided by the kernel at build as well
as run time.
diff --git a/include/time.h b/include/time.h
index 5a65822..d5bddeb 100644
--- a/include/time.h
+++ b/include/time.h
@@ -28,6 +28,8 @@ 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;
/* Now define the internal interfaces. */
struct tm;
diff --git a/sysdeps/posix/clock_getres.c b/sysdeps/posix/clock_getres.c
index e7924e0..6b0d5da 100644
--- a/sysdeps/posix/clock_getres.c
+++ b/sysdeps/posix/clock_getres.c
@@ -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)
diff --git a/sysdeps/unix/sysv/linux/clock_getres.c b/sysdeps/unix/sysv/linux/clock_getres.c
index 5d94f59..6b895f1 100644
--- a/sysdeps/unix/sysv/linux/clock_getres.c
+++ b/sysdeps/unix/sysv/linux/clock_getres.c
@@ -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>
diff --git a/time/Versions b/time/Versions
index fd83818..52feca6 100644
--- a/time/Versions
+++ b/time/Versions
@@ -65,4 +65,13 @@ libc {
GLIBC_2.16 {
timespec_get;
}
+ GLIBC_2.29 {
+ __ctime64; __ctime64_r;
+ __gmtime64; __gmtime64_r;
+ __localtime64; __localtime64_r;
+ __mktime64; __timelocal64_r; __timegm64;
+ __clock_gettime64;
+ __clock_settime64;
+ __clock_getres_time64;
+ }
}
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=f380b5e890f0cc2adfb38301b91880b4716b504f
commit f380b5e890f0cc2adfb38301b91880b4716b504f
Author: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
Date: Fri Sep 8 00:41:35 2017 +0200
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.
diff --git a/include/time.h b/include/time.h
index 9efd153..5a65822 100644
--- a/include/time.h
+++ b/include/time.h
@@ -26,6 +26,8 @@ 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;
/* Now define the internal interfaces. */
struct tm;
diff --git a/sysdeps/unix/clock_settime.c b/sysdeps/unix/clock_settime.c
index 38813ed..13abe31 100644
--- a/sysdeps/unix/clock_settime.c
+++ b/sysdeps/unix/clock_settime.c
@@ -68,9 +68,67 @@ 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)
{
int retval;
diff --git a/sysdeps/unix/sysv/linux/clock_settime.c b/sysdeps/unix/sysv/linux/clock_settime.c
index 5f3f22f..5913dd6 100644
--- a/sysdeps/unix/sysv/linux/clock_settime.c
+++ b/sysdeps/unix/sysv/linux/clock_settime.c
@@ -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>
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=d460b6f1b4bda9a80454be24a82c31ee0116aadb
commit d460b6f1b4bda9a80454be24a82c31ee0116aadb
Author: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
Date: Sun Apr 8 11:15:24 2018 +0200
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.
diff --git a/include/time.h b/include/time.h
index 162afa1..9efd153 100644
--- a/include/time.h
+++ b/include/time.h
@@ -24,6 +24,9 @@ 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;
+
/* Now define the internal interfaces. */
struct tm;
diff --git a/nptl/pthread_clock_gettime.c b/nptl/pthread_clock_gettime.c
index 6bc75cf..508821b 100644
--- a/nptl/pthread_clock_gettime.c
+++ b/nptl/pthread_clock_gettime.c
@@ -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
diff --git a/sysdeps/unix/clock_gettime.c b/sysdeps/unix/clock_gettime.c
index 96df78a..88c1955 100644
--- a/sysdeps/unix/clock_gettime.c
+++ b/sysdeps/unix/clock_gettime.c
@@ -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)
diff --git a/sysdeps/unix/sysv/linux/clock_gettime.c b/sysdeps/unix/sysv/linux/clock_gettime.c
index d837fa3..9920ffa 100644
--- a/sysdeps/unix/sysv/linux/clock_gettime.c
+++ b/sysdeps/unix/sysv/linux/clock_gettime.c
@@ -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>
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=158c8a3dbcae1ca80bdb708bb0bf8d1145d1b4aa
commit 158c8a3dbcae1ca80bdb708bb0bf8d1145d1b4aa
Author: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
Date: Fri Sep 8 00:41:33 2017 +0200
Y2038: add struct __timespec64
* 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
diff --git a/include/bits/types/struct_timespec64.h b/include/bits/types/struct_timespec64.h
new file mode 100644
index 0000000..4286968
--- /dev/null
+++ b/include/bits/types/struct_timespec64.h
@@ -0,0 +1 @@
+#include <time/bits/types/struct_timespec64.h>
diff --git a/include/time.h b/include/time.h
index 0c5c002..162afa1 100644
--- a/include/time.h
+++ b/include/time.h
@@ -145,5 +145,87 @@ fits_in_time_t (__time64_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
diff --git a/io/fcntl.h b/io/fcntl.h
index 6b0e9fa..db00642 100644
--- a/io/fcntl.h
+++ b/io/fcntl.h
@@ -73,6 +73,7 @@ typedef __pid_t pid_t;
/* For XPG all symbols from <sys/stat.h> should also be available. */
#ifdef __USE_XOPEN2K8
# include <bits/types/struct_timespec.h>
+# include <bits/types/struct_timespec64.h>
#endif
#if defined __USE_XOPEN || defined __USE_XOPEN2K8
# include <bits/stat.h>
diff --git a/io/sys/poll.h b/io/sys/poll.h
index 68f68ca..a4c2547 100644
--- a/io/sys/poll.h
+++ b/io/sys/poll.h
@@ -26,6 +26,7 @@
#ifdef __USE_GNU
# include <bits/types/__sigset_t.h>
# include <bits/types/struct_timespec.h>
+# include <bits/types/struct_timespec64.h>
#endif
diff --git a/io/sys/stat.h b/io/sys/stat.h
index 762c853..a1092f5 100644
--- a/io/sys/stat.h
+++ b/io/sys/stat.h
@@ -28,6 +28,7 @@
#ifdef __USE_XOPEN2K8
# include <bits/types/struct_timespec.h>
+# include <bits/types/struct_timespec64.h>
#endif
#if defined __USE_XOPEN || defined __USE_XOPEN2K
diff --git a/misc/sys/select.h b/misc/sys/select.h
index 6dd0c83..1285dc4 100644
--- a/misc/sys/select.h
+++ b/misc/sys/select.h
@@ -37,6 +37,7 @@
#include <bits/types/struct_timeval.h>
#ifdef __USE_XOPEN2K
# include <bits/types/struct_timespec.h>
+# include <bits/types/struct_timespec64.h>
#endif
#ifndef __suseconds_t_defined
diff --git a/posix/sched.h b/posix/sched.h
index 619b3b3..732c12b 100644
--- a/posix/sched.h
+++ b/posix/sched.h
@@ -30,6 +30,7 @@
#include <bits/types/time_t.h>
#include <bits/types/struct_timespec.h>
+#include <bits/types/struct_timespec64.h>
#ifndef __USE_XOPEN2K
# include <time.h>
#endif
diff --git a/resolv/netdb.h b/resolv/netdb.h
index 003800e..96f675d 100644
--- a/resolv/netdb.h
+++ b/resolv/netdb.h
@@ -35,6 +35,7 @@
#ifdef __USE_GNU
# include <bits/types/sigevent_t.h>
# include <bits/types/struct_timespec.h>
+# include <bits/types/struct_timespec64.h>
#endif
#include <bits/netdb.h>
diff --git a/rt/aio.h b/rt/aio.h
index c3a1f4b..ffda0de 100644
--- a/rt/aio.h
+++ b/rt/aio.h
@@ -27,6 +27,7 @@
#include <bits/types/sigevent_t.h>
#include <bits/sigevent-consts.h>
#include <bits/types/struct_timespec.h>
+#include <bits/types/struct_timespec64.h>
__BEGIN_DECLS
diff --git a/rt/mqueue.h b/rt/mqueue.h
index 5f354b4..39e2a24 100644
--- a/rt/mqueue.h
+++ b/rt/mqueue.h
@@ -23,6 +23,7 @@
#include <fcntl.h>
#include <bits/types/sigevent_t.h>
#include <bits/types/struct_timespec.h>
+#include <bits/types/struct_timespec64.h>
/* Get the definition of mqd_t and struct mq_attr. */
#include <bits/mqueue.h>
diff --git a/signal/signal.h b/signal/signal.h
index 87dc82a..caa2915 100644
--- a/signal/signal.h
+++ b/signal/signal.h
@@ -51,6 +51,7 @@ typedef __uid_t uid_t;
#ifdef __USE_POSIX199309
/* We need `struct timespec' later on. */
# include <bits/types/struct_timespec.h>
+# include <bits/types/struct_timespec64.h>
#endif
#if defined __USE_POSIX199309 || defined __USE_XOPEN_EXTENDED
diff --git a/sysdeps/nptl/pthread.h b/sysdeps/nptl/pthread.h
index df049ab..41b915e 100644
--- a/sysdeps/nptl/pthread.h
+++ b/sysdeps/nptl/pthread.h
@@ -27,6 +27,7 @@
#include <bits/setjmp.h>
#include <bits/wordsize.h>
#include <bits/types/struct_timespec.h>
+#include <bits/types/struct_timespec64.h>
/* Detach state. */
diff --git a/sysdeps/pthread/semaphore.h b/sysdeps/pthread/semaphore.h
index ff672eb..312433f 100644
--- a/sysdeps/pthread/semaphore.h
+++ b/sysdeps/pthread/semaphore.h
@@ -22,6 +22,7 @@
#include <sys/types.h>
#ifdef __USE_XOPEN2K
# include <bits/types/struct_timespec.h>
+# include <bits/types/struct_timespec64.h>
#endif
/* Get the definition for sem_t. */
diff --git a/sysdeps/unix/sysv/linux/hppa/pthread.h b/sysdeps/unix/sysv/linux/hppa/pthread.h
index 11a024d..e4640b3 100644
--- a/sysdeps/unix/sysv/linux/hppa/pthread.h
+++ b/sysdeps/unix/sysv/linux/hppa/pthread.h
@@ -27,6 +27,7 @@
#include <bits/setjmp.h>
#include <bits/wordsize.h>
#include <bits/types/struct_timespec.h>
+#include <bits/types/struct_timespec64.h>
/* Detach state. */
diff --git a/sysvipc/sys/sem.h b/sysvipc/sys/sem.h
index 200765b..b6a7eb2 100644
--- a/sysvipc/sys/sem.h
+++ b/sysvipc/sys/sem.h
@@ -31,6 +31,7 @@
#ifdef __USE_GNU
# include <bits/types/struct_timespec.h>
+# include <bits/types/struct_timespec64.h>
#endif
/* The following System V style IPC functions implement a semaphore
diff --git a/time/Makefile b/time/Makefile
index ec3e39d..61b8904 100644
--- a/time/Makefile
+++ b/time/Makefile
@@ -27,7 +27,7 @@ headers := time.h sys/time.h sys/timeb.h bits/time.h \
bits/types/struct_itimerspec.h \
bits/types/struct_timespec.h bits/types/struct_timeval.h \
bits/types/struct_tm.h bits/types/timer_t.h \
- bits/types/time_t.h
+ bits/types/time_t.h bits/types/struct_timespec64.h
routines := offtime asctime clock ctime ctime_r difftime \
gmtime localtime mktime time \
diff --git a/time/bits/types/struct_itimerspec.h b/time/bits/types/struct_itimerspec.h
index 17cc1ac..d36295a 100644
--- a/time/bits/types/struct_itimerspec.h
+++ b/time/bits/types/struct_itimerspec.h
@@ -3,6 +3,7 @@
#include <bits/types.h>
#include <bits/types/struct_timespec.h>
+#include <bits/types/struct_timespec64.h>
/* POSIX.1b structure for timer start values and intervals. */
struct itimerspec
diff --git a/time/bits/types/struct_timespec64.h b/time/bits/types/struct_timespec64.h
new file mode 100644
index 0000000..2221bed
--- /dev/null
+++ b/time/bits/types/struct_timespec64.h
@@ -0,0 +1,29 @@
+#ifndef __timespec64_defined
+#define __timespec64_defined 1
+
+#include <bits/types.h>
+#include <endian.h>
+
+/* Y2036proof structure for a time value. This is like a `struct timeval' but
+ has nanoseconds instead of microseconds. To keep tings Posix-ish, we keep
+ the nanoseconds field a signed long, but since Linux has a 64-bit signed int,
+ we pad it with a 32-bit int, which should always be 0.
+ Note that the public type has an anonymous bitfield as padding, so that
+ it cannot be written into (or read from). */
+#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
diff --git a/time/time.h b/time/time.h
index 4b55e34..c9282e2 100644
--- a/time/time.h
+++ b/time/time.h
@@ -40,6 +40,7 @@
#if defined __USE_POSIX199309 || defined __USE_ISOC11
# include <bits/types/struct_timespec.h>
+# include <bits/types/struct_timespec64.h>
#endif
#ifdef __USE_POSIX199309
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=33098a3d802138bc117ecc76d7e8920550d4f7fe
commit 33098a3d802138bc117ecc76d7e8920550d4f7fe
Author: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
Date: Sun Jun 10 10:47:12 2018 +0200
Y2038: provide kernel support indication
* New function __y2038_get_kernel_support() returns:
* 0 if the underlying kernel does not support Y2038 at all
* > 0 if the underlying kernel has some support for Y2038
* < 0 if the underlying kernel support for Y2038 is broken
* New function __y2038_set_kernel_support() allows indicating
a kernel's Y2038 support (or support failure)
* Default implementation (covering non-Linux kernels) always
returns 0 (no support).
diff --git a/misc/Makefile b/misc/Makefile
index 9a87e81..dd64bf2 100644
--- a/misc/Makefile
+++ b/misc/Makefile
@@ -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
generated += tst-error1.mtrace tst-error1-mem.out \
tst-allocate_once.mtrace tst-allocate_once-mem.out
diff --git a/misc/Versions b/misc/Versions
index 900e4ff..e242bf7 100644
--- a/misc/Versions
+++ b/misc/Versions
@@ -158,6 +158,10 @@ libc {
GLIBC_2.26 {
preadv2; preadv64v2; pwritev2; pwritev64v2;
}
+ GLIBC_2.29 {
+ __y2038_get_kernel_support;
+ __y2038_set_kernel_support;
+ }
GLIBC_PRIVATE {
__madvise;
__mktemp;
diff --git a/misc/y2038-support.c b/misc/y2038-support.c
new file mode 100644
index 0000000..e401cb1
--- /dev/null
+++ b/misc/y2038-support.c
@@ -0,0 +1,32 @@
+/* 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/>. */
+
+/* By default glibc assumes the underlying kernel does not support Y2038 */
+int __default_y2038_get_kernel_support (void)
+{
+ return 0;
+}
+weak_alias (__default_y2038_get_kernel_support, __y2038_get_kernel_support)
+
+/* By default glibc just ignores Y2038 support indication setting */
+int __default_y2038_set_kernel_support (int new with __attribute__ ((unused)))
+{
+ return 0;
+}
+weak_alias (__default_y2038_set_kernel_support, __y2038_set_kernel_support)
diff --git a/misc/y2038-support.h b/misc/y2038-support.h
new file mode 100644
index 0000000..ec7891b
--- /dev/null
+++ b/misc/y2038-support.h
@@ -0,0 +1,36 @@
+/* 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/>. */
+
+/* Get Y2038 kernel support.
+ * 0 means no suppport
+ * > 0 means (some) support
+ * < 0 means support is broken
+ */
+extern int __y2038_get_kernel_support (void);
+
+/* Set Y2038 support.
+ * 0 means no suppport
+ * > 0 means (some) support
+ * < 0 means support is broken
+ * Architectures should call this with new > 0 as soon as they know that
+ * their underlying kernel has Y2038 support.
+ * Implementations should call this with new < 0 as soon as they detect
+ * that a Y2038 kernel support failure occurred.
+ * As a courtesy, the previous support indication is returned. */
+extern int __y2038_set_kernel_support (int new);
diff --git a/sysdeps/unix/sysv/linux/y2038-support.c b/sysdeps/unix/sysv/linux/y2038-support.c
new file mode 100644
index 0000000..f325efc
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/y2038-support.c
@@ -0,0 +1,40 @@
+/* y2038 Linux 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/>. */
+
+/* By default the underlying Linux kernel is assumed not to support Y2038.
+ * Any Linux architecture may claim Y2038 kernel support by setting
+ * __y2038_linux_support.
+ */
+int __y2038_linux_support = 0;
+
+/* For Linux, Y2038 kernel support is determined by __y2038_linux_support */
+
+int __linux_y2038_get_kernel_support (void)
+{
+ return __y2038_linux_support;
+}
+strong_alias (__linux_y2038_get_kernel_support, __y2038_get_kernel_support)
+
+int __linux_y2038_set_kernel_support (int new)
+{
+ int previous = __y2038_linux_support;
+ __y2038_linux_support = new;
+ return previous;
+}
+strong_alias (__linux_y2038_set_kernel_support, __y2038_set_kernel_support)
diff --git a/sysdeps/unix/sysv/linux/y2038-support.h b/sysdeps/unix/sysv/linux/y2038-support.h
new file mode 100644
index 0000000..7dcbe0b
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/y2038-support.h
@@ -0,0 +1,30 @@
+/* y2038 Linux 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/>. */
+
+/* Indicates Y2038 support.
+ * 0 means no suppport
+ * > 0 means (some) support
+ * < 0 means support is broken
+ * Can be read directly from within libc linux-related files.
+ * Can be written non-zero to indicate support or lack thereof.
+ */
+extern int __y2038_linux_support;
+
+/* As a fallback, provide generic Y2038 support indication */
+#include <misc/y2038-support.h>
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=f03fd63f9b4dca5b9c70cc2518e3eeaa20529ec0
commit f03fd63f9b4dca5b9c70cc2518e3eeaa20529ec0
Author: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
Date: Wed Mar 29 11:57:53 2017 +0200
Y2038: add function __difftime64
* __difftime: provide a 64-bit-time version (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.
diff --git a/include/time.h b/include/time.h
index 62c0e11..0c5c002 100644
--- a/include/time.h
+++ b/include/time.h
@@ -125,6 +125,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);
/* Use in the clock_* functions. Size of the field representing the
diff --git a/time/difftime.c b/time/difftime.c
index 7c5dd98..e3a4e57 100644
--- a/time/difftime.c
+++ b/time/difftime.c
@@ -31,9 +31,9 @@
time_t is known to be an integer type. */
static double
-subtract (time_t time1, time_t time0)
+subtract (__time64_t time1, __time64_t time0)
{
- if (! TYPE_SIGNED (time_t))
+ if (! TYPE_SIGNED (__time64_t))
return time1 - time0;
else
{
@@ -76,9 +76,9 @@ subtract (time_t time1, time_t time0)
1 is unsigned in C, so it need not be compared to zero. */
uintmax_t hdt = dt / 2;
- time_t ht1 = time1 / 2;
- time_t ht0 = time0 / 2;
- time_t dht = ht1 - ht0;
+ __time64_t ht1 = time1 / 2;
+ __time64_t ht0 = time0 / 2;
+ __time64_t dht = ht1 - ht0;
if (2 < dht - hdt + 1)
{
@@ -99,18 +99,18 @@ subtract (time_t time1, time_t time0)
/* Return the difference between TIME1 and TIME0. */
double
-__difftime (time_t time1, time_t time0)
+__difftime64 (__time64_t time1, __time64_t time0)
{
/* Convert to double and then subtract if no double-rounding error could
result. */
- if (TYPE_BITS (time_t) <= DBL_MANT_DIG
- || (TYPE_FLOATING (time_t) && sizeof (time_t) < sizeof (long double)))
+ if (TYPE_BITS (__time64_t) <= DBL_MANT_DIG
+ || (TYPE_FLOATING (__time64_t) && sizeof (__time64_t) < sizeof (long double)))
return (double) time1 - (double) time0;
/* Likewise for long double. */
- if (TYPE_BITS (time_t) <= LDBL_MANT_DIG || TYPE_FLOATING (time_t))
+ if (TYPE_BITS (__time64_t) <= LDBL_MANT_DIG || TYPE_FLOATING (__time64_t))
return (long double) time1 - (long double) time0;
/* Subtract the smaller integer from the larger, convert the difference to
@@ -118,4 +118,17 @@ __difftime (time_t time1, time_t time0)
return time1 < time0 ? - subtract (time0, time1) : subtract (time1, time0);
}
+
+/* Provide a 32-bit wrapper if needed */
+
+#if __TIMESIZE != 64
+
+double
+__difftime (time_t time1, time_t time0)
+{
+ return __difftime64 (time1, time0);
+}
+
+#endif
+
strong_alias (__difftime, difftime)
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=680ed897cdb1095aa035f30e08467f77ea1d3594
commit 680ed897cdb1095aa035f30e08467f77ea1d3594
Author: Paul Eggert <eggert@cs.ucla.edu>
Date: Fri Aug 31 23:45:31 2018 -0700
Add support for __time64_t to mktime, timegm
* include/time.h, time/mktime.c, time/timegm.c:
Change externally-visible names to their __xxx64yyy version.
* include/time.h (fits_in_time_t): New static function.
* time/mktime.c (mktime) [_LIBC]: New wrapper function.
* time/timegm.c (timegm) [_LIBC]: New wrapper function.
diff --git a/include/time.h b/include/time.h
index c2b43ad..62c0e11 100644
--- a/include/time.h
+++ b/include/time.h
@@ -50,13 +50,13 @@ extern void __tzset_parse_tz (const char *tz) attribute_hidden;
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
@@ -131,5 +131,13 @@ 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;
+}
+
#endif
#endif
diff --git a/time/mktime.c b/time/mktime.c
index 4ff7490..d8bbae4 100644
--- a/time/mktime.c
+++ b/time/mktime.c
@@ -51,6 +51,7 @@
#include <time.h>
+#include <errno.h>
#include <limits.h>
#include <stdbool.h>
#include <stdlib.h>
@@ -125,11 +126,11 @@ my_tzset (void)
to be subtracted from each other, and sometimes with an offset
added to them, without worrying about overflow.
- Much of the code uses long_int to represent time_t values, to
- lessen the hassle of dealing with platforms where time_t is
- unsigned, and because long_int should suffice to represent all
- time_t values that mktime can generate even on platforms where
- time_t is excessively wide. */
+ Much of the code uses long_int to represent __time64_t values, to
+ lessen the hassle of dealing with Gnulib-using platforms where
+ __time64_t is time_t and time_t is unsigned, and because long_int
+ should suffice to represent all __time64_t values that mktime can
+ generate even on platforms where __time64_t is excessively wide. */
#if INT_MAX <= LONG_MAX / 3 / 366 / 24 / 60 / 60
typedef long int long_int;
@@ -157,16 +158,17 @@ shr (long_int a, int b)
: a / (one << b) - (a % (one << b) < 0));
}
-/* Bounds for the intersection of time_t and long_int. */
+/* Bounds for the intersection of __time64_t and long_int. */
static long_int const mktime_min
- = ((TYPE_SIGNED (time_t) && TYPE_MINIMUM (time_t) < TYPE_MINIMUM (long_int))
- ? TYPE_MINIMUM (long_int) : TYPE_MINIMUM (time_t));
+ = ((TYPE_SIGNED (__time64_t)
+ && TYPE_MINIMUM (__time64_t) < TYPE_MINIMUM (long_int))
+ ? TYPE_MINIMUM (long_int) : TYPE_MINIMUM (__time64_t));
static long_int const mktime_max
- = (TYPE_MAXIMUM (long_int) < TYPE_MAXIMUM (time_t)
- ? TYPE_MAXIMUM (long_int) : TYPE_MAXIMUM (time_t));
+ = (TYPE_MAXIMUM (long_int) < TYPE_MAXIMUM (__time64_t)
+ ? TYPE_MAXIMUM (long_int) : TYPE_MAXIMUM (__time64_t));
-verify (TYPE_IS_INTEGER (time_t));
+verify (TYPE_IS_INTEGER (__time64_t));
#define EPOCH_YEAR 1970
#define TM_YEAR_BASE 1900
@@ -247,11 +249,11 @@ long_int_avg (long_int a, long_int b)
return shr (a, 1) + shr (b, 1) + ((a | b) & 1);
}
-/* Return a time_t value corresponding to (YEAR-YDAY HOUR:MIN:SEC),
+/* Return a __time64_t value corresponding to (YEAR-YDAY HOUR:MIN:SEC),
assuming that T corresponds to *TP and that no clock adjustments
occurred between *TP and the desired time.
Although T and the returned value are of type long_int,
- they represent time_t values and must be in time_t range.
+ they represent __time64_t values and must be in __time64_t range.
If TP is null, return a value not equal to T; this avoids false matches.
YEAR and YDAY must not be so large that multiplying them by three times the
number of seconds in a year (or day, respectively) would overflow long_int.
@@ -282,22 +284,22 @@ guess_time_tm (long_int year, long_int yday, int hour, int min, int sec,
}
/* Use CONVERT to convert T to a struct tm value in *TM. T must be in
- range for time_t. Return TM if successful, NULL if T is out of
+ range for __time64_t. Return TM if successful, NULL if T is out of
range for CONVERT. */
static struct tm *
-convert_time (struct tm *(*convert) (const time_t *, struct tm *),
+convert_time (struct tm *(*convert) (const __time64_t *, struct tm *),
long_int t, struct tm *tm)
{
- time_t x = t;
+ __time64_t x = t;
return convert (&x, tm);
}
/* Use CONVERT to convert *T to a broken down time in *TP.
If *T is out of range for conversion, adjust it so that
it is the nearest in-range value and then convert that.
- A value is in range if it fits in both time_t and long_int. */
+ A value is in range if it fits in both __time64_t and long_int. */
static struct tm *
-ranged_convert (struct tm *(*convert) (const time_t *, struct tm *),
+ranged_convert (struct tm *(*convert) (const __time64_t *, struct tm *),
long_int *t, struct tm *tp)
{
struct tm *r;
@@ -339,15 +341,15 @@ ranged_convert (struct tm *(*convert) (const time_t *, struct tm *),
}
-/* Convert *TP to a time_t value, inverting
+/* Convert *TP to a __time64_t value, inverting
the monotonic and mostly-unit-linear conversion function CONVERT.
Use *OFFSET to keep track of a guess at the offset of the result,
compared to what the result would be for UTC without leap seconds.
If *OFFSET's guess is correct, only one CONVERT call is needed.
This function is external because it is used also by timegm.c. */
-time_t
+__time64_t
__mktime_internal (struct tm *tp,
- struct tm *(*convert) (const time_t *, struct tm *),
+ struct tm *(*convert) (const __time64_t *, struct tm *),
mktime_offset_t *offset)
{
long_int t, gt, t0, t1, t2, dt;
@@ -518,9 +520,9 @@ __mktime_internal (struct tm *tp,
#if defined _LIBC || NEED_MKTIME_WORKING || NEED_MKTIME_WINDOWS
-/* Convert *TP to a time_t value. */
-time_t
-mktime (struct tm *tp)
+/* Convert *TP to a __time64_t value. */
+__time64_t
+__mktime64 (struct tm *tp)
{
/* POSIX.1 8.1.1 requires that whenever mktime() is called, the
time zone names contained in the external variable 'tzname' shall
@@ -529,7 +531,7 @@ mktime (struct tm *tp)
# if defined __LIBC || NEED_MKTIME_WORKING
static mktime_offset_t localtime_offset;
- return __mktime_internal (tp, __localtime_r, &localtime_offset);
+ return __mktime_internal (tp, __localtime64_r, &localtime_offset);
# else
# undef mktime
return mktime (tp);
@@ -537,8 +539,22 @@ mktime (struct tm *tp)
}
#endif /* _LIBC || NEED_MKTIME_WORKING || NEED_MKTIME_WINDOWS */
+#ifdef _LIBC
+/* The 32-bit-time wrapper. */
+time_t
+mktime (struct tm *tp)
+{
+ __time64_t t64 = __mktime64 (tp);
+ if (fits_in_time_t (t64))
+ return t64;
+ __set_errno (EOVERFLOW);
+ return -1;
+}
+#endif
+
#ifdef weak_alias
weak_alias (mktime, timelocal)
+weak_alias (__mktime64, __timelocal64)
#endif
#ifdef _LIBC
diff --git a/time/timegm.c b/time/timegm.c
index 229fff2..99b5436 100644
--- a/time/timegm.c
+++ b/time/timegm.c
@@ -24,11 +24,26 @@
#include <time.h>
#include "mktime-internal.h"
+#include <errno.h>
+
+__time64_t
+__timegm64 (struct tm *tmp)
+{
+ static long int gmtime_offset;
+ tmp->tm_isdst = 0;
+ return __mktime_internal (tmp, __gmtime64_r, &gmtime_offset);
+}
+
+#ifdef _LIBC
time_t
timegm (struct tm *tmp)
{
- static mktime_offset_t gmtime_offset;
- tmp->tm_isdst = 0;
- return __mktime_internal (tmp, __gmtime_r, &gmtime_offset);
+ __time64_t t64 = __timegm64 (tmp);
+ if (fits_in_time_t (t64))
+ return t64;
+ __set_errno (EOVERFLOW);
+ return -1;
}
+
+#endif
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=32bc55ef9a4cff8c7a8c0825421fd332d570b198
commit 32bc55ef9a4cff8c7a8c0825421fd332d570b198
Author: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
Date: Mon Jun 18 21:14:43 2018 +0200
Y2038: make __tz_convert compatible with 64-bit-time
* __tz_compute: Pass timer as a __time64_t rather than time_t.
* __offtime: Pass __timer as a __time64_t value rather than
a const time_t pointer.
* __tz_convert: Likewise.
* localtime: provide a 64-bit time version and make the 32-bit
time version a wrapper of it.
* localtime_r: Likewise.
* ctime: Likewise.
* ctime_r: Likewise.
* gmtime: Likewise.
* gmtime_r: Likewise.
diff --git a/include/time.h b/include/time.h
index 082b574..c2b43ad 100644
--- a/include/time.h
+++ b/include/time.h
@@ -47,7 +47,7 @@ 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
@@ -57,18 +57,47 @@ extern time_t __mktime_internal (struct tm *__tp,
struct tm *(*__func) (const time_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 __localtime64 localtime
+#else
+extern struct tm *__localtime64 (const __time64_t *__timer);
+#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;
@@ -77,8 +106,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);
diff --git a/time/ctime.c b/time/ctime.c
index 1222614..286c6b5 100644
--- a/time/ctime.c
+++ b/time/ctime.c
@@ -20,9 +20,22 @@
/* Return a string as returned by asctime which
is the representation of *T in that form. */
char *
-ctime (const time_t *t)
+__ctime64 (const __time64_t *t)
{
/* The C Standard says ctime (t) is equivalent to asctime (localtime (t)).
In particular, ctime and asctime must yield the same pointer. */
- return asctime (localtime (t));
+ return asctime (__localtime64 (t));
}
+
+/* Provide a 32-bit wrapper if needed */
+
+#if __TIMESIZE != 64
+
+char *
+ctime (const time_t *t)
+{
+ __time64_t t64 = *t;
+ return __ctime64 (&t64);
+}
+
+#endif
diff --git a/time/ctime_r.c b/time/ctime_r.c
index c111146..8408959 100644
--- a/time/ctime_r.c
+++ b/time/ctime_r.c
@@ -22,8 +22,21 @@
/* Return a string as returned by asctime which is the representation
of *T in that form. Reentrant version. */
char *
-ctime_r (const time_t *t, char *buf)
+__ctime64_r (const __time64_t *t, char *buf)
{
struct tm tm;
- return __asctime_r (__localtime_r (t, &tm), buf);
+ return __asctime_r (__localtime64_r (t, &tm), buf);
}
+
+/* Provide a 32-bit wrapper if needed */
+
+#if __TIMESIZE != 64
+
+char *
+ctime_r (const time_t *t, char *buf)
+{
+ __time64_t t64 = *t;
+ return __ctime64_r (&t64, buf);
+}
+
+#endif
diff --git a/time/gmtime.c b/time/gmtime.c
index dc33b3e..d485a38 100644
--- a/time/gmtime.c
+++ b/time/gmtime.c
@@ -18,20 +18,49 @@
#include <time.h>
-/* Return the `struct tm' representation of *T in UTC,
+/* Return the `struct tm' representation of T in UTC,
using *TP to store the result. */
struct tm *
+__gmtime64_r (const __time64_t *t, struct tm *tp)
+{
+ return __tz_convert (*t, 0, tp);
+}
+
+/* Provide a 32-bit wrapper if needed */
+
+#if __TIMESIZE != 64
+
+struct tm *
__gmtime_r (const time_t *t, struct tm *tp)
{
- return __tz_convert (t, 0, tp);
+ __time64_t t64 = *t;
+ return __gmtime64_r (&t64, tp);
}
+
+#endif
+
+/* This always works because either __TIMESIZE != 64 and __gmtime_r exists
+ or __TIMESIZE == 64 and the definition of __gmtime64_r above actually
+ defined __gmtime_r. */
libc_hidden_def (__gmtime_r)
weak_alias (__gmtime_r, gmtime_r)
+/* Return the `struct tm' representation of 64-bit-time *T in UTC. */
+struct tm *
+__gmtime64 (const __time64_t *t)
+{
+ return __tz_convert (*t, 0, &_tmbuf);
+}
+
+/* Provide a 32-bit wrapper if needed */
+
+#if __TIMESIZE != 64
-/* Return the `struct tm' representation of *T in UTC. */
struct tm *
gmtime (const time_t *t)
{
- return __tz_convert (t, 0, &_tmbuf);
+ __time64_t t64 = *t;
+ return __gmtime64 (&t64);
}
+
+#endif
diff --git a/time/localtime.c b/time/localtime.c
index 8684a8a..e36d6cc 100644
--- a/time/localtime.c
+++ b/time/localtime.c
@@ -21,21 +21,49 @@
/* The C Standard says that localtime and gmtime return the same pointer. */
struct tm _tmbuf;
-
/* Return the `struct tm' representation of *T in local time,
using *TP to store the result. */
struct tm *
+__localtime64_r (const __time64_t *t, struct tm *tp)
+{
+ return __tz_convert (*t, 1, tp);
+}
+
+/* Provide a 32-bit wrapper if needed */
+
+#if __TIMESIZE != 64
+
+struct tm *
__localtime_r (const time_t *t, struct tm *tp)
{
- return __tz_convert (t, 1, tp);
+ __time64_t t64 = *t;
+ return __localtime64_r (&t64, tp);
}
-weak_alias (__localtime_r, localtime_r)
+#endif
+
+/* This always works because either __TIMESIZE != 64 and __localtime_r
+ exists or __TIMESIZE == 64 and the definition of __localtime64_r above
+ actually defined __localtime_r. */
+weak_alias (__localtime_r, localtime_r)
/* Return the `struct tm' representation of *T in local time. */
struct tm *
+__localtime64 (const __time64_t *t)
+{
+ return __tz_convert (*t, 1, &_tmbuf);
+}
+
+/* Provide a 32-bit wrapper if needed */
+
+#if __TIMESIZE != 64
+
+struct tm *
localtime (const time_t *t)
{
- return __tz_convert (t, 1, &_tmbuf);
+ __time64_t t64 = *t;
+ return __localtime64 (&t64);
}
libc_hidden_def (localtime)
+
+#endif
diff --git a/time/offtime.c b/time/offtime.c
index 04c4838..3309fcd 100644
--- a/time/offtime.c
+++ b/time/offtime.c
@@ -21,18 +21,18 @@
#define SECS_PER_HOUR (60 * 60)
#define SECS_PER_DAY (SECS_PER_HOUR * 24)
-/* Compute the `struct tm' representation of *T,
+/* 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. */
int
-__offtime (const time_t *t, long int offset, struct tm *tp)
+__offtime (__time64_t t, long int offset, struct tm *tp)
{
- time_t days, rem, y;
+ __time64_t days, rem, y;
const unsigned short int *ip;
- days = *t / SECS_PER_DAY;
- rem = *t % SECS_PER_DAY;
+ days = t / SECS_PER_DAY;
+ rem = t % SECS_PER_DAY;
rem += offset;
while (rem < 0)
{
@@ -60,7 +60,7 @@ __offtime (const time_t *t, long int offset, struct tm *tp)
while (days < 0 || days >= (__isleap (y) ? 366 : 365))
{
/* Guess a corrected year, assuming 365 days per year. */
- time_t yg = y + days / 365 - (days % 365 < 0);
+ __time64_t yg = y + days / 365 - (days % 365 < 0);
/* Adjust DAYS and Y to match the guessed year. */
days -= ((yg - y) * 365
diff --git a/time/tzfile.c b/time/tzfile.c
index 844a68d..3920525 100644
--- a/time/tzfile.c
+++ b/time/tzfile.c
@@ -633,16 +633,10 @@ __tzfile_compute (__time64_t timer, int use_localtime,
/* Convert to broken down structure. If this fails do not
use the string. */
- {
- time_t truncated = timer;
- if (__glibc_unlikely (truncated != timer
- || ! __offtime (&truncated, 0, tp)))
- goto use_last;
- }
-
- /* Use the rules from the TZ string to compute the change.
- timer fits into time_t due to the truncation check
- above. */
+ if (__glibc_unlikely (! __offtime (timer, 0, tp)))
+ goto use_last;
+
+ /* Use the rules from the TZ string to compute the change. */
__tz_compute (timer, tp, 1);
/* If tzspec comes from posixrules loaded by __tzfile_default,
diff --git a/time/tzset.c b/time/tzset.c
index a828b9f..834cc3c 100644
--- a/time/tzset.c
+++ b/time/tzset.c
@@ -16,7 +16,6 @@
<http://www.gnu.org/licenses/>. */
#include <ctype.h>
-#include <errno.h>
#include <libc-lock.h>
#include <stdbool.h>
#include <stddef.h>
@@ -27,7 +26,7 @@
#include <timezone/tzfile.h>
-#define SECSPERDAY ((time_t) 86400)
+#define SECSPERDAY ((__time64_t) 86400)
char *__tzname[2] = { (char *) "GMT", (char *) "GMT" };
int __daylight = 0;
@@ -55,7 +54,7 @@ typedef struct
/* We cache the computed time of change for a
given year so we don't have to recompute it. */
- time_t change; /* When to change to this zone. */
+ __time64_t change; /* When to change to this zone. */
int computed_for; /* Year above is computed for. */
} tz_rule;
@@ -416,7 +415,7 @@ tzset_internal (int always)
tz_rules[0].name = tz_rules[1].name = "UTC";
if (J0 != 0)
tz_rules[0].type = tz_rules[1].type = J0;
- tz_rules[0].change = tz_rules[1].change = (time_t) -1;
+ tz_rules[0].change = tz_rules[1].change = -1;
update_vars ();
return;
}
@@ -424,13 +423,13 @@ tzset_internal (int always)
__tzset_parse_tz (tz);
}
-/* Figure out the exact time (as a time_t) in YEAR
+/* Figure out the exact time (as a __time64_t) in YEAR
when the change described by RULE will occur and
put it in RULE->change, saving YEAR in RULE->computed_for. */
static void
compute_change (tz_rule *rule, int year)
{
- time_t t;
+ __time64_t t;
if (year != -1 && rule->computed_for == year)
/* Operations on times in 2 BC will be slower. Oh well. */
@@ -516,7 +515,7 @@ compute_change (tz_rule *rule, int year)
/* Figure out the correct timezone for TM and set `__tzname',
`__timezone', and `__daylight' accordingly. */
void
-__tz_compute (time_t timer, struct tm *tm, int use_localtime)
+__tz_compute (__time64_t timer, struct tm *tm, int use_localtime)
{
compute_change (&tz_rules[0], 1900 + tm->tm_year);
compute_change (&tz_rules[1], 1900 + tm->tm_year);
@@ -562,20 +561,14 @@ __tzset (void)
}
weak_alias (__tzset, tzset)
-/* Return the `struct tm' representation of *TIMER in the local timezone.
+/* Return the `struct tm' representation of TIMER in the local timezone.
Use local time if USE_LOCALTIME is nonzero, UTC otherwise. */
struct tm *
-__tz_convert (const time_t *timer, int use_localtime, struct tm *tp)
+__tz_convert (__time64_t timer, int use_localtime, struct tm *tp)
{
long int leap_correction;
int leap_extra_secs;
- if (timer == NULL)
- {
- __set_errno (EINVAL);
- return NULL;
- }
-
__libc_lock_lock (tzset_lock);
/* Update internal database according to current TZ setting.
@@ -584,14 +577,14 @@ __tz_convert (const time_t *timer, int use_localtime, struct tm *tp)
tzset_internal (tp == &_tmbuf && use_localtime);
if (__use_tzfile)
- __tzfile_compute (*timer, use_localtime, &leap_correction,
+ __tzfile_compute (timer, use_localtime, &leap_correction,
&leap_extra_secs, tp);
else
{
if (! __offtime (timer, 0, tp))
tp = NULL;
else
- __tz_compute (*timer, tp, use_localtime);
+ __tz_compute (timer, tp, use_localtime);
leap_correction = 0L;
leap_extra_secs = 0;
}
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=1575bcfed3b040afb0284b4c4254e0f506da4746
commit 1575bcfed3b040afb0284b4c4254e0f506da4746
Author: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
Date: Mon Jun 18 21:14:42 2018 +0200
Y2038: Add 64-bit time for all architectures
* Add macro __TIMESIZE equal to the bit size of time_t.
It equals the architecture __WORDSIZE except for x32
where it equals 64.
* Add type __time64_t which is always 64-bit. On 64-bit
architectures and on x32, it is #defined as time_t.
On other architectures, it has its own definition.
* Replace all occurrences of internal_time_t with
__time64_t.
diff --git a/bits/time64.h b/bits/time64.h
new file mode 100644
index 0000000..a524588
--- /dev/null
+++ b/bits/time64.h
@@ -0,0 +1,37 @@
+/* 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
+
+/* See <bits/types.h> for the meaning of these macros. This file exists so
+ that <bits/types.h> need not vary across different GNU platforms. */
+
+#if __TIMESIZE == 64
+/* If we already have 64-bit time then use it. */
+# define __TIME64_T_TYPE __TIME_T_TYPE
+#else
+/* Define a 64-bit type alongsize the 32-bit one. */
+# define __TIME64_T_TYPE __SQUAD_TYPE
+#endif
+
+#endif /* bits/time64.h */
diff --git a/bits/timesize.h b/bits/timesize.h
new file mode 100644
index 0000000..d8a7804
--- /dev/null
+++ b/bits/timesize.h
@@ -0,0 +1,22 @@
+/* Bit size of the time_t type at glibc build time, general case.
+ 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 <bits/wordsize.h>
+
+/* Size in bits of the 'time_t' type. */
+#define __TIMESIZE __WORDSIZE
diff --git a/include/time.h b/include/time.h
index e30c5fc..082b574 100644
--- a/include/time.h
+++ b/include/time.h
@@ -3,6 +3,7 @@
#ifndef _ISOMAC
# include <bits/types/locale_t.h>
+# include <stdbool.h>
extern __typeof (strftime_l) __strftime_l;
libc_hidden_proto (__strftime_l)
@@ -26,10 +27,6 @@ extern __typeof (clock_getcpuclockid) __clock_getcpuclockid;
/* 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,7 +40,7 @@ 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,
@@ -101,7 +98,6 @@ extern char * __strptime_internal (const char *rp, const char *fmt,
extern double __difftime (time_t time1, time_t time0);
-
/* Use in the clock_* functions. Size of the field representing the
actual clock ID. */
#define CLOCK_IDFIELD_SIZE 3
diff --git a/posix/bits/types.h b/posix/bits/types.h
index 5e22ce4..f363381 100644
--- a/posix/bits/types.h
+++ b/posix/bits/types.h
@@ -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 (_TIME_BITS==64). */
+#endif
+
#undef __STD_TYPE
#endif /* bits/types.h */
diff --git a/stdlib/Makefile b/stdlib/Makefile
index 01194bb..bdb0a18 100644
--- a/stdlib/Makefile
+++ b/stdlib/Makefile
@@ -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 bits/timesize.h \
routines := \
atof atoi atol atoll \
diff --git a/sysdeps/unix/sysv/linux/x86/bits/time64.h b/sysdeps/unix/sysv/linux/x86/bits/time64.h
new file mode 100644
index 0000000..a5e97a0
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/x86/bits/time64.h
@@ -0,0 +1,40 @@
+/* bits/time64.h -- underlying types for __time64_t. Linux/x86-64 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
+
+/* See <bits/types.h> for the meaning of these macros. This file exists so
+ that <bits/types.h> need not vary across different GNU platforms. */
+
+#if defined __x86_64__ && defined __ILP32__
+/* For x32, time is 64-bit even though word size is 32-bit. */
+# define __TIME64_T_TYPE __SQUAD_TYPE
+#elif __TIMESIZE == 64
+/* If we already have 64-bit time then use it. */
+# define __TIME64_T_TYPE __TIME_T_TYPE
+#else
+/* Define a 64-bit type alongsize the 32-bit one. */
+# define __TIME64_T_TYPE __SQUAD_TYPE
+#endif
+
+#endif /* bits/time64.h */
diff --git a/sysdeps/unix/sysv/linux/x86/bits/timesize.h b/sysdeps/unix/sysv/linux/x86/bits/timesize.h
new file mode 100644
index 0000000..8b88ab8
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/x86/bits/timesize.h
@@ -0,0 +1,25 @@
+/* Bit size of the time_t type at glibc build time, x86-64 and x32 case.
+ 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/>. */
+
+#if defined __x86_64__ && defined __ILP32__
+/* For x32, time is 64-bit even though word size is 32-bit. */
+# define __TIMESIZE 64
+#else
+/* For others, time size is word size. */
+# define __TIMESIZE __WORDSIZE
+#endif
diff --git a/time/tzfile.c b/time/tzfile.c
index 72ef75f..844a68d 100644
--- a/time/tzfile.c
+++ b/time/tzfile.c
@@ -44,12 +44,12 @@ struct ttinfo
struct leap
{
- internal_time_t transition; /* Time the transition takes effect. */
+ __time64_t transition; /* Time the transition takes effect. */
long int change; /* Seconds of correction to apply. */
};
static size_t num_transitions;
-libc_freeres_ptr (static internal_time_t *transitions);
+libc_freeres_ptr (static __time64_t *transitions);
static unsigned char *type_idxs;
static size_t num_types;
static struct ttinfo *types;
@@ -113,8 +113,8 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
size_t tzspec_len;
char *new = NULL;
- _Static_assert (sizeof (internal_time_t) == 8,
- "internal_time_t must be eight bytes");
+ _Static_assert (sizeof (__time64_t) == 8,
+ "__time64_t must be eight bytes");
__use_tzfile = 0;
@@ -217,9 +217,9 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
if (__builtin_expect (num_transitions
> ((SIZE_MAX - (__alignof__ (struct ttinfo) - 1))
- / (sizeof (internal_time_t) + 1)), 0))
+ / (sizeof (__time64_t) + 1)), 0))
goto lose;
- total_size = num_transitions * (sizeof (internal_time_t) + 1);
+ total_size = num_transitions * (sizeof (__time64_t) + 1);
total_size = ((total_size + __alignof__ (struct ttinfo) - 1)
& ~(__alignof__ (struct ttinfo) - 1));
types_idx = total_size;
@@ -276,7 +276,7 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
goto lose;
type_idxs = (unsigned char *) transitions + (num_transitions
- * sizeof (internal_time_t));
+ * sizeof (__time64_t));
types = (struct ttinfo *) ((char *) transitions + types_idx);
zone_names = (char *) types + num_types * sizeof (struct ttinfo);
leaps = (struct leap *) ((char *) transitions + leaps_idx);
@@ -578,7 +578,7 @@ __tzfile_default (const char *std, const char *dst,
}
void
-__tzfile_compute (internal_time_t timer, int use_localtime,
+__tzfile_compute (__time64_t timer, int use_localtime,
long int *leap_correct, int *leap_hit,
struct tm *tp)
{
@@ -667,7 +667,7 @@ __tzfile_compute (internal_time_t timer, int use_localtime,
initial search spot from it. Half of a gregorian year
has on average 365.2425 * 86400 / 2 = 15778476 seconds.
The value i can be truncated if size_t is smaller than
- internal_time_t, but this is harmless because it is just
+ __time64_t, but this is harmless because it is just
a guess. */
i = (transitions[num_transitions - 1] - timer) / 15778476;
if (i < num_transitions)
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=63aaf075fff33777b3e3013a5bd90d140f073a8b
commit 63aaf075fff33777b3e3013a5bd90d140f073a8b
Author: Paul Eggert <eggert@cs.ucla.edu>
Date: Sun Sep 9 09:06:25 2018 -0700
Fix mktime localtime offset confusion
[BZ #23603]
* include/time.h (__mktime_internal): The localtime offset is now
of type long int instead of time_t. This is the longstanding type
in glibc, and it is more than enough to represent difference
between localtime and gmtime even if it is 32 bits and time_t is
64. Changing it now will let us avoid an unnecessary change when
time_t is widened to 64 bits on 32-bit platforms.
* time/mktime-internal.h (mktime_offset_t): Now long int.
diff --git a/include/time.h b/include/time.h
index 23d2580..e30c5fc 100644
--- a/include/time.h
+++ b/include/time.h
@@ -55,11 +55,11 @@ extern void __tz_compute (time_t timer, struct tm *tm, int use_localtime)
/* 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
- by FUNC. Keep track of next guess for time_t offset in *OFFSET. */
+ 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 *),
- time_t *__offset) attribute_hidden;
+ long int *__offset) attribute_hidden;
extern struct tm *__localtime_r (const time_t *__timer,
struct tm *__tp) attribute_hidden;
diff --git a/time/mktime-internal.h b/time/mktime-internal.h
index ba1d9c7..cfd9127 100644
--- a/time/mktime-internal.h
+++ b/time/mktime-internal.h
@@ -1 +1 @@
-typedef time_t mktime_offset_t;
+typedef long int mktime_offset_t;
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=519466d3616c5af128997c96d02c112b8b47b16b
commit 519466d3616c5af128997c96d02c112b8b47b16b
Author: Paul Eggert <eggert@cs.ucla.edu>
Date: Sun Sep 9 09:06:24 2018 -0700
Merge mktime, timegm from upstream Gnulib
[BZ #23603][BZ #16346]
This fixes some obscure problems with integer overflow.
Although it looks scary, it is almost all a byte-for-byte copy
from Gnulib, and the Gnulib code has been tested reasonably well.
* include/intprops.h: New file, copied from Gnulib.
* include/verify.h, time/mktime-internal.h:
New tiny files, simplified from Gnulib.
* time/mktime.c: Copy from Gnulib. This has the following changes:
Do not include config.h if DEBUG_MKTIME is nonzero.
Include stdbool.h, intprops.h, verify.h.
Include string.h only if needed.
Include stdlib.h on MS-Windows.
Include mktime-internal.h.
(DEBUG_MKTIME): Default to 0, and simplify later uses.
(NEED_MKTIME_INTERNAL, NEED_MKTIME_WINDOWS)
(NEED_MKTIME_WORKING): Give default values to pacify -Wundef,
which glibc uses. Default NEED_MKTIME_WORKING to DEBUG_MKTIME, to
simplify later conditionals; default the others to zero. Use
these conditionals to express only the code needed on the current
platform. In uses of these conditionals, explicitly spell out how
_LIBC affects things, so itâ??s easier to review from a glibc
viewpoint.
(WRAPV): Remove; no longer needed now that we have
systematic overflow checking.
(my_tzset, __tzset) [!_LIBC]: New function and macro, to better
compartmentalize tzset issues. Move system-dependent tzsettish
code here from mktime.
(verify): Remove; now done by verify.h. All uses changed.
(long_int): Use a more-conservative definition, to avoid
integer overflow.
(SHR): Remove, replacing with ...
(shr): New function, which means we neednâ??t worry about side
effects in args, and conversion analysis is simpler.
(TYPE_IS_INTEGER, TYPE_TWOS_COMPLEMENT, TYPE_SIGNED, TYPE_MINIMUM)
(TYPE_MAXIMUM, TIME_T_MIN, TIME_T_MAX, TIME_T_MIDPOINT)
(time_t_avg, time_t_add_ok): Remove.
(mktime_min, mktime_max): New constants.
(leapyear, isdst_differ): Use bool for booleans.
(ydhms_diff, guess_time_tm, ranged_convert, __mktime_internal):
Use long_int, not time_t, for mktime differences.
(long_int_avg): New function, replacing time_t_avg.
INT_ADD_WRAPV replaces time_t_add_ok.
(guess_time_tm): 6th arg is now long_int, not time_t const *.
All uses changed.
(convert_time): New function.
(ranged_convert): Use it.
(__mktime_internal): Last arg now points to mktime_offset_t, not
time_t. All uses changed. This is a no-op on glibc, where
mktime_offset_t is always time_t. Use int, not time_t, for UTC
offset guess. Directly check for integer overflow instead of
using a heuristic that works only 99.9...% of the time.
Access *OFFSET only once, to avoid an unlikely race if the
compiler delays a load and if this cascades into a signed integer
overflow.
(mktime): Move tzsettish code to my_tzset, and move
localtime_offset to within mktime so that it doesnâ??t
need a separate ifdef.
(main) [DEBUG_MKTIME]: Speed up by using localtime_r
instead of localtime.
* time/timegm.c: Copy from Gnulib. This has the following changes:
Include mktime-internal.h.
[!_LIBC]: Include config.h and time.h. Do not include
timegm.h or time_r.h. Make __mktime_internal a macro,
and include mktime-internal.h to get its declaration.
(timegm): Temporary is now mktime_offset_t, not time_t.
This affects only Gnulib.
diff --git a/include/intprops.h b/include/intprops.h
new file mode 100644
index 0000000..9702aec
--- /dev/null
+++ b/include/intprops.h
@@ -0,0 +1,455 @@
+/* intprops.h -- properties of integer types
+
+ Copyright (C) 2001-2018 Free Software Foundation, Inc.
+
+ This program 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.
+
+ This program 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 this program. If not, see <https://www.gnu.org/licenses/>. */
+
+/* Written by Paul Eggert. */
+
+#ifndef _GL_INTPROPS_H
+#define _GL_INTPROPS_H
+
+#include <limits.h>
+
+/* Return a value with the common real type of E and V and the value of V.
+ Do not evaluate E. */
+#define _GL_INT_CONVERT(e, v) ((1 ? 0 : (e)) + (v))
+
+/* Act like _GL_INT_CONVERT (E, -V) but work around a bug in IRIX 6.5 cc; see
+ <https://lists.gnu.org/r/bug-gnulib/2011-05/msg00406.html>. */
+#define _GL_INT_NEGATE_CONVERT(e, v) ((1 ? 0 : (e)) - (v))
+
+/* The extra casts in the following macros work around compiler bugs,
+ e.g., in Cray C 5.0.3.0. */
+
+/* True if the arithmetic type T is an integer type. bool counts as
+ an integer. */
+#define TYPE_IS_INTEGER(t) ((t) 1.5 == 1)
+
+/* True if the real type T is signed. */
+#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
+
+/* Return 1 if the real expression E, after promotion, has a
+ signed or floating type. Do not evaluate E. */
+#define EXPR_SIGNED(e) (_GL_INT_NEGATE_CONVERT (e, 1) < 0)
+
+
+/* Minimum and maximum values for integer types and expressions. */
+
+/* The width in bits of the integer type or expression T.
+ Do not evaluate T.
+ Padding bits are not supported; this is checked at compile-time below. */
+#define TYPE_WIDTH(t) (sizeof (t) * CHAR_BIT)
+
+/* The maximum and minimum values for the integer type T. */
+#define TYPE_MINIMUM(t) ((t) ~ TYPE_MAXIMUM (t))
+#define TYPE_MAXIMUM(t) \
+ ((t) (! TYPE_SIGNED (t) \
+ ? (t) -1 \
+ : ((((t) 1 << (TYPE_WIDTH (t) - 2)) - 1) * 2 + 1)))
+
+/* The maximum and minimum values for the type of the expression E,
+ after integer promotion. E is not evaluated. */
+#define _GL_INT_MINIMUM(e) \
+ (EXPR_SIGNED (e) \
+ ? ~ _GL_SIGNED_INT_MAXIMUM (e) \
+ : _GL_INT_CONVERT (e, 0))
+#define _GL_INT_MAXIMUM(e) \
+ (EXPR_SIGNED (e) \
+ ? _GL_SIGNED_INT_MAXIMUM (e) \
+ : _GL_INT_NEGATE_CONVERT (e, 1))
+#define _GL_SIGNED_INT_MAXIMUM(e) \
+ (((_GL_INT_CONVERT (e, 1) << (TYPE_WIDTH ((e) + 0) - 2)) - 1) * 2 + 1)
+
+/* Work around OpenVMS incompatibility with C99. */
+#if !defined LLONG_MAX && defined __INT64_MAX
+# define LLONG_MAX __INT64_MAX
+# define LLONG_MIN __INT64_MIN
+#endif
+
+/* This include file assumes that signed types are two's complement without
+ padding bits; the above macros have undefined behavior otherwise.
+ If this is a problem for you, please let us know how to fix it for your host.
+ This assumption is tested by the intprops-tests module. */
+
+/* Does the __typeof__ keyword work? This could be done by
+ 'configure', but for now it's easier to do it by hand. */
+#if (2 <= __GNUC__ \
+ || (1210 <= __IBMC__ && defined __IBM__TYPEOF__) \
+ || (0x5110 <= __SUNPRO_C && !__STDC__))
+# define _GL_HAVE___TYPEOF__ 1
+#else
+# define _GL_HAVE___TYPEOF__ 0
+#endif
+
+/* Return 1 if the integer type or expression T might be signed. Return 0
+ if it is definitely unsigned. This macro does not evaluate its argument,
+ and expands to an integer constant expression. */
+#if _GL_HAVE___TYPEOF__
+# define _GL_SIGNED_TYPE_OR_EXPR(t) TYPE_SIGNED (__typeof__ (t))
+#else
+# define _GL_SIGNED_TYPE_OR_EXPR(t) 1
+#endif
+
+/* Bound on length of the string representing an unsigned integer
+ value representable in B bits. log10 (2.0) < 146/485. The
+ smallest value of B where this bound is not tight is 2621. */
+#define INT_BITS_STRLEN_BOUND(b) (((b) * 146 + 484) / 485)
+
+/* Bound on length of the string representing an integer type or expression T.
+ Subtract 1 for the sign bit if T is signed, and then add 1 more for
+ a minus sign if needed.
+
+ Because _GL_SIGNED_TYPE_OR_EXPR sometimes returns 0 when its argument is
+ signed, this macro may overestimate the true bound by one byte when
+ applied to unsigned types of size 2, 4, 16, ... bytes. */
+#define INT_STRLEN_BOUND(t) \
+ (INT_BITS_STRLEN_BOUND (TYPE_WIDTH (t) - _GL_SIGNED_TYPE_OR_EXPR (t)) \
+ + _GL_SIGNED_TYPE_OR_EXPR (t))
+
+/* Bound on buffer size needed to represent an integer type or expression T,
+ including the terminating null. */
+#define INT_BUFSIZE_BOUND(t) (INT_STRLEN_BOUND (t) + 1)
+
+
+/* Range overflow checks.
+
+ The INT_<op>_RANGE_OVERFLOW macros return 1 if the corresponding C
+ operators might not yield numerically correct answers due to
+ arithmetic overflow. They do not rely on undefined or
+ implementation-defined behavior. Their implementations are simple
+ and straightforward, but they are a bit harder to use than the
+ INT_<op>_OVERFLOW macros described below.
+
+ Example usage:
+
+ long int i = ...;
+ long int j = ...;
+ if (INT_MULTIPLY_RANGE_OVERFLOW (i, j, LONG_MIN, LONG_MAX))
+ printf ("multiply would overflow");
+ else
+ printf ("product is %ld", i * j);
+
+ Restrictions on *_RANGE_OVERFLOW macros:
+
+ These macros do not check for all possible numerical problems or
+ undefined or unspecified behavior: they do not check for division
+ by zero, for bad shift counts, or for shifting negative numbers.
+
+ These macros may evaluate their arguments zero or multiple times,
+ so the arguments should not have side effects. The arithmetic
+ arguments (including the MIN and MAX arguments) must be of the same
+ integer type after the usual arithmetic conversions, and the type
+ must have minimum value MIN and maximum MAX. Unsigned types should
+ use a zero MIN of the proper type.
+
+ These macros are tuned for constant MIN and MAX. For commutative
+ operations such as A + B, they are also tuned for constant B. */
+
+/* Return 1 if A + B would overflow in [MIN,MAX] arithmetic.
+ See above for restrictions. */
+#define INT_ADD_RANGE_OVERFLOW(a, b, min, max) \
+ ((b) < 0 \
+ ? (a) < (min) - (b) \
+ : (max) - (b) < (a))
+
+/* Return 1 if A - B would overflow in [MIN,MAX] arithmetic.
+ See above for restrictions. */
+#define INT_SUBTRACT_RANGE_OVERFLOW(a, b, min, max) \
+ ((b) < 0 \
+ ? (max) + (b) < (a) \
+ : (a) < (min) + (b))
+
+/* Return 1 if - A would overflow in [MIN,MAX] arithmetic.
+ See above for restrictions. */
+#define INT_NEGATE_RANGE_OVERFLOW(a, min, max) \
+ ((min) < 0 \
+ ? (a) < - (max) \
+ : 0 < (a))
+
+/* Return 1 if A * B would overflow in [MIN,MAX] arithmetic.
+ See above for restrictions. Avoid && and || as they tickle
+ bugs in Sun C 5.11 2010/08/13 and other compilers; see
+ <https://lists.gnu.org/r/bug-gnulib/2011-05/msg00401.html>. */
+#define INT_MULTIPLY_RANGE_OVERFLOW(a, b, min, max) \
+ ((b) < 0 \
+ ? ((a) < 0 \
+ ? (a) < (max) / (b) \
+ : (b) == -1 \
+ ? 0 \
+ : (min) / (b) < (a)) \
+ : (b) == 0 \
+ ? 0 \
+ : ((a) < 0 \
+ ? (a) < (min) / (b) \
+ : (max) / (b) < (a)))
+
+/* Return 1 if A / B would overflow in [MIN,MAX] arithmetic.
+ See above for restrictions. Do not check for division by zero. */
+#define INT_DIVIDE_RANGE_OVERFLOW(a, b, min, max) \
+ ((min) < 0 && (b) == -1 && (a) < - (max))
+
+/* Return 1 if A % B would overflow in [MIN,MAX] arithmetic.
+ See above for restrictions. Do not check for division by zero.
+ Mathematically, % should never overflow, but on x86-like hosts
+ INT_MIN % -1 traps, and the C standard permits this, so treat this
+ as an overflow too. */
+#define INT_REMAINDER_RANGE_OVERFLOW(a, b, min, max) \
+ INT_DIVIDE_RANGE_OVERFLOW (a, b, min, max)
+
+/* Return 1 if A << B would overflow in [MIN,MAX] arithmetic.
+ See above for restrictions. Here, MIN and MAX are for A only, and B need
+ not be of the same type as the other arguments. The C standard says that
+ behavior is undefined for shifts unless 0 <= B < wordwidth, and that when
+ A is negative then A << B has undefined behavior and A >> B has
+ implementation-defined behavior, but do not check these other
+ restrictions. */
+#define INT_LEFT_SHIFT_RANGE_OVERFLOW(a, b, min, max) \
+ ((a) < 0 \
+ ? (a) < (min) >> (b) \
+ : (max) >> (b) < (a))
+
+/* True if __builtin_add_overflow (A, B, P) works when P is non-null. */
+#if 5 <= __GNUC__ && !defined __ICC
+# define _GL_HAS_BUILTIN_OVERFLOW 1
+#else
+# define _GL_HAS_BUILTIN_OVERFLOW 0
+#endif
+
+/* True if __builtin_add_overflow_p (A, B, C) works. */
+#define _GL_HAS_BUILTIN_OVERFLOW_P (7 <= __GNUC__)
+
+/* The _GL*_OVERFLOW macros have the same restrictions as the
+ *_RANGE_OVERFLOW macros, except that they do not assume that operands
+ (e.g., A and B) have the same type as MIN and MAX. Instead, they assume
+ that the result (e.g., A + B) has that type. */
+#if _GL_HAS_BUILTIN_OVERFLOW_P
+# define _GL_ADD_OVERFLOW(a, b, min, max) \
+ __builtin_add_overflow_p (a, b, (__typeof__ ((a) + (b))) 0)
+# define _GL_SUBTRACT_OVERFLOW(a, b, min, max) \
+ __builtin_sub_overflow_p (a, b, (__typeof__ ((a) - (b))) 0)
+# define _GL_MULTIPLY_OVERFLOW(a, b, min, max) \
+ __builtin_mul_overflow_p (a, b, (__typeof__ ((a) * (b))) 0)
+#else
+# define _GL_ADD_OVERFLOW(a, b, min, max) \
+ ((min) < 0 ? INT_ADD_RANGE_OVERFLOW (a, b, min, max) \
+ : (a) < 0 ? (b) <= (a) + (b) \
+ : (b) < 0 ? (a) <= (a) + (b) \
+ : (a) + (b) < (b))
+# define _GL_SUBTRACT_OVERFLOW(a, b, min, max) \
+ ((min) < 0 ? INT_SUBTRACT_RANGE_OVERFLOW (a, b, min, max) \
+ : (a) < 0 ? 1 \
+ : (b) < 0 ? (a) - (b) <= (a) \
+ : (a) < (b))
+# define _GL_MULTIPLY_OVERFLOW(a, b, min, max) \
+ (((min) == 0 && (((a) < 0 && 0 < (b)) || ((b) < 0 && 0 < (a)))) \
+ || INT_MULTIPLY_RANGE_OVERFLOW (a, b, min, max))
+#endif
+#define _GL_DIVIDE_OVERFLOW(a, b, min, max) \
+ ((min) < 0 ? (b) == _GL_INT_NEGATE_CONVERT (min, 1) && (a) < - (max) \
+ : (a) < 0 ? (b) <= (a) + (b) - 1 \
+ : (b) < 0 && (a) + (b) <= (a))
+#define _GL_REMAINDER_OVERFLOW(a, b, min, max) \
+ ((min) < 0 ? (b) == _GL_INT_NEGATE_CONVERT (min, 1) && (a) < - (max) \
+ : (a) < 0 ? (a) % (b) != ((max) - (b) + 1) % (b) \
+ : (b) < 0 && ! _GL_UNSIGNED_NEG_MULTIPLE (a, b, max))
+
+/* Return a nonzero value if A is a mathematical multiple of B, where
+ A is unsigned, B is negative, and MAX is the maximum value of A's
+ type. A's type must be the same as (A % B)'s type. Normally (A %
+ -B == 0) suffices, but things get tricky if -B would overflow. */
+#define _GL_UNSIGNED_NEG_MULTIPLE(a, b, max) \
+ (((b) < -_GL_SIGNED_INT_MAXIMUM (b) \
+ ? (_GL_SIGNED_INT_MAXIMUM (b) == (max) \
+ ? (a) \
+ : (a) % (_GL_INT_CONVERT (a, _GL_SIGNED_INT_MAXIMUM (b)) + 1)) \
+ : (a) % - (b)) \
+ == 0)
+
+/* Check for integer overflow, and report low order bits of answer.
+
+ The INT_<op>_OVERFLOW macros return 1 if the corresponding C operators
+ might not yield numerically correct answers due to arithmetic overflow.
+ The INT_<op>_WRAPV macros also store the low-order bits of the answer.
+ These macros work correctly on all known practical hosts, and do not rely
+ on undefined behavior due to signed arithmetic overflow.
+
+ Example usage, assuming A and B are long int:
+
+ if (INT_MULTIPLY_OVERFLOW (a, b))
+ printf ("result would overflow\n");
+ else
+ printf ("result is %ld (no overflow)\n", a * b);
+
+ Example usage with WRAPV flavor:
+
+ long int result;
+ bool overflow = INT_MULTIPLY_WRAPV (a, b, &result);
+ printf ("result is %ld (%s)\n", result,
+ overflow ? "after overflow" : "no overflow");
+
+ Restrictions on these macros:
+
+ These macros do not check for all possible numerical problems or
+ undefined or unspecified behavior: they do not check for division
+ by zero, for bad shift counts, or for shifting negative numbers.
+
+ These macros may evaluate their arguments zero or multiple times, so the
+ arguments should not have side effects.
+
+ The WRAPV macros are not constant expressions. They support only
+ +, binary -, and *. The result type must be signed.
+
+ These macros are tuned for their last argument being a constant.
+
+ Return 1 if the integer expressions A * B, A - B, -A, A * B, A / B,
+ A % B, and A << B would overflow, respectively. */
+
+#define INT_ADD_OVERFLOW(a, b) \
+ _GL_BINARY_OP_OVERFLOW (a, b, _GL_ADD_OVERFLOW)
+#define INT_SUBTRACT_OVERFLOW(a, b) \
+ _GL_BINARY_OP_OVERFLOW (a, b, _GL_SUBTRACT_OVERFLOW)
+#if _GL_HAS_BUILTIN_OVERFLOW_P
+# define INT_NEGATE_OVERFLOW(a) INT_SUBTRACT_OVERFLOW (0, a)
+#else
+# define INT_NEGATE_OVERFLOW(a) \
+ INT_NEGATE_RANGE_OVERFLOW (a, _GL_INT_MINIMUM (a), _GL_INT_MAXIMUM (a))
+#endif
+#define INT_MULTIPLY_OVERFLOW(a, b) \
+ _GL_BINARY_OP_OVERFLOW (a, b, _GL_MULTIPLY_OVERFLOW)
+#define INT_DIVIDE_OVERFLOW(a, b) \
+ _GL_BINARY_OP_OVERFLOW (a, b, _GL_DIVIDE_OVERFLOW)
+#define INT_REMAINDER_OVERFLOW(a, b) \
+ _GL_BINARY_OP_OVERFLOW (a, b, _GL_REMAINDER_OVERFLOW)
+#define INT_LEFT_SHIFT_OVERFLOW(a, b) \
+ INT_LEFT_SHIFT_RANGE_OVERFLOW (a, b, \
+ _GL_INT_MINIMUM (a), _GL_INT_MAXIMUM (a))
+
+/* Return 1 if the expression A <op> B would overflow,
+ where OP_RESULT_OVERFLOW (A, B, MIN, MAX) does the actual test,
+ assuming MIN and MAX are the minimum and maximum for the result type.
+ Arguments should be free of side effects. */
+#define _GL_BINARY_OP_OVERFLOW(a, b, op_result_overflow) \
+ op_result_overflow (a, b, \
+ _GL_INT_MINIMUM (_GL_INT_CONVERT (a, b)), \
+ _GL_INT_MAXIMUM (_GL_INT_CONVERT (a, b)))
+
+/* Store the low-order bits of A + B, A - B, A * B, respectively, into *R.
+ Return 1 if the result overflows. See above for restrictions. */
+#define INT_ADD_WRAPV(a, b, r) \
+ _GL_INT_OP_WRAPV (a, b, r, +, __builtin_add_overflow, INT_ADD_OVERFLOW)
+#define INT_SUBTRACT_WRAPV(a, b, r) \
+ _GL_INT_OP_WRAPV (a, b, r, -, __builtin_sub_overflow, INT_SUBTRACT_OVERFLOW)
+#define INT_MULTIPLY_WRAPV(a, b, r) \
+ _GL_INT_OP_WRAPV (a, b, r, *, __builtin_mul_overflow, INT_MULTIPLY_OVERFLOW)
+
+/* Nonzero if this compiler has GCC bug 68193 or Clang bug 25390. See:
+ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68193
+ https://llvm.org/bugs/show_bug.cgi?id=25390
+ For now, assume all versions of GCC-like compilers generate bogus
+ warnings for _Generic. This matters only for older compilers that
+ lack __builtin_add_overflow. */
+#if __GNUC__
+# define _GL__GENERIC_BOGUS 1
+#else
+# define _GL__GENERIC_BOGUS 0
+#endif
+
+/* Store the low-order bits of A <op> B into *R, where OP specifies
+ the operation. BUILTIN is the builtin operation, and OVERFLOW the
+ overflow predicate. Return 1 if the result overflows. See above
+ for restrictions. */
+#if _GL_HAS_BUILTIN_OVERFLOW
+# define _GL_INT_OP_WRAPV(a, b, r, op, builtin, overflow) builtin (a, b, r)
+#elif 201112 <= __STDC_VERSION__ && !_GL__GENERIC_BOGUS
+# define _GL_INT_OP_WRAPV(a, b, r, op, builtin, overflow) \
+ (_Generic \
+ (*(r), \
+ signed char: \
+ _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
+ signed char, SCHAR_MIN, SCHAR_MAX), \
+ short int: \
+ _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
+ short int, SHRT_MIN, SHRT_MAX), \
+ int: \
+ _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
+ int, INT_MIN, INT_MAX), \
+ long int: \
+ _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \
+ long int, LONG_MIN, LONG_MAX), \
+ long long int: \
+ _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long long int, \
+ long long int, LLONG_MIN, LLONG_MAX)))
+#else
+# define _GL_INT_OP_WRAPV(a, b, r, op, builtin, overflow) \
+ (sizeof *(r) == sizeof (signed char) \
+ ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
+ signed char, SCHAR_MIN, SCHAR_MAX) \
+ : sizeof *(r) == sizeof (short int) \
+ ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
+ short int, SHRT_MIN, SHRT_MAX) \
+ : sizeof *(r) == sizeof (int) \
+ ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
+ int, INT_MIN, INT_MAX) \
+ : _GL_INT_OP_WRAPV_LONGISH(a, b, r, op, overflow))
+# ifdef LLONG_MAX
+# define _GL_INT_OP_WRAPV_LONGISH(a, b, r, op, overflow) \
+ (sizeof *(r) == sizeof (long int) \
+ ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \
+ long int, LONG_MIN, LONG_MAX) \
+ : _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long long int, \
+ long long int, LLONG_MIN, LLONG_MAX))
+# else
+# define _GL_INT_OP_WRAPV_LONGISH(a, b, r, op, overflow) \
+ _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \
+ long int, LONG_MIN, LONG_MAX)
+# endif
+#endif
+
+/* Store the low-order bits of A <op> B into *R, where the operation
+ is given by OP. Use the unsigned type UT for calculation to avoid
+ overflow problems. *R's type is T, with extrema TMIN and TMAX.
+ T must be a signed integer type. Return 1 if the result overflows. */
+#define _GL_INT_OP_CALC(a, b, r, op, overflow, ut, t, tmin, tmax) \
+ (sizeof ((a) op (b)) < sizeof (t) \
+ ? _GL_INT_OP_CALC1 ((t) (a), (t) (b), r, op, overflow, ut, t, tmin, tmax) \
+ : _GL_INT_OP_CALC1 (a, b, r, op, overflow, ut, t, tmin, tmax))
+#define _GL_INT_OP_CALC1(a, b, r, op, overflow, ut, t, tmin, tmax) \
+ ((overflow (a, b) \
+ || (EXPR_SIGNED ((a) op (b)) && ((a) op (b)) < (tmin)) \
+ || (tmax) < ((a) op (b))) \
+ ? (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a, b, op, ut, t), 1) \
+ : (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a, b, op, ut, t), 0))
+
+/* Return the low-order bits of A <op> B, where the operation is given
+ by OP. Use the unsigned type UT for calculation to avoid undefined
+ behavior on signed integer overflow, and convert the result to type T.
+ UT is at least as wide as T and is no narrower than unsigned int,
+ T is two's complement, and there is no padding or trap representations.
+ Assume that converting UT to T yields the low-order bits, as is
+ done in all known two's-complement C compilers. E.g., see:
+ https://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html
+
+ According to the C standard, converting UT to T yields an
+ implementation-defined result or signal for values outside T's
+ range. However, code that works around this theoretical problem
+ runs afoul of a compiler bug in Oracle Studio 12.3 x86. See:
+ https://lists.gnu.org/r/bug-gnulib/2017-04/msg00049.html
+ As the compiler bug is real, don't try to work around the
+ theoretical problem. */
+
+#define _GL_INT_OP_WRAPV_VIA_UNSIGNED(a, b, op, ut, t) \
+ ((t) ((ut) (a) op (ut) (b)))
+
+#endif /* _GL_INTPROPS_H */
diff --git a/include/verify.h b/include/verify.h
new file mode 100644
index 0000000..00e78d3
--- /dev/null
+++ b/include/verify.h
@@ -0,0 +1,2 @@
+/* Gnulib <verify.h>, simplified by assuming GCC 4.6 or later. */
+#define verify(R) _Static_assert (R, "verify (" #R ")")
diff --git a/time/mktime-internal.h b/time/mktime-internal.h
new file mode 100644
index 0000000..ba1d9c7
--- /dev/null
+++ b/time/mktime-internal.h
@@ -0,0 +1 @@
+typedef time_t mktime_offset_t;
diff --git a/time/mktime.c b/time/mktime.c
index 5f038a2..4ff7490 100644
--- a/time/mktime.c
+++ b/time/mktime.c
@@ -15,13 +15,30 @@
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/>. */
+ <https://www.gnu.org/licenses/>. */
-/* Define this to have a standalone program to test this implementation of
+/* Define this to 1 to have a standalone program to test this implementation of
mktime. */
-/* #define DEBUG_MKTIME 1 */
+#ifndef DEBUG_MKTIME
+# define DEBUG_MKTIME 0
+#endif
-#ifndef _LIBC
+/* The following macros influence what gets defined when this file is compiled:
+
+ Macro/expression Which gnulib module This compilation unit
+ should define
+
+ _LIBC (glibc proper) mktime
+
+ NEED_MKTIME_WORKING mktime rpl_mktime
+ || NEED_MKTIME_WINDOWS
+
+ NEED_MKTIME_INTERNAL mktime-internal mktime_internal
+
+ DEBUG_MKTIME (defined manually) my_mktime, main
+ */
+
+#if !defined _LIBC && !DEBUG_MKTIME
# include <config.h>
#endif
@@ -35,114 +52,128 @@
#include <time.h>
#include <limits.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
-#include <string.h> /* For the real memcpy prototype. */
+#include <intprops.h>
+#include <verify.h>
-#if defined DEBUG_MKTIME && DEBUG_MKTIME
+#if DEBUG_MKTIME
# include <stdio.h>
-# include <stdlib.h>
/* Make it work even if the system's libc has its own mktime routine. */
# undef mktime
# define mktime my_mktime
#endif /* DEBUG_MKTIME */
-/* Some of the code in this file assumes that signed integer overflow
- silently wraps around. This assumption can't easily be programmed
- around, nor can it be checked for portably at compile-time or
- easily eliminated at run-time.
-
- Define WRAPV to 1 if the assumption is valid and if
- #pragma GCC optimize ("wrapv")
- does not trigger GCC bug 51793
- <http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51793>.
- Otherwise, define it to 0; this forces the use of slower code that,
- while not guaranteed by the C Standard, works on all production
- platforms that we know about. */
-#ifndef WRAPV
-# if (((__GNUC__ == 4 && 4 <= __GNUC_MINOR__) || 4 < __GNUC__) \
- && defined __GLIBC__)
-# pragma GCC optimize ("wrapv")
-# define WRAPV 1
-# else
-# define WRAPV 0
+#ifndef NEED_MKTIME_INTERNAL
+# define NEED_MKTIME_INTERNAL 0
+#endif
+#ifndef NEED_MKTIME_WINDOWS
+# define NEED_MKTIME_WINDOWS 0
+#endif
+#ifndef NEED_MKTIME_WORKING
+# define NEED_MKTIME_WORKING DEBUG_MKTIME
+#endif
+
+#include "mktime-internal.h"
+
+#ifndef _LIBC
+static void
+my_tzset (void)
+{
+# if NEED_MKTIME_WINDOWS
+ /* Rectify the value of the environment variable TZ.
+ There are four possible kinds of such values:
+ - Traditional US time zone names, e.g. "PST8PDT". Syntax: see
+ <https://msdn.microsoft.com/en-us/library/90s5c885.aspx>
+ - Time zone names based on geography, that contain one or more
+ slashes, e.g. "Europe/Moscow".
+ - Time zone names based on geography, without slashes, e.g.
+ "Singapore".
+ - Time zone names that contain explicit DST rules. Syntax: see
+ <http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html#tag_08_03>
+ The Microsoft CRT understands only the first kind. It produces incorrect
+ results if the value of TZ is of the other kinds.
+ But in a Cygwin environment, /etc/profile.d/tzset.sh sets TZ to a value
+ of the second kind for most geographies, or of the first kind in a few
+ other geographies. If it is of the second kind, neutralize it. For the
+ Microsoft CRT, an absent or empty TZ means the time zone that the user
+ has set in the Windows Control Panel.
+ If the value of TZ is of the third or fourth kind -- Cygwin programs
+ understand these syntaxes as well --, it does not matter whether we
+ neutralize it or not, since these values occur only when a Cygwin user
+ has set TZ explicitly; this case is 1. rare and 2. under the user's
+ responsibility. */
+ const char *tz = getenv ("TZ");
+ if (tz != NULL && strchr (tz, '/') != NULL)
+ _putenv ("TZ=");
+# elif HAVE_TZSET
+ tzset ();
# endif
+}
+# undef __tzset
+# define __tzset() my_tzset ()
#endif
-/* Verify a requirement at compile-time (unlike assert, which is runtime). */
-#define verify(name, assertion) struct name { char a[(assertion) ? 1 : -1]; }
+#if defined _LIBC || NEED_MKTIME_WORKING || NEED_MKTIME_INTERNAL
+
+/* A signed type that can represent an integer number of years
+ multiplied by three times the number of seconds in a year. It is
+ needed when converting a tm_year value times the number of seconds
+ in a year. The factor of three comes because these products need
+ to be subtracted from each other, and sometimes with an offset
+ added to them, without worrying about overflow.
+
+ Much of the code uses long_int to represent time_t values, to
+ lessen the hassle of dealing with platforms where time_t is
+ unsigned, and because long_int should suffice to represent all
+ time_t values that mktime can generate even on platforms where
+ time_t is excessively wide. */
-/* A signed type that is at least one bit wider than int. */
-#if INT_MAX <= LONG_MAX / 2
+#if INT_MAX <= LONG_MAX / 3 / 366 / 24 / 60 / 60
typedef long int long_int;
#else
typedef long long int long_int;
#endif
-verify (long_int_is_wide_enough, INT_MAX == INT_MAX * (long_int) 2 / 2);
+verify (INT_MAX <= TYPE_MAXIMUM (long_int) / 3 / 366 / 24 / 60 / 60);
/* Shift A right by B bits portably, by dividing A by 2**B and
- truncating towards minus infinity. A and B should be free of side
- effects, and B should be in the range 0 <= B <= INT_BITS - 2, where
- INT_BITS is the number of useful bits in an int. GNU code can
- assume that INT_BITS is at least 32.
+ truncating towards minus infinity. B should be in the range 0 <= B
+ <= LONG_INT_BITS - 2, where LONG_INT_BITS is the number of useful
+ bits in a long_int. LONG_INT_BITS is at least 32.
ISO C99 says that A >> B is implementation-defined if A < 0. Some
implementations (e.g., UNICOS 9.0 on a Cray Y-MP EL) don't shift
right in the usual way when A < 0, so SHR falls back on division if
ordinary A >> B doesn't seem to be the usual signed shift. */
-#define SHR(a, b) \
- ((-1 >> 1 == -1 \
- && (long_int) -1 >> 1 == -1 \
- && ((time_t) -1 >> 1 == -1 || ! TYPE_SIGNED (time_t))) \
- ? (a) >> (b) \
- : (a) / (1 << (b)) - ((a) % (1 << (b)) < 0))
-
-/* The extra casts in the following macros work around compiler bugs,
- e.g., in Cray C 5.0.3.0. */
-
-/* True if the arithmetic type T is an integer type. bool counts as
- an integer. */
-#define TYPE_IS_INTEGER(t) ((t) 1.5 == 1)
-
-/* True if negative values of the signed integer type T use two's
- complement, or if T is an unsigned integer type. */
-#define TYPE_TWOS_COMPLEMENT(t) ((t) ~ (t) 0 == (t) -1)
-
-/* True if the arithmetic type T is signed. */
-#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
-
-/* The maximum and minimum values for the integer type T. These
- macros have undefined behavior if T is signed and has padding bits.
- If this is a problem for you, please let us know how to fix it for
- your host. */
-#define TYPE_MINIMUM(t) \
- ((t) (! TYPE_SIGNED (t) \
- ? (t) 0 \
- : ~ TYPE_MAXIMUM (t)))
-#define TYPE_MAXIMUM(t) \
- ((t) (! TYPE_SIGNED (t) \
- ? (t) -1 \
- : ((((t) 1 << (sizeof (t) * CHAR_BIT - 2)) - 1) * 2 + 1)))
-
-#ifndef TIME_T_MIN
-# define TIME_T_MIN TYPE_MINIMUM (time_t)
-#endif
-#ifndef TIME_T_MAX
-# define TIME_T_MAX TYPE_MAXIMUM (time_t)
-#endif
-#define TIME_T_MIDPOINT (SHR (TIME_T_MIN + TIME_T_MAX, 1) + 1)
-verify (time_t_is_integer, TYPE_IS_INTEGER (time_t));
-verify (twos_complement_arithmetic,
- (TYPE_TWOS_COMPLEMENT (int)
- && TYPE_TWOS_COMPLEMENT (long_int)
- && TYPE_TWOS_COMPLEMENT (time_t)));
+static long_int
+shr (long_int a, int b)
+{
+ long_int one = 1;
+ return (-one >> 1 == -1
+ ? a >> b
+ : a / (one << b) - (a % (one << b) < 0));
+}
+
+/* Bounds for the intersection of time_t and long_int. */
+
+static long_int const mktime_min
+ = ((TYPE_SIGNED (time_t) && TYPE_MINIMUM (time_t) < TYPE_MINIMUM (long_int))
+ ? TYPE_MINIMUM (long_int) : TYPE_MINIMUM (time_t));
+static long_int const mktime_max
+ = (TYPE_MAXIMUM (long_int) < TYPE_MAXIMUM (time_t)
+ ? TYPE_MAXIMUM (long_int) : TYPE_MAXIMUM (time_t));
+
+verify (TYPE_IS_INTEGER (time_t));
#define EPOCH_YEAR 1970
#define TM_YEAR_BASE 1900
-verify (base_year_is_a_multiple_of_100, TM_YEAR_BASE % 100 == 0);
+verify (TM_YEAR_BASE % 100 == 0);
-/* Return 1 if YEAR + TM_YEAR_BASE is a leap year. */
-static int
+/* Is YEAR + TM_YEAR_BASE a leap year? */
+static bool
leapyear (long_int year)
{
/* Don't add YEAR to TM_YEAR_BASE, as that might overflow.
@@ -166,20 +197,9 @@ const unsigned short int __mon_yday[2][13] =
};
-#ifndef _LIBC
-/* Portable standalone applications should supply a <time.h> that
- declares a POSIX-compliant localtime_r, for the benefit of older
- implementations that lack localtime_r or have a nonstandard one.
- See the gnulib time_r module for one way to implement this. */
-# undef __localtime_r
-# define __localtime_r localtime_r
-# define __mktime_internal mktime_internal
-# include "mktime-internal.h"
-#endif
-
-/* Return 1 if the values A and B differ according to the rules for
- tm_isdst: A and B differ if one is zero and the other positive. */
-static int
+/* Do the values A and B differ according to the rules for tm_isdst?
+ A and B differ if one is zero and the other positive. */
+static bool
isdst_differ (int a, int b)
{
return (!a != !b) && (0 <= a) && (0 <= b);
@@ -187,107 +207,68 @@ isdst_differ (int a, int b)
/* Return an integer value measuring (YEAR1-YDAY1 HOUR1:MIN1:SEC1) -
(YEAR0-YDAY0 HOUR0:MIN0:SEC0) in seconds, assuming that the clocks
- were not adjusted between the time stamps.
+ were not adjusted between the timestamps.
The YEAR values uses the same numbering as TP->tm_year. Values
- need not be in the usual range. However, YEAR1 must not be less
- than 2 * INT_MIN or greater than 2 * INT_MAX.
-
- The result may overflow. It is the caller's responsibility to
- detect overflow. */
+ need not be in the usual range. However, YEAR1 must not overflow
+ when multiplied by three times the number of seconds in a year, and
+ likewise for YDAY1 and three times the number of seconds in a day. */
-static time_t
+static long_int
ydhms_diff (long_int year1, long_int yday1, int hour1, int min1, int sec1,
int year0, int yday0, int hour0, int min0, int sec0)
{
- verify (C99_integer_division, -1 / 2 == 0);
+ verify (-1 / 2 == 0);
/* Compute intervening leap days correctly even if year is negative.
Take care to avoid integer overflow here. */
- int a4 = SHR (year1, 2) + SHR (TM_YEAR_BASE, 2) - ! (year1 & 3);
- int b4 = SHR (year0, 2) + SHR (TM_YEAR_BASE, 2) - ! (year0 & 3);
+ int a4 = shr (year1, 2) + shr (TM_YEAR_BASE, 2) - ! (year1 & 3);
+ int b4 = shr (year0, 2) + shr (TM_YEAR_BASE, 2) - ! (year0 & 3);
int a100 = a4 / 25 - (a4 % 25 < 0);
int b100 = b4 / 25 - (b4 % 25 < 0);
- int a400 = SHR (a100, 2);
- int b400 = SHR (b100, 2);
+ int a400 = shr (a100, 2);
+ int b400 = shr (b100, 2);
int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
- /* Compute the desired time in time_t precision. Overflow might
- occur here. */
- time_t tyear1 = year1;
- time_t years = tyear1 - year0;
- time_t days = 365 * years + yday1 - yday0 + intervening_leap_days;
- time_t hours = 24 * days + hour1 - hour0;
- time_t minutes = 60 * hours + min1 - min0;
- time_t seconds = 60 * minutes + sec1 - sec0;
+ /* Compute the desired time without overflowing. */
+ long_int years = year1 - year0;
+ long_int days = 365 * years + yday1 - yday0 + intervening_leap_days;
+ long_int hours = 24 * days + hour1 - hour0;
+ long_int minutes = 60 * hours + min1 - min0;
+ long_int seconds = 60 * minutes + sec1 - sec0;
return seconds;
}
-/* Return the average of A and B, even if A + B would overflow. */
-static time_t
-time_t_avg (time_t a, time_t b)
+/* Return the average of A and B, even if A + B would overflow.
+ Round toward positive infinity. */
+static long_int
+long_int_avg (long_int a, long_int b)
{
- return SHR (a, 1) + SHR (b, 1) + (a & b & 1);
-}
-
-/* Return 1 if A + B does not overflow. If time_t is unsigned and if
- B's top bit is set, assume that the sum represents A - -B, and
- return 1 if the subtraction does not wrap around. */
-static int
-time_t_add_ok (time_t a, time_t b)
-{
- if (! TYPE_SIGNED (time_t))
- {
- time_t sum = a + b;
- return (sum < a) == (TIME_T_MIDPOINT <= b);
- }
- else if (WRAPV)
- {
- time_t sum = a + b;
- return (sum < a) == (b < 0);
- }
- else
- {
- time_t avg = time_t_avg (a, b);
- return TIME_T_MIN / 2 <= avg && avg <= TIME_T_MAX / 2;
- }
-}
-
-/* Return 1 if A + B does not overflow. */
-static int
-time_t_int_add_ok (time_t a, int b)
-{
- verify (int_no_wider_than_time_t, INT_MAX <= TIME_T_MAX);
- if (WRAPV)
- {
- time_t sum = a + b;
- return (sum < a) == (b < 0);
- }
- else
- {
- int a_odd = a & 1;
- time_t avg = SHR (a, 1) + (SHR (b, 1) + (a_odd & b));
- return TIME_T_MIN / 2 <= avg && avg <= TIME_T_MAX / 2;
- }
+ return shr (a, 1) + shr (b, 1) + ((a | b) & 1);
}
/* Return a time_t value corresponding to (YEAR-YDAY HOUR:MIN:SEC),
- assuming that *T corresponds to *TP and that no clock adjustments
+ assuming that T corresponds to *TP and that no clock adjustments
occurred between *TP and the desired time.
- If TP is null, return a value not equal to *T; this avoids false matches.
- If overflow occurs, yield the minimal or maximal value, except do not
- yield a value equal to *T. */
-static time_t
+ Although T and the returned value are of type long_int,
+ they represent time_t values and must be in time_t range.
+ If TP is null, return a value not equal to T; this avoids false matches.
+ YEAR and YDAY must not be so large that multiplying them by three times the
+ number of seconds in a year (or day, respectively) would overflow long_int.
+ If the returned value would be out of range, yield the minimal or
+ maximal in-range value, except do not yield a value equal to T. */
+static long_int
guess_time_tm (long_int year, long_int yday, int hour, int min, int sec,
- const time_t *t, const struct tm *tp)
+ long_int t, const struct tm *tp)
{
if (tp)
{
- time_t d = ydhms_diff (year, yday, hour, min, sec,
- tp->tm_year, tp->tm_yday,
- tp->tm_hour, tp->tm_min, tp->tm_sec);
- if (time_t_add_ok (*t, d))
- return *t + d;
+ long_int result;
+ long_int d = ydhms_diff (year, yday, hour, min, sec,
+ tp->tm_year, tp->tm_yday,
+ tp->tm_hour, tp->tm_min, tp->tm_sec);
+ if (! INT_ADD_WRAPV (t, d, &result))
+ return result;
}
/* Overflow occurred one way or another. Return the nearest result
@@ -295,32 +276,51 @@ guess_time_tm (long_int year, long_int yday, int hour, int min, int sec,
if the actual difference is nonzero, as that would cause a false
match; and don't oscillate between two values, as that would
confuse the spring-forward gap detector. */
- return (*t < TIME_T_MIDPOINT
- ? (*t <= TIME_T_MIN + 1 ? *t + 1 : TIME_T_MIN)
- : (TIME_T_MAX - 1 <= *t ? *t - 1 : TIME_T_MAX));
+ return (t < long_int_avg (mktime_min, mktime_max)
+ ? (t <= mktime_min + 1 ? t + 1 : mktime_min)
+ : (mktime_max - 1 <= t ? t - 1 : mktime_max));
+}
+
+/* Use CONVERT to convert T to a struct tm value in *TM. T must be in
+ range for time_t. Return TM if successful, NULL if T is out of
+ range for CONVERT. */
+static struct tm *
+convert_time (struct tm *(*convert) (const time_t *, struct tm *),
+ long_int t, struct tm *tm)
+{
+ time_t x = t;
+ return convert (&x, tm);
}
/* Use CONVERT to convert *T to a broken down time in *TP.
If *T is out of range for conversion, adjust it so that
- it is the nearest in-range value and then convert that. */
+ it is the nearest in-range value and then convert that.
+ A value is in range if it fits in both time_t and long_int. */
static struct tm *
ranged_convert (struct tm *(*convert) (const time_t *, struct tm *),
- time_t *t, struct tm *tp)
+ long_int *t, struct tm *tp)
{
- struct tm *r = convert (t, tp);
+ struct tm *r;
+ if (*t < mktime_min)
+ *t = mktime_min;
+ else if (mktime_max < *t)
+ *t = mktime_max;
+ r = convert_time (convert, *t, tp);
if (!r && *t)
{
- time_t bad = *t;
- time_t ok = 0;
+ long_int bad = *t;
+ long_int ok = 0;
- /* BAD is a known unconvertible time_t, and OK is a known good one.
+ /* BAD is a known unconvertible value, and OK is a known good one.
Use binary search to narrow the range between BAD and OK until
they differ by 1. */
- while (bad != ok + (bad < 0 ? -1 : 1))
+ while (true)
{
- time_t mid = *t = time_t_avg (ok, bad);
- r = convert (t, tp);
+ long_int mid = long_int_avg (ok, bad);
+ if (mid != ok && mid != bad)
+ break;
+ r = convert_time (convert, mid, tp);
if (r)
ok = mid;
else
@@ -331,8 +331,7 @@ ranged_convert (struct tm *(*convert) (const time_t *, struct tm *),
{
/* The last conversion attempt failed;
revert to the most recent successful attempt. */
- *t = ok;
- r = convert (t, tp);
+ r = convert_time (convert, ok, tp);
}
}
@@ -349,9 +348,9 @@ ranged_convert (struct tm *(*convert) (const time_t *, struct tm *),
time_t
__mktime_internal (struct tm *tp,
struct tm *(*convert) (const time_t *, struct tm *),
- time_t *offset)
+ mktime_offset_t *offset)
{
- time_t t, gt, t0, t1, t2;
+ long_int t, gt, t0, t1, t2, dt;
struct tm tm;
/* The maximum number of probes (calls to CONVERT) should be enough
@@ -381,9 +380,7 @@ __mktime_internal (struct tm *tp,
long_int year = lyear_requested + mon_years;
/* The other values need not be in range:
- the remaining code handles minor overflows correctly,
- assuming int and time_t arithmetic wraps around.
- Major overflows are caught at the end. */
+ the remaining code handles overflows correctly. */
/* Calculate day of year from year, month, and day of month.
The result need not be in range. */
@@ -393,7 +390,8 @@ __mktime_internal (struct tm *tp,
long_int lmday = mday;
long_int yday = mon_yday + lmday;
- time_t guessed_offset = *offset;
+ mktime_offset_t off = *offset;
+ int negative_offset_guess;
int sec_requested = sec;
@@ -410,71 +408,14 @@ __mktime_internal (struct tm *tp,
/* Invert CONVERT by probing. First assume the same offset as last
time. */
+ INT_SUBTRACT_WRAPV (0, off, &negative_offset_guess);
t0 = ydhms_diff (year, yday, hour, min, sec,
- EPOCH_YEAR - TM_YEAR_BASE, 0, 0, 0, - guessed_offset);
-
- if (TIME_T_MAX / INT_MAX / 366 / 24 / 60 / 60 < 3)
- {
- /* time_t isn't large enough to rule out overflows, so check
- for major overflows. A gross check suffices, since if t0
- has overflowed, it is off by a multiple of TIME_T_MAX -
- TIME_T_MIN + 1. So ignore any component of the difference
- that is bounded by a small value. */
-
- /* Approximate log base 2 of the number of time units per
- biennium. A biennium is 2 years; use this unit instead of
- years to avoid integer overflow. For example, 2 average
- Gregorian years are 2 * 365.2425 * 24 * 60 * 60 seconds,
- which is 63113904 seconds, and rint (log2 (63113904)) is
- 26. */
- int ALOG2_SECONDS_PER_BIENNIUM = 26;
- int ALOG2_MINUTES_PER_BIENNIUM = 20;
- int ALOG2_HOURS_PER_BIENNIUM = 14;
- int ALOG2_DAYS_PER_BIENNIUM = 10;
- int LOG2_YEARS_PER_BIENNIUM = 1;
-
- int approx_requested_biennia =
- (SHR (year_requested, LOG2_YEARS_PER_BIENNIUM)
- - SHR (EPOCH_YEAR - TM_YEAR_BASE, LOG2_YEARS_PER_BIENNIUM)
- + SHR (mday, ALOG2_DAYS_PER_BIENNIUM)
- + SHR (hour, ALOG2_HOURS_PER_BIENNIUM)
- + SHR (min, ALOG2_MINUTES_PER_BIENNIUM)
- + (LEAP_SECONDS_POSSIBLE
- ? 0
- : SHR (sec, ALOG2_SECONDS_PER_BIENNIUM)));
-
- int approx_biennia = SHR (t0, ALOG2_SECONDS_PER_BIENNIUM);
- int diff = approx_biennia - approx_requested_biennia;
- int approx_abs_diff = diff < 0 ? -1 - diff : diff;
-
- /* IRIX 4.0.5 cc miscalculates TIME_T_MIN / 3: it erroneously
- gives a positive value of 715827882. Setting a variable
- first then doing math on it seems to work.
- (ghazi@caip.rutgers.edu) */
- time_t time_t_max = TIME_T_MAX;
- time_t time_t_min = TIME_T_MIN;
- time_t overflow_threshold =
- (time_t_max / 3 - time_t_min / 3) >> ALOG2_SECONDS_PER_BIENNIUM;
-
- if (overflow_threshold < approx_abs_diff)
- {
- /* Overflow occurred. Try repairing it; this might work if
- the time zone offset is enough to undo the overflow. */
- time_t repaired_t0 = -1 - t0;
- approx_biennia = SHR (repaired_t0, ALOG2_SECONDS_PER_BIENNIUM);
- diff = approx_biennia - approx_requested_biennia;
- approx_abs_diff = diff < 0 ? -1 - diff : diff;
- if (overflow_threshold < approx_abs_diff)
- return -1;
- guessed_offset += repaired_t0 - t0;
- t0 = repaired_t0;
- }
- }
+ EPOCH_YEAR - TM_YEAR_BASE, 0, 0, 0, negative_offset_guess);
/* Repeatedly use the error to improve the guess. */
for (t = t1 = t2 = t0, dst2 = 0;
- (gt = guess_time_tm (year, yday, hour, min, sec, &t,
+ (gt = guess_time_tm (year, yday, hour, min, sec, t,
ranged_convert (convert, &t, &tm)),
t != gt);
t1 = t2, t2 = t, t = gt, dst2 = tm.tm_isdst != 0)
@@ -531,65 +472,70 @@ __mktime_internal (struct tm *tp,
for (delta = stride; delta < delta_bound; delta += stride)
for (direction = -1; direction <= 1; direction += 2)
- if (time_t_int_add_ok (t, delta * direction))
- {
- time_t ot = t + delta * direction;
- struct tm otm;
- ranged_convert (convert, &ot, &otm);
- if (! isdst_differ (isdst, otm.tm_isdst))
- {
- /* We found the desired tm_isdst.
- Extrapolate back to the desired time. */
- t = guess_time_tm (year, yday, hour, min, sec, &ot, &otm);
- ranged_convert (convert, &t, &tm);
- goto offset_found;
- }
- }
+ {
+ long_int ot;
+ if (! INT_ADD_WRAPV (t, delta * direction, &ot))
+ {
+ struct tm otm;
+ ranged_convert (convert, &ot, &otm);
+ if (! isdst_differ (isdst, otm.tm_isdst))
+ {
+ /* We found the desired tm_isdst.
+ Extrapolate back to the desired time. */
+ t = guess_time_tm (year, yday, hour, min, sec, ot, &otm);
+ ranged_convert (convert, &t, &tm);
+ goto offset_found;
+ }
+ }
+ }
}
offset_found:
- *offset = guessed_offset + t - t0;
+ /* Set *OFFSET to the low-order bits of T - T0 - NEGATIVE_OFFSET_GUESS.
+ This is just a heuristic to speed up the next mktime call, and
+ correctness is unaffected if integer overflow occurs here. */
+ INT_SUBTRACT_WRAPV (t, t0, &dt);
+ INT_SUBTRACT_WRAPV (dt, negative_offset_guess, offset);
if (LEAP_SECONDS_POSSIBLE && sec_requested != tm.tm_sec)
{
/* Adjust time to reflect the tm_sec requested, not the normalized value.
Also, repair any damage from a false match due to a leap second. */
- int sec_adjustment = (sec == 0 && tm.tm_sec == 60) - sec;
- if (! time_t_int_add_ok (t, sec_requested))
- return -1;
- t1 = t + sec_requested;
- if (! time_t_int_add_ok (t1, sec_adjustment))
- return -1;
- t2 = t1 + sec_adjustment;
- if (! convert (&t2, &tm))
+ long_int sec_adjustment = sec == 0 && tm.tm_sec == 60;
+ sec_adjustment -= sec;
+ sec_adjustment += sec_requested;
+ if (INT_ADD_WRAPV (t, sec_adjustment, &t)
+ || ! (mktime_min <= t && t <= mktime_max)
+ || ! convert_time (convert, t, &tm))
return -1;
- t = t2;
}
*tp = tm;
return t;
}
+#endif /* _LIBC || NEED_MKTIME_WORKING || NEED_MKTIME_INTERNAL */
-/* FIXME: This should use a signed type wide enough to hold any UTC
- offset in seconds. 'int' should be good enough for GNU code. We
- can't fix this unilaterally though, as other modules invoke
- __mktime_internal. */
-static time_t localtime_offset;
+#if defined _LIBC || NEED_MKTIME_WORKING || NEED_MKTIME_WINDOWS
/* Convert *TP to a time_t value. */
time_t
mktime (struct tm *tp)
{
-#ifdef _LIBC
/* POSIX.1 8.1.1 requires that whenever mktime() is called, the
time zone names contained in the external variable 'tzname' shall
be set as if the tzset() function had been called. */
__tzset ();
-#endif
+# if defined __LIBC || NEED_MKTIME_WORKING
+ static mktime_offset_t localtime_offset;
return __mktime_internal (tp, __localtime_r, &localtime_offset);
+# else
+# undef mktime
+ return mktime (tp);
+# endif
}
+#endif /* _LIBC || NEED_MKTIME_WORKING || NEED_MKTIME_WINDOWS */
#ifdef weak_alias
weak_alias (mktime, timelocal)
@@ -600,7 +546,7 @@ libc_hidden_def (mktime)
libc_hidden_weak (timelocal)
#endif
-#if defined DEBUG_MKTIME && DEBUG_MKTIME
+#if DEBUG_MKTIME
static int
not_equal_tm (const struct tm *a, const struct tm *b)
@@ -652,6 +598,14 @@ main (int argc, char **argv)
time_t tk, tl, tl1;
char trailer;
+ /* Sanity check, plus call tzset. */
+ tl = 0;
+ if (! localtime (&tl))
+ {
+ printf ("localtime (0) fails\n");
+ status = 1;
+ }
+
if ((argc == 3 || argc == 4)
&& (sscanf (argv[1], "%d-%d-%d%c",
&tm.tm_year, &tm.tm_mon, &tm.tm_mday, &trailer)
@@ -665,12 +619,7 @@ main (int argc, char **argv)
tm.tm_isdst = argc == 3 ? -1 : atoi (argv[3]);
tmk = tm;
tl = mktime (&tmk);
- lt = localtime (&tl);
- if (lt)
- {
- tml = *lt;
- lt = &tml;
- }
+ lt = localtime_r (&tl, &tml);
printf ("mktime returns %ld == ", (long int) tl);
print_tm (&tmk);
printf ("\n");
@@ -685,16 +634,16 @@ main (int argc, char **argv)
if (argc == 4)
for (tl = from; by < 0 ? to <= tl : tl <= to; tl = tl1)
{
- lt = localtime (&tl);
+ lt = localtime_r (&tl, &tml);
if (lt)
{
- tmk = tml = *lt;
+ tmk = tml;
tk = mktime (&tmk);
status |= check_result (tk, tmk, tl, &tml);
}
else
{
- printf ("localtime (%ld) yields 0\n", (long int) tl);
+ printf ("localtime_r (%ld) yields 0\n", (long int) tl);
status = 1;
}
tl1 = tl + by;
@@ -705,16 +654,16 @@ main (int argc, char **argv)
for (tl = from; by < 0 ? to <= tl : tl <= to; tl = tl1)
{
/* Null benchmark. */
- lt = localtime (&tl);
+ lt = localtime_r (&tl, &tml);
if (lt)
{
- tmk = tml = *lt;
+ tmk = tml;
tk = tl;
status |= check_result (tk, tmk, tl, &tml);
}
else
{
- printf ("localtime (%ld) yields 0\n", (long int) tl);
+ printf ("localtime_r (%ld) yields 0\n", (long int) tl);
status = 1;
}
tl1 = tl + by;
diff --git a/time/timegm.c b/time/timegm.c
index fb720e2..229fff2 100644
--- a/time/timegm.c
+++ b/time/timegm.c
@@ -17,31 +17,18 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
-#ifdef HAVE_CONFIG_H
+#ifndef _LIBC
# include <config.h>
#endif
-#ifdef _LIBC
-# include <time.h>
-#else
-# include "timegm.h"
-
-/* Portable standalone applications should supply a "time_r.h" that
- declares a POSIX-compliant gmtime_r, for the benefit of older
- implementations that lack gmtime_r or have a nonstandard one.
- See the gnulib time_r module for one way to implement this. */
-# include <time_r.h>
-# undef __gmtime_r
-# define __gmtime_r gmtime_r
-time_t __mktime_internal (struct tm *,
- struct tm * (*) (time_t const *, struct tm *),
- time_t *);
-#endif
+#include <time.h>
+
+#include "mktime-internal.h"
time_t
timegm (struct tm *tmp)
{
- static time_t gmtime_offset;
+ static mktime_offset_t gmtime_offset;
tmp->tm_isdst = 0;
return __mktime_internal (tmp, __gmtime_r, &gmtime_offset);
}
-----------------------------------------------------------------------
hooks/post-receive
--
GNU C Library master sources