[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
This commit is contained in:
@@ -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
|
||||
|
||||
53
libcxx/include/__support/ibm/gettod_zos.h
Normal file
53
libcxx/include/__support/ibm/gettod_zos.h
Normal file
@@ -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
|
||||
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user