[PATCH] libc: replace string/strsignal.c with musl copy

61 views
Skip to first unread message

Waldemar Kozaczuk

unread,
Aug 25, 2020, 11:54:12 PM8/25/20
to osv...@googlegroups.com, Waldemar Kozaczuk
This patch replaces libc/string/strsignal.c with a musl
copy under musl/src/string/strsignal.c. The musl copy
is newer and only slightly different.

This patch also adds relevant tests to tst-string.cc
to test strsignal() logic. Please note we disable
real-time signal test until we upgrade to newer version
of musl.

I have also noticed that on Linux strsignal()
returns messages ending with signal number like so:
'Unknown signal -1' whereas musl version simply
returns 'Unknown signal' without the signal number.
This might be fixed in future version of musl.

Signed-off-by: Waldemar Kozaczuk <jwkoz...@gmail.com>
---
Makefile | 2 +-
libc/string/strsignal.c | 99 -----------------------------------------
tests/tst-string.cc | 38 ++++++++++++++++
3 files changed, 39 insertions(+), 100 deletions(-)
delete mode 100644 libc/string/strsignal.c

diff --git a/Makefile b/Makefile
index 9a490211..c123d05b 100644
--- a/Makefile
+++ b/Makefile
@@ -1600,7 +1600,7 @@ musl += string/strpbrk.o
musl += string/strrchr.o
musl += string/strsep.o
libc += string/stresep.o
-libc += string/strsignal.o
+musl += string/strsignal.o
musl += string/strspn.o
musl += string/strstr.o
musl += string/strtok.o
diff --git a/libc/string/strsignal.c b/libc/string/strsignal.c
deleted file mode 100644
index 3b0ae6d7..00000000
--- a/libc/string/strsignal.c
+++ /dev/null
@@ -1,99 +0,0 @@
-#include <signal.h>
-#include <string.h>
-
-#if (SIGHUP == 1) && (SIGINT == 2) && (SIGQUIT == 3) && (SIGILL == 4) \
- && (SIGTRAP == 5) && (SIGABRT == 6) && (SIGBUS == 7) && (SIGFPE == 8) \
- && (SIGKILL == 9) && (SIGUSR1 == 10) && (SIGSEGV == 11) && (SIGUSR2 == 12) \
- && (SIGPIPE == 13) && (SIGALRM == 14) && (SIGTERM == 15) && (SIGSTKFLT == 16) \
- && (SIGCHLD == 17) && (SIGCONT == 18) && (SIGSTOP == 19) && (SIGTSTP == 20) \
- && (SIGTTIN == 21) && (SIGTTOU == 22) && (SIGURG == 23) && (SIGXCPU == 24) \
- && (SIGXFSZ == 25) && (SIGVTALRM == 26) && (SIGPROF == 27) && (SIGWINCH == 28) \
- && (SIGPOLL == 29) && (SIGPWR == 30) && (SIGSYS == 31)
-
-#define sigmap(x) x
-
-#else
-
-static const char map[] = {
- [SIGHUP] = 1,
- [SIGINT] = 2,
- [SIGQUIT] = 3,
- [SIGILL] = 4,
- [SIGTRAP] = 5,
- [SIGABRT] = 6,
- [SIGBUS] = 7,
- [SIGFPE] = 8,
- [SIGKILL] = 9,
- [SIGUSR1] = 10,
- [SIGSEGV] = 11,
- [SIGUSR2] = 12,
- [SIGPIPE] = 13,
- [SIGALRM] = 14,
- [SIGTERM] = 15,
- [SIGSTKFLT] = 16,
- [SIGCHLD] = 17,
- [SIGCONT] = 18,
- [SIGSTOP] = 19,
- [SIGTSTP] = 20,
- [SIGTTIN] = 21,
- [SIGTTOU] = 22,
- [SIGURG] = 23,
- [SIGXCPU] = 24,
- [SIGXFSZ] = 25,
- [SIGVTALRM] = 26,
- [SIGPROF] = 27,
- [SIGWINCH] = 28,
- [SIGPOLL] = 29,
- [SIGPWR] = 30,
- [SIGSYS] = 31
-};
-
-#define sigmap(x) ((unsigned)(x) > sizeof map ? 0 : map[(unsigned)(x)])
-
-#endif
-
-static const char strings[] =
- "Unknown signal\0"
- "Hangup\0"
- "Interrupt\0"
- "Quit\0"
- "Illegal instruction\0"
- "Trace/breakpoint trap\0"
- "Aborted\0"
- "Bus error\0"
- "Floating point exception\0"
- "Killed\0"
- "User defined signal 1\0"
- "Segmentation fault\0"
- "User defined signal 2\0"
- "Broken pipe\0"
- "Alarm clock\0"
- "Terminated\0"
- "Stack fault\0"
- "Child exited\0"
- "Continued\0"
- "Stopped (signal)\0"
- "Stopped\0"
- "Stopped (tty input)\0"
- "Stopped (tty output)\0"
- "Urgent I/O condition\0"
- "CPU time limit exceeded\0"
- "File size limit exceeded\0"
- "Virtual timer expired\0"
- "Profiling timer expired\0"
- "Window changed\0"
- "I/O possible\0"
- "Power failure\0"
- "Bad system call";
-
-char *strsignal(int signum)
-{
- char *s = (char *)strings;
-
- signum = sigmap(signum);
- if ((unsigned)signum - 1 > 31) signum = 0;
-
- for (; signum--; s++) for (; *s; s++);
-
- return s;
-}
diff --git a/tests/tst-string.cc b/tests/tst-string.cc
index f6ce1990..b6199e0b 100644
--- a/tests/tst-string.cc
+++ b/tests/tst-string.cc
@@ -26,6 +26,8 @@
// PLUS some minor tweaks (mostly macros) that adapt it to run with boost unit framework
// instead of Google's test framework

+// gcc tests/tst-string.cc -lstdc++ -lboost_unit_test_framework -lboost_filesystem -o /tmp/a
+//#define BOOST_TEST_DYN_LINK //ONLY FOR LINUX
#define BOOST_TEST_MODULE tst-string

#include <boost/test/unit_test.hpp>
@@ -34,6 +36,10 @@ namespace utf = boost::unit_test;
#define TEST(MODULE_NAME,TEST_NAME) BOOST_AUTO_TEST_CASE(MODULE_NAME##TEST_NAME)
#define ASSERT_TRUE(EXP) BOOST_REQUIRE(EXP)
#define ASSERT_GT(EXP1,EXP2) BOOST_REQUIRE((EXP1)>(EXP2))
+#define ASSERT_EQ(EXP1,EXP2) BOOST_CHECK_EQUAL(EXP1,EXP2)
+#define ASSERT_STREQ(EXP1,EXP2) BOOST_CHECK_EQUAL(EXP1,EXP2)
+
+#include <signal.h>

