[libcxx-commits] [libcxx] cb2d2ae - [SystemZ][ZOS] Provide CLOCK_MONOTONIC alternative

Zbigniew Sarbinowski via libcxx-commits libcxx-commits at lists.llvm.org
Fri Feb 12 10:40:36 PST 2021


Author: Zbigniew Sarbinowski
Date: 2021-02-12T18:39:48Z
New Revision: cb2d2ae56ae3f0554c40c2d7f231ca5058e4d50c

URL: https://github.com/llvm/llvm-project/commit/cb2d2ae56ae3f0554c40c2d7f231ca5058e4d50c
DIFF: https://github.com/llvm/llvm-project/commit/cb2d2ae56ae3f0554c40c2d7f231ca5058e4d50c.diff

LOG: [SystemZ][ZOS] Provide CLOCK_MONOTONIC alternative

We need CLOCK_MONOTONIC equivalent implementation for z/OS within libc++. The default implementation is asserting.

On z/OS the lack of  'clock_gettime()' and 'time_point()' force us to look for alternatives.
The current proposal is to use `gettimeofday()` for CLOCK_MONOTONIC  which is also used in CLOCK_REALTIME.  This will allow us to skip the assertion with compromised CLOCK_MONOTONIC implementation which will not guarantee to never go back in time because it will use `gettimeofday()` but only when it's set.

Is this a good compromise for platforms which does not support monotonic clock?
Hopefully this will spark the discussion and agreement how to proceed in this situation.

Reviewed By: #libc, ldionne, hubert.reinterpretcast

Differential Revision: https://reviews.llvm.org/D93542

Added: 
    libcxx/include/__support/ibm/gettod_zos.h

Modified: 
    libcxx/include/CMakeLists.txt
    libcxx/src/chrono.cpp

Removed: 
    


################################################################################
diff  --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index ec172f587c5d..ae19e26ca4f5 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -153,6 +153,7 @@ set(files
   strstream
   __support/android/locale_bionic.h
   __support/fuchsia/xlocale.h
+  __support/ibm/gettod_zos.h
   __support/ibm/limits.h
   __support/ibm/locale_mgmt_aix.h
   __support/ibm/nanosleep.h

diff  --git a/libcxx/include/__support/ibm/gettod_zos.h b/libcxx/include/__support/ibm/gettod_zos.h
new file mode 100644
index 000000000000..46e02a6c8b8d
--- /dev/null
+++ b/libcxx/include/__support/ibm/gettod_zos.h
@@ -0,0 +1,53 @@
+// -*- 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_GETTOD_ZOS_H
+#define _LIBCPP_SUPPORT_IBM_GETTOD_ZOS_H
+
+#include <time.h>
+
+static inline int gettimeofdayMonotonic(struct timespec64* Output) {
+
+  // The POSIX gettimeofday() function is not available on z/OS. Therefore,
+  // we will call stcke and other hardware instructions in implement equivalent.
+  // Note that nanoseconds alone will overflow when reaching new epoch in 2042.
+
+  struct _t {
+    uint64_t Hi;
+    uint64_t Lo;
+  };
+  struct _t Value = {0, 0};
+  uint64_t CC = 0;
+  asm(" stcke %0\n"
+      " ipm %1\n"
+      " srlg %1,%1,28\n"
+      : "=m"(Value), "+r"(CC)::);
+
+  if (CC != 0) {
+    errno = EMVSTODNOTSET;
+    return CC;
+  }
+  uint64_t us = (Value.Hi >> 4);
+  uint64_t ns = ((Value.Hi & 0x0F) << 8) + (Value.Lo >> 56);
+  ns = (ns * 1000) >> 12;
+  us = us - 2208988800000000;
+
+  register uint64_t DivPair0 asm("r0"); // dividend (upper half), remainder
+  DivPair0 = 0;
+  register uint64_t DivPair1 asm("r1"); // dividend (lower half), quotient
+  DivPair1 = us;
+  uint64_t Divisor = 1000000;
+  asm(" dlgr %0,%2" : "+r"(DivPair0), "+r"(DivPair1) : "r"(Divisor) :);
+
+  Output->tv_sec = DivPair1;
+  Output->tv_nsec = DivPair0 * 1000 + ns;
+  return 0;
+}
+
+#endif // _LIBCPP_SUPPORT_IBM_GETTOD_ZOS_H

diff  --git a/libcxx/src/chrono.cpp b/libcxx/src/chrono.cpp
index 085fbfde26c1..b586f6fa1b14 100644
--- a/libcxx/src/chrono.cpp
+++ b/libcxx/src/chrono.cpp
@@ -6,9 +6,20 @@
 //
 //===----------------------------------------------------------------------===//
 
+#if defined(__MVS__)
+// As part of monotonic clock support on z/OS we need macro _LARGE_TIME_API
+// to be defined before any system header to include definition of struct timespec64.
+#define _LARGE_TIME_API
+#endif
+
 #include "chrono"
 #include "cerrno"        // errno
 #include "system_error"  // __throw_system_error
+
+#if defined(__MVS__)
+#include <__support/ibm/gettod_zos.h> // gettimeofdayMonotonic
+#endif
+
 #include <time.h>        // clock_gettime and CLOCK_{MONOTONIC,REALTIME,MONOTONIC_RAW}
 #include "include/apple_availability.h"
 
@@ -218,6 +229,16 @@ static steady_clock::time_point __libcpp_steady_clock_now() {
   return steady_clock::time_point(steady_clock::duration(dur));
 }
 
+#elif defined(__MVS__)
+
+static steady_clock::time_point __libcpp_steady_clock_now() {
+  struct timespec64 ts;
+  if (0 != gettimeofdayMonotonic(&ts))
+    __throw_system_error(errno, "failed to obtain time of day");
+
+  return steady_clock::time_point(seconds(ts.tv_sec) + nanoseconds(ts.tv_nsec));
+}
+
 #elif defined(CLOCK_MONOTONIC)
 
 static steady_clock::time_point __libcpp_steady_clock_now() {


        


More information about the libcxx-commits mailing list