- Fix nanoseconds in clock_gettime for Mac

- Hide clock_gettime in favor of cpputils::time::now()
- Add test cases to cpputils::time::now()
This commit is contained in:
Sebastian Messmer 2018-05-16 22:18:45 -07:00
parent 3ccb46c537
commit 61cad69671
7 changed files with 183 additions and 63 deletions

View File

@ -44,6 +44,7 @@ set(SOURCES
system/homedir.cpp
system/memory_nonwindows.cpp
system/memory_windows.cpp
system/time.cpp
)
add_library(${PROJECT_NAME} STATIC ${SOURCES})

View File

@ -1,24 +1,35 @@
#pragma once
#ifndef MESSMER_CPPUTILS_SYSTEM_CLOCKGETTIME_H
#define MESSMER_CPPUTILS_SYSTEM_CLOCKGETTIME_H
#include "time.h"
#if defined(__MACH__) && !defined(CLOCK_REALTIME)
// Implements clock_gettime for Mac OS X before 10.12 (where it is not implemented by in the standard library)
// Source: http://stackoverflow.com/a/9781275/829568
// Caution: The returned value is less precise than the returned value from a linux clock_gettime would be.
#if defined(__MACH__) && !defined(CLOCK_REALTIME)
#include <sys/time.h>
#define CLOCK_REALTIME 0
inline int clock_gettime(int /*clk_id*/, struct timespec *result) {
namespace {
int clock_gettime(int /*clk_id*/, struct timespec *result) {
struct timeval now;
int rv = gettimeofday(&now, nullptr);
if (rv) {
return rv;
}
result->tv_sec = now.tv_sec;
result->tv_nsec = now.tv_sec * 1000;
result->tv_nsec = now.tv_usec * 1000;
return 0;
}
#endif
}
#endif
namespace cpputils {
namespace time {
struct timespec now() {
struct timespec now{};
clock_gettime(CLOCK_REALTIME, &now);
return now;
}
}
}

View File

@ -2,21 +2,14 @@
#ifndef MESSMER_CPPUTILS_SYSTEM_TIME_H
#define MESSMER_CPPUTILS_SYSTEM_TIME_H
#include <sys/types.h>
#include "clock_gettime.h"
// TODO Test
#include <time.h>
namespace cpputils {
namespace time {
namespace time {
inline timespec now() {
struct timespec now{};
clock_gettime(CLOCK_REALTIME, &now);
return now;
}
timespec now();
}
}
}
inline bool operator==(const timespec &lhs, const timespec &rhs) {

View File

@ -7,7 +7,7 @@
#include "CryFile.h"
#include <fspp/fuse/FuseErrnoException.h>
#include <cpp-utils/pointer/cast.h>
#include <cpp-utils/system/clock_gettime.h>
#include <cpp-utils/system/time.h>
#include <cpp-utils/system/stat.h>
#include <cpp-utils/logging/logging.h>
@ -170,8 +170,7 @@ void CryNode::stat(struct ::stat *result) const {
result->st_size = fsblobstore::DirBlob::DIR_LSTAT_SIZE;
//TODO If possible without performance loss, then for a directory, st_nlink should return number of dir entries (including "." and "..")
result->st_nlink = 1;
struct timespec now{};
clock_gettime(CLOCK_REALTIME, &now);
struct timespec now = cpputils::time::now();
result->st_atim = now;
result->st_mtim = now;
result->st_ctim = now;

View File

@ -45,7 +45,7 @@ set(SOURCES
assert/backtrace_include_test.cpp
assert/assert_include_test.cpp
assert/assert_debug_test.cpp
system/ClockGetTimeTest.cpp
system/TimeTest.cpp
system/MemoryTest.cpp
system/HomedirTest.cpp
)

View File

@ -1,40 +0,0 @@
#include <gtest/gtest.h>
#include <cpp-utils/system/clock_gettime.h>
#include <chrono>
#include <thread>
namespace {
struct timespec _gettime() {
struct timespec current_time;
int res = clock_gettime(CLOCK_REALTIME, &current_time);
EXPECT_EQ(0, res);
return current_time;
}
uint64_t _to_nanos(struct timespec time) {
constexpr uint64_t nanos = UINT64_C(1000000000);
return time.tv_sec * nanos + time.tv_nsec;
}
}
TEST(ClockGetTimeTest, DoesntCrash) {
_gettime();
}
TEST(ClockGetTimeTest, IsLaterThanYear2010) {
struct timespec current_time = _gettime();
EXPECT_LT(1262304000, current_time.tv_sec);
}
TEST(ClockGetTimeTest, IsNondecreasing) {
uint64_t time1 = _to_nanos(_gettime());
uint64_t time2 = _to_nanos(_gettime());
EXPECT_LE(time1, time2);
}
TEST(ClockGetTimeTest, IsIncreasedAfterPause) {
uint64_t time1 = _to_nanos(_gettime());
std::this_thread::sleep_for(std::chrono::milliseconds(10));
uint64_t time2 = _to_nanos(_gettime());
EXPECT_LT(time1, time2);
}

View File

@ -0,0 +1,156 @@
#include <gtest/gtest.h>
#include <cpp-utils/system/time.h>
#include <chrono>
#include <thread>
using cpputils::time::now;
namespace {
uint64_t _to_nanos(struct timespec time) {
constexpr uint64_t nanos = UINT64_C(1000000000);
return time.tv_sec * nanos + time.tv_nsec;
}
}
TEST(TimeTest, DoesntCrash) {
now();
}
TEST(TimeTest, IsLaterThanYear2010) {
struct timespec current_time = now();
constexpr time_t year_2010_timestamp = 1262304000;
EXPECT_LT(year_2010_timestamp, current_time.tv_sec);
}
TEST(TimeTest, IsNondecreasing) {
uint64_t time1 = _to_nanos(now());
uint64_t time2 = _to_nanos(now());
EXPECT_LE(time1, time2);
}
TEST(TimeTest, IsIncreasedAfterPause) {
uint64_t time1 = _to_nanos(now());
std::this_thread::sleep_for(std::chrono::milliseconds(10));
uint64_t time2 = _to_nanos(now());
EXPECT_LT(time1, time2);
}
constexpr struct timespec time1 {1262304000, 000000000};
constexpr struct timespec time2 {1262304000, 000000001};
constexpr struct timespec time3 {1262304000, 100000000};
constexpr struct timespec time4 {1262304001, 000000001};
TEST(TimeTest, LessThan) {
EXPECT_FALSE(time1 < time1);
EXPECT_TRUE(time1 < time2);
EXPECT_TRUE(time1 < time3);
EXPECT_TRUE(time1 < time4);
EXPECT_FALSE(time2 < time1);
EXPECT_FALSE(time2 < time2);
EXPECT_TRUE(time2 < time3);
EXPECT_TRUE(time2 < time4);
EXPECT_FALSE(time3 < time1);
EXPECT_FALSE(time3 < time2);
EXPECT_FALSE(time3 < time3);
EXPECT_TRUE(time3 < time4);
EXPECT_FALSE(time4 < time1);
EXPECT_FALSE(time4 < time2);
EXPECT_FALSE(time4 < time3);
EXPECT_FALSE(time4 < time4);
}
TEST(TimeTest, GreaterThan) {
EXPECT_FALSE(time1 > time1);
EXPECT_FALSE(time1 > time2);
EXPECT_FALSE(time1 > time3);
EXPECT_FALSE(time1 > time4);
EXPECT_TRUE(time2 > time1);
EXPECT_FALSE(time2 > time2);
EXPECT_FALSE(time2 > time3);
EXPECT_FALSE(time2 > time4);
EXPECT_TRUE(time3 > time1);
EXPECT_TRUE(time3 > time2);
EXPECT_FALSE(time3 > time3);
EXPECT_FALSE(time3 > time4);
EXPECT_TRUE(time4 > time1);
EXPECT_TRUE(time4 > time2);
EXPECT_TRUE(time4 > time3);
EXPECT_FALSE(time4 > time4);
}
TEST(TimeTest, LessEquals) {
EXPECT_TRUE(time1 <= time1);
EXPECT_TRUE(time1 <= time2);
EXPECT_TRUE(time1 <= time3);
EXPECT_TRUE(time1 <= time4);
EXPECT_FALSE(time2 <= time1);
EXPECT_TRUE(time2 <= time2);
EXPECT_TRUE(time2 <= time3);
EXPECT_TRUE(time2 <= time4);
EXPECT_FALSE(time3 <= time1);
EXPECT_FALSE(time3 <= time2);
EXPECT_TRUE(time3 <= time3);
EXPECT_TRUE(time3 <= time4);
EXPECT_FALSE(time4 <= time1);
EXPECT_FALSE(time4 <= time2);
EXPECT_FALSE(time4 <= time3);
EXPECT_TRUE(time4 <= time4);
}
TEST(TimeTest, GreaterEquals) {
EXPECT_TRUE(time1 >= time1);
EXPECT_FALSE(time1 >= time2);
EXPECT_FALSE(time1 >= time3);
EXPECT_FALSE(time1 >= time4);
EXPECT_TRUE(time2 >= time1);
EXPECT_TRUE(time2 >= time2);
EXPECT_FALSE(time2 >= time3);
EXPECT_FALSE(time2 >= time4);
EXPECT_TRUE(time3 >= time1);
EXPECT_TRUE(time3 >= time2);
EXPECT_TRUE(time3 >= time3);
EXPECT_FALSE(time3 >= time4);
EXPECT_TRUE(time4 >= time1);
EXPECT_TRUE(time4 >= time2);
EXPECT_TRUE(time4 >= time3);
EXPECT_TRUE(time4 >= time4);
}
TEST(TimeTest, Equals) {
EXPECT_TRUE(time1 == time1);
EXPECT_FALSE(time1 == time2);
EXPECT_FALSE(time1 == time3);
EXPECT_FALSE(time1 == time4);
EXPECT_FALSE(time2 == time1);
EXPECT_TRUE(time2 == time2);
EXPECT_FALSE(time2 == time3);
EXPECT_FALSE(time2 == time4);
EXPECT_FALSE(time3 == time1);
EXPECT_FALSE(time3 == time2);
EXPECT_TRUE(time3 == time3);
EXPECT_FALSE(time3 == time4);
EXPECT_FALSE(time4 == time1);
EXPECT_FALSE(time4 == time2);
EXPECT_FALSE(time4 == time3);
EXPECT_TRUE(time4 == time4);
}
TEST(TimeTest, NotEquals) {
EXPECT_FALSE(time1 != time1);
EXPECT_TRUE(time1 != time2);
EXPECT_TRUE(time1 != time3);
EXPECT_TRUE(time1 != time4);
EXPECT_TRUE(time2 != time1);
EXPECT_FALSE(time2 != time2);
EXPECT_TRUE(time2 != time3);
EXPECT_TRUE(time2 != time4);
EXPECT_TRUE(time3 != time1);
EXPECT_TRUE(time3 != time2);
EXPECT_FALSE(time3 != time3);
EXPECT_TRUE(time3 != time4);
EXPECT_TRUE(time4 != time1);
EXPECT_TRUE(time4 != time2);
EXPECT_TRUE(time4 != time3);
EXPECT_FALSE(time4 != time4);
}