TEST(STRING_TEST, strxfrm_smoke) {
locale_t l(newlocale(LC_ALL, "C.UTF-8", nullptr));
@@ -59,3 +65,35 @@ TEST(STRING_TEST, strcoll_smoke) {
ASSERT_TRUE(strcoll_l("aac", "aab", l) > 0);
freelocale(l);
}
+
+TEST(STRING_TEST, strsignal) {
+ // A regular signal.
+ ASSERT_STREQ("Hangup", strsignal(1));
+
+ // A real-time signal.
+ // TODO: Disable unti we upgrade musl
+ //ASSERT_STREQ("Real-time signal 14", strsignal(SIGRTMIN + 14));
+
+ // Errors.
+ ASSERT_STREQ("Unknown signal", strsignal(-1)); // Too small.
+ ASSERT_STREQ("Unknown signal", strsignal(0)); // Still too small.
+ ASSERT_STREQ("Unknown signal", strsignal(1234)); // Too large.
+}
+
+static void* ConcurrentStrSignalFn(void*) {
+ bool equal = (strcmp("Unknown signal", strsignal(2002)) == 0);
+ return reinterpret_cast<void*>(equal);
+}
+
+TEST(STRING_TEST, strsignal_concurrent) {
+ const char* strsignal1001 = strsignal(1001);
+ ASSERT_STREQ("Unknown signal", strsignal1001);
+
+ pthread_t t;
+ ASSERT_EQ(0, pthread_create(&t, nullptr, ConcurrentStrSignalFn, nullptr));
+ void* result;
+ ASSERT_EQ(0, pthread_join(t, &result));
+ ASSERT_TRUE(static_cast<bool>(result));
+
+ ASSERT_STREQ("Unknown signal", strsignal1001);
+}
--
2.26.2

Waldemar Kozaczuk

unread,
Aug 25, 2020, 11:54:16 PM8/25/20
to osv...@googlegroups.com, Waldemar Kozaczuk
This patch adds new unit test tst-time.cc that tests many time-related
including following:
tzset()
gmtime()
gmtime_r()
localtime()
localtime_r()
mktime()
strftime()
timegm()
strftime()
strptime()

The test is actually based on bionics time-test.cpp as the
comments in the top of the source files document.

Please note that some of the tests mostly related to strptime and strftime
are commented out as they fail with current version of musl. Hopefully
we will enable them once we upgrade to newer version of musl.

Signed-off-by: Waldemar Kozaczuk <jwkoz...@gmail.com>
---
tests/tst-time.cc | 698 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 698 insertions(+)
create mode 100644 tests/tst-time.cc

diff --git a/tests/tst-time.cc b/tests/tst-time.cc
new file mode 100644
index 00000000..420cae3d
--- /dev/null
+++ b/tests/tst-time.cc
@@ -0,0 +1,698 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Copyright (C) 2020 Waldemar Kozaczuk
+ *
+ * This work is open source software, licensed under the terms of the
+ * BSD license as described in the LICENSE file in the top-level directory.
+ */
+
+// This test is based on tests/string_time.cpp from the bionic project
+// (https://android.googlesource.com/platform/bionic as of commit: 9c6d60d073db079a87fbeb5de3e72ac12838a480)
+// PLUS some minor tweaks (mostly macros) that adapt it to run with boost unit framework
+// instead of Google's test framework
+//
+// In addition some tests (most of them related to strptime and strftime)
+// have been commented out as they do not pass on OSv.
+// We hope that many of them will pass once we upgrade musl.
+#include <time.h>
+
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <atomic>
+#include <chrono>
+
+// gcc tests/tst-time.cc -lstdc++ -lboost_unit_test_framework -lboost_filesystem -o /tmp/a
+//#define BOOST_TEST_DYN_LINK //ONLY FOR LINUX
+#define BOOST_TEST_MODULE tst-time
+
+#include <boost/test/unit_test.hpp>
+namespace utf = boost::unit_test;
+
+#define TEST(MODULE_NAME,TEST_NAME) BOOST_AUTO_TEST_CASE(MODULE_NAME##_##TEST_NAME)
+
+#define EXPECT_TRUE(EXP) BOOST_REQUIRE(EXP)
+#define EXPECT_EQ(EXP1,EXP2) BOOST_CHECK_EQUAL(EXP1,EXP2)
+#define EXPECT_STREQ(EXP1,EXP2) BOOST_CHECK_EQUAL(EXP1,EXP2)
+
+#define ASSERT_TRUE(EXP) BOOST_REQUIRE(EXP)
+#define ASSERT_EQ(EXP1,EXP2) BOOST_CHECK_EQUAL(EXP1,EXP2)
+#define ASSERT_STREQ(EXP1,EXP2) BOOST_CHECK_EQUAL(EXP1,EXP2)
+#define ASSERT_NE(EXP1,EXP2) BOOST_REQUIRE((EXP1) != (EXP2))
+#define ASSERT_GE(EXP1,EXP2) BOOST_REQUIRE((EXP1) >= (EXP2))
+#define ASSERT_LT(EXP1,EXP2) BOOST_REQUIRE((EXP1) < (EXP2))
+#define ASSERT_LE(EXP1,EXP2) BOOST_REQUIRE((EXP1) <= (EXP2))
+
+TEST(time, time) {
+ // Acquire time
+ time_t p1, t1 = time(&p1);
+ // valid?
+ ASSERT_NE(static_cast<time_t>(0), t1);
+ ASSERT_NE(static_cast<time_t>(-1), t1);
+ ASSERT_EQ(p1, t1);
+
+ // Acquire time one+ second later
+ usleep(1010000);
+ time_t p2, t2 = time(&p2);
+ // valid?
+ ASSERT_NE(static_cast<time_t>(0), t2);
+ ASSERT_NE(static_cast<time_t>(-1), t2);
+ ASSERT_EQ(p2, t2);
+
+ // Expect time progression
+ ASSERT_LT(p1, p2);
+ ASSERT_LE(t2 - t1, static_cast<time_t>(2));
+
+ // Expect nullptr call to produce same results
+ ASSERT_LE(t2, time(nullptr));
+ ASSERT_LE(time(nullptr) - t2, static_cast<time_t>(1));
+}
+
+TEST(time, gmtime) {
+ time_t t = 0;
+ tm* broken_down = gmtime(&t);
+ ASSERT_TRUE(broken_down != nullptr);
+ ASSERT_EQ(0, broken_down->tm_sec);
+ ASSERT_EQ(0, broken_down->tm_min);
+ ASSERT_EQ(0, broken_down->tm_hour);
+ ASSERT_EQ(1, broken_down->tm_mday);
+ ASSERT_EQ(0, broken_down->tm_mon);
+ ASSERT_EQ(1970, broken_down->tm_year + 1900);
+}
+
+TEST(time, gmtime_r) {
+ struct tm tm = {};
+ time_t t = 0;
+ struct tm* broken_down = gmtime_r(&t, &tm);
+ ASSERT_EQ(broken_down, &tm);
+ ASSERT_EQ(0, broken_down->tm_sec);
+ ASSERT_EQ(0, broken_down->tm_min);
+ ASSERT_EQ(0, broken_down->tm_hour);
+ ASSERT_EQ(1, broken_down->tm_mday);
+ ASSERT_EQ(0, broken_down->tm_mon);
+ ASSERT_EQ(1970, broken_down->tm_year + 1900);
+}
+
+/* TODO: FAILS on OSv
+TEST(time, gmtime_no_stack_overflow_14313703) {
+ // Is it safe to call tzload on a thread with a small stack?
+ // http://b/14313703
+ // https://code.google.com/p/android/issues/detail?id=61130
+ pthread_attr_t a;
+ ASSERT_EQ(0, pthread_attr_init(&a));
+ ASSERT_EQ(0, pthread_attr_setstacksize(&a, PTHREAD_STACK_MIN));
+
+ pthread_t t;
+ ASSERT_EQ(0, pthread_create(&t, &a, gmtime_no_stack_overflow_14313703_fn, nullptr));
+ ASSERT_EQ(0, pthread_join(t, nullptr));
+}*/
+
+TEST(time, mktime_empty_TZ) {
+ // tzcode used to have a bug where it didn't reinitialize some internal state.
+
+ // Choose a time where DST is set.
+ struct tm t;
+ memset(&t, 0, sizeof(tm));
+ t.tm_year = 1980 - 1900;
+ t.tm_mon = 6;
+ t.tm_mday = 2;
+
+ setenv("TZ", "America/Los_Angeles", 1);
+ tzset();
+ ASSERT_EQ(static_cast<time_t>(331372800U), mktime(&t));
+
+ memset(&t, 0, sizeof(tm));
+ t.tm_year = 1980 - 1900;
+ t.tm_mon = 6;
+ t.tm_mday = 2;
+
+ setenv("TZ", "", 1); // Implies UTC.
+ tzset();
+ ASSERT_EQ(static_cast<time_t>(331344000U), mktime(&t));
+}
+
+TEST(time, mktime_10310929) {
+ struct tm t;
+ memset(&t, 0, sizeof(tm));
+ t.tm_year = 200;
+ t.tm_mon = 2;
+ t.tm_mday = 10;
+
+#if !defined(__LP64__)
+ // 32-bit bionic stupidly had a signed 32-bit time_t.
+ ASSERT_EQ(-1, mktime(&t));
+ ASSERT_EQ(EOVERFLOW, errno);
+#else
+ // Everyone else should be using a signed 64-bit time_t.
+ ASSERT_GE(sizeof(time_t) * 8, 64U);
+
+ setenv("TZ", "America/Los_Angeles", 1);
+ tzset();
+ errno = 0;
+ ASSERT_EQ(static_cast<time_t>(4108348800U), mktime(&t));
+ ASSERT_EQ(0, errno);
+
+ setenv("TZ", "UTC", 1);
+ tzset();
+ errno = 0;
+ ASSERT_EQ(static_cast<time_t>(4108320000U), mktime(&t));
+ ASSERT_EQ(0, errno);
+#endif
+}
+
+TEST(time, mktime_EOVERFLOW) {
+ struct tm t;
+ memset(&t, 0, sizeof(tm));
+
+ // LP32 year range is 1901-2038, so this year is guaranteed not to overflow.
+ t.tm_year = 2016 - 1900;
+
+ t.tm_mon = 2;
+ t.tm_mday = 10;
+
+ errno = 0;
+ ASSERT_NE(static_cast<time_t>(-1), mktime(&t));
+ ASSERT_EQ(0, errno);
+
+ // This will overflow for LP32 or LP64.
+ t.tm_year = INT_MAX;
+
+ errno = 0;
+ //ASSERT_EQ(static_cast<time_t>(-1), mktime(&t)); - fails on Linux
+ //ASSERT_EQ(EOVERFLOW, errno);
+}
+
+TEST(time, strftime) {
+ setenv("TZ", "UTC", 1);
+
+ struct tm t;
+ memset(&t, 0, sizeof(tm));
+ t.tm_year = 200;
+ t.tm_mon = 2;
+ t.tm_mday = 10;
+
+ char buf[64];
+
+ // Seconds since the epoch.
+#if defined(__BIONIC__) || defined(__LP64__) // Not 32-bit glibc.
+ /* TODO: Pending musl upgrade
+ EXPECT_EQ(10U, strftime(buf, sizeof(buf), "%s", &t));
+ EXPECT_STREQ("4108320000", buf);*/
+#endif
+
+ // Date and time as text.
+ EXPECT_EQ(24U, strftime(buf, sizeof(buf), "%c", &t));
+ EXPECT_STREQ("Sun Mar 10 00:00:00 2100", buf);
+}
+
+TEST(time, strftime_null_tm_zone) {
+ // Netflix on Nexus Player wouldn't start (http://b/25170306).
+ struct tm t;
+ memset(&t, 0, sizeof(tm));
+
+ //char buf[64];
+
+ setenv("TZ", "America/Los_Angeles", 1);
+ tzset();
+
+ t.tm_isdst = 0; // "0 if Daylight Savings Time is not in effect".
+ /* TODO: Pending musl upgrade
+ EXPECT_EQ(5U, strftime(buf, sizeof(buf), "<%Z>", &t));
+ EXPECT_STREQ("<PST>", buf);*/
+
+#if defined(__BIONIC__) // glibc 2.19 only copes with tm_isdst being 0 and 1.
+ t.tm_isdst = 2; // "positive if Daylight Savings Time is in effect"
+ EXPECT_EQ(5U, strftime(buf, sizeof(buf), "<%Z>", &t));
+ EXPECT_STREQ("<PDT>", buf);
+
+ t.tm_isdst = -123; // "and negative if the information is not available".
+ EXPECT_EQ(2U, strftime(buf, sizeof(buf), "<%Z>", &t));
+ EXPECT_STREQ("<>", buf);
+#endif
+
+ setenv("TZ", "UTC", 1);
+ tzset();
+
+ t.tm_isdst = 0;
+ /* TODO: Pending musl upgrade
+ EXPECT_EQ(5U, strftime(buf, sizeof(buf), "<%Z>", &t));
+ EXPECT_STREQ("<UTC>", buf);*/
+
+#if defined(__BIONIC__) // glibc 2.19 thinks UTC DST is "UTC".
+ t.tm_isdst = 1; // UTC has no DST.
+ EXPECT_EQ(2U, strftime(buf, sizeof(buf), "<%Z>", &t));
+ EXPECT_STREQ("<>", buf);
+#endif
+}
+
+TEST(time, strftime_l) {
+ locale_t cloc = newlocale(LC_ALL, "C.UTF-8", nullptr);
+ locale_t old_locale = uselocale(cloc);
+
+ setenv("TZ", "UTC", 1);
+
+ struct tm t;
+ memset(&t, 0, sizeof(tm));
+ t.tm_year = 200;
+ t.tm_mon = 2;
+ t.tm_mday = 10;
+
+ // Date and time as text.
+ char buf[64];
+ EXPECT_EQ(24U, strftime_l(buf, sizeof(buf), "%c", &t, cloc));
+ EXPECT_STREQ("Sun Mar 10 00:00:00 2100", buf);
+
+ uselocale(old_locale);
+ freelocale(cloc);
+}
+
+TEST(time, strptime) {
+ setenv("TZ", "UTC", 1);
+
+ struct tm t;
+ char buf[64];
+
+ memset(&t, 0, sizeof(t));
+ strptime("11:14", "%R", &t);
+ strftime(buf, sizeof(buf), "%H:%M", &t);
+ EXPECT_STREQ("11:14", buf);
+
+ memset(&t, 0, sizeof(t));
+ strptime("09:41:53", "%T", &t);
+ strftime(buf, sizeof(buf), "%H:%M:%S", &t);
+ EXPECT_STREQ("09:41:53", buf);
+}
+
+/* TODO: Disable until upgrade of musl
+TEST(time, strptime_l) {
+ setenv("TZ", "UTC", 1);
+
+ struct tm t;
+ char buf[64];
+
+ memset(&t, 0, sizeof(t));
+ strptime_l("11:14", "%R", &t, LC_GLOBAL_LOCALE);
+ strftime_l(buf, sizeof(buf), "%H:%M", &t, LC_GLOBAL_LOCALE);
+ EXPECT_STREQ("11:14", buf);
+
+ memset(&t, 0, sizeof(t));
+ strptime_l("09:41:53", "%T", &t, LC_GLOBAL_LOCALE);
+ strftime_l(buf, sizeof(buf), "%H:%M:%S", &t, LC_GLOBAL_LOCALE);
+ EXPECT_STREQ("09:41:53", buf);
+}*/
+
+/* TODO: Disable until upgrade of musl
+TEST(time, strptime_F) {
+ setenv("TZ", "UTC", 1);
+
+ struct tm tm = {};
+ ASSERT_EQ('\0', *strptime("2019-03-26", "%F", &tm));
+ EXPECT_EQ(119, tm.tm_year);
+ EXPECT_EQ(2, tm.tm_mon);
+ EXPECT_EQ(26, tm.tm_mday);
+}*/
+
+/* many fail in Linux -> access violation
+TEST(time, strptime_P_p) {
+ setenv("TZ", "UTC", 1);
+
+ // For parsing, %P and %p are the same: case doesn't matter.
+
+ struct tm tm = {.tm_hour = 12};
+ ASSERT_EQ('\0', *strptime("AM", "%p", &tm));
+ EXPECT_EQ(0, tm.tm_hour);
+
+ tm = {.tm_hour = 12};
+ ASSERT_EQ('\0', *strptime("am", "%p", &tm));
+ EXPECT_EQ(0, tm.tm_hour);
+
+ tm = {.tm_hour = 12};
+ ASSERT_EQ('\0', *strptime("AM", "%P", &tm));
+ EXPECT_EQ(0, tm.tm_hour);
+
+ tm = {.tm_hour = 12};
+ ASSERT_EQ('\0', *strptime("am", "%P", &tm));
+ EXPECT_EQ(0, tm.tm_hour);
+}*/
+
+/* TODO: Disable until upgrade of musl
+TEST(time, strptime_u) {
+ setenv("TZ", "UTC", 1);
+
+ struct tm tm = {};
+ ASSERT_EQ('\0', *strptime("2", "%u", &tm));
+ EXPECT_EQ(2, tm.tm_wday);
+}*/
+
+/* Access violation on Linux
+TEST(time, strptime_v) {
+ setenv("TZ", "UTC", 1);
+
+ struct tm tm = {};
+ ASSERT_EQ('\0', *strptime("26-Mar-1980", "%v", &tm));
+ EXPECT_EQ(80, tm.tm_year);
+ EXPECT_EQ(2, tm.tm_mon);
+ EXPECT_EQ(26, tm.tm_mday);
+}*/
+
+TEST(time, strptime_V_G_g) {
+ setenv("TZ", "UTC", 1);
+
+ // %V (ISO-8601 week number), %G (year of week number, without century), and
+ // %g (year of week number) have no effect when parsed, and are supported
+ // solely so that it's possible for strptime(3) to parse everything that
+ // strftime(3) can output.
+ struct tm tm = {};
+ //ASSERT_EQ('\0', *strptime("1 2 3", "%V %G %g", &tm));
+ struct tm zero = {};
+ EXPECT_TRUE(memcmp(&tm, &zero, sizeof(tm)) == 0);
+}
+
+#define NS_PER_S 1000000000
+TEST(time, clock_gettime) {
+ // Try to ensure that our vdso clock_gettime is working.
+ timespec ts1;
+ ASSERT_EQ(0, clock_gettime(CLOCK_MONOTONIC, &ts1));
+ timespec ts2;
+ ASSERT_EQ(0, syscall(__NR_clock_gettime, CLOCK_MONOTONIC, &ts2));
+
+ // What's the difference between the two?
+ ts2.tv_sec -= ts1.tv_sec;
+ ts2.tv_nsec -= ts1.tv_nsec;
+ if (ts2.tv_nsec < 0) {
+ --ts2.tv_sec;
+ ts2.tv_nsec += NS_PER_S;
+ }
+
+ // To try to avoid flakiness we'll accept answers within 10,000,000ns (0.01s).
+ ASSERT_EQ(0, ts2.tv_sec);
+ ASSERT_TRUE(ts2.tv_nsec < 10000000);
+}
+
+TEST(time, clock_gettime_CLOCK_REALTIME) {
+ timespec ts;
+ ASSERT_EQ(0, clock_gettime(CLOCK_REALTIME, &ts));
+}
+
+TEST(time, clock_gettime_CLOCK_MONOTONIC) {
+ timespec ts;
+ ASSERT_EQ(0, clock_gettime(CLOCK_MONOTONIC, &ts));
+}
+
+TEST(time, clock_gettime_CLOCK_PROCESS_CPUTIME_ID) {
+ timespec ts;
+ ASSERT_EQ(0, clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts));
+}
+
+TEST(time, clock_gettime_CLOCK_THREAD_CPUTIME_ID) {
+ timespec ts;
+ ASSERT_EQ(0, clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts));
+}
+
+TEST(time, clock_gettime_CLOCK_BOOTTIME) {
+ timespec ts;
+ ASSERT_EQ(0, clock_gettime(CLOCK_BOOTTIME, &ts));
+}
+
+TEST(time, clock_gettime_unknown) {
+ errno = 0;
+ timespec ts;
+ ASSERT_EQ(-1, clock_gettime(-1, &ts));
+ ASSERT_EQ(EINVAL, errno);
+}
+
+TEST(time, clock_getres_CLOCK_REALTIME) {
+ timespec ts;
+ ASSERT_EQ(0, clock_getres(CLOCK_REALTIME, &ts));
+ ASSERT_EQ(1, ts.tv_nsec);
+ ASSERT_EQ(0, ts.tv_sec);
+}
+
+TEST(time, clock_getres_CLOCK_MONOTONIC) {
+ timespec ts;
+ ASSERT_EQ(0, clock_getres(CLOCK_MONOTONIC, &ts));
+ ASSERT_EQ(1, ts.tv_nsec);
+ ASSERT_EQ(0, ts.tv_sec);
+}
+
+TEST(time, clock_getres_CLOCK_PROCESS_CPUTIME_ID) {
+ timespec ts;
+ ASSERT_EQ(0, clock_getres(CLOCK_PROCESS_CPUTIME_ID, &ts));
+}
+
+TEST(time, clock_getres_CLOCK_THREAD_CPUTIME_ID) {
+ timespec ts;
+ ASSERT_EQ(0, clock_getres(CLOCK_THREAD_CPUTIME_ID, &ts));
+}
+
+/* Fails on OSv - disable for now
+TEST(time, clock_getres_CLOCK_BOOTTIME) {
+ timespec ts;
+ ASSERT_EQ(0, clock_getres(CLOCK_BOOTTIME, &ts));
+ ASSERT_EQ(1, ts.tv_nsec);
+ ASSERT_EQ(0, ts.tv_sec);
+}*/
+
+TEST(time, clock_getres_unknown) {
+ errno = 0;
+ timespec ts = { -1, -1 };
+ ASSERT_EQ(-1, clock_getres(-1, &ts));
+ ASSERT_EQ(EINVAL, errno);
+ ASSERT_EQ(-1, ts.tv_nsec);
+ ASSERT_EQ(-1, ts.tv_sec);
+}
+
+/*TODO: Investigate why the assert is failing on OSv
+TEST(time, clock) {
+ // clock(3) is hard to test, but a 1s sleep should cost less than 5ms.
+ clock_t t0 = clock();
+ sleep(1);
+ clock_t t1 = clock();
+ ASSERT_LT(t1 - t0, 5 * (CLOCKS_PER_SEC / 1000));
+}*/
+
+/* Crashes?
+TEST(time, clock_getcpuclockid_current) {
+ clockid_t clockid;
+ ASSERT_EQ(0, clock_getcpuclockid(getpid(), &clockid));
+ timespec ts;
+ ASSERT_EQ(0, clock_gettime(clockid, &ts));
+}
+
+TEST(time, clock_getcpuclockid_parent) {
+ clockid_t clockid;
+ ASSERT_EQ(0, clock_getcpuclockid(getppid(), &clockid));
+ timespec ts;
+ ASSERT_EQ(0, clock_gettime(clockid, &ts)); Crashes?
+}*/
+
+TEST(time, nanosleep) {
+ auto t0 = std::chrono::steady_clock::now();
+ const timespec ts = {.tv_nsec = 5000000};
+ ASSERT_EQ(0, nanosleep(&ts, nullptr));
+ auto t1 = std::chrono::steady_clock::now();
+ ASSERT_TRUE((int64_t)std::chrono::duration_cast<std::chrono::nanoseconds> (t1-t0).count() >= 5000000);
+}
+
+/*TODO: Fails on OSv
+TEST(time, nanosleep_EINVAL) {
+ timespec ts = {.tv_sec = -1};
+ errno = 0;
+ ASSERT_EQ(-1, nanosleep(&ts, nullptr));
+ ASSERT_EQ(EINVAL, errno);
+}*/
+
+TEST(time, bug_31938693) {
+ // User-visible symptoms in N:
+ // http://b/31938693
+ // https://code.google.com/p/android/issues/detail?id=225132
+
+ // Actual underlying bug (the code change, not the tzdata upgrade that first exposed the bug):
+ // http://b/31848040
+
+ // This isn't a great test, because very few time zones were actually affected, and there's
+ // no real logic to which ones were affected: it was just a coincidence of the data that came
+ // after them in the tzdata file.
+
+ time_t t = 1475619727;
+ struct tm tm;
+
+ setenv("TZ", "America/Los_Angeles", 1);
+ tzset();
+ ASSERT_TRUE(localtime_r(&t, &tm) != nullptr);
+ EXPECT_EQ(15, tm.tm_hour);
+
+ setenv("TZ", "Europe/London", 1);
+ tzset();
+ ASSERT_TRUE(localtime_r(&t, &tm) != nullptr);
+ EXPECT_EQ(23, tm.tm_hour);
+
+ setenv("TZ", "America/Atka", 1);
+ tzset();
+ ASSERT_TRUE(localtime_r(&t, &tm) != nullptr);
+ EXPECT_EQ(13, tm.tm_hour);
+
+ setenv("TZ", "Pacific/Apia", 1);
+ tzset();
+ ASSERT_TRUE(localtime_r(&t, &tm) != nullptr);
+ EXPECT_EQ(12, tm.tm_hour);
+
+ setenv("TZ", "Pacific/Honolulu", 1);
+ tzset();
+ ASSERT_TRUE(localtime_r(&t, &tm) != nullptr);
+ EXPECT_EQ(12, tm.tm_hour);
+
+ setenv("TZ", "Asia/Magadan", 1);
+ tzset();
+ ASSERT_TRUE(localtime_r(&t, &tm) != nullptr);
+ EXPECT_EQ(9, tm.tm_hour);
+}
+
+TEST(time, bug_31339449) {
+ // POSIX says localtime acts as if it calls tzset.
+ // tzset does two things:
+ // 1. it sets the time zone ctime/localtime/mktime/strftime will use.
+ // 2. it sets the global `tzname`.
+ // POSIX says localtime_r need not set `tzname` (2).
+ // Q: should localtime_r set the time zone (1)?
+ // Upstream tzcode (and glibc) answer "no", everyone else answers "yes".
+
+ // Pick a time, any time...
+ time_t t = 1475619727;
+
+ // Call tzset with a specific timezone.
+ setenv("TZ", "America/Atka", 1);
+ tzset();
+
+ // If we change the timezone and call localtime, localtime should use the new timezone.
+ setenv("TZ", "America/Los_Angeles", 1);
+ struct tm* tm_p = localtime(&t);
+ EXPECT_EQ(15, tm_p->tm_hour);
+
+ // Reset the timezone back.
+ setenv("TZ", "America/Atka", 1);
+ tzset();
+
+#if defined(__BIONIC__)
+ // If we change the timezone again and call localtime_r, localtime_r should use the new timezone.
+ setenv("TZ", "America/Los_Angeles", 1);
+ struct tm tm = {};
+ localtime_r(&t, &tm);
+ EXPECT_EQ(15, tm.tm_hour);
+#else
+ // The BSDs agree with us, but glibc gets this wrong.
+#endif
+}
+
+TEST(time, asctime) {
+ const struct tm tm = {};
+ ASSERT_STREQ("Sun Jan 0 00:00:00 1900\n", asctime(&tm));
+}
+
+TEST(time, asctime_r) {
+ const struct tm tm = {};
+ char buf[256];
+ ASSERT_EQ(buf, asctime_r(&tm, buf));
+ ASSERT_STREQ("Sun Jan 0 00:00:00 1900\n", buf);
+}
+
+TEST(time, ctime) {
+ setenv("TZ", "UTC", 1);
+ const time_t t = 0;
+ ASSERT_STREQ("Thu Jan 1 00:00:00 1970\n", ctime(&t));
+}
+
+TEST(time, ctime_r) {
+ setenv("TZ", "UTC", 1);
+ const time_t t = 0;
+ char buf[256];
+ ASSERT_EQ(buf, ctime_r(&t, buf));
+ ASSERT_STREQ("Thu Jan 1 00:00:00 1970\n", buf);
+}
+
+// https://issuetracker.google.com/37128336
+/* TODO: Disable until upgrade of musl
+TEST(time, strftime_strptime_s) {
+ char buf[32];
+ const struct tm tm0 = { .tm_mday = 1, .tm_mon = 0, .tm_year = 1982-1900 };
+
+ setenv("TZ", "America/Los_Angeles", 1);
+ strftime(buf, sizeof(buf), "<%s>", &tm0);
+ EXPECT_STREQ("<378720000>", buf);
+
+ setenv("TZ", "UTC", 1);
+ strftime(buf, sizeof(buf), "<%s>", &tm0);
+ EXPECT_STREQ("<378691200>", buf);
+
+ struct tm tm;
+
+ setenv("TZ", "America/Los_Angeles", 1);
+ tzset();
+ memset(&tm, 0xff, sizeof(tm));
+ char* p = strptime("378720000x", "%s", &tm);
+ ASSERT_EQ('x', *p);
+ EXPECT_EQ(0, tm.tm_sec);
+ EXPECT_EQ(0, tm.tm_min);
+ EXPECT_EQ(0, tm.tm_hour);
+ EXPECT_EQ(1, tm.tm_mday);
+ EXPECT_EQ(0, tm.tm_mon);
+ EXPECT_EQ(82, tm.tm_year);
+ EXPECT_EQ(5, tm.tm_wday);
+ EXPECT_EQ(0, tm.tm_yday);
+ EXPECT_EQ(0, tm.tm_isdst);
+
+ setenv("TZ", "UTC", 1);
+ tzset();
+ memset(&tm, 0xff, sizeof(tm));
+ p = strptime("378691200x", "%s", &tm);
+ ASSERT_EQ('x', *p);
+ EXPECT_EQ(0, tm.tm_sec);
+ EXPECT_EQ(0, tm.tm_min);
+ EXPECT_EQ(0, tm.tm_hour);
+ EXPECT_EQ(1, tm.tm_mday);
+ EXPECT_EQ(0, tm.tm_mon);
+ EXPECT_EQ(82, tm.tm_year);
+ EXPECT_EQ(5, tm.tm_wday);
+ EXPECT_EQ(0, tm.tm_yday);
+ EXPECT_EQ(0, tm.tm_isdst);
+}*/
+
+/* TODO: Disable until upgrade of musl
+TEST(time, strptime_s_nothing) {
+ struct tm tm;
+ ASSERT_EQ(nullptr, strptime("x", "%s", &tm));
+}*/
+
+TEST(time, timespec_get) {
+#if __BIONIC__
+ timespec ts = {};
+ ASSERT_EQ(0, timespec_get(&ts, 123));
+ ASSERT_EQ(TIME_UTC, timespec_get(&ts, TIME_UTC));
+#else
+// GTEST_SKIP() << "glibc doesn't have timespec_get until 2.21";
+#endif
+}
+
+TEST(time, difftime) {
+ ASSERT_EQ(1.0, difftime(1, 0));
+}
--
2.26.2

