From e521c7506e18ae7df7973cee3f2ec41ccf8c3c2f Mon Sep 17 00:00:00 2001 From: Joel Rosdahl Date: Thu, 30 Jul 2020 13:03:24 +0200 Subject: [PATCH] Add Util::localtime, abstracting localtime_r --- cmake/GenerateConfigurationFile.cmake | 1 - cmake/config.h.in | 3 --- src/Util.cpp | 14 ++++++++++++++ src/Util.hpp | 5 +++++ src/ccache.cpp | 3 +-- src/hashutil.cpp | 23 ++++++++++------------- src/legacy_util.cpp | 17 ----------------- src/legacy_util.hpp | 3 --- src/logging.cpp | 7 ++++--- src/stats.cpp | 18 ++++++++++-------- 10 files changed, 44 insertions(+), 50 deletions(-) diff --git a/cmake/GenerateConfigurationFile.cmake b/cmake/GenerateConfigurationFile.cmake index 0ef550728..d16964876 100644 --- a/cmake/GenerateConfigurationFile.cmake +++ b/cmake/GenerateConfigurationFile.cmake @@ -23,7 +23,6 @@ set(functions getopt_long getpwuid gettimeofday - localtime_r mkstemp posix_fallocate realpath diff --git a/cmake/config.h.in b/cmake/config.h.in index 4eeecdd8b..34935e05f 100644 --- a/cmake/config.h.in +++ b/cmake/config.h.in @@ -75,9 +75,6 @@ /* Define to 1 if you have the header file. */ #cmakedefine HAVE_LINUX_FS_H -/* Define to 1 if you have the `localtime_r' function. */ -#cmakedefine HAVE_LOCALTIME_R - /* Define to 1 if the system has the type `long long'. */ #cmakedefine HAVE_LONG_LONG diff --git a/src/Util.cpp b/src/Util.cpp index 452104bb5..8678b1c62 100644 --- a/src/Util.cpp +++ b/src/Util.cpp @@ -57,6 +57,8 @@ # endif #endif +using nonstd::nullopt; +using nonstd::optional; using nonstd::string_view; namespace { @@ -720,6 +722,18 @@ is_precompiled_header(string_view path) || get_extension(dir_name(path)) == ".gch"; } +optional +localtime(optional time) +{ + time_t timestamp = time ? *time : ::time(nullptr); + tm result; + if (localtime_r(×tamp, &result)) { + return result; + } else { + return nullopt; + } +} + std::string make_relative_path(const Context& ctx, string_view path) { diff --git a/src/Util.hpp b/src/Util.hpp index c3485c5c8..0141f3fae 100644 --- a/src/Util.hpp +++ b/src/Util.hpp @@ -23,6 +23,7 @@ #include "CacheFile.hpp" #include "Config.hpp" +#include "third_party/nonstd/optional.hpp" #include "third_party/nonstd/string_view.hpp" #include @@ -269,6 +270,10 @@ is_dir_separator(char ch) // Headers" in GCC docs). bool is_precompiled_header(nonstd::string_view path); +// Thread-safe version of `localtime(3)`. If `time` is not specified the current +// time of day is used. +nonstd::optional localtime(nonstd::optional time = {}); + // Make a relative path from current working directory to `path` if `path` is // under the base directory. std::string make_relative_path(const Context& ctx, nonstd::string_view path); diff --git a/src/ccache.cpp b/src/ccache.cpp index e1e49cdc8..2ecc1f10a 100644 --- a/src/ccache.cpp +++ b/src/ccache.cpp @@ -1898,8 +1898,7 @@ static enum stats do_cache_compilation(Context& ctx, const char* const* argv); static int cache_compilation(int argc, const char* const* argv) { - // Needed for portability when using localtime_r. - tzset(); + tzset(); // Needed for localtime_r. auto ctx = std::make_unique(); SignalHandler signal_handler(*ctx); diff --git a/src/hashutil.cpp b/src/hashutil.cpp index 12f5761c8..f76ba7b8b 100644 --- a/src/hashutil.cpp +++ b/src/hashutil.cpp @@ -250,15 +250,14 @@ hash_source_code_string(const Context& ctx, // Make sure that the hash sum changes if the (potential) expansion of // __DATE__ changes. - time_t t = time(nullptr); - struct tm now; hash.hash_delimiter("date"); - if (!localtime_r(&t, &now)) { + auto now = Util::localtime(); + if (!now) { return HASH_SOURCE_CODE_ERROR; } - hash.hash(now.tm_year); - hash.hash(now.tm_mon); - hash.hash(now.tm_mday); + hash.hash(now->tm_year); + hash.hash(now->tm_mon); + hash.hash(now->tm_mday); } if (result & HASH_SOURCE_CODE_FOUND_TIME) { // We don't know for sure that the program actually uses the __TIME__ macro, @@ -278,18 +277,16 @@ hash_source_code_string(const Context& ctx, return HASH_SOURCE_CODE_ERROR; } - time_t t = stat.mtime(); - tm modified; - hash.hash_delimiter("timestamp"); - if (!localtime_r(&t, &modified)) { + auto modified_time = Util::localtime(stat.mtime()); + if (!modified_time) { return HASH_SOURCE_CODE_ERROR; } - + hash.hash_delimiter("timestamp"); #ifdef HAVE_ASCTIME_R char buffer[26]; - auto timestamp = asctime_r(&modified, buffer); + auto timestamp = asctime_r(&*modified_time, buffer); #else - auto timestamp = asctime(&modified); + auto timestamp = asctime(&*modified_time); #endif if (!timestamp) { return HASH_SOURCE_CODE_ERROR; diff --git a/src/legacy_util.cpp b/src/legacy_util.cpp index e77ee159e..ac5e0339c 100644 --- a/src/legacy_util.cpp +++ b/src/legacy_util.cpp @@ -34,23 +34,6 @@ # include #endif -#if !defined(_WIN32) && !defined(HAVE_LOCALTIME_R) -// localtime_r replacement. (Mingw-w64 has an inline localtime_r which is not -// detected by AC_CHECK_FUNCS.) -struct tm* -localtime_r(const time_t* timep, struct tm* result) -{ - struct tm* tm = localtime(timep); - if (tm) { - *result = *tm; - return result; - } else { - memset(result, 0, sizeof(*result)); - return NULL; - } -} -#endif - // Return current user's home directory, or throw FatalError if it can't be // determined. const char* diff --git a/src/legacy_util.hpp b/src/legacy_util.hpp index 89e0973af..1c37959c5 100644 --- a/src/legacy_util.hpp +++ b/src/legacy_util.hpp @@ -22,9 +22,6 @@ #include -#ifndef HAVE_LOCALTIME_R -struct tm* localtime_r(const time_t* timep, struct tm* result); -#endif const char* get_home_directory(); bool is_full_path(const char* path); void update_mtime(const char* path); diff --git a/src/logging.cpp b/src/logging.cpp index dc277ba07..d2b62b521 100644 --- a/src/logging.cpp +++ b/src/logging.cpp @@ -21,6 +21,7 @@ #include "Config.hpp" #include "File.hpp" +#include "Util.hpp" #include "exceptions.hpp" #include "execute.hpp" @@ -100,11 +101,11 @@ log_prefix(bool log_updated_time) #ifdef HAVE_GETTIMEOFDAY if (log_updated_time) { char timestamp[100]; - struct tm tm; struct timeval tv; gettimeofday(&tv, nullptr); - if (localtime_r((time_t*)&tv.tv_sec, &tm) != nullptr) { - strftime(timestamp, sizeof(timestamp), "%Y-%m-%dT%H:%M:%S", &tm); + auto tm = Util::localtime(tv.tv_sec); + if (tm) { + strftime(timestamp, sizeof(timestamp), "%Y-%m-%dT%H:%M:%S", &*tm); } else { snprintf(timestamp, sizeof(timestamp), "%lu", tv.tv_sec); } diff --git a/src/stats.cpp b/src/stats.cpp index dabc39ac2..c57aaa2f5 100644 --- a/src/stats.cpp +++ b/src/stats.cpp @@ -192,10 +192,11 @@ static std::string format_timestamp(uint64_t timestamp) { if (timestamp > 0) { - struct tm tm; - localtime_r(reinterpret_cast(×tamp), &tm); - char buffer[100]; - strftime(buffer, sizeof(buffer), "%c", &tm); + auto tm = Util::localtime(timestamp); + char buffer[100] = "?"; + if (tm) { + strftime(buffer, sizeof(buffer), "%c", &*tm); + } return std::string(" ") + buffer; } else { return {}; @@ -405,10 +406,11 @@ stats_summary(const Context& ctx) fmt::print("secondary config (readonly) {}\n", ctx.config.secondary_config_path()); if (last_updated > 0) { - struct tm tm; - localtime_r(&last_updated, &tm); - char timestamp[100]; - strftime(timestamp, sizeof(timestamp), "%c", &tm); + auto tm = Util::localtime(last_updated); + char timestamp[100] = "?"; + if (tm) { + strftime(timestamp, sizeof(timestamp), "%c", &*tm); + } fmt::print("stats updated {}\n", timestamp); } -- 2.47.3