From: Zbigniew Sarbinowski Date: Thu, 12 Nov 2020 16:22:04 +0000 (-0500) Subject: [SystemZ][ZOS] Porting the time functions within libc++ to z/OS X-Git-Tag: llvmorg-13-init~6284 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=173b51169b838255aff4d4ff4eb6014b101a9687;p=platform%2Fupstream%2Fllvm.git [SystemZ][ZOS] Porting the time functions within libc++ to z/OS This patch is one part of many steps required to build libc++ and libc++abi libraries on z/OS. This particular deals with time related functions and consists of the following 3 parts. 1) Initialization of :timeval within libc++ library need to be adjusted to work on z/OS. The following is z/OS definition from time.h which includes additional aggregate member. typedef signed int suseconds_t; struct timeval { time_t tv_sec; char tv_usec_pad[4]; suseconds_t tv_usec; }; In contracts the following is definition from time.h on Linux. typedef long int __suseconds_t; struct timeval { __time_t tv_sec; __suseconds_t tv_usec; }; 2) In addition, retrieving ::timespec within libc++ library needs to be adjusted to compensate the difference of some of the members of ::stat depending of the target host. Here are the 2 members in conflict on z/OS extracted from stat.h. struct stat { ... time_t st_atime; time_t st_mtime; ... }; In contract here is Linux equivalent from stat.h. struct stat { ... struct timespec st_atim; struct timespec st_mtim; ... }; 3) On Linux both members are of type timespec whereas on z/OS an object of type timespec need to be constructed first before retrieving it within libc++ library. The libc++ header file __threading_support calls nanosleep, which is not available on z/OS. The equivalent functionality will be implemented by using both sleep() and usleep(). Reviewed By: ldionne, #libc Differential Revision: https://reviews.llvm.org/D87940 --- diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index aab0276..df16956 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -179,6 +179,29 @@ set(files wctype.h ) +if(LIBCXX_INSTALL_SUPPORT_HEADERS) + set(files + ${files} + support/android/locale_bionic.h + support/fuchsia/xlocale.h + support/ibm/limits.h + support/ibm/locale_mgmt_aix.h + support/ibm/nanosleep.h + support/ibm/support.h + support/ibm/xlocale.h + support/musl/xlocale.h + support/newlib/xlocale.h + support/solaris/floatingpoint.h + support/solaris/wchar.h + support/solaris/xlocale.h + support/win32/limits_msvc_win32.h + support/win32/locale_win32.h + support/xlocale/__nop_locale_mgmt.h + support/xlocale/__posix_l_fallback.h + support/xlocale/__strtonum_fallback.h + ) +endif() + configure_file("__config_site.in" "${LIBCXX_BINARY_DIR}/__config_site" @ONLY) diff --git a/libcxx/include/__threading_support b/libcxx/include/__threading_support index fe770a8..a9ab425d 100644 --- a/libcxx/include/__threading_support +++ b/libcxx/include/__threading_support @@ -16,6 +16,10 @@ #include #include +#ifdef __MVS__ +#include +#endif + #ifndef _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER #pragma GCC system_header #endif diff --git a/libcxx/include/support/ibm/nanosleep.h b/libcxx/include/support/ibm/nanosleep.h new file mode 100644 index 0000000..c82f4eb --- /dev/null +++ b/libcxx/include/support/ibm/nanosleep.h @@ -0,0 +1,38 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP_SUPPORT_IBM_NANOSLEEP_H +#define _LIBCPP_SUPPORT_IBM_NANOSLEEP_H + +#include + +inline int nanosleep(const struct timespec* req, struct timespec* rem) +{ + // The nanosleep() function is not available on z/OS. Therefore, we will call + // sleep() to sleep for whole seconds and usleep() to sleep for any remaining + // fraction of a second. Any remaining nanoseconds will round up to the next + // microsecond. + + useconds_t __micro_sec = (rem->tv_nsec + 999) / 1000; + if (__micro_sec > 999999) + { + ++rem->tv_sec; + __micro_sec -= 1000000; + } + while (rem->tv_sec) + rem->tv_sec = sleep(rem->tv_sec); + if (__micro_sec) { + rem->tv_nsec = __micro_sec * 1000; + return usleep(__micro_sec); + } + rem->tv_nsec = 0; + return 0; +} + +#endif // _LIBCPP_SUPPORT_IBM_NANOSLEEP_H diff --git a/libcxx/src/filesystem/filesystem_common.h b/libcxx/src/filesystem/filesystem_common.h index dc55f93..a82f651 100644 --- a/libcxx/src/filesystem/filesystem_common.h +++ b/libcxx/src/filesystem/filesystem_common.h @@ -198,7 +198,8 @@ private: using chrono::duration; using chrono::duration_cast; -using TimeSpec = timespec; +using TimeSpec = struct timespec; +using TimeVal = struct timeval; using StatT = struct stat; template ; #if defined(__APPLE__) -TimeSpec extract_mtime(StatT const& st) { return st.st_mtimespec; } -TimeSpec extract_atime(StatT const& st) { return st.st_atimespec; } +inline TimeSpec extract_mtime(StatT const& st) { return st.st_mtimespec; } +inline TimeSpec extract_atime(StatT const& st) { return st.st_atimespec; } +#elif defined(__MVS__) +inline TimeSpec extract_mtime(StatT const& st) { + TimeSpec TS = {st.st_mtime, 0}; + return TS; +} +inline TimeSpec extract_atime(StatT const& st) { + TimeSpec TS = {st.st_atime, 0}; + return TS; +} #else -TimeSpec extract_mtime(StatT const& st) { return st.st_mtim; } -TimeSpec extract_atime(StatT const& st) { return st.st_atim; } +inline TimeSpec extract_mtime(StatT const& st) { return st.st_mtim; } +inline TimeSpec extract_atime(StatT const& st) { return st.st_atim; } #endif -// allow the utimes implementation to compile even it we're not going -// to use it. - -bool posix_utimes(const path& p, std::array const& TS, - error_code& ec) { +inline TimeVal make_timeval(TimeSpec const& ts) { using namespace chrono; auto Convert = [](long nsec) { - using int_type = decltype(std::declval< ::timeval>().tv_usec); + using int_type = decltype(std::declval().tv_usec); auto dur = duration_cast(nanoseconds(nsec)).count(); return static_cast(dur); }; - struct ::timeval ConvertedTS[2] = {{TS[0].tv_sec, Convert(TS[0].tv_nsec)}, - {TS[1].tv_sec, Convert(TS[1].tv_nsec)}}; + TimeVal TV = {}; + TV.tv_sec = ts.tv_sec; + TV.tv_usec = Convert(ts.tv_nsec); + return TV; +} + +inline bool posix_utimes(const path& p, std::array const& TS, + error_code& ec) { + TimeVal ConvertedTS[2] = {make_timeval(TS[0]), make_timeval(TS[1])}; if (::utimes(p.c_str(), ConvertedTS) == -1) { ec = capture_errno(); return true;