Waldemar Kozaczuk

unread,
Aug 25, 2020, 11:54:18 PM8/25/20
to osv...@googlegroups.com, Waldemar Kozaczuk
Signed-off-by: Waldemar Kozaczuk <jwkoz...@gmail.com>
---
libc/time/__tz.c | 389 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 389 insertions(+)
create mode 100644 libc/time/__tz.c

diff --git a/libc/time/__tz.c b/libc/time/__tz.c
new file mode 100644
index 00000000..a76a7b48
--- /dev/null
+++ b/libc/time/__tz.c
@@ -0,0 +1,389 @@
+#include "time_impl.h"
+#include <stdint.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include "libc.h"
+
+long __timezone = 0;
+int __daylight = 0;
+char *__tzname[2] = { 0, 0 };
+
+weak_alias(__timezone, timezone);
+weak_alias(__daylight, daylight);
+weak_alias(__tzname, tzname);
+
+static char std_name[TZNAME_MAX+1];
+static char dst_name[TZNAME_MAX+1];
+
+static int dst_off;
+static int r0[5], r1[5];
+
+static const unsigned char *zi, *trans, *index, *types, *abbrevs;
+static size_t map_size;
+
+static char old_tz_buf[32];
+static char *old_tz = old_tz_buf;
+static size_t old_tz_size = sizeof old_tz_buf;
+
+static int lock[2];
+
+static int getint(const char **p)
+{
+ unsigned x;
+ for (x=0; **p-'0'<10U; (*p)++) x = **p-'0' + 10*x;
+ return x;
+}
+
+static int getsigned(const char **p)
+{
+ if (**p == '-') {
+ ++*p;
+ return -getint(p);
+ }
+ if (**p == '+') ++*p;
+ return getint(p);
+}
+
+static int getoff(const char **p)
+{
+ int off = 3600*getsigned(p);
+ if (**p == ':') {
+ ++*p;
+ off += 60*getint(p);
+ if (**p == ':') {
+ ++*p;
+ off += getint(p);
+ }
+ }
+ return off;
+}
+
+static void getrule(const char **p, int rule[5])
+{
+ int r = rule[0] = **p;
+
+ if (r!='M') {
+ if (r=='J') ++*p;
+ else rule[0] = 0;
+ rule[1] = getint(p);
+ } else {
+ ++*p; rule[1] = getint(p);
+ ++*p; rule[2] = getint(p);
+ ++*p; rule[3] = getint(p);
+ }
+
+ if (**p=='/') {
+ ++*p;
+ rule[4] = getoff(p);
+ } else {
+ rule[4] = 7200;
+ }
+}
+
+static void getname(char *d, const char **p)
+{
+ int i;
+ if (**p == '<') {
+ ++*p;
+ for (i=0; **p!='>' && i<TZNAME_MAX; i++)
+ d[i] = (*p)[i];
+ ++*p;
+ } else {
+ for (i=0; ((*p)[i]|32)-'a'<26U && i<TZNAME_MAX; i++)
+ d[i] = (*p)[i];
+ }
+ *p += i;
+ d[i] = 0;
+}
+
+#define VEC(...) ((const unsigned char[]){__VA_ARGS__})
+
+static uint32_t zi_read32(const unsigned char *z)
+{
+ return (unsigned)z[0]<<24 | z[1]<<16 | z[2]<<8 | z[3];
+}
+
+static size_t zi_dotprod(const unsigned char *z, const unsigned char *v, size_t n)
+{
+ size_t y;
+ uint32_t x;
+ for (y=0; n; n--, z+=4, v++) {
+ x = zi_read32(z);
+ y += x * *v;
+ }
+ return y;
+}
+
+int __munmap(void *, size_t);
+
+static void do_tzset()
+{
+ char buf[NAME_MAX+25], *pathname=buf+24;
+ const char *try, *s;
+ const unsigned char *map = 0;
+ size_t i;
+ static const char search[] =
+ "/usr/share/zoneinfo/\0/share/zoneinfo/\0/etc/zoneinfo/\0";
+
+ s = getenv("TZ");
+ if (!s) s = "";
+
+ if (old_tz && !strcmp(s, old_tz)) return;
+
+ if (zi) __munmap((void *)zi, map_size);
+
+ /* Cache the old value of TZ to check if it has changed. Avoid
+ * free so as not to pull it into static programs. Growth
+ * strategy makes it so free would have minimal benefit anyway. */
+ i = strlen(s);
+ if (i > PATH_MAX+1) s = "", i = 0;
+ if (i >= old_tz_size) {
+ old_tz_size *= 2;
+ if (i >= old_tz_size) old_tz_size = i+1;
+ if (old_tz_size > PATH_MAX+2) old_tz_size = PATH_MAX+2;
+ old_tz = malloc(old_tz_size);
+ }
+ if (old_tz) memcpy(old_tz, s, i+1);
+
+ if (*s == ':') s++;
+
+ /* Non-suid can use an absolute tzfile pathname or a relative
+ * pathame beginning with "."; in secure mode, only the
+ * standard path will be searched. */
+ if (*s == '/' || *s == '.') {
+ if (!libc.secure) map = __map_file(s, &map_size);
+ } else {
+ for (i=0; s[i] && s[i]!=','; i++) {
+ if (s[i]=='/') {
+ size_t l = strlen(s);
+ if (l > NAME_MAX || strchr(s, '.'))
+ break;
+ memcpy(pathname, s, l+1);
+ pathname[l] = 0;
+ for (try=search; !map && *try; try+=l) {
+ l = strlen(try);
+ memcpy(pathname-l, try, l);
+ map = __map_file(pathname-l, &map_size);
+ }
+ break;
+ }
+ }
+ }
+
+ zi = map;
+ if (map) {
+ int scale = 2;
+ if (sizeof(time_t) > 4 && map[4]=='2') {
+ size_t skip = zi_dotprod(zi, VEC(1,1,8,5,6,1), 6);
+ trans = zi+skip+44+20;
+ scale++;
+ } else {
+ trans = zi+44;
+ }
+ index = trans + (zi_read32(trans-12) << scale);
+ types = index + zi_read32(trans-12);
+ abbrevs = types + 6*zi_read32(trans-8);
+ if (zi[map_size-1] == '\n') {
+ for (s = (const char *)zi+map_size-2; *s!='\n'; s--);
+ s++;
+ } else {
+ s = 0;
+ }
+ }
+
+ if (!s) s = "GMT0";
+ getname(std_name, &s);
+ __tzname[0] = std_name;
+ __timezone = getoff(&s);
+ getname(dst_name, &s);
+ __tzname[1] = dst_name;
+ if (dst_name[0]) {
+ __daylight = 1;
+ if (*s == '+' || *s=='-' || *s-'0'<10U)
+ dst_off = getoff(&s);
+ else
+ dst_off = __timezone - 3600;
+ } else {
+ __daylight = 0;
+ dst_off = 0;
+ }
+
+ if (*s == ',') s++, getrule(&s, r0);
+ if (*s == ',') s++, getrule(&s, r1);
+}
+
+/* Search zoneinfo rules to find the one that applies to the given time,
+ * and determine alternate opposite-DST-status rule that may be needed. */
+
+static size_t scan_trans(long long t, int local, size_t *alt)
+{
+ int scale = 3 - (trans == zi+44);
+ uint64_t x;
+ int off = 0;
+
+ size_t a = 0, n = (index-trans)>>scale, m;
+
+ if (!n) {
+ if (alt) *alt = 0;
+ return 0;
+ }
+
+ /* Binary search for 'most-recent rule before t'. */
+ while (n > 1) {
+ m = a + n/2;
+ x = zi_read32(trans + (m<<scale));
+ if (scale == 3) x = x<<32 | zi_read32(trans + (m<<scale) + 4);
+ else x = (int32_t)x;
+ if (local) off = (int32_t)zi_read32(types + 6 * index[m-1]);
+ if (t - off < (int64_t)x) {
+ n /= 2;
+ } else {
+ a = m;
+ n -= n/2;
+ }
+ }
+
+ /* First and last entry are special. First means to use lowest-index
+ * non-DST type. Last means to apply POSIX-style rule if available. */
+ n = (index-trans)>>scale;
+ if (a == n-1) return -1;
+ if (a == 0) {
+ x = zi_read32(trans + (a<<scale));
+ if (scale == 3) x = x<<32 | zi_read32(trans + (a<<scale) + 4);
+ else x = (int32_t)x;
+ if (local) off = (int32_t)zi_read32(types + 6 * index[a-1]);
+ if (t - off < (int64_t)x) {
+ for (a=0; a<(abbrevs-types)/6; a++) {
+ if (types[6*a+4] != types[4]) break;
+ }
+ if (a == (abbrevs-types)/6) a = 0;
+ if (types[6*a+4]) {
+ *alt = a;
+ return 0;
+ } else {
+ *alt = 0;
+ return a;
+ }
+ }
+ }
+
+ /* Try to find a neighboring opposite-DST-status rule. */
+ if (alt) {
+ if (a && types[6*index[a-1]+4] != types[6*index[a]+4])
+ *alt = index[a-1];
+ else if (a+1<n && types[6*index[a+1]+4] != types[6*index[a]+4])
+ *alt = index[a+1];
+ else
+ *alt = index[a];
+ }
+
+ return index[a];
+}
+
+static int days_in_month(int m, int is_leap)
+{
+ if (m==2) return 28+is_leap;
+ else return 30+((0xad5>>(m-1))&1);
+}
+
+/* Convert a POSIX DST rule plus year to seconds since epoch. */
+
+static long long rule_to_secs(const int *rule, int year)
+{
+ int is_leap;
+ long long t = __year_to_secs(year, &is_leap);
+ int x, m, n, d;
+ if (rule[0]!='M') {
+ x = rule[1];
+ if (rule[0]=='J' && (x < 60 || !is_leap)) x--;
+ t += 86400 * x;
+ } else {
+ m = rule[1];
+ n = rule[2];
+ d = rule[3];
+ t += __month_to_secs(m-1, is_leap);
+ int wday = (int)((t + 4*86400) % (7*86400)) / 86400;
+ int days = d - wday;
+ if (days < 0) days += 7;
+ if (n == 5 && days+28 >= days_in_month(m, is_leap)) n = 4;
+ t += 86400 * (days + 7*(n-1));
+ }
+ t += rule[4];
+ return t;
+}
+
+/* Determine the time zone in effect for a given time in seconds since the
+ * epoch. It can be given in local or universal time. The results will
+ * indicate whether DST is in effect at the queried time, and will give both
+ * the GMT offset for the active zone/DST rule and the opposite DST. This
+ * enables a caller to efficiently adjust for the case where an explicit
+ * DST specification mismatches what would be in effect at the time. */
+
+void __secs_to_zone(long long t, int local, int *isdst, long *offset, long *oppoff, const char **zonename)
+{
+ LOCK(lock);
+
+ do_tzset();
+
+ if (zi) {
+ size_t alt, i = scan_trans(t, local, &alt);
+ if (i != -1) {
+ *isdst = types[6*i+4];
+ *offset = -(int32_t)zi_read32(types+6*i);
+ *zonename = (const char *)abbrevs + types[6*i+5];
+ if (oppoff) *oppoff = -(int32_t)zi_read32(types+6*alt);
+ UNLOCK(lock);
+ return;
+ }
+ }
+
+ if (!__daylight) goto std;
+
+ /* FIXME: may be broken if DST changes right at year boundary?
+ * Also, this could be more efficient.*/
+ long long y = t / 31556952 + 70;
+ while (__year_to_secs(y, 0) > t) y--;
+ while (__year_to_secs(y+1, 0) < t) y++;
+
+ long long t0 = rule_to_secs(r0, y);
+ long long t1 = rule_to_secs(r1, y);
+
+ if (t0 < t1) {
+ if (!local) {
+ t0 += __timezone;
+ t1 += dst_off;
+ }
+ if (t >= t0 && t < t1) goto dst;
+ goto std;
+ } else {
+ if (!local) {
+ t1 += __timezone;
+ t0 += dst_off;
+ }
+ if (t >= t1 && t < t0) goto std;
+ goto dst;
+ }
+std:
+ *isdst = 0;
+ *offset = __timezone;
+ if (oppoff) *oppoff = dst_off;
+ *zonename = __tzname[0];
+ UNLOCK(lock);
+ return;
+dst:
+ *isdst = 1;
+ *offset = dst_off;
+ if (oppoff) *oppoff = __timezone;
+ *zonename = __tzname[1];
+ UNLOCK(lock);
+}
+
+void __tzset()
+{
+ LOCK(lock);
+ do_tzset();
+ UNLOCK(lock);
+}
+
+weak_alias(__tzset, tzset);
--
2.26.2

