From patchwork Mon Apr 29 10:46:09 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lukasz Majewski X-Patchwork-Id: 32448 Received: (qmail 97851 invoked by alias); 29 Apr 2019 10:46:47 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 97789 invoked by uid 89); 29 Apr 2019 10:46:47 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-19.5 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_NUMSUBJECT, RCVD_IN_DNSWL_LOW autolearn=ham version=3.3.1 spammy=1775, moreover X-HELO: mail-out.m-online.net From: Lukasz Majewski To: libc-alpha@sourceware.org Cc: Stepan Golosunov , Arnd Bergmann , Paul Eggert , Joseph Myers , Lukasz Majewski Subject: [PATCH v2 3/7] y2038: Provide conversion helpers for struct __timespec64 Date: Mon, 29 Apr 2019 12:46:09 +0200 Message-Id: <20190429104613.16209-4-lukma@denx.de> In-Reply-To: <20190429104613.16209-1-lukma@denx.de> References: <20190414220841.20243-1-lukma@denx.de> <20190429104613.16209-1-lukma@denx.de> Those functions allow easy conversion between Y2038 safe struct __timespec64 and other time related data structures. An inline function has been added to clear padding of struct __timespec64. This function shall be used when Y2038 safe system passes the data to Linux kernel (as it expects upper 32 bits of tv_nsec being zeroed). Moreover, those functions are NOT compiled when one runs 64 bit system (the __TIMESIZE == 64) and are used only for 32 bit wrappers (like __clock_gettime). * 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. * include/time.h (timespec64_clear_padding): Likewise. --- Changes for v2: - Add timespec64_clear_padding function --- include/time.h | 102 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/include/time.h b/include/time.h index 7540ac0f8b..9827d2f045 100644 --- a/include/time.h +++ b/include/time.h @@ -3,6 +3,7 @@ #ifndef _ISOMAC # include +# include # include extern __typeof (strftime_l) __strftime_l; @@ -177,5 +178,106 @@ extern double __difftime (time_t time1, time_t time0); actual clock ID. */ #define CLOCK_IDFIELD_SIZE 3 +/* Check whether T fits in time_t. */ +static inline bool +in_time_t_range (__time64_t t) +{ + time_t s = t; + return s == t; +} + +# if __TIMESIZE != 64 +/* Set to zero the struct __timespec64's tv_pad. */ +static inline void +timespec64_clear_padding (const struct __timespec64 *tp) +{ + ((struct __timespec64*)tp)->tv_pad = 0; +} +/* 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 (! in_time_t_range (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 (! in_time_t_range (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 #endif