From patchwork Sun Apr 7 19:33:51 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mike Crowe X-Patchwork-Id: 32182 Received: (qmail 81583 invoked by alias); 7 Apr 2019 19:34:33 -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 81514 invoked by uid 89); 7 Apr 2019 19:34:32 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-23.1 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, RCVD_IN_DNSWL_LOW autolearn=ham version=3.3.1 spammy=paul, suffice, distributed X-HELO: avasout03.plus.net X-CM-Score: 0.00 From: Mike Crowe To: libc-alpha@sourceware.org Cc: Mike Crowe Subject: [PATCH v2 2/6] support: Add timespec-related helper functions Date: Sun, 7 Apr 2019 20:33:51 +0100 Message-Id: <1b09fef9f8a0b6955378a9f9c35bc4dd91650289.1554665560.git-series.mac@mcrowe.com> In-Reply-To: References: In-Reply-To: References: * support/timespec.h: New file. Provide timespec helper functions along with macros in the style of those in check.h. * support/timespec.c: New file. Implement check functions declared in support/timespec.h. * support/timespec-add.c: New file from gnulib containing timespec_add implementation that handles overflow. * support/timespec-sub.c: New file from gnulib containing timespec_sub implementation that handles overflow. * support/README: Mention timespec.h. --- ChangeLog | 16 +++++++++- support/Makefile | 3 ++- support/README | 5 +++- support/timespec-add.c | 75 +++++++++++++++++++++++++++++++++++++++++- support/timespec-sub.c | 75 +++++++++++++++++++++++++++++++++++++++++- support/timespec.c | 63 ++++++++++++++++++++++++++++++++++- support/timespec.h | 79 +++++++++++++++++++++++++++++++++++++++++++- 7 files changed, 316 insertions(+) create mode 100644 support/timespec-add.c create mode 100644 support/timespec-sub.c create mode 100644 support/timespec.c create mode 100644 support/timespec.h diff --git a/ChangeLog b/ChangeLog index 8c26806..49dc84e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,21 @@ 2019-04-06 Mike Crowe + * support/timespec.h: New file. Provide timespec helper functions + along with macros in the style of those in check.h. + + * support/timespec.c: New file. Implement check functions declared + in support/timespec.h. + + * support/timespec-add.c: New file from gnulib containing + timespec_add implementation that handles overflow. + + * support/timespec-sub.c: New file from gnulib containing + timespec_sub implementation that handles overflow. + + * support/README: Mention timespec.h. + +2019-04-06 Mike Crowe + * support/xclock_gettime.c (xclock_gettime): New file. Provide clock_gettime wrapper for use in tests that fails the test rather than returning failure. diff --git a/support/Makefile b/support/Makefile index 1d37f70..94a1416 100644 --- a/support/Makefile +++ b/support/Makefile @@ -70,6 +70,9 @@ libsupport-routines = \ support_test_main \ support_test_verify_impl \ temp_file \ + timespec \ + timespec-add \ + timespec-sub \ write_message \ xaccept \ xaccept4 \ diff --git a/support/README b/support/README index d82f472..e33067e 100644 --- a/support/README +++ b/support/README @@ -28,3 +28,8 @@ header files provide related declarations: * check.h * temp_file.h * test-driver.h + +For tests that make use of struct timespec, the following header file +contains additional macros and helper functions: + +* timespec.h diff --git a/support/timespec-add.c b/support/timespec-add.c new file mode 100644 index 0000000..523eac8 --- /dev/null +++ b/support/timespec-add.c @@ -0,0 +1,75 @@ +/* Add two struct timespec values. + + Copyright (C) 2011-2019 Free Software Foundation, Inc. + + This file is part of the GNU C Library, although it originally came + from gnulib. + + 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 + . */ + +/* Written by Paul Eggert. */ + +/* Return the sum of two timespec values A and B. On overflow, return + an extremal value. This assumes 0 <= tv_nsec < TIMESPEC_HZ. */ + +#include +#include "timespec.h" + +#include "intprops.h" + +struct timespec +timespec_add (struct timespec a, struct timespec b) +{ + time_t rs = a.tv_sec; + time_t bs = b.tv_sec; + int ns = a.tv_nsec + b.tv_nsec; + int nsd = ns - TIMESPEC_HZ; + int rns = ns; + time_t tmin = TYPE_MINIMUM (time_t); + time_t tmax = TYPE_MAXIMUM (time_t); + + if (0 <= nsd) + { + rns = nsd; + if (bs < tmax) + bs++; + else if (rs < 0) + rs++; + else + goto high_overflow; + } + + /* INT_ADD_WRAPV is not appropriate since time_t might be unsigned. + In theory time_t might be narrower than int, so plain + INT_ADD_OVERFLOW does not suffice. */ + if (! INT_ADD_OVERFLOW (rs, bs) && tmin <= rs + bs && rs + bs <= tmax) + rs += bs; + else + { + if (rs < 0) + { + rs = tmin; + rns = 0; + } + else + { + high_overflow: + rs = tmax; + rns = TIMESPEC_HZ - 1; + } + } + + return make_timespec (rs, rns); +} diff --git a/support/timespec-sub.c b/support/timespec-sub.c new file mode 100644 index 0000000..7e67e87 --- /dev/null +++ b/support/timespec-sub.c @@ -0,0 +1,75 @@ +/* Subtract two struct timespec values. + + Copyright (C) 2011-2019 Free Software Foundation, Inc. + + This file is part of the GNU C Library, although it originally came + from gnulib. + + 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 + . */ + +/* Written by Paul Eggert. */ + +/* Return the difference between two timespec values A and B. On + overflow, return an extremal value. This assumes 0 <= tv_nsec < + TIMESPEC_HZ. */ + +#include +#include "timespec.h" + +#include "intprops.h" + +struct timespec +timespec_sub (struct timespec a, struct timespec b) +{ + time_t rs = a.tv_sec; + time_t bs = b.tv_sec; + int ns = a.tv_nsec - b.tv_nsec; + int rns = ns; + time_t tmin = TYPE_MINIMUM (time_t); + time_t tmax = TYPE_MAXIMUM (time_t); + + if (ns < 0) + { + rns = ns + TIMESPEC_HZ; + if (bs < tmax) + bs++; + else if (- TYPE_SIGNED (time_t) < rs) + rs--; + else + goto low_overflow; + } + + /* INT_SUBTRACT_WRAPV is not appropriate since time_t might be unsigned. + In theory time_t might be narrower than int, so plain + INT_SUBTRACT_OVERFLOW does not suffice. */ + if (! INT_SUBTRACT_OVERFLOW (rs, bs) && tmin <= rs - bs && rs - bs <= tmax) + rs -= bs; + else + { + if (rs < 0) + { + low_overflow: + rs = tmin; + rns = 0; + } + else + { + rs = tmax; + rns = TIMESPEC_HZ - 1; + } + } + + return make_timespec (rs, rns); +} diff --git a/support/timespec.c b/support/timespec.c new file mode 100644 index 0000000..c34fe73 --- /dev/null +++ b/support/timespec.c @@ -0,0 +1,63 @@ +/* Support code for timespec checks. + Copyright (C) 2019 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include + +void +test_timespec_before_impl (const char *file, int line, + const struct timespec left, + const struct timespec right) +{ + if (left.tv_sec > right.tv_sec + || (left.tv_sec == right.tv_sec + && left.tv_nsec > right.tv_nsec)) { + const int saved_errno = errno; + support_record_failure (); + const struct timespec diff = timespec_sub (left, right); + printf ("%s:%d: %ld.%09lds not before %ld.%09lds " + "(difference %ld.%09lds)n", + file, line, + left.tv_sec, left.tv_nsec, + right.tv_sec, right.tv_nsec, + diff.tv_sec, diff.tv_nsec); + errno = saved_errno; + } +} + +void +test_timespec_equal_or_after_impl (const char *file, int line, + const struct timespec left, + const struct timespec right) +{ + if (left.tv_sec < right.tv_sec + || (left.tv_sec == right.tv_sec + && left.tv_nsec < right.tv_nsec)) { + const int saved_errno = errno; + support_record_failure (); + const struct timespec diff = timespec_sub (right, left); + printf ("%s:%d: %ld.%09lds not after %ld.%09lds " + "(difference %ld.%09lds)n", + file, line, + left.tv_sec, left.tv_nsec, + right.tv_sec, right.tv_nsec, + diff.tv_sec, diff.tv_nsec); + errno = saved_errno; + } +} diff --git a/support/timespec.h b/support/timespec.h new file mode 100644 index 0000000..4a8b341 --- /dev/null +++ b/support/timespec.h @@ -0,0 +1,79 @@ +/* Useful functions for tests that use struct timespec. + Copyright (C) 2019 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef SUPPORT_TIMESPEC_H +#define SUPPORT_TIMESPEC_H + +#include +#include +#include +#include + +struct timespec timespec_add (struct timespec, struct timespec) + __attribute__((const)); +struct timespec timespec_sub (struct timespec, struct timespec) + __attribute__((const)); + +static inline struct timespec +make_timespec (time_t s, long int ns) +{ + struct timespec r; + r.tv_sec = s; + r.tv_nsec = ns; + return r; +} + +enum { TIMESPEC_HZ = 1000000000 }; + +void test_timespec_before_impl (const char *file, int line, + const struct timespec left, + const struct timespec right); + +void test_timespec_equal_or_after_impl (const char *file, int line, + const struct timespec left, + const struct timespec right); + +/* Check that the timespec on the left represents a time before the + time on the right. */ +#define TEST_TIMESPEC_BEFORE(left, right) \ + test_timespec_before_impl (__FILE__, __LINE__, (left), (right)) + +#define TEST_TIMESPEC_BEFORE_NOW(left, clockid) \ + ({ \ + struct timespec now; \ + const int saved_errno = errno; \ + xclock_gettime ((clockid), &now); \ + TEST_TIMESPEC_BEFORE ((left), now); \ + errno = saved_errno; \ + }) + +/* Check that the timespec on the left represents a after before the + time on the right. */ +#define TEST_TIMESPEC_EQUAL_OR_AFTER(left, right) \ + test_timespec_equal_or_after_impl (__FILE__, __LINE__, left, right) + +#define TEST_TIMESPEC_NOW_OR_AFTER(clockid, right) \ + ({ \ + struct timespec now; \ + const int saved_errno = errno; \ + xclock_gettime ((clockid), &now); \ + TEST_TIMESPEC_EQUAL_OR_AFTER (now, (right)); \ + errno = saved_errno; \ + }) + +#endif /* SUPPORT_TIMESPEC_H */