Waldemar Kozaczuk

unread,
Aug 25, 2020, 11:54:21 PM8/25/20
to osv...@googlegroups.com, Waldemar Kozaczuk
Most of the files under libc/time/ were copied from older version
of musl than the musl/ folder and never changed since:
- gmtime.c
- gmtime_r.c
- localtime.c
- localtime_r.c
- mktime.c
- strftime.c
- timegm.c
- __time.h
- __tm_to_time.c

Following files were changed at some point to
support different way of locking and default UTC timezone:
- __time_to_tm.c
- tzset.c

So this patch replaces most of the files under libc/time
with their musl copies via makefile. Also this patch drops
some files (__time.h, __time_to_tm.c, __tm_to_time.c, __tm_to_time.c)
and adds many new ones (__map_file.c, __month_to_secs.c, __secs_to_tm.c,
__tm_to_secs.c, __year_to_secs.c, time_impl.h) via makefile.

Please note that __tz.c is actually copied as is from musl src/time/
and then modified in following ways:
- adjust locking logic to use mutex_t
- use UTC instead of GMT as a default timezone (this is fixed in the
newer version of musl we will be upgrading to)
- fix one of the bugs when parsing timezone data (this was manually
applied from newer version of musl than we have in musl/ now)

Please note this patch effectively follows the changes made
to original musl sources with this commit - https://git.musl-libc.org/cgit/musl/commit/?id=1cc81f5cb0df2b66a795ff0c26d7bbc4d16e13c6.
New logic also supports reading timezone data
from directories like /usr/share/zoneinfo. That is a reason
we add some of these file to the test image from host to
accomodate some of the unit tests in tst-time.cc.

Finally, we could have waited with this update until upgrade to new musl,
but I think that eliminating most files from libc/time/ now
is actually going to make easier to do eventual updgrade in future as the
structure of this directory has not changed fundamentally in
future versions of musl.

Signed-off-by: Waldemar Kozaczuk <jwkoz...@gmail.com>
---
Makefile | 25 +++--
libc/aliases.ld | 4 +
libc/locale/strftime_l.c | 11 --
libc/syscall_to_function.h | 4 +-
libc/time/__time.h | 9 --
libc/time/__time_to_tm.c | 88 ----------------
libc/time/__tm_to_time.c | 33 ------
libc/time/__tz.c | 16 +--
libc/time/gmtime.c | 11 --
libc/time/gmtime_r.c | 10 --
libc/time/localtime.c | 12 ---
libc/time/localtime_r.c | 11 --
libc/time/mktime.c | 24 -----
libc/time/strftime.c | 172 -------------------------------
libc/time/time_impl.h | 1 +
libc/time/timegm.c | 9 --
libc/time/tzset.c | 173 --------------------------------
modules/tests/Makefile | 2 +-
modules/tests/usr.manifest.skel | 4 +
19 files changed, 36 insertions(+), 583 deletions(-)
delete mode 100644 libc/locale/strftime_l.c
delete mode 100644 libc/time/__time.h
delete mode 100644 libc/time/__time_to_tm.c
delete mode 100644 libc/time/__tm_to_time.c
delete mode 100644 libc/time/gmtime.c
delete mode 100644 libc/time/gmtime_r.c
delete mode 100644 libc/time/localtime.c
delete mode 100644 libc/time/localtime_r.c
delete mode 100644 libc/time/mktime.c
delete mode 100644 libc/time/strftime.c
create mode 120000 libc/time/time_impl.h
delete mode 100644 libc/time/timegm.c
delete mode 100644 libc/time/tzset.c

diff --git a/Makefile b/Makefile
index c123d05b..6d39e5bf 100644
--- a/Makefile
+++ b/Makefile
@@ -1046,7 +1046,6 @@ musl += locale/strcasecmp_l.o
musl += locale/strcoll.o
musl += locale/strerror_l.o
musl += locale/strfmon.o
-libc += locale/strftime_l.o
musl += locale/strncasecmp_l.o
libc += locale/strtod_l.o
libc += locale/strtof_l.o
@@ -1645,24 +1644,28 @@ musl += temp/mkostemp.o
musl += temp/mkostemps.o

libc += time/__asctime.o
-libc += time/__time_to_tm.o
-libc += time/__tm_to_time.o
+musl += time/__map_file.o
+$(out)/musl/src/time/__map_file.o: CFLAGS += --include libc/syscall_to_function.h
+musl += time/__month_to_secs.o
+musl += time/__secs_to_tm.o
+musl += time/__tm_to_secs.o
+libc += time/__tz.o
+musl += time/__year_to_secs.o
musl += time/asctime.o
musl += time/asctime_r.o
musl += time/ctime.o
musl += time/ctime_r.o
musl += time/difftime.o
musl += time/getdate.o
-libc += time/gmtime.o
-libc += time/gmtime_r.o
-libc += time/localtime.o
-libc += time/localtime_r.o
-libc += time/mktime.o
-libc += time/strftime.o
+musl += time/gmtime.o
+musl += time/gmtime_r.o
+musl += time/localtime.o
+musl += time/localtime_r.o
+musl += time/mktime.o
+musl += time/strftime.o
musl += time/strptime.o
musl += time/time.o
-libc += time/timegm.o
-libc += time/tzset.o
+musl += time/timegm.o
libc += time/wcsftime.o
libc += time/ftime.o # verbatim copy of the file as in 4b15d9f46a2b@musl
$(out)/libc/time/ftime.o: CFLAGS += -Ilibc/include
diff --git a/libc/aliases.ld b/libc/aliases.ld
index 0bc91597..e2e2e73c 100644
--- a/libc/aliases.ld
+++ b/libc/aliases.ld
@@ -31,6 +31,10 @@ __setlocale = setlocale;
/* multibyte */
__mbrlen = mbrlen;

+/* memory */
+__munmap = munmap;
+__mmap = mmap;
+
/* stdio */
__dup3 = dup3;

diff --git a/libc/locale/strftime_l.c b/libc/locale/strftime_l.c
deleted file mode 100644
index 0193866e..00000000
--- a/libc/locale/strftime_l.c
+++ /dev/null
@@ -1,11 +0,0 @@
-#include <locale.h>
-#include <time.h>
-#include "libc.h"
-
-size_t __strftime_l(char *restrict s, size_t n, const char *restrict f, const struct tm *restrict tm, locale_t l)
-{
- return strftime(s, n, f, tm);
-}
-
-/* OSv local: a libstdc++ build against glibc wants the __ version */
-weak_alias(__strftime_l, strftime_l);
diff --git a/libc/syscall_to_function.h b/libc/syscall_to_function.h
index 08d7ce93..a58b4222 100644
--- a/libc/syscall_to_function.h
+++ b/libc/syscall_to_function.h
@@ -1,7 +1,7 @@
#include <bits/syscall.h>
#include <unistd.h>

-#define __OSV_TO_FUNCTION_SYS_open(filename, flags, perm) (open(filename, flags, perm))
+#define __OSV_TO_FUNCTION_SYS_open(filename, flags, ...) (open(filename, flags __VA_OPT__(,) __VA_ARGS__))

#define __OSV_TO_FUNCTION_SYS_close(fd) (close(fd))

@@ -15,6 +15,8 @@

#define __OSV_TO_FUNCTION_SYS_ioctl(fd, cmd, args) (ioctl(fd, cmd, args))

+#define __OSV_TO_FUNCTION_SYS_fstat(fd, st) (fstat(fd, st))
+
#define __OSV_TO_FUNCTION_SYS_unlink(path) (unlink(path))

#define __OSV_TO_FUNCTION_SYS_rmdir(path) (rmdir(path))
diff --git a/libc/time/__time.h b/libc/time/__time.h
deleted file mode 100644
index 967e5180..00000000
--- a/libc/time/__time.h
+++ /dev/null
@@ -1,9 +0,0 @@
-time_t __tm_to_time(struct tm *);
-struct tm *__time_to_tm(time_t, struct tm *);
-void __tzset(void);
-struct tm *__dst_adjust(struct tm *tm);
-
-extern long __timezone;
-extern int __daylight;
-extern int __dst_offset;
-extern char *__tzname[2];
diff --git a/libc/time/__time_to_tm.c b/libc/time/__time_to_tm.c
deleted file mode 100644
index 48ea1f75..00000000
--- a/libc/time/__time_to_tm.c
+++ /dev/null
@@ -1,88 +0,0 @@
-#include <time.h>
-
-/* C defines the rounding for division in a nonsensical way */
-#define Q(a,b) ((a)>0 ? (a)/(b) : -(((b)-(a)-1)/(b)))
-
-#define DAYS_PER_400Y (365*400 + 97)
-#define DAYS_PER_100Y (365*100 + 24)
-#define DAYS_PER_4Y (365*4 + 1)
-
-/* FIXME: use lldiv once it's fixed to compute quot,rem together */
-struct tm *__time_to_tm(time_t t, struct tm *tm)
-{
- /* months are march-based */
- static const int days_thru_month[] = {31,61,92,122,153,184,214,245,275,306,337,366};
- long long bigday;
- unsigned int day, year4, year100;
- int year, year400;
- int month;
- int leap;
- int hour, min, sec;
- int wday, mday, yday;
-
- /* start from 2000-03-01 (multiple of 400 years) */
- t += -946684800 - 86400*(31+29);
-
- bigday = Q(t, 86400);
- sec = t-bigday*86400;
-
- hour = sec/3600;
- sec -= hour*3600;
- min = sec/60;
- sec -= min*60;
-
- /* 2000-03-01 was a wednesday */
- wday = (3+bigday)%7;
- if (wday < 0) wday += 7;
-
- t = -946684800LL - 86400*(31+29) + 9000000;
-
- year400 = Q(bigday, DAYS_PER_400Y);
- day = bigday-year400*DAYS_PER_400Y;
-
- year100 = day/DAYS_PER_100Y;
- if (year100 == 4) year100--;
- day -= year100*DAYS_PER_100Y;
-
- year4 = day/DAYS_PER_4Y;
- if (year4 == 25) year4--;
- day -= year4*DAYS_PER_4Y;
-
- year = day/365;
- if (year == 4) year--;
- day -= year*365;
-
- leap = !year && (year4 || !year100);
- yday = day + 31+28 + leap;
- if (yday >= 365+leap) yday -= 365+leap;
-
- year += 4*year4 + 100*year100 + 400*year400 + 2000-1900;
-
- for (month=0; days_thru_month[month] <= day; month++);
- if (month) day -= days_thru_month[month-1];
- month += 2;
- if (month >= 12) {
- month -= 12;
- year++;
- }
-
- mday = day+1;
-
- tm->tm_sec = sec;
- tm->tm_min = min;
- tm->tm_hour= hour;
- tm->tm_mday= mday;
- tm->tm_mon = month;
- tm->tm_year= year;
- tm->tm_wday= wday;
- tm->tm_yday= yday;
-#ifdef __USE_BSD
- tm->tm_zone = "GMT";
- tm->tm_gmtoff = 0;
-#else
- tm->__tm_zone = "GMT";
- tm->__tm_gmtoff = 0;
-#endif
-
- return tm;
-}
diff --git a/libc/time/__tm_to_time.c b/libc/time/__tm_to_time.c
deleted file mode 100644
index 9f11805d..00000000
--- a/libc/time/__tm_to_time.c
+++ /dev/null
@@ -1,33 +0,0 @@
-#include <time.h>
-
-/* C defines the rounding for division in a nonsensical way */
-#define Q(a,b) ((a)>0 ? (a)/(b) : -(((b)-(a)-1)/(b)))
-
-time_t __tm_to_time(struct tm *tm)
-{
- time_t year = tm->tm_year + -100;
- int month = tm->tm_mon;
- int day = tm->tm_mday;
- int z4, z100, z400;
-
- /* normalize month */
- if (month >= 12) {
- year += month/12;
- month %= 12;
- } else if (month < 0) {
- year += month/12;
- month %= 12;
- if (month) {
- month += 12;
- year--;
- }
- }
- z4 = Q(year - (month < 2), 4);
- z100 = Q(z4, 25);
- z400 = Q(z100, 4);
- day += year*365 + z4 - z100 + z400 +
- month[(const int []){0,31,59,90,120,151,181,212,243,273,304,334}];
- return (long long)day*86400
- + tm->tm_hour*3600 + tm->tm_min*60 + tm->tm_sec
- - -946684800; /* the dawn of time :) */
-}
diff --git a/libc/time/__tz.c b/libc/time/__tz.c
index a76a7b48..cadece11 100644
--- a/libc/time/__tz.c
+++ b/libc/time/__tz.c
@@ -2,6 +2,7 @@
#include <stdint.h>
#include <limits.h>
#include <stdlib.h>
+#undef _BSD_SOURCE // avoid conflict of static index variable with index() function in include/api/strings.h
#include <string.h>
#include "libc.h"

@@ -15,6 +16,7 @@ weak_alias(__tzname, tzname);

static char std_name[TZNAME_MAX+1];
static char dst_name[TZNAME_MAX+1];
+const char __utc[] = "UTC";

static int dst_off;
static int r0[5], r1[5];
@@ -26,7 +28,7 @@ static char old_tz_buf[32];
static char *old_tz = old_tz_buf;
static size_t old_tz_size = sizeof old_tz_buf;

-static int lock[2];
+static mutex_t lock;

static int getint(const char **p)
{
@@ -127,7 +129,7 @@ static void do_tzset()
"/usr/share/zoneinfo/\0/share/zoneinfo/\0/etc/zoneinfo/\0";

s = getenv("TZ");
- if (!s) s = "";
+ if (!s) s = __utc;

if (old_tz && !strcmp(s, old_tz)) return;

@@ -137,7 +139,7 @@ static void do_tzset()
* free so as not to pull it into static programs. Growth
* strategy makes it so free would have minimal benefit anyway. */
i = strlen(s);
- if (i > PATH_MAX+1) s = "", i = 0;
+ if (i > PATH_MAX+1) s = __utc, i = 0;
if (i >= old_tz_size) {
old_tz_size *= 2;
if (i >= old_tz_size) old_tz_size = i+1;
@@ -152,7 +154,7 @@ static void do_tzset()
* pathame beginning with "."; in secure mode, only the
* standard path will be searched. */
if (*s == '/' || *s == '.') {
- if (!libc.secure) map = __map_file(s, &map_size);
+ map = __map_file(s, &map_size);
} else {
for (i=0; s[i] && s[i]!=','; i++) {
if (s[i]=='/') {
@@ -175,8 +177,8 @@ static void do_tzset()
if (map) {
int scale = 2;
if (sizeof(time_t) > 4 && map[4]=='2') {
- size_t skip = zi_dotprod(zi, VEC(1,1,8,5,6,1), 6);
- trans = zi+skip+44+20;
+ size_t skip = zi_dotprod(zi+20, VEC(1,1,8,5,6,1), 6);
+ trans = zi+skip+44+44;
scale++;
} else {
trans = zi+44;
@@ -192,7 +194,7 @@ static void do_tzset()
}
}

- if (!s) s = "GMT0";
+ if (!s) s = __utc;
getname(std_name, &s);
__tzname[0] = std_name;
__timezone = getoff(&s);
diff --git a/libc/time/gmtime.c b/libc/time/gmtime.c
deleted file mode 100644
index d4d5d1f1..00000000
--- a/libc/time/gmtime.c
+++ /dev/null
@@ -1,11 +0,0 @@
-#include <time.h>
-
-#include "__time.h"
-
-struct tm *gmtime(const time_t *t)
-{
- static struct tm tm;
- __time_to_tm(*t, &tm);
- tm.tm_isdst = 0;
- return &tm;
-}
diff --git a/libc/time/gmtime_r.c b/libc/time/gmtime_r.c
deleted file mode 100644
index 13a2548f..00000000
--- a/libc/time/gmtime_r.c
+++ /dev/null
@@ -1,10 +0,0 @@
-#include <time.h>
-
-#include "__time.h"
-
-struct tm *gmtime_r(const time_t *restrict t, struct tm *restrict result)
-{
- __time_to_tm(*t, result);
- result->tm_isdst = 0;
- return result;
-}
diff --git a/libc/time/localtime.c b/libc/time/localtime.c
deleted file mode 100644
index abd5e84d..00000000
--- a/libc/time/localtime.c
+++ /dev/null
@@ -1,12 +0,0 @@
-#include <time.h>
-
-#include "__time.h"
-
-struct tm *localtime(const time_t *t)
-{
- static struct tm tm;
- __tzset();
- __time_to_tm(*t - __timezone, &tm);
- tm.tm_isdst = -1;
- return __dst_adjust(&tm);
-}
diff --git a/libc/time/localtime_r.c b/libc/time/localtime_r.c
deleted file mode 100644
index 389a5917..00000000
--- a/libc/time/localtime_r.c
+++ /dev/null
@@ -1,11 +0,0 @@
-#include <time.h>
-
-#include "__time.h"
-
-struct tm *localtime_r(const time_t *restrict t, struct tm *restrict result)
-{
- __tzset();
- __time_to_tm(*t - __timezone, result);
- result->tm_isdst = -1;
- return __dst_adjust(result);
-}
diff --git a/libc/time/mktime.c b/libc/time/mktime.c
deleted file mode 100644
index 858cd50d..00000000
--- a/libc/time/mktime.c
+++ /dev/null
@@ -1,24 +0,0 @@
-#include <time.h>
-
-#include "__time.h"
-
-time_t mktime(struct tm *tm)
-{
- int isdst = tm->tm_isdst;
- time_t t, lt;
-
- __tzset();
-
- tm->tm_sec += __timezone;
- if (isdst > 0) tm->tm_sec += __dst_offset;
-
- t = __tm_to_time(tm);
-
- lt = t - __timezone;
- if (isdst > 0) lt -= __dst_offset;
- __time_to_tm(lt, tm);
-
- __dst_adjust(tm);
-
- return t;
-}
diff --git a/libc/time/strftime.c b/libc/time/strftime.c
deleted file mode 100644
index b69a83a4..00000000
--- a/libc/time/strftime.c
+++ /dev/null
@@ -1,172 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <langinfo.h>
-#include <time.h>
-#include "__time.h"
-
-// FIXME: integer overflows
-
-const char *__langinfo(nl_item);
-
-size_t strftime(char *restrict s, size_t n, const char *restrict f, const struct tm *restrict tm)
-{
- nl_item item;
- int val;
- const char *fmt;
- size_t l;
- for (l=0; *f && l<n; f++) {
- if (*f == '%') {
-do_fmt:
- switch (*++f) {
- case '%':
- goto literal;
- case 'E':
- case 'O':
- goto do_fmt;
- case 'a':
- item = ABDAY_1 + tm->tm_wday;
- goto nl_strcat;
- case 'A':
- item = DAY_1 + tm->tm_wday;
- goto nl_strcat;
- case 'h':
- case 'b':
- item = ABMON_1 + tm->tm_mon;
- goto nl_strcat;
- case 'B':
- item = MON_1 + tm->tm_mon;
- goto nl_strcat;
- case 'c':
- item = D_T_FMT;
- goto nl_strftime;
- case 'C':
- val = (1900+tm->tm_year) / 100;
- fmt = "%02d";
- goto number;
- case 'd':
- val = tm->tm_mday;
- fmt = "%02d";
- goto number;
- case 'D':
- fmt = "%m/%d/%y";
- goto recu_strftime;
- case 'e':
- val = tm->tm_mday;
- fmt = "%2d";
- goto number;
- case 'F':
- fmt = "%Y-%m-%d";
- goto recu_strftime;
- case 'g':
- // FIXME
- val = 0; //week_based_year(tm)%100;
- fmt = "%02d";
- goto number;
- case 'G':
- // FIXME
- val = 0; //week_based_year(tm);
- fmt = "%04d";
- goto number;
- case 'H':
- val = tm->tm_hour;
- fmt = "%02d";
- goto number;
- case 'I':
- val = tm->tm_hour;
- if (!val) val = 12;
- else if (val > 12) val -= 12;
- fmt = "%02d";
- goto number;
- case 'j':
- val = tm->tm_yday+1;
- fmt = "%03d";
- goto number;
- case 'm':
- val = tm->tm_mon+1;
- fmt = "%02d";
- goto number;
- case 'M':
- val = tm->tm_min;
- fmt = "%02d";
- goto number;
- case 'n':
- s[l++] = '\n';
- continue;
- case 'p':
- item = tm->tm_hour >= 12 ? PM_STR : AM_STR;
- goto nl_strcat;
- case 'r':
- item = T_FMT_AMPM;
- goto nl_strftime;
- case 'R':
- fmt = "%H:%M";
- goto recu_strftime;
- case 'S':
- val = tm->tm_sec;
- fmt = "%02d";
- goto number;
- case 't':
- s[l++] = '\t';
- continue;
- case 'T':
- fmt = "%H:%M:%S";
- goto recu_strftime;
- case 'u':
- val = tm->tm_wday ? tm->tm_wday : 7;
- fmt = "%d";
- goto number;
- case 'U':
- case 'V':
- case 'W':
- // FIXME: week number mess..
- continue;
- case 'w':
- val = tm->tm_wday;
- fmt = "%d";
- goto number;
- case 'x':
- item = D_FMT;
- goto nl_strftime;
- case 'X':
- item = T_FMT;
- goto nl_strftime;
- case 'y':
- val = tm->tm_year % 100;
- fmt = "%02d";
- goto number;
- case 'Y':
- val = tm->tm_year + 1900;
- fmt = "%04d";
- goto number;
- case 'z':
- if (tm->tm_isdst < 0) continue;
- val = -__timezone - (tm->tm_isdst ? __dst_offset : 0);
- l += snprintf(s+l, n-l, "%+.2d%.2d", val/3600, abs(val%3600)/60);
- continue;
- case 'Z':
- if (tm->tm_isdst < 0 || !__tzname[0] || !__tzname[0][0])
- continue;
- l += snprintf(s+l, n-l, "%s", __tzname[!!tm->tm_isdst]);
- continue;
- default:
- return 0;
- }
- }
-literal:
- s[l++] = *f;
- continue;
-number:
- l += snprintf(s+l, n-l, fmt, val);
- continue;
-nl_strcat:
- l += snprintf(s+l, n-l, "%s", __langinfo(item));
- continue;
-nl_strftime:
- fmt = __langinfo(item);
-recu_strftime:
- l += strftime(s+l, n-l, fmt, tm);
- }
- if (l >= n) return 0;
- s[l] = 0;
- return l;
-}
diff --git a/libc/time/time_impl.h b/libc/time/time_impl.h
new file mode 120000
index 00000000..c4f1d67b
--- /dev/null
+++ b/libc/time/time_impl.h
@@ -0,0 +1 @@
+../../musl/src/time/time_impl.h
\ No newline at end of file
diff --git a/libc/time/timegm.c b/libc/time/timegm.c
deleted file mode 100644
index 6d08917e..00000000
--- a/libc/time/timegm.c
+++ /dev/null
@@ -1,9 +0,0 @@
-#define _GNU_SOURCE
-#include <time.h>
-
-#include "__time.h"
-
-time_t timegm(struct tm *tm)
-{
- return __tm_to_time(tm);
-}
diff --git a/libc/time/tzset.c b/libc/time/tzset.c
deleted file mode 100644
index 3b2c9313..00000000
--- a/libc/time/tzset.c
+++ /dev/null
@@ -1,173 +0,0 @@
-#include <time.h>
-#include <ctype.h>
-#include <limits.h>
-#include <stdlib.h>
-#include <string.h>
-#include "libc.h"
-
-#include "__time.h"
-
-long __timezone = 0;
-int __daylight = 0;
-char *__tzname[2] = { 0, 0 };
-int __dst_offset = 0;
-
-weak_alias(__timezone, timezone);
-weak_alias(__daylight, daylight);
-weak_alias(__tzname, tzname);
-
-static char std_name[TZNAME_MAX+1];
-static char dst_name[TZNAME_MAX+1];
-
-/* all elements are zero-based */
-static struct rule {
- signed char month;
- signed char week;
- short day;
- int time;
-} __dst_start, __dst_end;
-
-static void zname(char *d, char **s)
-{
- int i;
- for (i=0; i<TZNAME_MAX && isalpha(d[i]=**s); i++, (*s)++);
- d[i] = 0;
-}
-
-static int hhmmss(char **s)
-{
- int ofs = strtol(*s, s, 10)*3600;
- if (ofs >= 0) {
- if (**s == ':') ofs += strtol(*s+1, s, 10)*60;
- if (**s == ':') ofs += strtol(*s+1, s, 10);
- } else {
- if (**s == ':') ofs -= strtol(*s+1, s, 10)*60;
- if (**s == ':') ofs -= strtol(*s+1, s, 10);
- }
- return ofs;
-}
-
-static int dstrule(struct rule *rule, char **s)
-{
- if (**s != ',') return -1;
- switch (*++*s) {
- case 'J':
- rule->month = 'J';
- rule->day = strtol(*s+1, s, 10)-1;
- break;
- case 'M':
- rule->month = strtol(*s+1, s, 10)-1;
- if (**s != '.' || rule->month < 0 || rule->month > 11)
- return -1;
- rule->week = strtol(*s+1, s, 10)-1;
- if (**s != '.' || rule->week < 0 || rule->week > 4)
- return -1;
- rule->day = strtol(*s+1, s, 10);
- if (rule->day < 0 || rule->day > 6)
- return -1;
- break;
- default:
- rule->month = 'L';
- rule->day = strtol(*s+1, s, 10);
- break;
- }
- if (**s == '/') {
- (*s)++;
- rule->time = hhmmss(s);
- } else rule->time = 7200;
- return 0;
-}
-
-void tzset(void)
-{
- char *z, *a;
-
- strcpy(std_name, "UTC");
- strcpy(dst_name, "UTC");
- __tzname[0] = std_name;
- __tzname[1] = dst_name;
- __timezone = 0;
- __daylight = 0;
-
- if (!(z = getenv("TZ")) || !isalpha(*z)) return;
-
- zname(std_name, &z);
- __timezone = hhmmss(&z);
-
- zname(dst_name, &z);
- if (dst_name[0]) __daylight=1;
- a = z;
- __dst_offset = hhmmss(&z) - __timezone;
- if (z==a) __dst_offset = -3600;
-
- if (dstrule(&__dst_start, &z) || dstrule(&__dst_end, &z))
- __daylight = 0;
-}
-
-void __tzset(void)
-{
- static mutex_t lock;
- static int init;
- if (init) return;
- LOCK(lock);
- if (!init) tzset();
- init=1;
- UNLOCK(lock);
-}
-
-static int is_leap(int year)
-{
- year -= 100;
- return !(year&3) && ((year%100) || !(year%400));
-}
-
-static int cutoff_yday(struct tm *tm, struct rule *rule)
-{
- static const char days_in_month[] = {31,28,31,30,31,30,31,31,30,31,30,31};
- static const int first_day[] = {0,31,59,90,120,151,181,212,243,273,304,335};
- int yday, mday, leap;
-
- switch (rule->month) {
- case 'J':
- return rule->day + (tm->tm_mon > 1 && is_leap(tm->tm_year));
- case 'L':
- return rule->day;
- default:
- yday = first_day[rule->month];
- leap = is_leap(tm->tm_year);
- if (rule->month > 1 && leap) yday++;
- mday = (rule->day - (yday + tm->tm_wday - tm->tm_yday) + 1400)%7 + 7*rule->week;
- if (mday >= days_in_month[rule->month] + (leap && rule->month == 1))
- mday -= 7;
- return mday + yday;
- }
-}
-
-struct tm *__dst_adjust(struct tm *tm)
-{
- time_t t;
- int start, end, secs;
- int after_start, before_end;
-
- if (tm->tm_isdst >= 0) return tm;
- if (!__daylight) {
- tm->tm_isdst = 0;
- return tm;
- }
-
- secs = tm->tm_hour*3600 + tm->tm_min*60 + tm->tm_sec;
- start = cutoff_yday(tm, &__dst_start);
- end = cutoff_yday(tm, &__dst_end);
-
- after_start = (tm->tm_yday > start || (tm->tm_yday == start && secs >= __dst_start.time));
- before_end = (tm->tm_yday < end || (tm->tm_yday == end && secs < __dst_end.time));
-
- if ((after_start && before_end) || ((end < start) && (after_start || before_end))) {
- tm->tm_sec -= __dst_offset;
- tm->tm_isdst = 1;
- t = __tm_to_time(tm);
- return __time_to_tm(t, tm);
- } else tm->tm_isdst = 0;
-
- return tm;
-}
diff --git a/modules/tests/Makefile b/modules/tests/Makefile
index 78f215e6..be89e531 100644
--- a/modules/tests/Makefile
+++ b/modules/tests/Makefile
@@ -246,7 +246,7 @@ common-boost-tests := tst-vfs.so tst-libc-locking.so misc-fs-stress.so \
tst-bsd-tcp1-zsndrcv.so tst-async.so tst-rcu-list.so tst-tcp-listen.so \
tst-poll.so tst-bitset-iter.so tst-timer-set.so tst-clock.so \
tst-rcu-hashtable.so tst-unordered-ring-mpsc.so \
- tst-seek.so tst-ctype.so tst-wctype.so tst-string.so
+ tst-seek.so tst-ctype.so tst-wctype.so tst-string.so tst-time.so

boost-tests := $(common-boost-tests)

diff --git a/modules/tests/usr.manifest.skel b/modules/tests/usr.manifest.skel
index 8f2c824c..9b768150 100644
--- a/modules/tests/usr.manifest.skel
+++ b/modules/tests/usr.manifest.skel
@@ -1 +1,5 @@
/testrunner.so: ./tests/testrunner.so
+/usr/share/zoneinfo/America/**: /usr/share/zoneinfo/America/**
+/usr/share/zoneinfo/Europe/**: /usr/share/zoneinfo/Europe/**
+/usr/share/zoneinfo/Pacific/**: /usr/share/zoneinfo/Pacific/**
+/usr/share/zoneinfo/Asia/**: /usr/share/zoneinfo/Asia/**
--
2.26.2

Waldemar Kozaczuk

unread,
Aug 25, 2020, 11:54:22 PM8/25/20
to osv...@googlegroups.com, Waldemar Kozaczuk
The relevant files under libc/locale and libc/time/__asctime.c
are pretty much identical to their copies under musl/
so we are replacing them with current version.

Signed-off-by: Waldemar Kozaczuk <jwkoz...@gmail.com>
---
Makefile | 5 ++-
libc/locale/langinfo.c | 61 -------------------------------------
libc/locale/nl_langinfo_l.c | 11 -------
libc/time/__asctime.c | 28 -----------------
4 files changed, 2 insertions(+), 103 deletions(-)
delete mode 100644 libc/locale/langinfo.c
delete mode 100644 libc/locale/nl_langinfo_l.c
delete mode 100644 libc/time/__asctime.c

diff --git a/Makefile b/Makefile
index 6d39e5bf..2d19ccc6 100644
--- a/Makefile
+++ b/Makefile
@@ -1038,9 +1038,8 @@ musl += locale/iswspace_l.o
musl += locale/iswupper_l.o
musl += locale/iswxdigit_l.o
musl += locale/isxdigit_l.o
-libc += locale/langinfo.o
+musl += locale/langinfo.o
musl += locale/localeconv.o
-libc += locale/nl_langinfo_l.o
musl += locale/setlocale.o
musl += locale/strcasecmp_l.o
musl += locale/strcoll.o
@@ -1643,7 +1642,7 @@ musl += temp/mktemp.o
musl += temp/mkostemp.o
musl += temp/mkostemps.o

-libc += time/__asctime.o
+musl += time/__asctime.o
musl += time/__map_file.o
$(out)/musl/src/time/__map_file.o: CFLAGS += --include libc/syscall_to_function.h
musl += time/__month_to_secs.o
diff --git a/libc/locale/langinfo.c b/libc/locale/langinfo.c
deleted file mode 100644
index 01593148..00000000
--- a/libc/locale/langinfo.c
+++ /dev/null
@@ -1,61 +0,0 @@
-#include <locale.h>
-#include <langinfo.h>
-#include "libc.h"
-
-static const char c_time[] =
- "Sun\0" "Mon\0" "Tue\0" "Wed\0" "Thu\0" "Fri\0" "Sat\0"
- "Sunday\0" "Monday\0" "Tuesday\0" "Wednesday\0"
- "Thursday\0" "Friday\0" "Saturday\0"
- "Jan\0" "Feb\0" "Mar\0" "Apr\0" "May\0" "Jun\0"
- "Jul\0" "Aug\0" "Sep\0" "Oct\0" "Nov\0" "Dec\0"
- "January\0" "February\0" "March\0" "April\0"
- "May\0" "June\0" "July\0" "August\0"
- "September\0" "October\0" "November\0" "December\0"
- "AM\0" "PM\0"
- "%a %b %e %T %Y\0"
- "%m/%d/%y\0"
- "%H:%M:%S\0"
- "%I:%M:%S %p\0"
- "\0"
- "%m/%d/%y\0"
- "0123456789"
- "%a %b %e %T %Y\0"
- "%H:%M:%S";
-
-static const char c_messages[] = "^[yY]\0" "^[nN]";
-static const char c_numeric[] = ".\0" "";
-
-char *__langinfo(nl_item item)
-{
- int cat = item >> 16;
- int idx = item & 65535;
- const char *str;
-
- if (item == CODESET) return "UTF-8";
-
- switch (cat) {
- case LC_NUMERIC:
- if (idx > 1) return NULL;
- str = c_numeric;
- break;
- case LC_TIME:
- if (idx > 0x31) return NULL;
- str = c_time;
- break;
- case LC_MONETARY:
- if (idx > 0) return NULL;
- str = "";
- break;
- case LC_MESSAGES:
- if (idx > 1) return NULL;
- str = c_messages;
- break;
- default:
- return NULL;
- }
-
- for (; idx; idx--, str++) for (; *str; str++);
- return (char *)str;
-}
-
-weak_alias(__langinfo, nl_langinfo);
diff --git a/libc/locale/nl_langinfo_l.c b/libc/locale/nl_langinfo_l.c
deleted file mode 100644
index 2c5a9794..00000000
--- a/libc/locale/nl_langinfo_l.c
+++ /dev/null
@@ -1,11 +0,0 @@
-#include <locale.h>
-#include <langinfo.h>
-#include "libc.h"
-
-char *__nl_langinfo_l(nl_item item, locale_t l)
-{
- return nl_langinfo(item);
-}
-
-/* OSv local: a libstdc++ build against glibc wants the __ version */
-weak_alias(__nl_langinfo_l, nl_langinfo_l);
diff --git a/libc/time/__asctime.c b/libc/time/__asctime.c
deleted file mode 100644
index 5362f0db..00000000
--- a/libc/time/__asctime.c
+++ /dev/null
@@ -1,28 +0,0 @@
-#include <time.h>
-#include <stdio.h>
-#include <langinfo.h>
-#include "atomic.h"
-
-const char *__langinfo(nl_item);
-
-char *__asctime(const struct tm *restrict tm, char *restrict buf)
-{
- /* FIXME: change __langinfo to __C_langinfo once we have locales */
- if (snprintf(buf, 26, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n",
- __langinfo(ABDAY_1+tm->tm_wday),
- __langinfo(ABMON_1+tm->tm_mon),
- tm->tm_mday, tm->tm_hour,
- tm->tm_min, tm->tm_sec,
- 1900 + tm->tm_year) >= 26)
- {
- /* ISO C requires us to use the above format string,
- * even if it will not fit in the buffer. Thus asctime_r
- * is _supposed_ to crash if the fields in tm are too large.
- * We follow this behavior and crash "gracefully" to warn
- * application developers that they may not be so lucky
- * on other implementations (e.g. stack smashing..).
- */
- a_crash();
- }
- return buf;
-}
--
2.26.2

Waldemar Kozaczuk

unread,
Aug 25, 2020, 11:54:25 PM8/25/20
to osv...@googlegroups.com, Waldemar Kozaczuk
Signed-off-by: Waldemar Kozaczuk <jwkoz...@gmail.com>
---
Makefile | 3 +--
libc/locale/wcsftime_l.c | 11 -----------
libc/time/wcsftime.c | 32 --------------------------------
3 files changed, 1 insertion(+), 45 deletions(-)
delete mode 100644 libc/locale/wcsftime_l.c
delete mode 100644 libc/time/wcsftime.c

diff --git a/Makefile b/Makefile
index 2d19ccc6..fb91e62a 100644
--- a/Makefile
+++ b/Makefile
@@ -1057,7 +1057,6 @@ musl += locale/towlower_l.o
musl += locale/towupper_l.o
libc += locale/uselocale.o
musl += locale/wcscoll.o
-libc += locale/wcsftime_l.o
musl += locale/wcsxfrm.o
musl += locale/wctrans_l.o
musl += locale/wctype_l.o
@@ -1665,7 +1664,7 @@ musl += time/strftime.o
musl += time/strptime.o
musl += time/time.o
musl += time/timegm.o
-libc += time/wcsftime.o
+musl += time/wcsftime.o
libc += time/ftime.o # verbatim copy of the file as in 4b15d9f46a2b@musl
$(out)/libc/time/ftime.o: CFLAGS += -Ilibc/include

diff --git a/libc/locale/wcsftime_l.c b/libc/locale/wcsftime_l.c
deleted file mode 100644
index 5f346a3b..00000000
--- a/libc/locale/wcsftime_l.c
+++ /dev/null
@@ -1,11 +0,0 @@
-#include <wchar.h>
-#include <time.h>
-
-#include "libc.h"
-
-size_t __wcsftime_l(wchar_t *restrict wcs, size_t n, const wchar_t *restrict f,
- const struct tm *restrict tm, locale_t loc)
-{
- return wcsftime(wcs, n, f, tm);
-}
-weak_alias(__wcsftime_l, wcsftime_l);
diff --git a/libc/time/wcsftime.c b/libc/time/wcsftime.c
deleted file mode 100644
index da6c1f8a..00000000
--- a/libc/time/wcsftime.c
+++ /dev/null
@@ -1,32 +0,0 @@
-#include <wchar.h>
-#include <time.h>
-#include <string.h>
-
-size_t wcsftime(wchar_t *restrict wcs, size_t n, const wchar_t *restrict f, const struct tm *restrict tm)
-{
- size_t k, n0=n;
- char out[100], in[4];
- while (*f) {
- if (!n) return 0;
- if (*f != '%') {
- *wcs++ = *f++;
- n--;
- continue;
- }
- in[2] = in[3] = 0;
- in[0] = *f++;
- if (strchr("EO", (in[1]=*f++)))
- in[2] = *f++;
- k = strftime(out, sizeof out, in, tm);
- if (!k) return 0;
- k = mbsrtowcs(wcs, (const char *[]){out}, n, 0);
- if (k==(size_t)-1) return 0;
- wcs += k;
- n -= k;
- }
- if (!n) return 0;
- *wcs++ = 0;
- return n0-n;
-}
-
-
--
2.26.2

Commit Bot

unread,
Aug 26, 2020, 4:07:43 AM8/26/20
to osv...@googlegroups.com, Waldemar Kozaczuk
From: Waldemar Kozaczuk <jwkoz...@gmail.com>
Committer: Nadav Har'El <n...@scylladb.com>
Branch: master

libc: replace string/strsignal.c with musl copy

This patch replaces libc/string/strsignal.c with a musl
copy under musl/src/string/strsignal.c. The musl copy
is newer and only slightly different.

This patch also adds relevant tests to tst-string.cc
to test strsignal() logic. Please note we disable
real-time signal test until we upgrade to newer version
of musl.

I have also noticed that on Linux strsignal()
returns messages ending with signal number like so:
'Unknown signal -1' whereas musl version simply
returns 'Unknown signal' without the signal number.
This might be fixed in future version of musl.

Signed-off-by: Waldemar Kozaczuk <jwkoz...@gmail.com>
Message-Id: <20200826035356.20...@gmail.com>

---
diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -1600,7 +1600,7 @@ musl += string/strpbrk.o
musl += string/strrchr.o
musl += string/strsep.o
libc += string/stresep.o
-libc += string/strsignal.o
+musl += string/strsignal.o
musl += string/strspn.o
musl += string/strstr.o
musl += string/strtok.o
diff --git a/libc/string/strsignal.c b/libc/string/strsignal.c
--- a/libc/string/strsignal.c
+++ b/libc/string/strsignal.c

Nadav Har'El

unread,
Aug 26, 2020, 4:11:12 AM8/26/20
to Waldemar Kozaczuk, Osv Dev
I will commit, but I think you forgot to patch the makefile to actually build this test? If that's true please send a followup patch.

--
Nadav Har'El
n...@scylladb.com


--
You received this message because you are subscribed to the Google Groups "OSv Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email to osv-dev+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/osv-dev/20200826035356.201786-2-jwkozaczuk%40gmail.com.

Nadav Har'El

unread,
Aug 26, 2020, 4:16:51 AM8/26/20
to Waldemar Kozaczuk, Osv Dev
Can you please explain the motivation of this?
I thought maybe you are copying it instead of just enabling it in the Makefile because you needed to change it - but the I don't see changes in the next patches.
So what's the motivation?

--
Nadav Har'El
n...@scylladb.com

On Wed, Aug 26, 2020 at 6:54 AM Waldemar Kozaczuk <jwkoz...@gmail.com> wrote:
--
You received this message because you are subscribed to the Google Groups "OSv Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email to osv-dev+u...@googlegroups.com.

Nadav Har'El

unread,
Aug 26, 2020, 4:19:33 AM8/26/20
to Waldemar Kozaczuk, Osv Dev
Oh, I now realize the *next* patch actually does change __tz.cc. And also the Makefile for the tests that I asked about the previous patch. So sorry about the spam.


--
Nadav Har'El
n...@scylladb.com

Commit Bot

unread,
Aug 26, 2020, 4:31:48 AM8/26/20
to osv...@googlegroups.com, Waldemar Kozaczuk
From: Waldemar Kozaczuk <jwkoz...@gmail.com>
Committer: Nadav Har'El <n...@scylladb.com>
Branch: master

tests: added bionic-based unit test to test time libc functions

This patch adds new unit test tst-time.cc that tests many time-related
including following:
tzset()
gmtime()
gmtime_r()
localtime()
localtime_r()
mktime()
strftime()
timegm()
strftime()
strptime()

The test is actually based on bionics time-test.cpp as the
comments in the top of the source files document.

Please note that some of the tests mostly related to strptime and strftime
are commented out as they fail with current version of musl. Hopefully
we will enable them once we upgrade to newer version of musl.

Signed-off-by: Waldemar Kozaczuk <jwkoz...@gmail.com>
Message-Id: <20200826035356.20...@gmail.com>

---
diff --git a/tests/tst-time.cc b/tests/tst-time.cc
--- a/tests/tst-time.cc

Commit Bot

unread,
Aug 26, 2020, 4:31:49 AM8/26/20
to osv...@googlegroups.com, Waldemar Kozaczuk
From: Waldemar Kozaczuk <jwkoz...@gmail.com>
Committer: Nadav Har'El <n...@scylladb.com>
Branch: master

libc: copy time/__tz.c from musl as is

Signed-off-by: Waldemar Kozaczuk <jwkoz...@gmail.com>
Message-Id: <20200826035356.20...@gmail.com>

---
diff --git a/libc/time/__tz.c b/libc/time/__tz.c
--- a/libc/time/__tz.c

Commit Bot

unread,
Aug 26, 2020, 4:31:52 AM8/26/20
to osv...@googlegroups.com, Waldemar Kozaczuk
From: Waldemar Kozaczuk <jwkoz...@gmail.com>
Committer: Nadav Har'El <n...@scylladb.com>
Branch: master

libc: replace langinfo with musl copies

The relevant files under libc/locale and libc/time/__asctime.c
are pretty much identical to their copies under musl/
so we are replacing them with current version.

Signed-off-by: Waldemar Kozaczuk <jwkoz...@gmail.com>
Message-Id: <20200826035356.20...@gmail.com>

---
diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -1038,9 +1038,8 @@ musl += locale/iswspace_l.o
musl += locale/iswupper_l.o
musl += locale/iswxdigit_l.o
musl += locale/isxdigit_l.o
-libc += locale/langinfo.o
+musl += locale/langinfo.o
musl += locale/localeconv.o
-libc += locale/nl_langinfo_l.o
musl += locale/setlocale.o
musl += locale/strcasecmp_l.o
musl += locale/strcoll.o
@@ -1643,7 +1642,7 @@ musl += temp/mktemp.o
musl += temp/mkostemp.o
musl += temp/mkostemps.o

-libc += time/__asctime.o
+musl += time/__asctime.o
musl += time/__map_file.o
$(out)/musl/src/time/__map_file.o: CFLAGS += --include libc/syscall_to_function.h
musl += time/__month_to_secs.o
diff --git a/libc/locale/langinfo.c b/libc/locale/langinfo.c
--- a/libc/locale/langinfo.c
+++ b/libc/locale/langinfo.c
--- a/libc/locale/nl_langinfo_l.c
+++ b/libc/locale/nl_langinfo_l.c
@@ -1,11 +0,0 @@
-#include <locale.h>
-#include <langinfo.h>
-#include "libc.h"
-
-char *__nl_langinfo_l(nl_item item, locale_t l)
-{
- return nl_langinfo(item);
-}
-
-/* OSv local: a libstdc++ build against glibc wants the __ version */
-weak_alias(__nl_langinfo_l, nl_langinfo_l);
diff --git a/libc/time/__asctime.c b/libc/time/__asctime.c
--- a/libc/time/__asctime.c
+++ b/libc/time/__asctime.c

Commit Bot

unread,
Aug 26, 2020, 4:31:52 AM8/26/20
to osv...@googlegroups.com, Waldemar Kozaczuk
From: Waldemar Kozaczuk <jwkoz...@gmail.com>
Committer: Nadav Har'El <n...@scylladb.com>
Branch: master

libc: replaced most libc/time/ files with their musl copies
Message-Id: <20200826035356.20...@gmail.com>

---
diff --git a/Makefile b/Makefile
--- a/libc/aliases.ld
+++ b/libc/aliases.ld
@@ -31,6 +31,10 @@ __setlocale = setlocale;
/* multibyte */
__mbrlen = mbrlen;

+/* memory */
+__munmap = munmap;
+__mmap = mmap;
+
/* stdio */
__dup3 = dup3;

diff --git a/libc/locale/strftime_l.c b/libc/locale/strftime_l.c
--- a/libc/locale/strftime_l.c
+++ b/libc/locale/strftime_l.c
@@ -1,11 +0,0 @@
-#include <locale.h>
-#include <time.h>
-#include "libc.h"
-
-size_t __strftime_l(char *restrict s, size_t n, const char *restrict f, const struct tm *restrict tm, locale_t l)
-{
- return strftime(s, n, f, tm);
-}
-
-/* OSv local: a libstdc++ build against glibc wants the __ version */
-weak_alias(__strftime_l, strftime_l);
diff --git a/libc/syscall_to_function.h b/libc/syscall_to_function.h
--- a/libc/syscall_to_function.h
+++ b/libc/syscall_to_function.h
@@ -1,7 +1,7 @@
#include <bits/syscall.h>
#include <unistd.h>

-#define __OSV_TO_FUNCTION_SYS_open(filename, flags, perm) (open(filename, flags, perm))
+#define __OSV_TO_FUNCTION_SYS_open(filename, flags, ...) (open(filename, flags __VA_OPT__(,) __VA_ARGS__))

#define __OSV_TO_FUNCTION_SYS_close(fd) (close(fd))

@@ -15,6 +15,8 @@

#define __OSV_TO_FUNCTION_SYS_ioctl(fd, cmd, args) (ioctl(fd, cmd, args))

+#define __OSV_TO_FUNCTION_SYS_fstat(fd, st) (fstat(fd, st))
+
#define __OSV_TO_FUNCTION_SYS_unlink(path) (unlink(path))

#define __OSV_TO_FUNCTION_SYS_rmdir(path) (rmdir(path))
diff --git a/libc/time/__time.h b/libc/time/__time.h
--- a/libc/time/__time.h
+++ b/libc/time/__time.h
@@ -1,9 +0,0 @@
-time_t __tm_to_time(struct tm *);
-struct tm *__time_to_tm(time_t, struct tm *);
-void __tzset(void);
-struct tm *__dst_adjust(struct tm *tm);
-
-extern long __timezone;
-extern int __daylight;
-extern int __dst_offset;
-extern char *__tzname[2];
diff --git a/libc/time/__time_to_tm.c b/libc/time/__time_to_tm.c
--- a/libc/time/__time_to_tm.c
+++ b/libc/time/__time_to_tm.c
--- a/libc/time/__tm_to_time.c
+++ b/libc/time/__tm_to_time.c
--- a/libc/time/gmtime.c
+++ b/libc/time/gmtime.c
@@ -1,11 +0,0 @@
-#include <time.h>
-
-#include "__time.h"
-
-struct tm *gmtime(const time_t *t)
-{
- static struct tm tm;
- __time_to_tm(*t, &tm);
- tm.tm_isdst = 0;
- return &tm;
-}
diff --git a/libc/time/gmtime_r.c b/libc/time/gmtime_r.c
--- a/libc/time/gmtime_r.c
+++ b/libc/time/gmtime_r.c
@@ -1,10 +0,0 @@
-#include <time.h>
-
-#include "__time.h"
-
-struct tm *gmtime_r(const time_t *restrict t, struct tm *restrict result)
-{
- __time_to_tm(*t, result);
- result->tm_isdst = 0;
- return result;
-}
diff --git a/libc/time/localtime.c b/libc/time/localtime.c
--- a/libc/time/localtime.c
+++ b/libc/time/localtime.c
@@ -1,12 +0,0 @@
-#include <time.h>
-
-#include "__time.h"
-
-struct tm *localtime(const time_t *t)
-{
- static struct tm tm;
- __tzset();
- __time_to_tm(*t - __timezone, &tm);
- tm.tm_isdst = -1;
- return __dst_adjust(&tm);
-}
diff --git a/libc/time/localtime_r.c b/libc/time/localtime_r.c
--- a/libc/time/localtime_r.c
+++ b/libc/time/localtime_r.c
@@ -1,11 +0,0 @@
-#include <time.h>
-
-#include "__time.h"
-
-struct tm *localtime_r(const time_t *restrict t, struct tm *restrict result)
-{
- __tzset();
- __time_to_tm(*t - __timezone, result);
- result->tm_isdst = -1;
- return __dst_adjust(result);
-}
diff --git a/libc/time/mktime.c b/libc/time/mktime.c
--- a/libc/time/mktime.c
+++ b/libc/time/mktime.c
--- a/libc/time/strftime.c
+++ b/libc/time/strftime.c
--- a/libc/time/time_impl.h
+++ b/libc/time/time_impl.h
@@ -0,0 +1 @@
+../../musl/src/time/time_impl.h
\ No newline at end of file
diff --git a/libc/time/timegm.c b/libc/time/timegm.c
--- a/libc/time/timegm.c
+++ b/libc/time/timegm.c
@@ -1,9 +0,0 @@
-#define _GNU_SOURCE
-#include <time.h>
-
-#include "__time.h"
-
-time_t timegm(struct tm *tm)
-{
- return __tm_to_time(tm);
-}
diff --git a/libc/time/tzset.c b/libc/time/tzset.c
--- a/libc/time/tzset.c
+++ b/libc/time/tzset.c
--- a/modules/tests/Makefile
+++ b/modules/tests/Makefile
@@ -246,7 +246,7 @@ common-boost-tests := tst-vfs.so tst-libc-locking.so misc-fs-stress.so \
tst-bsd-tcp1-zsndrcv.so tst-async.so tst-rcu-list.so tst-tcp-listen.so \
tst-poll.so tst-bitset-iter.so tst-timer-set.so tst-clock.so \
tst-rcu-hashtable.so tst-unordered-ring-mpsc.so \
- tst-seek.so tst-ctype.so tst-wctype.so tst-string.so
+ tst-seek.so tst-ctype.so tst-wctype.so tst-string.so tst-time.so

boost-tests := $(common-boost-tests)

diff --git a/modules/tests/usr.manifest.skel b/modules/tests/usr.manifest.skel

Commit Bot

unread,
Aug 26, 2020, 4:31:53 AM8/26/20
to osv...@googlegroups.com, Waldemar Kozaczuk
From: Waldemar Kozaczuk <jwkoz...@gmail.com>
Committer: Nadav Har'El <n...@scylladb.com>
Branch: master

libc: replaced wcsftime files with their almost identical musl copies

Signed-off-by: Waldemar Kozaczuk <jwkoz...@gmail.com>
Message-Id: <20200826035356.20...@gmail.com>

---
diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -1057,7 +1057,6 @@ musl += locale/towlower_l.o
musl += locale/towupper_l.o
libc += locale/uselocale.o
musl += locale/wcscoll.o
-libc += locale/wcsftime_l.o
musl += locale/wcsxfrm.o
musl += locale/wctrans_l.o
musl += locale/wctype_l.o
@@ -1665,7 +1664,7 @@ musl += time/strftime.o
musl += time/strptime.o
musl += time/time.o
musl += time/timegm.o
-libc += time/wcsftime.o
+musl += time/wcsftime.o
libc += time/ftime.o # verbatim copy of the file as in 4b15d9f46a2b@musl
$(out)/libc/time/ftime.o: CFLAGS += -Ilibc/include

diff --git a/libc/locale/wcsftime_l.c b/libc/locale/wcsftime_l.c
--- a/libc/locale/wcsftime_l.c
+++ b/libc/locale/wcsftime_l.c
@@ -1,11 +0,0 @@
-#include <wchar.h>
-#include <time.h>
-
-#include "libc.h"
-
-size_t __wcsftime_l(wchar_t *restrict wcs, size_t n, const wchar_t *restrict f,
- const struct tm *restrict tm, locale_t loc)
-{
- return wcsftime(wcs, n, f, tm);
-}
-weak_alias(__wcsftime_l, wcsftime_l);
diff --git a/libc/time/wcsftime.c b/libc/time/wcsftime.c
--- a/libc/time/wcsftime.c
+++ b/libc/time/wcsftime.c
Reply all
Reply to author
Forward
0 new messages